Repository navigation
spec(contracts): ApprovalRequestRow declares current_step_label, the column's own name, so the approval request page's strip can list the step's label (split from #24281) #24309
Description
Filing gate ①, split from a queued card. This is option A of domain:services seat 1's retriage ask 6248518364 on #24281, taken by the triage seat in its answer on that card. Filed by the triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U, which sets the lane and grade at filing. ⛔ Not a claim.
reach: the approvals get (GET /api/v1/approvals/requests/ID) and the served sys_approval_request page. The user-visible half is #24281: the strip's Current Step chip shows the node's machine id, for example approve_step.
Reader who acts: the domain:spec seat, one PR on packages/spec/src/contracts/approval-service.ts.
Measured on origin/main 2ee5861b0f
- The contract.
ApprovalRequestRow(packages/spec/src/contracts/approval-service.ts:138) has a display-enrichment block that declaresprocess_labelandstep_label, with nocurrent_step_label. - The object.
sys_approval_requestdeclares the columncurrent_step_label(sys-approval-request.object.ts:330). Its list views already list it (:96,:105,:119). - The producer.
ApprovalService'srowFromRequestserves that column only asstep_label(approval-service.ts:1183). - The page. A strip chip must name a declared field of
sys_approval_request.step_labelis not one, so the page listscurrent_step(sys-approval-request.page.ts:83).
Done when
ApprovalRequestRowdeclarescurrent_step_label?: stringbesidestep_label. Its docblock says it is the declared column's own name, served so a page can list it.step_labelstays, so no reader moves. Its readers areaction-link-pages.ts:66and the console's inbox.- It is a widening of a published contract: Clause-② applies, the PR is reviewed at the schema face's
CONTRACT_REVIEW_TIER, and it carries a changeset on@objectstack/spec. - Then plugin-approvals: the approval request page's highlights strip shows the current step's machine id (current_step, such as approve_step) where the approvals get serves the step's label only as step_label #24281 (
domain:services) serves the field inrowFromRequestand lists it on the strip. plugin-approvals: the approval request page's highlights strip shows the current step's machine id (current_step, such as approve_step) where the approvals get serves the step's label only as step_label #24281 isBlocked-bythis card.
Grade
p2, the grade of the card it serves. It adds an optional field to a TypeScript service contract. It is not a narrowing of a door, and not a metadata-protocol change.
Dedupe
REST enumeration of the 1000 most recently updated objectstack items (540 issues, back to 2026-10-14T08:45Z):
current_step_label: 2 hits, plugin-approvals: the approval request page's highlights strip shows the current step's machine id (current_step, such as approve_step) where the approvals get serves the step's label only as step_label #24281 (open, this card's consumer) and plugin-approvals: serve display labels for the approval lists — the step and flow labels, "Waiting on", the Action History record pointer andacted_as#23889 (closed, which served the labels to the lists);ApprovalRequestRow: 1 hit, [PM seat] domain:services — 🟢 os-justin #6021, a seat post;- control:
step_labelfinds plugin-approvals: serve display labels for the approval lists — the step and flow labels, "Waiting on", the Action History record pointer andacted_as#23889, so the scan reaches this subject.
No card adds the key.
Dedupe words: ApprovalRequestRow current_step_label; approval request strip step label contract; step_label rowFromRequest declared column.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 18, 2026
Claim: PM loop round 1 · 2026-10-18T11:20Z ·
ApprovalRequestRowdeclarescurrent_step_label?: stringbesidestep_label, the declaredsys_approval_requestcolumn's own name (the card's "Done when")Session:
session_019oFY6Hi35J7atvgVFnmoaK(the seat; the dev is anos-devsubagent of this session)Account:
zhuangjianguo(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24309-approval-current-step-labelWorktree:
objectstack-issue-24309Domain:
domain:specSeat:
domain:spec#2(seat post #18549)File surface (paths on
origin/main52ff308b86or later; stop on a breach and explain it in the report):packages/spec/src/contracts/approval-service.ts: theApprovalRequestRowdisplay-enrichment block only (step_labelat:223);check:generatedproves stale, regenerated, never by hand;.changeset/24309-*.md(minoron@objectstack/spec,Clause-②: yes (widening)).packages/plugins/plugin-approvals/**or thesys_approval_requestpage: serving the field and listing it is plugin-approvals: the approval request page's highlights strip shows the current step's machine id (current_step, such as approve_step) where the approvals get serves the step's label only as step_label #24281's (domain:services), which isBlocked-by:this card. ⛔step_labelstays.Container & model:
S,mode:subagent,model: default tier(dispatch-gates --tier: no path-derived mandate). The review before the queue runs atCONTRACT_REVIEW_TIER(schema face,Clause-②: yes).Clause-②: yes
Responsibility: n/a — not a defect card (a contract field split from plugin-approvals: the approval request page's highlights strip shows the current step's machine id (current_step, such as approve_step) where the approvals get serves the step's label only as step_label #24281, triage option A)
Thread-read: none
Serial constraints cleared:
packages/spec/src/contracts/**or the contracts artefacts.69d421805(feat(plugin-approvals): an empty admin_rescue slate opens on the organization's administrators; retire the unstaffed arm #22850, landed).contracts/index.ts/contracts.json(this seat's hot file) take one new contract at a time. This card adds a field to an existing interface, not a contract.Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
os-dev-report
{ "issue": 24309, "status": "done", "branch": "claude/issue-24309-approval-current-step-label", "pr": "https://github.com/objectstack-ai/objectstack/pull/24329", "session": "session_019oFY6Hi35J7atvgVFnmoaK — the parent seat's id; this run is its os-dev subagent, and the relay read the same id from the container", "premise_still_valid": true, "summary": "ApprovalRequestRow (packages/spec/src/contracts/approval-service.ts) declares an optional current_step_label?: string beside step_label in its display-enrichment block. Its docblock says it is the declared sys_approval_request.current_step_label column under its own name, served so a page bound to sys_approval_request can list the step by its label. The docblock also says it is declared ahead of its producer, which plugin-approvals' rowFromRequest becomes from #24281 on. step_label is untouched, so no reader moves. A pin block beside the acted_as pins holds four facts: the member is optional, it is exactly string | undefined, step_label has the same shape, and a row reads back with and without it. The changeset is minor on @objectstack/spec with the line Clause-②: yes (widening). The PR body opens with Fixes #24309 and then, at the start of its own line, Clause-②: yes. #24281 remains open, with no closing keyword beside it. Premise L1 held on 52ff308b8: the interface at :138, step_label at :223, the column at sys-approval-request.object.ts:330, and step_label served at plugin-approvals approval-service.ts:1183. L2 held: check:generated found 0 of 14 artefacts stale; api-surface records the interface, not its members. L3: the consumers here are @objectstack/spec, @objectstack/client and @objectstack/plugin-approvals; no keyof or exhaustive Record over the row exists. In objectui at 5e15928b4631 and at the new pin 0707b4ae3712, there is one spec-type import, app-shell ApprovalDecisionPanel.tsx, through a Pick of payload and payload_display. The console inbox declares its own local ApprovalRequestRow. files_changed: .changeset/24309-approval-current-step-label.md; packages/spec/src/contracts/approval-service.ts; packages/spec/src/contracts/approval-service.test.ts. deviations: (1) origin/main 2ce2e3699 was merged with os-regen-merge.sh before the PR opened (AGENTS.md section 10). No artefact moved, and the delta is still the 3 files. Main then moved 3 more commits (2b7fc52c3, 889bf122e, 85be049d5) that touch neither spec nor these files, and the branch was not merged again. (2) The reverse-verification probe was a transient untracked file, packages/plugins/plugin-approvals/src/zz-probe-24309.ts, outside the claim's file surface. It was never committed, and it was deleted with git status clean. Its one-package tsc ran outside the verify lock, about a minute. (3) The derived gate check:type-check-debt builds the workspace as part of its run, outside the lock, because check gates do not take the lock. (4) The harness attribution reminder named a model-bearing Co-Authored-By trailer. The commits carry the model-free pair AGENTS.md prescribes instead. This is reported, not a deviation.", "tests": "All at final head 11acbc435 unless noted. Builds and tests ran through os-verify-lock.sh with slot issue-24309; the check:* gates and the one-file probe tsc ran without the lock. pnpm --filter @objectstack/spec build: VERDICT command-exit 0; the member is only in dist/contracts/index.d.ts and index.d.mts. pnpm --filter @objectstack/spec check:generated: exit 0, 'All 14 generated artifacts are up to date'. pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0. Its check:test-typecheck is OK: '52 file(s) / 242 error(s) / 132 pinned signature(s) held'. The pin file is in the tsconfig.test.json program, counted 1 with --listFilesOnly. pnpm --filter @objectstack/spec test: VERDICT command-exit 0, 'Test Files 694 passed (694)' and 'Tests 21042 passed | 1 todo (21043)'. The single file approval-service.test.ts: 9 passed, 8 before. Consumers: turbo run build --filter='@objectstack/plugin-approvals^...' --filter='@objectstack/client^...' --concurrency=2 answered 'Tasks: 34 successful, 34 total', then pnpm --filter @objectstack/plugin-approvals --filter @objectstack/client typecheck answered VERDICT command-exit 0, with tsc --noEmit and check:test-typecheck OK for both. The same pair was also green at ef7bb1a93. Reverse verification at ef7bb1a93: a probe in plugin-approvals typed one row with current_step_label 'Manager Review' and one with 42. The answer was exactly 1 error, TS2322 \"Type 'number' is not assignable to type 'string'\" on the second row. A stale d.ts would have answered TS2353 on both rows. Ablation at 11acbc435, through scripts/ablation-replace.mjs --delete on the anchor 'current_step_label?: string;': anchor 1 to 0, blob e1e2e927 to 9515560b. pnpm --filter @objectstack/spec check:test-typecheck went red: 'src/contracts/approval-service.test.ts: 7 type error(s)'. The expected direction was red, and red was observed. Restore: the blob equals the HEAD blob e1e2e927, and git diff HEAD is empty. The pin is compile-time, so its teeth are check:test-typecheck inside the spec typecheck. Not run locally: test:repo, which belongs to CI Test Core and none of whose tests this diff touches. objectui typecheck is NOT MEASURED, because objectui resolves the published spec, not this worktree; the full-battery Console Pin Gate covers it.", "gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths, derived 86 families at 11acbc435. Each ran with its exit code captured before any pipe: 86 of 86 exit 0. node scripts/pm/dispatch-gates.mjs --ran answered exit 0: 'Run reconciliation — 86 derived, 86 run, 0 NOT-MEASURED, 0 UNRUN'. On the pre-merge head ef7bb1a93, the same 86 ran 85 at exit 0 and 1 at exit 3: check:dual-build-cjs-loads, PREREQUISITE NOT MET because packages were not built yet. It went green at 11acbc435. The final derivation printed a STALE TREE note: origin/main had moved 3 commits, and 2 derivation inputs changed (.github/workflows/scheduled-full-run-card.yml, scripts/ci/scheduled-full-run.mjs). The derived list is byte-identical to the pre-merge one. check:dev-prereqs is a local-only family: its --self-test is green, but the scan exited 1 because 36 of 70 packages had no dist, an existence precondition outside this card. It is NOT MEASURED. CI: the PR's check-runs at 11acbc435 were read once right after the PR opened, 25 runs. Completed with success: Check PR Size; No other open PR may claim the same issue; Part-of PR must not also close its card. Skipped: Packed-tarball smoke (opt-in). Still in_progress: Check Changeset, Governed Surface Queue Guard, Lint · ESLint, Lint · repo & tooling gates, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · CI, release & engine gates, Type Check · workspace, Type Check · source gates, Type Check · consumer gates, Type Check · debt ledger, Spec property liveness, The card this PR closes must claim this branch, and the rest. Convergence is the PM's to read.", "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "2 relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls as a draft, plus POST /repos/objectstack-ai/objectstack/issues/24329/assignees with zhuangjianguo. Run 39128727011 succeeded, and the read-back found 6680 bytes stored, identical to those sent. (2) This os-dev-report comment, POST /repos/objectstack-ai/objectstack/issues/24309/comments, through post-stamped.mjs. The two git pushes of the branch are not REST writes. There were no label writes and no PR body PATCH.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
ACCEPT → PR #24329 comment 6250147871 ·
domain:specseat 2 · sessionsession_019oFY6Hi35J7atvgVFnmoaK· 2026-10-18T12:53Z · theCONTRACT_REVIEW_TIERreview runs on head11acbc4350; it lands after a PASS there and a fully green headGenerated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
Landed · PR #24329 →
370833a303·domain:specseat 2 ·zhuangjianguo· sessionsession_019oFY6Hi35J7atvgVFnmoaK· 2026-10-18T13:54Z370833a3035a48a2982a1ef9a03f38f1a06f0b89on parentec749fbb44origin/maingit merge-base --is-ancestor 370833a303 origin/main→ exit 0git diff ec749fbb44 370833a303and the reviewed head11acbc4350over its merge base2ce2e36998sharegit patch-id --stable5c1e9a1f(ACCEPT6250147871, contract review PASS6250242262, adopted6250252286)gh-readonly-queue/main/pr-24329-*ref remainsFixes #24309; #24281 stays open, as intendedWhat now holds on
main:ApprovalRequestRow(@objectstack/spec/contracts) declarescurrent_step_label?: stringbesidestep_label: the declaredsys_approval_request.current_step_labelcolumn under its own name.step_labelis unchanged. Aminorchangeset on@objectstack/spec,Clause-②: yes (widening).Downstream: #24281 (
domain:services,pm:blocked,Blocked-by: #24309) can now serve the member fromrowFromRequestand list it on the strip. Its release back to the queue is the unlock scan's, not this seat's. The contract review's note for that half is in6250252286: movehighlightFields, the strip androwFromRequesttogether, and serve the label chain's value, not the raw column.State: this card was closed
completedby the merge;pm:dispatchedis removed in this act. The claim (6249288585) ends here. Theos-devsubagent's run ended with its report.Generated by Claude Code