Skip to content

feat(record-pages): Details tabs reference the objects' fieldGroups (lead, opportunity, case) - #1990

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-806-detail-sections-group-ref
Oct 3, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-806-detail-sections-group-ref

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #806
Fixes #1452
Fixes #970

What changed

The three record pages that author their own record:details body (lead, opportunity, case) now write every section as a { group: 'KEY' } reference to the object's fieldGroups. This is maintainer ruling C (decision batch #21, 2026-09-03, verbatim 「批次 #21 同意」), ruled once for the class. Membership now has one declaration site, the group: on each field. The page curates only the order.

Not done, by the ruling and the dispatch: no fields: enumeration, no hideEmpty, no hand-mirrored groups, no fieldGroups change, no src/*/views/*.view.ts change.

One commit per card: 51b4d611 (#806, lead), 6543e055 (#1452, opportunity), ca778782 (#970, case), 42a65819 (changeset).

Measurement first: the restart probe (#806 Restart-probe:) reads green

Setup: origin/main 0b2a9d4d, @objectstack/console 17.6.0, headless Chromium /opt/pw-browsers/chromium, port 4806.

  • Each leg booted objectstack start --artifact with a fresh home and a fresh SQLite DB, from a cwd that has no objectstack.config.ts. The server ran in its own session and was torn down by process group.
  • Only the record:details sections of lead_detail_page differ between legs. Each leg was a scratchpad copy of dist/objectstack.json. The worktree was never edited.
leg sections served by GET /api/v1/meta/pages/lead_detail_page Details tab
A baseline the 6 authored name/label/fields sections renders Lead Information, Contact, Lead Detail, Duplicate Management, Description (Address is empty, so it is dropped); 0 page errors
B group refs 10 { group } entries, in crm_lead fieldGroups order renders Identity, Company Information, Contact Information, Qualification, Additional Info, Communication Preferences, Conversion, Duplicate Management; no "failed to render", 0 page errors; Notes, Do Not Call, Email Opt Out, Next Follow-up Date and Last Contacted are all reachable
C control 2 invented name/label/fields sections renders Probe Control One and Probe Control Two

Every leg passed three gates: health, the listener PID belongs to the started process group, and the served metadata equals the leg artifact. All three legs logged the same two to four Failed to load resource: 404 console lines.

⚠️ One run was discarded as an instrument failure. The first B run booted from the worktree cwd. There, objectstack start loaded objectstack.config.ts rather than --artifact and served the authored sections. The served-metadata gate caught this, and B was re-run from a cwd with no config.

What the Details tab reaches, before and after

Both runs used the same seed, the same browser procedure and the same gates. Before is artifact 0b2a9d4d; after is ca778782. "After a click" means one of two things:

  • the group starts collapsed because its fieldGroups entry declares collapse: 'collapsed', so you click the heading; or
  • the field is empty and sits behind the section's "Show N empty fields" toggle.

Lead (a suspected-duplicate lead with notes, do-not-call and follow-up dates set)

  • Newly reachable: notes, do_not_call, email_opt_out, next_followup_date, last_contacted_date, need_type, estimated_amount, conversion_approval_status, full_name, is_converted, and converted_account / converted_contact / converted_opportunity / converted_date.
  • Still reachable: every field the old six sections showed.
  • Lost: none.
  • Moved: description is now inside Additional Info, which starts collapsed. Duplicate Management also starts collapsed (the banner copy still says to open it).
  • Order: Identity, Company Information, Contact Information, Communication Preferences, Qualification, Assignment, Address, Conversion, Duplicate Management, Additional Info. Communication Preferences sits under the numbers a rep dials, and Additional Info (with Description) stays last, where the Description section was.

Opportunity (a new deal with a primary contact and no campaign)

  • Newly reachable: primary_contact, stage_entry_date, approval_status, approved_date, win_reason, loss_reason, loss_details, days_in_stage, is_private.
  • Lost on this record: crm_campaign while it is empty. The Campaigns group has that one member, and a group whose members are all empty renders nothing. The field is on the Edit form, and the group renders once a campaign is set.
  • The old Description section was collapsible: true. Notes & Next Steps is not collapsible, because collapsible cannot sit beside group.
  • Financials renders nothing on this page because amount and expected_revenue are both in the strip. It stays referenced so that a future member reaches the tab.

Case (an open case, plus a second case with a resolution and a first-response date)

  • Newly reachable: escalated_date, the crm_case 与 crm_lead 同病:三套互不相同的字段分组(fieldGroups 6 / 详情页 3 / 表单 3),escalated_date 三处写入、零处展示 #970 subject, under Escalation. Also subject, is_closed and, on the second case, first_response_date and resolved_by_article.
  • internal_notes is still reachable on the open case, in the System group. Measured: the group renders because is_closed is a boolean that always holds a value.
  • Lost on an open case: resolution and resolution_time_hours while they are empty. The Resolution group, and SLA & Priority once the strip's fields leave it, have no member with a value, so they render nothing. Measured on the second case: both groups render once a member carries a value. Close Case collects the resolution as a required screen input, and resolution_time_hours is readonly and derived at close.

Pins that moved with the sections

  • test/lead-duplicate-visibility.test.ts: the duplicates section is now found by group: 'duplicates'. Its members resolve from crm_lead's fields. The same four-field and strip-disjoint assertions apply, plus a new check that the section does not re-enumerate fields.
  • test/detail-section-dedup.test.ts: a group-reference section enumerates nothing, so the strip-dedupe rule has nothing to read in it. Its "carries at least one field" assertion now counts the group's visible members on the page's object. The lead_detail_page exemption is removed because that page no longer enumerates anything.
  • test/case-create-form-narrowing.test.ts: the detail.details surface now expands a { group } section into its members. first_response_date's roster entry changes from no surface to detail.details, with the reason (it arrives with the sla group).

No skip and no quarantine.

Token ratchet (pnpm hygiene:tokens, comment-stripped)

package interaction layer authored total
src/sales 27,999 → 27,633 96,911 → 96,545
src/service 5,784 → 5,592 20,736 → 20,544

No ceiling moved.

Verification

pnpm verify at 42a65819, under the shared lock, printed os-verify-lock: VERDICT command-exit 0 · held the lock 174s:

  • validate ✓
  • typecheck ✓
  • lint: 17 warnings/suggestions, 0 errors, none on a page or section
  • lint:i18n-gate: 0
  • hygiene: clean
  • token ratchet: clean
  • build ✓
  • test: 174 files, 3705 passed, 1 skipped (the pre-existing describe.runIf 16.x branch in test/dataset-granularity.test.ts)

Acceptance notes

  • File surface beyond the claim, forced by the platform: 8 locale files, src/sales/translations/{en,zh-CN,ja-JP,es-ES}/objects.{pipeline,service}.ts.
    • os validate refuses a _sections translation keyed to a section name nothing declares (translation-target-unknown, an error). The page-only names had to leave with the sections: lead info / crm_contact / detail / description, opportunity info / description, case info / status / description. Their comments were re-stated.
    • Translation values are unchanged.
    • test/field-groups-coverage.test.ts prose that this change made false (it called crm_lead "the standing counter-example") was re-stated.
  • Made false and left alone (⛔ out of reach here): the roster comment in src/service/views/case.view.ts, around lines 359–372, names the detail page's "Status & SLA section" and "Description section". Those sections no longer exist. That file is excluded by the ruling and held by 26 sections author span: 'full' and do not span the row at modal width — measured pixel-identical to writing nothing, and 24 of them were rewritten INTO that spelling by PR #1605 #1870.
  • zh-CN / ja-JP / es-ES crm_opportunity._sections.crm_forecast still reads "Stage & Forecast" (阶段与预测 / ステージ・売上予測 / Etapa y Previsión). en reads "Forecast & Metrics". This wording predates this PR and was written for the old page section of the same name. It is now the heading of the Forecast & Metrics group on the opportunity Details tab. Values were not changed (⛔ no coined translations).
  • first_response_date now has a human surface. It is in the sla group and writable on the object (no readonly), so the Details tab's inline edit applies where a profile grants update. Inline edit itself was not measured. Its single writer is event.hook.ts. Whether it should be readonly is an object decision, not this card's.
  • All-empty groups render nothing. This is the renderer default behind the three "lost while empty" fields above. It is the empty-section default that The opportunity's 详情 tab renders two fields out of the fourteen it authors — highlight fields are dropped and the sections left empty disappear #1211 owns, serialised after this fold on the opportunity sections.
  • Page-level columns: '2' does not reach group sections. They lay out their own column count; Identity rendered 4 columns. Measured in the browser, renderer behaviour, not changed here.
  • The token ratchet now suggests re-anchoring src/service interaction layer to about 6,000, and src/sales to about 30,000 (the sales suggestion predates this PR). Ceilings are untouched here.

Generated by Claude Code

claude added 4 commits October 3, 2026 00:10
The lead record page's record:details sections become ten `{ group }`
references to crm_lead's fieldGroups (ruling C, decision batch #21), so
membership has one declaration site and the page curates only the order.
Notes, Do Not Call / Email Opt Out, the follow-up dates and the conversion
block become reachable on the Details tab.

The four page-only section names leave the locale packs with the sections
(`os validate` refuses a translation keyed to an undeclared section), and
the two pins that read the sections resolve the group's members instead.

Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
…the Details tab

The opportunity record page's three hand-written record:details sections
become seven `{ group }` references to crm_opportunity's fieldGroups, the
same class ruling as the lead page. Primary Contact, the win/loss fields,
probability, approval status and the forecast metrics become reachable on
the Details tab; the strip's fields stay out of it because the renderer
drops what record:highlights registered.

The two page-only section names leave the locale packs with the sections.

Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
The case record page's three hand-written record:details sections become
six `{ group }` references to crm_case's fieldGroups, the same class ruling
as the lead and opportunity pages. escalated_date, written by three flows
and shown nowhere, arrives with the Escalation group; first_response_date
and resolved_by_article arrive with theirs.

The three page-only section names leave the locale packs with the
sections. The create-form pin resolves a group section to its members, and
first_response_date's roster entry records the surface it gained.

Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 3, 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 12:27am UTC

Request Review

@github-actions github-actions Bot added ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces labels Oct 3, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 3, 2026 00:36
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 1e47470 Oct 3, 2026
10 checks passed
hotlong pushed a commit that referenced this pull request Oct 3, 2026
…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
hotlong pushed a commit that referenced this pull request Oct 3, 2026
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment