Skip to content

spec: the flows.approvals translation rows read live, and ApprovalRequestRow's label docblocks name the reader's-locale label - #25103

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-24979-approvals-label-live
Oct 21, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-24979-approvals-label-live

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Closes #24979

Clause-②: no (ledger and docblock text only: no shape, key, default, accepted value or export moves)

What

The follow-up owed by #24863's landing (PR #24977, commit ba69b16). plugin-approvals now serves an approval request's flow, step and object labels in the reader's locale (packages/plugins/plugin-approvals/src/reader-locale-labels.ts). The spec side still said otherwise in two places. This PR fixes both:

  1. packages/spec/liveness/translation.json: flows.approvals and its one drilled child flows.approvals.label flip planned to live. This is the step the row's own planned note asked for ("Flip to live on the commit that cites that reader"). Both rows now cite the reader by file#symbol anchors. The child also cites its producer chain. The generated count shard liveness/state-counts/translation.md was regenerated with gen:liveness-counts (live 29 to 30, planned 1 to 0). The translation Notes cell in liveness/README.md gains one sentence for the flip, as the gate's stale-count message asks.
  2. packages/spec/src/contracts/approval-service.ts: the ApprovalRequestRow docblocks for process_label, step_label, current_step_label and object_label now say what is served. Each is the reader's-locale label, falling back to the stored snapshot (for object_label, the object's schema label). The stored columns are never rewritten by a read.

Text only: no type, key, default, accepted value or export moves. The docblocks ship in dist/contracts/index.d.ts, so this carries a @objectstack/spec patch changeset (.changeset/24979-approvals-label-live.md).

Each docblock statement, verified against plugin-approvals at origin/main a39389e

None of these files is touched by this diff, so the line numbers hold at this PR's head too.

Docblock statement Where plugin-approvals does it
The flow label is picked from flows.FLOW.label, the step label from flows.FLOW.approvals.NODE.label, the object label from objects.OBJECT.label reader-locale-labels.ts:73 flowLabelKey, :78 approvalStepLabelKey, :153 objectLabelKey
Picked through the i18n service in the read's ExecutionContext.locale, negotiated by resolveBundleLocale reader-locale-labels.ts:128-155 readerLabelsFor (:134 negotiation, :140 service.t(key, locale)); approval-service.ts:8250-8259 readerLabels; approvals-plugin.ts:273 wires i18nServiceSource
No locale, no i18n service or no pack entry: the snapshot is served reader-locale-labels.ts:132-133 (no locale or no service gives undefined), :142 (a miss echoes the key and picks nothing), :178, :181, :188 (overlay only when picked)
Picked on listRequests, getRequest and a write's echoed request approval-service.ts:8229-8230 (listRequests), :8371-8372 (loadRequest); getRequest (:8337-8338) and readBackRequest (:8326, every decision or write echo) go through loadRequest
step_label and current_step_label are always the same value approval-service.ts:1270, :1275 (both from one requestDisplayLabels value); reader-locale-labels.ts:182-183 (both overlaid together)
Fallback is the authored label as snapshotted at open, else the humanized machine name display-labels.ts:79-80 requestDisplayLabels (column, else the node-config snapshot, else the humanized name)
The stored column is never rewritten; the generic data door and list views serve the snapshot reader-locale-labels.ts:56-59 (header, "What stays"); the overlay mutates only the served row object (:174-189)
object_label falls back to the object's schema label approval-service.ts:7429-7433 objectLabelOf (schema.label), set at :7378 and :7574-7575 before the overlay

Deferred, not in this PR

The optional flowLabelKey / flowApprovalLabelKey helper beside flowRefusalMessageKey (issue body, "Optional") is not added. A new @objectstack/spec export is a widening, which the claim's Clause-② no excludes. reader-locale-labels.ts keeps spelling both keys locally, held to TranslationDataSchema by reader-locale-labels.test.ts.

Verification (head da0364f)

All runs below were taken on this head (no commit after them). The spec build and tests ran under the shared verify lock on a shared box.

  • pnpm --filter @objectstack/spec build: VERDICT command-exit 0. The edited docblocks are in dist/contracts/index.d.ts (one hit for the new text), so the published artifact moves and the changeset is a patch.
  • pnpm --filter @objectstack/spec typecheck (tsc, scripts and test typecheck) followed by vitest run: Test Files 778 passed (778), Tests 22683 passed, 1 todo; VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec test:repo: Test Files 72 passed (72), Tests 1237 passed (1237); VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec check:liveness: red before regeneration, as it should be (state-counts/translation.md is STALE: live 29 to 30, planned 1 to 0). After gen:liveness-counts it is green: every path#symbol anchor resolves (976 of 976), key-mention 747 anchored plus 1 exempt, and state-counts/ is current.
  • pnpm --filter @objectstack/spec check:generated: All 14 generated artifacts are up to date, against the dist this branch built.
  • node scripts/pm/dispatch-gates.mjs --commands derived 84 families for this diff, and all 84 were run. 81 exited 0. --ran with recorded exit codes: 84 derived, 81 run, 3 NOT-MEASURED, 0 UNRUN. Three were NOT MEASURED. Each exited 3 because a build it needs was missing, so it checked nothing: @objectstack/lint check:doc-formula-expressions (needs formula and lint dist), check:dual-build-cjs-loads (needs every package's dist), and check:lean-entry-closure (needs objectql dist). They are left to CI. The changeset gates (check-changeset-no-major, check-adr-0087-registration, check-empty-changeset, check:changeset-gate-self-tests), check:nul-bytes, check-spec-docblock-symbol-anchors, check:api-surface and check:docs are among the 81 that exited 0.
  • pnpm lint (repo-wide) was not run locally. It belongs to CI.

Acceptance notes

  • No open PR touches any of the four changed files under packages/spec (all 14 open PRs' file lists scanned before opening).
  • flow_steps[].label has no docblock that names the authored label (its member docblock is silent on the label's source), so it is left unchanged, although attachFlowSteps (approval-service.ts:8501) names steps by the same pick.

Generated by Claude Code

…Row's label docblocks name the reader's-locale label

plugin-approvals now serves a request's flow, step and object labels in the
reader's locale (reader-locale-labels.ts, commit ba69b16). Flip the
`flows.approvals` translation ledger row and its `label` child from planned
to live citing that reader, and say in the ApprovalRequestRow docblocks that
process_label / step_label / current_step_label / object_label are the
reader's-locale label falling back to the stored or schema label.

Claude-Session: https://claude.ai/code/session_01D6F9axfoPzR7t8G1J7Ytzz
Co-authored-by: Claude <noreply@anthropic.com>
…vals flip in the ledger README

Claude-Session: https://claude.ai/code/session_01D6F9axfoPzR7t8G1J7Ytzz
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Oct 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/state-counts/translation.md, packages/spec/liveness/translation.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/state-counts/translation.md, packages/spec/liveness/translation.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 144 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8f59304ddc45825f1f4d63f6956e07a75df68c9d → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 14c93525ac630f2e6c44650fd15e7c6757bfb712 — the merge of head da0364f8253b920b3ad6075405c9f380a302b8c7 into base 8f59304ddc45825f1f4d63f6956e07a75df68c9d, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 14c93525ac630f2e6c44650fd15e7c6757bfb712 && git checkout 14c93525ac630f2e6c44650fd15e7c6757bfb712
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8f59304ddc45825f1f4d63f6956e07a75df68c9d da0364f8253b920b3ad6075405c9f380a302b8c7 && git checkout -B drift-repro 8f59304ddc45825f1f4d63f6956e07a75df68c9d && git merge --no-ff da0364f8253b920b3ad6075405c9f380a302b8c7

node scripts/docs-audit/affected-docs.mjs --json 8f59304ddc45825f1f4d63f6956e07a75df68c9d

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: da0364f8253b920b3ad6075405c9f380a302b8c7
Local-runs: none
Scope: packages/spec/src/contracts/approval-service.ts, packages/spec/liveness/translation.json, packages/spec/liveness/state-counts/translation.md, packages/spec/liveness/README.md + .changeset/24979-approvals-label-live.md

① Derived judgments

② Semver level

@objectstack/spec patch, Clause-②: no. Only comment text inside ApprovalRequestRow changes, and it ships in dist/contracts/index.d.ts. No member is added, removed or retyped. The ledger files are not published type surface.

③ Boundary flags

packages/spec/liveness/** is not governed (check-governed-merges.mjs:1176-1184). The README edit is an append-only sentence. content/docs/releases/ is untouched, and no objectui pointer is introduced. The optional flowLabelKey helper is correctly deferred, because it would be a widening.

Implemented-by: claude/issue-24979-approvals-label-live
Reviewed-by: session_01D6F9axfoPzR7t8G1J7Ytzz

VERDICT: PASS

Seat re-read of the check-runs at landing: all 42 runs on da0364f825 have completed: 35 succeeded, the rest were skipped, and none is red.

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

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

2 participants