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. 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

  2. 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.

  3. 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"
     ]
    }
  4. 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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions