Skip to content

feat(opportunity): REQ-0006 qualification, the customer calendar, narrative and approval on status change - #1950

Merged
objectstack-fleet[bot] merged 11 commits into
mainfrom
claude/issue-1916-opportunity-qualification-status-approval
Oct 3, 2026
Merged

objectstack-fleet[bot] merged 11 commits into
mainfrom
claude/issue-1916-opportunity-qualification-status-approval

Conversation

@os-elon-musk

@os-elon-musk os-elon-musk commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1916
Clause-②: no. The change is app metadata on crm_opportunity and adds one flow; it touches no published schema and no accept set.

REQ-0006 for crm_opportunity: the qualification block, the customer's procurement calendar, the deal narrative, a business line beside type, and an approval gate on the won/lost call that ships switched off. One changeset names REQ-0006 (.changeset/opportunity-qualification-and-status-approval.md, minor).

Every REQ-0006 acceptance line is delivered, with the evidence below. Every REQ-0006 field can be edited in the console, and pnpm verify is green on this branch at 5a67d080 (after #1953 raised the src/sales ceilings to 59,000 / 107,000).

What is on the branch

  • Qualification (new group): Will Bid, Controllability, Priority, Deal Level, Involves Subcontracting, Subcontracting Note. The values are generic.
  • Customer calendar (in Sales Process): Customer Initiation, Expected Tender and Expected Signing dates, plus the tender and signing amounts. None of them is folded into close_date.
  • Deal Narrative (new group): Customer Background, Project Background, Risk Analysis, Payment Terms. All four are Field.textarea (see Editing surface).
  • Business Line: a separate select beside type.
  • Tender This Quarter list view: it windows expected_tender_date and never reads close_date.
  • Status-change gate:

Acceptance, line by line

# REQ-0006 acceptance Evidence
1 The form renders a qualification group and a narrative group from fieldGroups alone Browser, 17.6.0, fresh boot of 8333d7ee (served page sections equal to the compiled artifact and to source). The Details tab renders Classification, Campaigns, Sales Process, Qualification, Deal Narrative, Forecast & Metrics, Notes & Next Steps on a seeded deal and on a deal with only its required fields. The page references { group } only; nothing is enumerated. On a fresh boot of 033ba581, Details edit mode gave each of the three narrative fields an editor; typed values were saved, read back over REST, and shown after reload.
2 Customer-side dates reportable without touching close_date Browser: Tender This Quarter opened on No Tenders Expected This Quarter. After one deal got tender date = today and close date = a year out, it listed exactly that deal. The filter names expected_tender_date only.
3 Gate on: won/lost opens an approval and the stage waits; gate off: amount-tiered behaviour unchanged Gate on, 17.6.0, armed by flipping the default in a local, never-pushed copy: a new deal was born Pending. A direct close got 409 RECORD_LOCKED and the stage did not move. Requesting closed_won opened one flow:opportunity_status_change_approval request while the stage stayed negotiation. Approve moved the stage to closed_won with the verdict approved. Reject cleared the request and kept the stage; a direct close was still refused, and a re-request opened a fresh approval. Gate off, fresh boot of this branch: a direct close of a $5,000 deal succeeded, the verdict stayed not_required, and zero approval requests existed. A deal raised to $150,000 opened its usual flow:opportunity_approval request, and the new column stayed not_required. opportunity-approval.flow.ts is unchanged.
4 A writer with no session still engages the gate test/opportunity-status-change-approval-gate.test.ts: fired with no trigger user, the flow passes get_opportunity and stops only at the approval node (the harness ships no approval executor). With runAs stripped, it fails at get_opportunity with the engine's [runAs] refusal.
5 No signing-entity or revenue-recognition field; business line generic Neither field exists. business_line ships Product, Professional Services, Consulting, Support & Maintenance and Other.
6 pnpm verify green, and a changeset naming REQ-0006 os-verify-lock: VERDICT command-exit 0 on this branch at 5a67d080 (see Verification). The changeset .changeset/opportunity-qualification-and-status-approval.md names REQ-0006.

Editing surface (measured, 17.6.0)

  • Details tab, pencil: puts the whole tab into an edit mode with a Save bar. Every new select, boolean, date, currency and textarea field is editable there (saved, then read back over REST). Markdown fields get no editor.
    • So Customer Background, Project Background and Risk Analysis moved from Field.markdown to Field.textarea (033ba581). That is the same declaration payment_terms uses, and one of the two types REQ-0006 names. The maintainer ruled it on 2026-10-03: 「改成 textarea(推荐)」.
    • All three now take input there; the probe values were saved and read back identical.
    • The object's own description stays markdown. It is outside this card and still has no editor in that mode.
  • Edit / New dialog (the view's tabbed form): renders no tab for a { group } section. The same is true of the contact form's REQ-0004 buying centre on main. A markdown field that a form names does get an editor (the account dialog's Description).
  • This branch keeps { group: 'qualification' } and { group: 'narrative' } in the form. That is rung 2, like the contact precedent. They wait for the renderer, and they are not routed around.
  • The customer calendar is named on the form's Forecast tab, with its reason written beside it. tender_this_quarter filters on expected_tender_date, and test/metadata-references.test.ts requires a filtered field to be authorable in a form.
  • ea40e43a also named Business Line and Requested Status on the form. 3a907d2e took them out again: Details edit mode covers both, and the ruling on this card refused per-field enumeration.

hideEmpty on the two new page sections

Both are hideEmpty: false, for the reason #1211 gives in PR #1991. Every member is something the seller is expected to write, none of them is in the highlights strip, and no deal that predates REQ-0006 carries any of them. Without the key, both sections would vanish on exactly the deals where a seller needs to fill them in.

Three defects fixed in the gate as built

Each was found by reading the gate against its siblings, pinned by the new runtime file, and ablated (every ablation went red in the direction decided beforehand, and each restore was proven to equal HEAD):

  • A rejected deal was ungated. Only pending refused a direct close, so one rejection disarmed the gate for good. rejected now refuses too (as lead_automation does), and the flow re-opens from rejected on a new request. Ablation: 1 of 28 red, the "refused by an approver" case.
  • The start condition tested the current value, not the transition. The fix requires a new requested_status on the write, guarded fail-closed, as billing_handoff_closed_won does. Ablation: 2 of 28 red.
    • Measured live, with the term deleted and the gate armed: one re-entry per request, caught only by the engine's self-trigger guard. With the term in place: no re-entry.
    • 92f90e28 said the second run "died on DUPLICATE_REQUEST". That was inferred, not measured, and 8333d7ee corrects the comment.
  • The refusal code was APPROVAL_REQUIRED, which is not a platform ErrorCode. It is now RECORD_LOCKED / 409, the declared locked class. The hand-maintained refusal count goes from 20 to 21. Ablation: 4 red across the gate file and refusal-envelope.

Also in this round

  • Merge of main (25cd8d78). docs/STATUS.md was recomputed from the merged tree's own pnpm validate: 18 Objects, 361 Fields, 31 Flows (main retired demo_bootstrap). One semantic conflict was resolved in the merge: the two new currency fields dropped scale, which 17.6.0 refuses outright (fix(objects): drop scale from every currency field — objectstack main refuses it #1968).
  • The four locale packs: every field and option label, the view label and empty state, and the two section headings. lint:i18n-gate reads 0.
  • Docs. New pages sales/opportunity-qualification{,.zh-Hans,.zh-Hant}.mdx. The automation pages get the new row, a 31 count and an Approvals paragraph. opportunities{,…}.mdx get the view row and section, the new groups and fields, and the Details tab described as the object's groups (the old "three sections, seven fields" sentence has been untrue since feat(record-pages): Details tabs reference the objects' fieldGroups (lead, opportunity, case) #1990). README now says 31 flows.
  • Changeset: unchanged; the page change keeps it accurate.
  • The nine red classes in comment 5695722225 are closed here, all but the ratchet (that one is chore(ratchet): raise the two src/sales token ceilings to their anchor() (59,000 / 107,000) #1953): locale packs, automation docs, view rosters, the refusal sweep count, runtime coverage, metadata-references, docs metadata counts and lint:i18n-gate. The refusal count was edited by hand (20 to 21) and stays hand-maintained, as that comment requires. No guard was skipped, disabled or loosened.

Token ratchet (src/sales)

scope main 25cd8d7 (before #1953) this branch 5a67d08 ceiling on main since #1953
business semantics 53,433 55,279 59,000 (headroom 3,721)
interaction layer 27,646 27,996 31,000
authored total 96,558 98,761 107,000 (headroom 8,239)

History: this PR started as a measurement. On 85e5dbd, against 087b7c5, it read 55,986 / 55,000 and 101,395 / 100,000, and #1951 ruling A answered it with 59,000 / 107,000 (PR #1953). No ceiling is raised here, no prose was compressed, and nothing was moved into an unmetered directory.

Verification

Acceptance notes

Body rewritten 2026-10-03T05:06Z, after #1953 landed and this branch verified green at 5a67d080. It receipts PR comments 5695540995, 5695672077 and 5695722225.


Generated by Claude Code

…rative and approval on status change (REQ-0006)

Eighteen new fields on `crm_opportunity`, two new derived `fieldGroups`
sections, one new list view and one new approval flow — REQ-0006's B
items, the `crm_opportunity` half of REQ-0002 steps 8 through 14.

Qualification: will_bid, controllability, priority, deal_level,
is_subcontracted and its note. The customer's own procurement calendar:
customer_initiation_date, expected_tender_date, expected_signing_date and
the two amounts — never folded into `close_date`, which is a single date
and is OUR forecast close. Deal narrative: customer_background,
project_background, risk_analysis, payment_terms. business_line sits
BESIDE `type` and does not overload it. Signing entity and
revenue-recognition type get no field at all, by REQ-0006 acceptance 5.

Layout stays DERIVED: every field opts in with `group:` and no
`record:details` section or `form.sections` entry is authored, so
`pnpm validate` reports the data-entry fields as carrier-only. That
reading is expected, not a defect, and the reason is recorded beside the
block — the same verdict `crm_account`'s business-profile fields carry.

The status-change gate is an `approval` node in a new record-change flow,
and it SHIPS OFF: the switch is `status_change_approval_status`'s
`defaultValue`, shipped `not_required`, so its start condition is false
for every record that has ever existed and amount-tiered approval is
bit-for-bit what it is today. Not the flow's `status` — `draft` still
fires triggers and `obsolete` composes into a gate no install can turn
on, both measured and recorded on the lead-conversion sibling.

Because a record-change flow binds an AFTER hook, the rep writes a
REQUEST (`requested_status`) and the approved decision writes `stage`,
which is what acceptance 3's "the stage does not change until it is
decided" requires. A transition gate in `opportunity.hook.ts` refuses a
direct user move into a closed stage while the gate is armed; it reads
the gate column input-first so the approving flow's own single-payload
write passes.

NOT LANDABLE AS IT STANDS: this exceeds the `src/sales` token ratchet —
business semantics ~55,986 vs ~55,000 (over by ~986) and authored total
~101,395 vs ~100,000 (over by ~1,395). The tree is the measurement basis
for that gap and awaits a maintainer ceiling ruling.

Claude-Session: https://claude.ai/code/session_01T3YsvpK1PvYf9n1YUhYP6W

Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Oct 3, 2026 4:57am UTC

Request Review

Copy link
Copy Markdown
Collaborator Author

PM 说明:这两道红是预期的,⛔ 本 PR 不由施工席修,也 ⛔ 不重跑 CI

头 85e5dbd · 红的两道:Quality Checks、Build and Test (22.x)。PM 在本地逐条复现,成因只有两个:

① hygiene:tokens —— 本 PR 的阻塞物本身

✗ source token ratchet failed: 2 scope(s) over ceiling
  ✗ src/sales business semantics ~55,986 / 55,000  (超 986)
  ✗ src/sales authored total    ~101,395 / 100,000 (超 1,395)

同因连带 test/source-token-ratchet.test.ts 40 条里红 1 条。

这不是缺陷,是本 PR 的交付物。 本 PR 的目的就是把 REQ-0006 的完整实现写出来并量准,让缺口成为实测数字而不是推算。⛔ 抬天花板需要维护者裁决(scripts/check-source-token-ratchet.mjs 第 132-137 行),⛔ 不是施工席或 PM 能做的。

② lint:i18n-gate —— 132 条 i18n/missing-*,刻意未做

四个语言包故意没有编写。理由成立且 PM 采纳:语言包 ⛔ 不计入棘轮(src/sales/translations 是明文 EXCLUDED),而字段名册正是天花板裁决最可能改动的东西 ⇒ 现在写四份译文,裁决一改就得重写。

裁决在哪

决策卡 #1951(needs-user-decision · pm:blocking · p1)。四条路连同实测代价都在上面,含一条 #1928 时不存在的新选项。

⚠️ 顺带纠一处:57,000 / 103,000 这组数不符合 #1928 确立的 5% 缓冲规则(57,000 对 55,986 只有 1.8%)。按同一条 anchor() 应是 59,000 / 107,000。已写进 #1951。

PM 的处置


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

⚠️ 更正上一条:我写的「成因只有两个」是错的

上一条评论我写「PM 在本地逐条复现,成因只有两个」。那句话不成立。 我当时只复现了 hygiene:tokens 与 lint:i18n-gate 就下了结论 —— 那是定向子集,不是全量。

完整跑一次 pnpm test(本分支 85e5dbd,exit 1):

Test Files  9 failed | 163 passed (172)
Tests      23 failed | 3667 passed | 1 skipped (3691)

准确清单(9 个文件 / 23 条)

文件 红 类别
test/i18n-references.test.ts 6 四语言包未编写
test/automation-docs-coverage.test.ts 5 新流程未进 content/docs/administration/automation.{mdx,zh-Hans,zh-Hant}
test/docs-view-rosters.test.ts 4 新视图 tender_this_quarter 未进文档名册
test/refusal-envelope.test.ts 3 新拒绝点未进那份手维护的清扫计数
test/source-token-ratchet.test.ts 1 阻塞物本身
test/lint-i18n-gate.test.ts 1 同四语言包
test/runtime-coverage.test.ts 1 新流程/hook 无运行时测试命名
test/metadata-references.test.ts 1 同上游
test/docs-metadata-counts.test.ts 1 文档所述计数与注册数不符

这改变了什么、没改变什么

⛔ 没改变:阻塞判断与缺口数字。上面 9 类里只有 source-token-ratchet 一条是计量面内的;其余八类动的全是 src/*/translations、content/docs/、test/ 与文档名册 —— 按裁决与按路径都不计入棘轮。⇒ business semantics 超 986、authored total 超 1,395,一个字不动。

改变了:裁决之后的收尾工作量。我上一条让人以为「裁完只剩四个语言包」,实际是四语言包 + 三处文档页 + 视图名册 + 拒绝清扫计数 + 运行时测试命名。这条我先前说少了。

责任在我,⛔ 不在施工席

施工席的报告明写「NOT MEASURED: full pnpm verify and CI, since hygiene:tokens fails inside it by construction」,并只声称「9 files / 314 tests 的定向子集里 2 条红」。它没有宣称全量绿。 是我把定向子集的结果当成了全量结论。

处置不变


Generated by Claude Code

os-elon-musk pushed a commit that referenced this pull request Sep 18, 2026
`business semantics` 55,000 -> 59,000 and `authored total` 100,000 -> 107,000
in `scripts/check-source-token-ratchet.mjs`. Both are `anchor()` — the ruled
`ceil(reading x 1.05 / 1000) x 1000` — of the readings PR #1950's tree prints
(55,986 and 101,395), so the kind stays ANCHORED and the 5% working buffer is
the whole of the raise. The maintainer ruling authorising it is quoted in the
gate's own header and in the PR body, which is the condition the gate states
for raising an anchored ceiling.

The reading those two rows anchor from is not one `origin/main` prints, so the
recorded anchoring run names the tree it was taken on (`refs/pull/1950/head` at
85e5dbd) — the format this header already uses for a run that cannot be taken
on `main`. Nine of the twelve worked rows re-anchor onto that run; the three
whose `anchor()` now lands above the ceiling they carry keep their 2026-09-16
row and are recorded as declined re-anchorings, which is what keeps the
header's ledger self-consistent and `test/source-token-ratchet.test.ts` green.

No other ceiling moves, and nothing under `src/` is touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3YsvpK1PvYf9n1YUhYP6W
This was referenced Oct 2, 2026
claude added 3 commits October 3, 2026 03:30
Conflict: docs/STATUS.md, resolved by recomputing from the merged tree's
own `pnpm validate` rather than by picking a side: main retired the
demo_bootstrap flow (30 Flows) and this branch adds
opportunity_status_change_approval, so the merged stack registers
18 Objects / 361 Fields / 31 Flows.

Semantic conflict, resolved in this merge: main dropped `scale` from every
currency field (#1968) and the 17.6.0 pin now refuses the key outright
("`scale` is not valid on a `currency` field — delete the key"). The two
currency fields this branch adds, expected_tender_amount and
expected_signing_amount, carried `scale: 2`; it is removed so the merged
tree validates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…ion and narrative groups

Since #1990 every Details section is a `{ group }` reference to one of
crm_opportunity's fieldGroups, so a group the object declares renders on
the record page only once the page names it. The two groups REQ-0006
adds are referenced right after `sales_process`, in the order the object
declares them, and both keep `hideEmpty: false` on #1211's reasoning:
every member is something the seller is expected to fill in, and no deal
that predates REQ-0006 carries any of them, so the platform default would
hide both sections on every existing deal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…ns once per request, and refuses with a declared code

Three defects in the REQ-0006 gate as built, each found by reading it
against its siblings and pinned by a new runtime file:

- A rejected deal was ungated. The hook refused a direct close only while
  the verdict read `pending`, and the flow re-opened only from `pending`,
  so one rejection disarmed the gate on that deal for good: the rep could
  close it straight away with no approval. `rejected` now refuses too
  (as `lead_automation` refuses a conversion in both states) and a new
  request from `rejected` opens a fresh approval.
- The start condition tested the current value, not the transition. The
  approval node's own `pending` stamp is an update of the deal while the
  request is open, so it re-fired the flow and the second run died on the
  plugin's DUPLICATE_REQUEST guard. The condition now requires the request
  to be new on the write (`previous.requested_status` differs, guarded
  fail-closed), the idiom `billing_handoff_closed_won` records.
- The refusal carried `APPROVAL_REQUIRED`, which is no member of the
  platform ErrorCode enum, so the platform would have demoted it and
  derived the code from the status. It is now `RECORD_LOCKED` / 409, the
  declared `locked` class the lead gate uses; the hand-maintained refusal
  site count moves 20 -> 21.

test/opportunity-status-change-approval-gate.test.ts: the shipped-OFF
default, the start condition over every OFF and ARMED shape, both
approval branches, the write-path refusal envelope, and the user-less run
reaching the approval node (with the runAs counter-proof). Registered in
runtime-coverage's RUNTIME_TEST_FILES.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
@github-actions github-actions Bot added the ci/cd CI plumbing and the verification pipeline label Oct 3, 2026
claude added 6 commits October 3, 2026 03:46
…r locale packs; the form offers the customer calendar

The four `objects.pipeline.ts` packs (en, zh-CN, es-ES, ja-JP) gain every
REQ-0006 field label and option label, `will_bid`'s help text, the
`tender_this_quarter` view label and empty state, and the `qualification`
and `narrative` section headings. They were left out of the measurement
build on purpose until the ceiling ruling settled the field roster (#1951
ruling A); `pnpm lint:i18n-gate` now reads 0 `i18n/missing-*` issues.

opportunity.view.ts: the `forecast` form section names the customer's
procurement calendar (initiation, tender and signing dates and amounts).
`tender_this_quarter` filters on `expected_tender_date`, and a filtered
field that no form offers is a list view that can never match a deal a
rep created through the UI (`test/metadata-references.test.ts`). The
reason a `{ group: 'sales_process' }` reference cannot stand in is
written beside the fields (AGENTS.md ladder rung 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…tive and status-change gate, for reps and admins

- content/docs/sales/opportunity-qualification{,.zh-Hans,.zh-Hant}.mdx:
  the user-facing page REQ-0006's product response asks for — whether a
  deal is worth pursuing, the customer's procurement calendar against our
  close date, the deal narrative, the business line, and the optional
  sign-off on a won/lost call (off by default; how a request, approval
  and rejection play out; how an admin arms it). Business concepts, not a
  field roster. Registered in the three sales meta files.
- content/docs/administration/automation{,.zh-Hans,.zh-Hant}.mdx: the
  Opportunity Status Change Approval row, the header count 30 -> 31, and
  a paragraph under Approvals; the ledger in
  test/automation-docs-coverage.test.ts gains its two Chinese row labels.
- content/docs/sales/opportunities{,.zh-Hans,.zh-Hant}.mdx: the Tender This
  Quarter row and section (ten saved views), the two new field groups and
  the new fields in the field-group table, the customer calendar on the
  form's Forecast tab, and the Details tab described as the object's
  groups — it has been a list of `{ group }` references since #1990, so
  "three sections holding seven fields" was already untrue and this
  branch's two new sections would have made it more so. The zh-Hant name
  is pinned in test/docs-view-rosters.test.ts.
- README.md: 30 -> 31 flows, the count the stack registers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…line and request are editable

Measured on a fresh 17.6.0 boot of this branch: the record page's Details
tab draws the Qualification and Deal Narrative groups READ-ONLY (no inline
edit), and the Edit / New dialog is opportunity.view.ts's tabbed form,
which authors `sections` and therefore wins outright over the fieldGroups
derivation. So twelve of the eighteen REQ-0006 fields - the qualification
block, the narrative block, Business Line and Requested Status - rendered
but had no editing surface anywhere in the app, and with the gate armed a
rep could not raise a status-change request at all.

- `{ group: 'qualification' }` and `{ group: 'narrative' }` tabs: AGENTS.md
  ladder rung 2, exactly as contact.view.ts renders REQ-0004's buying
  centre. Nothing is enumerated; members, labels and icons come from the
  object, so REQ-0006 acceptance 1 holds on the form from fieldGroups alone.
- `business_line` beside `type` on the Forecast tab, and `requested_status`
  at the head of Win / Loss, visible only while the gate holds the deal
  (pending or rejected): rung 3, each with its reason written beside it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
… fields; correct ea40e43's reading

ea40e43's message says the Details tab draws the REQ-0006 groups
read-only. That reading was wrong: my probe missed the pencil. Re-measured
on the same 17.6.0 boot, the pencil puts the whole Details tab into an edit
mode with a Save bar. It edits every select, boolean, date, currency and
textarea field, so the qualification block, the customer calendar,
Business Line, Payment Terms and Requested Status can all be edited there
(saved and read back through REST). It offers no editor for a MARKDOWN
field, though: Customer Background, Project Background and Risk Analysis
stay read-only, and so does the object's own `description`.

The same boot also shows the tabbed Edit / New dialog renders no tab for a
`{ group }` section. That holds for the two references ea40e43 added and
for the contact form's REQ-0004 buying centre on `main`. A markdown field
the form NAMES does get an editor (the account dialog's Description).

So:
- `business_line` and `requested_status` come out of the form again.
  Details edit mode covers them, and per-field enumeration was the
  escape hatch the ruling on this card refused.
- `{ group: 'qualification' }` / `{ group: 'narrative' }` stay. They are
  the contract-correct rung-2 form, the same as the contact precedent, and
  they wait for the platform to render group sections in a tabbed form.
  They are not routed around (AGENTS.md: a platform defect is waited for).
  The note beside them now records what renders on 17.6.0 and what does not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…sured rather than as read

92f90e2 said that without the transition term the approval node's own
`pending` stamp re-fired the flow "and the second run died on the plugin's
DUPLICATE_REQUEST guard". The re-fire is real; the effect was inferred from
the plugin source and was wrong. Measured on a 17.6.0 boot with the gate
armed and the term deleted (local only, restored): one re-entry per request,
each caught by the engine's self-trigger guard, which warns that "the guard
as authored does not exclude the flow's own write-back"; no
DUPLICATE_REQUEST. With the term in place the same scenario logs no
re-entry at all. The flow and test comments now say that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…tails tab can write them

Customer Background, Project Background and Risk Analysis move from
Field.markdown to Field.textarea, the same declaration `payment_terms`
already uses (label and group, nothing else). REQ-0006's product response
names "Field.markdown / Field.textarea per field".

Measured on the 17.6.0 console: the Details tab's edit mode is the only
surface the narrative group renders on, since the tabbed Edit dialog draws
no `{ group }` section. That edit mode gives every textarea an editor and
offers none for a markdown field, so the three were readable but could
never be written. The maintainer ruled the textarea option on #1950
(2026-10-03, 「改成 textarea(推荐)」). The object's own `description` stays
markdown; it is outside this card.

The note above the narrative block records the reason, and the form's
group-reference note no longer calls these fields unwritable. No label,
translation, docs page or changeset text named their type, so nothing else
changes. Token reading unchanged (both type names are eight characters).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
… raise, #1994, #1963

No conflicts. #1953 raises the src/sales ceilings to 59,000 / 107,000, the
ruled answer to this branch's measurement. #1994 (tenant_admin profile) and
#1963 (tsx bump, pnpm-lock.yaml) do not touch this branch's file surface.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
@objectstack-fleet objectstack-fleet Bot changed the title feat(opportunity): REQ-0006 qualification, the customer calendar, narrative and approval on status change — BLOCKED on the src/sales token ceiling feat(opportunity): REQ-0006 qualification, the customer calendar, narrative and approval on status change Oct 3, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 3, 2026 05:09
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 4e072fd Oct 3, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Server-side behaviour — hooks, flows, actions ci/cd CI plumbing and the verification pipeline configuration Build and app configuration files documentation Improvements or additions to documentation metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Track A · crm_opportunity: the qualification group, milestone dates, subcontracting, narrative, and approval on STATUS CHANGE — REQ-0006

3 participants