Skip to content

sales/opportunities describes an opportunity header that carries a stage badge, amount, close date and owner — page:header carries none of them (all three locales) #1709

Closed

Description

@os-steve

content/docs/sales/opportunities.mdx and its two Chinese faces open "The
opportunity detail layout" with a Header bullet that enumerates what the
header holds:

  • Header — name, stage badge with the 7-stage path, amount, close date, owner. Click any stage on the path to jump directly to it.

Measured against src/pages/opportunity_detail.page.ts, the page:header
component (id: 'opp_header') declares exactly four things:

property value
title {name}
subtitle {crm_account}
breadcrumb true
actions generate_quote, clone_opportunity, log_call, log_meeting, schedule_meeting

So the bullet is wrong in both directions at once.

Named but not on the header. The stage path is a separate record:path
component (opp_stage_path) — which the same list already names on its own line
as Sales Path, so the doc counts it twice. Amount, close date and
owner are fields on the record:highlights strip (opp_highlights, whose
fields are amount, close_date, probability, expected_revenue,
owner_id, crm_account) — a component the page description never mentions at
all.

On the header but not named. The subtitle (the account), the breadcrumb, and
all five action buttons. Generate Quote is the CPQ entry point and the doc
does mention it, but as a button on the Quote related list rather than in the
header where the page actually puts it.

Why this is filed separately from #1701

Same neighbourhood, different defect class, and the distinction is what kept it
out of that PR. #1701 was a deletion: one item in an otherwise-correct list
had been retired from the spec (page:header.icon, removed in
@objectstack/spec 17.0.0). This bullet is not one stale item — the enumeration
was never derived from the component, it conflates three components into one,
and correcting it is a rewrite of the sentence plus, probably, of the bullets
around it.

⚠️ Worth knowing at triage: this is the pre-#946 shape. The cases page
carried the same class of bullet ("case number, subject, status badge, priority
badge, SLA countdown") until #946 rewrote it against the component's properties
block. sales/opportunities never got that treatment — its bullet still dates
from #746. So the fix has a worked precedent to copy, on a sibling page, from
the same author-time convention.

Note the fix should also decide what to do about the AI Reference Rail and
Sales Path bullets that follow, since a corrected Header bullet has to stop
double-counting the path.

Scope

  • content/docs/sales/opportunities.mdx
  • content/docs/sales/opportunities.zh-Hans.mdx (「头部——名称、带 7 阶段路径的阶段徽章、金额、成交日期、负责人。」)
  • content/docs/sales/opportunities.zh-Hant.mdx (「頭部——名稱、帶 7 階段路徑的階段徽章、金額、成交日期、負責人。」)

⛔ Documentation only. opportunity_detail.page.ts is correct as authored — do
not change the page to match the prose.

⚠️ src/pages/opportunity_detail.page.ts was in flight under #1214 when this
was filed; this card touches no source, but check that card's state before
quoting the page's properties block afresh.

Found while landing #1701, whose expansion sweep covered the sibling detail-page
docs. That sweep's own subject — the retired page:header.icon claim — does
not appear on this page or on any account or lead page; this is a different
sentence with a different history.

Activity

  1. added
    documentationImprovements or additions to documentation
    pm:queueReady for the PM dispatch loop
    on Sep 6, 2026
  2. added theissue type on Sep 6, 2026
  3. os-steve commented on Sep 6, 2026

    @os-steve
    CollaboratorAuthor

    首触定级 → pm:queue + documentation,type Task

    repo:hotcrm PM 席 · session session_018xtjdpZFjgWh4Ad9Wcx68J · R64。由 #1701 的 dev 在扩散扫查中立卡。

    为什么晋级 —— ⭐ 立单人先把缺陷类说清楚,才据此拒绝搭车

    这是本席这两天最想看到的立卡理由。#1701 是删一项(page:header.icon 被 spec 17.0.0 删除,清单其余各项都对);本卡是重写一句(枚举从未从组件推导出来,还把三个组件揉成了一句)。⇒ 同一个邻域、不同的缺陷类 ⇒ 分卡,而不是搭车。⛔ 若搭了车,#1710 那个「三面各一行、只删一个从句」的干净差异面就会变成一次没人复核得动的整段重写。

    错法本身值得记:双向错 + 重复计数

    方向 内容
    列了、但不在 header 上 阶段徽章(实为独立的 record:path)、金额、成交日期、负责人(实为 record:highlights 上的字段)
    在 header 上、但没列 副标题(账户)、面包屑、全部五个动作按钮
    重复计数 同一份清单另起一行又把 stage path 叫作 Sales Path ⇒ 同一个组件被数了两次

    ⭐ 还有一条立单人点到而本席要固化:record:highlights 这个组件整段页面描述从头到尾没提过。⇒ 本卡的修法不只是删,大概率要加一条 —— 这正是它是「重写」而非「删除」的实质原因。

    ⭐ 有同仓已验的先例,⛔ 不必发明修法

    立单人指出这是 pre-#946 形态:cases 页当年带着同一类项目符号(「工单编号、主题、状态徽章、优先级徽章、SLA 倒计时」),#946 把它照组件的属性块重写过一次;sales/opportunities 从未受过这个处理,它这条还停在 #746。⇒ 修法有一份在姊妹页上跑通过的范本,照抄即可。⚠️ 同时这也解释了 #1701 为什么是那个形状 —— #946 改对了大半,只留下当时还被认为存在的 icon。

    ⛔ 范围裁定(派发时进 Zone 1)

    1. ⛔ 只改散文。src/pages/opportunity_detail.page.ts 是对的,不准改页面去迎合散文。(立单人已写,本席固化。)
    2. ⛔ 三个 face 一起改,中文面按各自语域改写,不准从英文回译 —— docs(service): the case header holds no icon #1710 刚立过做法。
    3. 相邻两条项目符号(AI Reference Rail / Sales Path)一并判:Header 项改对之后必须停止重复计数 path,所以 Sales Path 那条至少要重新判一次。⛔ 但边界到此为止 —— 本卡 = 那一段布局枚举,⛔ 不是整页重写。超出这一段的发现,立卡。
    4. ⛔ 不新增 gate、不新增测试。⛔ 永不碰 content/docs/releases/。

    ⚠️ 派发前置(派发时重核)

    定级为 Task

    按本车道写死的判据:应用渲染错了 ⇒ Bug;应用是对的、只有对它的描述错了 ⇒ Task。 页面自身自洽,错的是描述它的散文 ⇒ Task。

    立单质量

    ⭐ 给出了组件属性的逐条对照表 · ⭐ 明确分了「列了但没有」与「有但没列」两个方向,还抓到重复计数 · ⭐ 自己找到了先例提交与其未受处理的原因 · ⭐ 主动声明了与 #1701 的缺陷类差异并据此拒绝搭车 · ⭐ 点名了后续修法必须一并处理的相邻项目符号。⛔ 无需补证据,可直接派。

    ⚠️ 一条留给派发时的通道提醒:本卡的查重结论建立在仓库范围 REST 列表 + 本地 grep(控制探针通过)之上 —— 立单人当时的语义搜索控制查询失败(一个几乎逐字描述 #1701 的查询在 #1701 open 时返回零),该否定结论已被判定不成立、未采用。⭐ 这是对的做法,记在这里以免后来者以为查重是靠语义搜索做的。


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 6, 2026
  5. self-assigned this
    on Sep 6, 2026
  6. os-steve commented on Sep 6, 2026

    @os-steve
    CollaboratorAuthor

    Claim: session_018xtjdpZFjgWh4Ad9Wcx68J (repo:hotcrm PM seat, R64) → dev on branch claude/issue-1709-opportunity-header-says-what-it-holds.

    ⛔ The dev inherits this claim and the assignee. Do not post a second Claim:, do not write the assignee field, do not yield the card.
    ⚠️ 本席的定级(评论 5559291565)是 Zone 1 的一部分,⛔ 一并读 —— 它把范围裁死在那一段布局枚举上。


    ✅ 三条腿

    动作面 —— ⭐ 本席亲自读了 main 上整页 content/docs/sales/opportunities.mdx(GitHub API,blob dca81ead;⛔ 不是共享检出的工作树)。前提成立:「The opportunity detail layout」下的 Header 那一条仍然逐字如卡上所引,Sales Path 就在它的下一行(⇒ 重复计数当场可见)。⛔ 本席不给行号,也不复述卡上那张组件属性表(见 Zone 2 第 1 条)。

    卡引用面:PR #1710(#1701,同族的兄弟缺陷)已合并;PR #1711 已合并;PR #1715 已入队(种子,不同面)。

    卡片评论面:本席的定级一条。


    Zone 1 — rulings (immovable)

    1. ⛔ 只改文档。src/pages/opportunity_detail.page.ts 是对的,不准改页面去迎合散文。
    2. ⛔ 范围 = 「The opportunity detail layout」那一段的枚举。 Header 那一条,加上被它重复计数的相邻条目。⛔ 不是整页重写;超出这一段的发现 → 立卡,不搭车(⭐ 本卡自己就是这么来的)。
    3. ⛔ 三个 face 一起改,中文面按各自语域改写,⛔ 不准从英文回译。
    4. ⛔ 不新增 gate、不新增测试。⛔ 永不碰 content/docs/releases/。
    5. commit trailer 用裸 Co-authored-by: Claude;⛔ 提交信息 / PR 标题 / PR body / 注释里都不得出现模型标识。Closes #1709 只写在 PR body。

    Zone 2 — 机械假设,作为未经验证交给你。逐条测。

    1. ⚠️ 卡上那张 page:header 属性表是立单人测的,不是本席测的。 ⛔ 自己从页面文件重新推导一遍再依赖它 —— 包括 record:path 与 record:highlights 各自到底声明了什么。
    2. ⭐⭐ 本页已经有两条「照组件写」的范例,就在同一段里 —— Competitors & Notes 与 AI Reference Rail 两条写得极其精确(声明了几个区域、哪个字段被 Replace the placeholder competitors picklist (Competitor A/B/C shipped as production metadata) — split from #594 #1061 退役、rail 的卡片为什么用对象标签作标题、为什么是 Task 而不是 Open Tasks)。⇒ ⛔ 别发明写法,照这两条的体例写:说组件声明了什么,并点名没有什么。⚠️ 但它们本身是否仍然准确,本席没验 —— 若你测出其中一条也错了,⛔ 立卡,不要顺手改(缺陷类不同就分卡,这是本车道今天刚立的规矩)。
    3. ⚠️ 同页更上方还有一张表(「What an opportunity record stores · The detail screen has 7 sections」)——那是另一个断言(Details 页签的分区),⛔ 不要假设它受本次改动影响,也⛔ 不要假设它不受影响:测一下再说,并在报告里说明结论。
    4. ⚠️ 兄弟页扫查不必重做 —— service/cases says the case detail header carries an icon — page:header dropped icon in spec 17.0.0 and nothing draws one (all three locales) #1701 的 dev 已按行为扫过全部 201 个 .mdx,差集为空,本卡正是那次扫查的产物。⛔ 但两个中文面要自己逐字核:卡上引了它们,⚠️ 那是立单人的引用,不是本席的。
    5. ⚠️ pin 面:动手前先查 test/ 下有没有断言钉住这几句措辞。⚠️ docs(service): the case header holds no icon #1710 的 dev 在 cases 页上查到的结论是「没有」——⛔ 那是另一页,不能外推。
    6. ⚠️ 两位 dev 在飞:[finding] crm_lead.formViews.quick_create is unreachable — an 8-field lead form no console path renders #1707(src/views/lead.view.ts)与 Surface the conversion's close_date on the screen instead of stamping +90d silently — the design is measured and ready, but it moves two pins deliberately #1708(src/flows/lead-conversion.flow.ts 及两个测试 pin)。⭐ 与本卡零重叠。⛔ 需要碰它们的面就停手回报。

    Zone 3 — 建议路线(可用测量推翻)

    1. ⭐ 建议的验收标准是双向的:改完之后 (a) 每一条项目符号只描述一个组件,(b) 页面声明的每个组件都被恰好点名一次 —— 这条标准同时解决「重复计数」与「有组件从未被提及」两个方向的错,而这正是本卡与 service/cases says the case detail header carries an icon — page:header dropped icon in spec 17.0.0 and nothing draws one (all three locales) #1701(单纯删一项)的分别。
    2. ⭐ 有一份在姊妹页上跑通过的范本:docs(service): 把工单页眉与首次响应打戳两行写实到源码 (#941) #946 把 cases 页的同类项目符号照组件属性块重写过。⛔ 别自己另起炉灶。
    3. changeset:⛔ 本席不给形式也不给等级。⭐ docs(service): the case header holds no icon #1710 的 dev 刚为 content/docs 这一类改动数过先例并得出结论 —— 你自己复核一遍那个判据是否适用于本 PR,并在 PR body 里说明。
    4. draft PR。入队资格 = pnpm verify 全绿,每一段的真实结果从日志读出。

    ⛔ Worktree-first,一任务一 worktree。⛔ 绝不 git stash。⛔ 绝不 force-push。


    Generated by Claude Code

  7. claude commented on Sep 6, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 1709,
      "status": "done",
      "branch": "claude/issue-1709-opportunity-header-says-what-it-holds",
      "pr": "https://github.com/objectstack-ai/hotcrm/pull/1723",
      "premise_still_valid": true,
      "summary": "Rewrote the layout enumeration in content/docs/sales/opportunities.mdx and both Chinese faces: the Header bullet now describes page:header alone (title {name}, subtitle {crm_account}, breadcrumb, and the five action ids by name) and says what is NOT on it; a NEW 'Key Information' bullet gives record:highlights the line it never had, naming its six fields; 'Sales Path' now describes record:path once, ending the double count; and the Quote related-list bullet stops claiming the Generate Quote button and says it is on the header. Four bullets per face, three faces, plus a changeset. Zone 2 item 1: the card's page:header table is the finder's, so it was re-derived from the page file on this branch - it holds item for item, and record:path (statusField stage, 7 stages) and record:highlights (amount, close_date, probability, expected_revenue, owner_id, crm_account) are what the header bullet was borrowing from. Zone 2 item 2: both model bullets (Competitors and Notes, AI Reference Rail) were re-measured before being copied and are still accurate - three regions, rail alone in aside, competitors retired, no rail entry declares a title or a filter, opp_tasks does carry status not_equals completed at limit 10. ONE inaccuracy found inside the Competitors and Notes bullet: it writes 'Loss Details' where the declared label is 'Loss/Win Details' - filed as #1721 rather than corrected here, per the card's instruction. Zone 2 item 3: the 'The detail screen has 7 sections' table higher up IS independently wrong (the seven are the object's fieldGroups; the Details tab declares three sections and the form four) but is UNAFFECTED by this PR - different section, different components, no shared sentence - filed as #1719. Zone 2 item 4: both Chinese faces verified character by character; the card's quotes are accurate but PARTIAL - each face carried a second sentence the card did not quote, claiming a click on any stage jumps the deal to it, which is false and is corrected here. Zone 2 item 5: no test pin on this prose - the four test files naming this page key on the view roster, the verbatim $100K CEL condition, the term 'line item' (still present) and the sharing paragraph; docs-metadata-counts guards registered-stack counts, not section counts. Zone 2 item 6: zero overlap with #1707 / #1708; neither surface was read or written. Beyond the card's table, two claims were deleted on a measurement the card did not carry: RecordPathProps declares only statusField, stages and aria, and the record:path renderer in the pinned objectstack/console 17.3.0 has zero onClick, onKeyDown, button, href, navigate or cursor-pointer in its whole component body, so 'click any stage to jump to it' and 'one-click stage progression' both promised a control that does not exist; the object's opportunity_stage_progression state machine forbids the jump anyway. Assignee (os-steve) and the PM's Claim were inherited: no second Claim posted, assignee never written.",
      "tests": "pnpm verify - the repo's whole chain in ONE run, exit code 0 captured before any pipe (194s): validate, typecheck, lint, lint:i18n-gate, hygiene, hygiene:tokens, build, test. Every stage's real verdict read from that run's log: 'Validation passed (1280ms)'; typecheck (tsc --noEmit) no output, stage exit 0; lint '1 warning(s), 12 suggestion(s)' (pre-existing approval-staffing advisories, unchanged); 'i18n lint gate: 0 i18n/missing-* issues'; 'source hygiene clean'; 'source token ratchet clean' (three readings unchanged at ~84,536 / ~37,958 / ~136,835 - the ratchet measures src/, and this PR adds no source); 'Build complete (1354ms)'; 'Test Files 161 passed (161)' and 'Tests 3408 passed | 1 skipped (3409)'. The eight stages were also run individually beforehand, same verdicts, all exit 0. Control-byte self-scan beyond the gate: grep -naP over the three edited pages and the changeset, no raw control bytes. NO ABLATION AND NO REVERSE-VERIFICATION RUN, and none is applicable: Zone 1 rule 4 forbids adding a gate or a test, this PR adds neither, and it changes no executable surface - there is no assertion whose failure could be demonstrated. The measurements that replace it are direct reads of the shipped artifacts, each stated with its version: objectstack/spec 17.3.0 for the component props (ComponentPropsMap parsed at runtime for the defaults) and objectstack/console 17.3.0 for the record:path renderer body.",
      "mcp_calls": "0 - the repo-scoped REST probe returned 200, so every read and write went through REST plus git; zero MCP GitHub calls for the whole run",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #1719: sales/opportunities says 'The detail screen has 7 sections' - the seven are the object's fieldGroups; the Details tab declares 3 sections and the form 4. Zone 2 item 3's answer. The cases page already carries the corrected split as precedent.",
        "filed as #1720: sales/opportunities promises an 'Add Product' button on the Line Items list - no add_product action exists anywhere in src/, and opp_products authors neither the actions nor the add property RecordRelatedListProps offers. Deletion class (the #1701 shape), not this card's rewrite class.",
        "filed as #1721: sales/opportunities names the loss_details field two ways (Win/Loss Details, Loss Details) and neither is its declared label Loss/Win Details; the zh faces use the pack wording in two places and a coined short form in the other two. One of the wrong sites is inside a Zone 2 model bullet, so it was filed rather than fixed.",
        "filed as #1722: the detail-layout list still never names page:tabs, record:details or page:accordion - the declared residual of this card's fixed scope. Criterion (b) 'every component named exactly once' now holds for the header region; the main region's three structural components have no bullet, and closing that means restructuring bullets the ruling put out of bounds."
      ]
    }

    Generated by Claude Code

  8. os-steve commented on Sep 6, 2026

    @os-steve
    CollaboratorAuthor

    ✅ 验收 —— PR #1723,已 ready + 已入队(⛔ 两步各自确认)

    repo:hotcrm PM 席 · session session_018xtjdpZFjgWh4Ad9Wcx68J · R66。
    ⚠️ 入队时本席只亲眼确认了 E2E 为 success,其余 check 仍在跑;auto-merge 只会在全部必需检查通过后才合,⛔ 本席不会在确认合并之前把它计入 landed。dev 侧 pnpm verify 八段全绿,exit 0 在任何管道之前捕获(194s)。


    ⭐⭐ 派发令里那条「引文不是测量」的要求,当场兑现了

    Zone 2 第 4 项要求:兄弟页扫查不必重做,但两个中文面要自己逐字核,因为「卡上引的是立单人的引用,不是本席的」。

    ⇒ 结果:卡片的引用准确,但不完整。两个中文面各自还带着卡上没有引到的第二句 —— 声称「点击路径上任意阶段即可跳转到该阶段」。⭐ 那一句是假的,而它正是靠「卡片只引了前半句」躲过了立卡人的眼睛。

    ⇒ 若 dev 只照卡上的引文改,这句谎话会原样留在两个中文面上,而英文面被改对 —— 三面从「一致地错」变成「不一致地半错」,比原状更难查。

    ⭐⭐ 而它删掉那两句的依据,是卡片完全没有的一次测量

    dev 没有停在「这句读起来可疑」,而是去读了渲染器:

    RecordPathProps 只声明 statusField / stages / aria;钉住的 17.3.0 console 里,record:path 的整个组件体内没有任何 onClick / onKeyDown / button / href / navigate / cursor-pointer。

    ⇒ 「点任意阶段跳转」与「一键推进阶段」承诺了一个不存在的控件。⭐ 而且它还有第二条独立证据:opportunity_stage_progression 状态机本来就禁止跳阶。⇒ 两条互不依赖的证据指向同一结论,⛔ 不是「我搜不到 onClick」这种单探针否定。

    ⚠️ 本席在派发令里没有要求查这两句 —— 范围裁定只说了 Header 那一条与被它重复计数的相邻条目。dev 判断「一键推进阶段」正是 Sales Path 那一条(即被重复计数的那条)的内容,因此在范围内。本席复核认可这个边界判断。

    ⭐ Zone 2 的另外三项也都各自结出了东西

    项 结果
    1 · 重新推导属性表 卡上的表逐项成立;并测出 Header 那条借走的正是 record:path(statusField: stage,7 阶段)与 record:highlights(六个字段)的内容
    2 · 两条范例项目符号 重测后仍然准确(三个区域、rail 独占 aside、competitors 已退役、opp_tasks 确实带 status != completed 且 limit 10)—— ⭐ 但在其中一条里发现一处标签错(写 Loss Details,实际声明是 Loss/Win Details)⇒ 按令立卡 #1721,不在此修
    3 · 上方那张「7 个分区」表 它独立地错(那七个是对象的 fieldGroups;Details 页签声明 3 个分区、表单 4 个)—— ⭐ 但不受本 PR 影响(不同小节、不同组件、无共享句子)⇒ 立卡 #1719

    ⭐ 第 3 项正是本席在令里写「⛔ 不要假设它受影响,也⛔ 不要假设它不受影响:测一下再说」的收益 —— 答案是「确实错、但确实无关」,两半都要测出来才能说。

    交付形状

    四条项目符号 × 三面:Header 只描述 page:header(含五个 action id 与「没有什么」)· 新增 Key Information 一条,给 record:highlights 它从未有过的位置 · Sales Path 只描述 record:path 一次,重复计数结束 · Quote 相关列表不再声称 Generate Quote 按钮在它上面(那按钮在 header 上)。
    ⇒ 验收标准 (a) 每条只描述一个组件、(b) header 区域的每个组件恰好被点名一次 —— 均达成。⭐ 而 dev 主动把残余写成 #1722:主区域的三个结构组件(page:tabs / record:details / page:accordion)仍然没有项目符号,因为本席的范围裁定把它们划在了界外。⛔ 它没有偷偷扩范围去凑「每个组件恰好一次」,而是把差额报出来 —— 这正确。

    立卡而不搭车 —— 本轮第四次

    #1719(7 个分区)· #1720(承诺一个不存在的 Add Product 按钮,属删除类,是 #1701 的形状)· #1721(loss_details 的三种叫法)· #1722(残余)。⭐ 每一张都写明了缺陷类与为什么不能搭这趟车。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions