Skip to content

Record path: a stage can be clicked to request that status, judged by the field's validation and state machine #28061

Closed

Description

@objectstack-fleet

domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

Filing gate: ③ triage-directed. The order on #27355 (rows 1, 5, 7, 8, 11) said: take what is ui-only, card the rest. The card thread measured each row on origin/main (report 6521287829, out_of_scope_findings). Rows 7, 8 and 11 are taken in PR #28060.
Reach: every record page with a record:path block. HotCRM's Sales tester asked for it on 18.2.0 (#27355 row 1; hotcrm#2320 Sales S1).
Reader who acts: domain:spec first (an opt-in key on RecordPathProps, contract review), then domain:ui (plugin-detail's record-path.tsx).
Duplicate search: search_issues "record path click stage to change status click-to-advance interactive" → #11243 (closed: made the inert path stop looking like a control), #26581 and #26694 (closed, path rendering). None asks for a press.

Observed

The record:path block draws the status field's stages as a progress rail, and nothing on it can be pressed. A user who wants to move a deal to the next stage opens the edit form and changes the picklist. record-path.tsx's header records the path as a readout with no handler and calls click-to-advance a separate feature. Its only channel (useRecordContext) exposes no field write.

Wanted

  • Spec: an opt-in key on RecordPathProps (name for review), off by default, so existing readouts keep their non-interactive look (The record page's lifecycle path looks like a control and is inert: stageField renders as a segmented button group with no handler, no cursor, and no tab stop #11243). Landing: packages/spec/src/ui/component.zod.ts.
  • Console: when the key is on, each reachable stage is a button gated by the reader's edit verdict on the status field. A press asks for confirmation, then writes through the same update path record:details uses, with the record's concurrency token. The server's refusal (an illegal transition, a missing required field) is shown in place. No server change is needed: every update is already judged against the object's state_machine validation rule (ADR-0020) and field-level edit rights.

Dedupe words: record path click stage, click-to-advance, path stage status change, record:path interactive, state machine path.

Related: #27355 (row 1), #11243.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 30, 2026
  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

    Claim: PM loop round 3 · 2026-10-30T15:11Z
    Session: session_01L9qibwb6hBqszPTYJobitm
    Account: os-tesla
    Branch: claude/project-thread-asm4hj (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-28061-<slug>)
    Worktree: objectstack-issue-28061
    Domain: domain:spec
    Seat: domain:spec#1
    Card thread: session session_01L9qibxNQzFQH8nBAaoSUkx; the dispatch order is in the seat's project, frame + card file.
    File surface: packages/spec/src/ui/component.zod.ts (one opt-in, default-off key on RecordPathProps), tests, generated artefacts, changeset. ⛔ Not the console half (plugin-detail record-path.tsx, a domain:ui follow-up the seat files), ⛔ no server change (stop on breach; explain in the report)
    Container & model: S/M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate; a widening of a published schema, so a contract review at CONTRACT_REVIEW_TIER is owed — in-seat, per the maintainer), effort: high
    Clause-②: yes
    Metadata-protocol: added
    Responsibility: packages/spec declares the record:path block as a readout with no way to opt into a press | the opt-in key, default off, keeps #11243's inert look | every record page with a record:path block (HotCRM Sales tester, #27355 row 1)
    Thread-read: none
    Premise: holds — on main RecordPathProps (component.zod.ts:2054) is a strictObject with no interactive key
    Serial constraints cleared: none — open PR #28138 edits the same file far from RecordPathProps (L6189); seat 2 told by mailbox split

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

    Claim correction · 2026-10-30T15:13Z · amends claim 6526133189, append-only

    File surface, amended by seat ruling: plus exactly one UNPUBLISHED_EXEMPTIONS entry record:path.allowStageChange in ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts. The card thread measured that any new RecordPathProps key reds the reverse direction of that parity test (Test UI, required) until the console half publishes the input. The entry self-clears on that day (stale check). Nothing else under ui/ changes.

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-tesla · session_01L9qibxNQzFQH8nBAaoSUkx

    os-dev-report

    {
     "issue": 28061,
     "status": "done",
     "branch": "claude/project-thread-asm4hj",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/28198",
     "session": "session_01L9qibxNQzFQH8nBAaoSUkx",
     "premise_still_valid": true,
     "summary": "RecordPathProps declares allowStageChange: z.boolean().optional(), no schema default; absent or false is the read-only rail as today. The describe and docblock carry the console contract from the card (stage buttons gated by the reader's edit verdict on statusField, confirm, write through the record:details update path with the concurrency token, refusal in place; no server change). Regenerated authorable-surface/ui.json and references/ui/component.mdx. Per seat ruling A, one UNPUBLISHED_EXEMPTIONS entry 'record:path.allowStageChange' in ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts keeps Test UI green until the console half publishes the input. Changeset: spec minor, Clause-② yes (widening), Metadata-protocol added.",
     "tests": "d9b26f02: spec typecheck + spec vitest under lock VERDICT command-exit 0, Test Files 843/843, Tests 23972 passed 1 todo. ui parity file 261/261. Control: exemption entry removed (grep -c 0) -> 1 failed 'record:path publishes every top-level key its spec props schema declares' (expected [ 'allowStageChange' ] to deeply equal []), 260 passed; restored with git checkout HEAD --, git diff HEAD empty. Merged head 526055d6: component.test.ts 353/353, parity file 261/261. No dist ablation: tests import src.",
     "gates": "dispatch-gates --commands derived 106 on d9b26f02; all 106 run with </dev/null, codes captured before pipes: 106 exit 0. Commands 60-106 overlapped a dts-less console^ build that rewrote dist/; re-run after a full declaration build: 47/47 exit 0. --ran reconcile: 106 derived, 106 run, 0 NOT-MEASURED. Ran list: spec-seat-1/r2026-10-30/out/28061-gates-ran-d9b26f02.list. Merge 526055d6 (4 commits, spec automation-domain only): build exit 0, check:generated all 14 up to date. CI check-runs: not read (seat reads).",
     "line_budget": "74 changed lines (+74/-0), 6 files, under the 3000 threshold",
     "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
     "files_changed": [
      ".changeset/28061-record-path-allow-stage-change.md",
      "content/docs/references/ui/component.mdx",
      "packages/spec/authorable-surface/ui.json",
      "packages/spec/src/ui/component.test.ts",
      "packages/spec/src/ui/component.zod.ts",
      "ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts"
     ],
     "deviations": [
      "File surface widened outside packages/spec by one UNPUBLISHED_EXEMPTIONS entry in ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, reported before code and ruled A by the seat.",
      "Gates 60-106 re-run after a dts-less build overlapped the first sweep; both runs exit 0.",
      "test:repo not run locally (CI's Test Core)."
     ],
     "mcp_calls": "3 — reads only: issue_read get x1, issue_read get_comments x2; 0 writes",
     "api_writes": "2 — fleet-write relay pr_create (objectstack-ai/objectstack#28198, body read back identical, 7247 bytes); post-stamped os-dev-report comment on #28061",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: spec seat 1 · console follow-up (domain:ui): plugin-detail record-path.tsx honours allowStageChange, the record:path registration publishes the input, the UNPUBLISHED_EXEMPTIONS entry is deleted, skills/objectstack-ui/rules/pages.md teaches the key · noted in the PR body for the seat to file"
     ]
    }
  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

    ACCEPT → PR #28198 comment 6528821692. Contract review PASS 6528734955 on head e0c5c2fd. Console half filed as #28199. Landing at 2026-10-30T17:16Z: pr_ready + automerge_enable sent.

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

Metadata

Metadata

Assignees

Labels

domain:specDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions