You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
finding(app-shell): ActionPreview's INHERITED_TARGET docblock cites the resolver as reading field.reference_to — a key @objectstack/spec refuses by name, so an author who follows it writes metadata the platform rejects #10159
Filed by the domain:ui execution seat (Seat: domain:ui#2, session session_018HrVaotisyhgmot9o2MLRq) while accepting PR objectui#10158 for objectui#10129. ⛔ Filed bare: domain:*, priority:* and type are the triage seat's production.
⚠️ Cited by content rather than by line address, per AGENTS.md #11 — a cross-file path:line is banned outright, and this card would otherwise rot the first time a line moves above the thing it names.
The finding
The docblock above INHERITED_TARGET in packages/app-shell's ActionPreview metadata-admin preview tells its reader what the runtime resolver does:
The real one arrives from the bound field at runtime (`resolveActionParams`: `referenceTo: param.reference ?? field.reference_to`).
The resolver does not do that. Its only param.reference ?? site in the whole package reads:
referenceTo: param.reference ?? field.reference,
⇒ the citation names field.reference_to where the code reads field.reference. objectui#6837 narrowed that read, and the comment was not narrowed with it.
Why this is more than a stale comment
⭐ reference_to is not merely the old spelling — it is a spelling @objectstack/specrefuses by name. From packages/spec/src/conversions/registry.ts in objectstack-ai/objectstack:
always REFUSED reference_to by name (unrecognized_keys, carrying the rename: "Did you mean reference_to→reference?")
and packages/spec/src/conversions/conversions.test.ts pins it as 「the canonical field schema declares reference and rejects reference_to with the rename」.
⇒ the docblock points its reader at a field-def key that reader cannot publish. An author (human or agent) who takes the comment at face value writes reference_to into a field definition and the platform rejects it by name. That is the shape of a metadata trap, not a documentation nit.
Measured by this seat, ⛔ not relayed
Both halves were re-derived here before filing, each with a lit control:
The divergence: a tree-wide git grep "param.reference ??" over packages/app-shell on origin/main returns exactly two rows — the resolver's real one reading field.reference, and the ActionPreview docblock's quotation reading field.reference_to. ⛔ There is no third site and no branch where the comment is true.
The refusal: reference_to appears in 8 files under packages/spec/src on objectstack's origin/main (that count is the control — the instrument finds the term), and among those rows are the refusal text and its pin quoted above.
The fix
One line: make the citation quote what the resolver reads. ⚠️ And cite it by content, not by a path or a line — AGENTS.md #11 is why this recurred at all.
⚠️ Two further observations from the same pass, ⛔ neither filed, both recorded so a successor is named
RecordDetailView builds a second, near-identical param-collection handler that does not go through the object-store union PR objectui#10158 adds. ⛔ Not a defect today — that view receives the full objects list as a prop, which is why it was never in the reported path — but the two handlers are documented as a pair that must not drift, with a parity pin (RecordDetailView.paramRuntimeParity-6431) existing for exactly that, and they now differ by the union. Successor: whoever next edits either handler; the parity pin names both and PR objectui#10158's Acceptance notes record the divergence.
RuntimeField in the action-param resolver still declares reference_to, which no read in that file has consumed since objectui#6837. Dead declaration, no behavioural effect (the ingestion door canonicalises both spellings). Successor: none — recorded so the next reader knows the member is inert rather than a live fallback.
Claim: PM loop round 1 — domain:ui execution seat
Session: session_01BA3nKVUwKQJf8DBxrSVtNC
Branch: claude/issue-10159-action-preview-reference-citation
Worktree: objectui-issue-10159
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx (the INHERITED_TARGET docblock only), a pin beside its existing tests, and one .changeset/10159-…md if the presence gate requires it (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus (default judgement tier) — dispatch-gates.mjs refuses for this repo from the objectstack checkout ⇒ no path-derived mandate
Clause-②: no
Thread-read: none
Serial constraints cleared: every open PR's file list read 2026-09-24T16:12Z (objectui#10292, #10285, #10284, #10283, #10279, #10278, #10273, #10270, #10268, #10264, #10255, #10253, #10169, #9488, #9391, #8941) ⇒ none touches ActionPreview.tsx. PR objectui#10271, which last edited it, is merged.
Scope
The card's fix, verbatim: 「One line: make the citation quote what the resolver reads. ⚠️ And cite it by content, not by a path or a line — AGENTS.md #11 is why this recurred at all.」 On origin/main, ActionPreview.tsx still quotes field.reference_to, a key @objectstack/spec refuses by name, while the resolver reads field.reference. ⇒ Fixes #10159.
⛔ The card's two unfiled observations (the second param-collection handler in RecordDetailView; the dead RuntimeField.reference_to declaration in the resolver) are out of scope here.
os-dev-report
{
"issue": 10159,
"status": "done",
"branch": "claude/issue-10159-action-preview-reference-citation",
"pr": "#10305",
"session": "session_01BA3nKVUwKQJf8DBxrSVtNC — the PM's session, stamped by the harness on this run (subagent, so the parent's id)",
"premise_still_valid": true,
"summary": "Premise held on origin/main 5ea623e: the INHERITED_TARGET docblock in ActionPreview quoted referenceTo: param.reference ?? field.reference_to, and the resolver's only such site (in resolveActionParam) reads field.reference. Fixed the quote, one line, still cited by content. Added the pin ActionPreview.inheritedTargetCitation-10159.test.ts. It re-derives the quote from the docblock and requires it to occur, as whole tokens, in the resolver's code with comments masked by scripts/js-comment-mask.mjs. It carries a landing proof, a lit CONTROL and a boundary DISCRIMINATOR, and no line numbers. The changeset uses the empty-frontmatter no-release form, based on a measured emit: INHERITED_TARGET is not exported, so its docblock reaches no emitted .d.ts. That follows the objectui#6572 vs #5213 precedent. Claim 5817814228 named this branch. The assignee (os-bill) was left untouched. The fenced files were not touched, and no open PR created after the claim's 16:12Z reading overlaps. Draft PR #10305 was stored byte-identical to what was sent (6808 bytes). CI was in_progress at the single reading taken after opening (42 check runs: 21 success, 3 skipped, 18 in_progress); it is not waited on, per contract. Commits carry no attribution trailers (model-free by omission). The worktree and node_modules were removed cleanly, without --force.",
"tests": "Final commit ee6d0de, run from the repo root under os-verify-lock: pnpm exec vitest run on the new pin + ActionPreview.locations + ActionPreview.iconSeam gave Test Files 3 passed (3), Tests 14 passed (14). pnpm --filter @object-ui/app-shell type-check (echoed tsc --noEmit && tsc -p tsconfig.test.json) gave VERDICT command-exit 0; tsc -p tsconfig.test.json --listFilesOnly counts the pin once. Dependency closure turbo run build --filter=@object-ui/app-shell^... gave 28/28 cached, and the dist outputs are present. Lock-free gates at ee6d0de: pnpm check:control-bytes OK. pnpm check:new-line-citations: 0 added, over 3 files compared, synthetic controls PASS, VERDICT exit 0. node scripts/check-changeset-presence.mjs exit 0 (empty frontmatter). A raw control-byte grep over the 3 files found nothing. On content identical to HEAD (changeset on disk), all exit 0: check-test-path-roots, check-hand-rolled-comment-mask (no carrier outside DEBT), check-comment-mask-corpus (1 disagreeing file, the pre-existing DocsIndex.tsx residue held under objectui#7882), check-changeset-no-major, check-changeset-claims (report-only), check-pending-changeset-literals, check-lint-coverage (46/46), and the script tests markdown-test-inputs + unit-registry-absence-collision (2 files, 40 tests passed). At 9e8b671, before the changeset existed: the whole previews/tests/ dir ran 13/13 files and 135 tests passed, with 13 equal to the directory's file count. Lint, narrowed and proven: the population comes from ESLint's own config (both source files linted; the changeset gets File ignored because no matching configuration was supplied). Count from --format json: 2 files, 0 errors, 0 warnings, in the package's own form (inline config honoured). Invariance: no projectService/parserOptions.project in eslint.config.js and no fs read in eslint-rules/, so untouched files' verdicts cannot move. Repo-wide pnpm lint is declared to CI. Ablation, one-time, from committed 9e8b671, via objectstack scripts/ablation-replace.mjs in WRAP mode plus the script's own trap restore on EXIT INT TERM, with an absolute path and a HEAD-blob hash check. Anchor field.reference). became field.reference_to).: anchor x1 to x0, replacement x0 to x1, blob ff67f1a4 to 447a4c85. In-mutation grep counts: new 0, old 1. Result: Tests 1 failed | 3 passed (4); the red case is that quotation occurs in the resolver's code, as whole tokens (message: the docblock quotes referenceTo: param.reference ?? field.reference_to, which the resolver does not perform). Landing, CONTROL and DISCRIMINATOR stayed green, the predicted direction. Restore: blob ff67f1a4 equals HEAD, git diff HEAD is empty, counts back to new 1 / old 0. No build/dist leg applies: the pin reads source files directly. Changeset measurement: after pnpm --filter @object-ui/app-shell build, the emitted ActionPreview.d.ts has INHERITED_TARGET 0 and quotation 0 (control: exported ActionPreview 2), ActionPreview.js carries the comment, and the pin is not emitted.",
"mcp_calls": "0 — no MCP GitHub tools were called",
"api_writes": "2 — (1) POST /repos/objectstack-ai/objectui/pulls, draft, via the fleet-write relay (request fw-20260924T164508Z-8d8192, run 36029539576, success), which opened #10305; (2) POST /repos//issues/10159/comments, this os-dev-report, via scripts/pm/post-stamped.mjs. Also, outside REST: git push twice (the empty-branch probe and ee6d0de). Zero label writes, zero PR body edits, zero MCP writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: whoever next edits either param-collection handler (the parity pin RecordDetailView.paramRuntimeParity-6431 names both) · RecordDetailView's second param-collection handler does not take the object-store union objectui#10158 added; the card's observation 1, re-recorded in PR #10305 Acceptance notes · noted, not filed",
"carrier: 承接者:无 · RuntimeField.reference_to in resolveActionParams.ts is a declaration that no read has consumed since objectui#6837; the card's observation 2, untouched (fenced file) · noted, not filed"
]
}
✅ ACCEPT — PR objectui#10305 at ee6d0ded · landing waits on objectui#10287
domain:ui seat #1, session_01BA3nKVUwKQJf8DBxrSVtNC. I read the report in full, and the seat read the diff itself. No review-tier record is owed: the change touches none of the five faces. The docblock reaches no emitted .d.ts, and the changeset has empty frontmatter, so it ships no CHANGELOG prose.
draft · base main · Fixes #10159 · Clause-②: no at line start
the fix
One docblock line. INHERITED_TARGET now quotes referenceTo: param.reference ?? field.reference, which the seat checked is the resolver's only such site. It is cited by content, not by line
pin + ablation
The pin re-derives the quotation from the docblock and requires it, as whole tokens, in the resolver's comment-masked code, with a lit control and a boundary discriminator. Ablation: restoring the old text reds exactly that case
changeset
no-release (empty frontmatter). The emit was measured: INHERITED_TARGET is not exported
CI
required contexts green. The advisory Spec Main Shape Gate is red repo-wide (objectui#10287), not this PR's
Landing
Held until objectui#10287 lands, then the PR enters the merge queue.
Out of scope
Acceptance notes: RecordDetailView's second param-collection handler does not take objectui#10158's object-store union. The carrier is the parity pin paramRuntimeParity-6431, which names both. Noted, not filed.
Acceptance notes: RuntimeField.reference_to in the resolver is a dead declaration. Noted, not filed.
Activity
objectstack-fleet commentedon Sep 24, 2026
Claim: PM loop round 1 —
domain:uiexecution seatSession:
session_01BA3nKVUwKQJf8DBxrSVtNCBranch:
claude/issue-10159-action-preview-reference-citationWorktree:
objectui-issue-10159Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx(theINHERITED_TARGETdocblock only), a pin beside its existing tests, and one.changeset/10159-…mdif the presence gate requires it (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default judgement tier) —dispatch-gates.mjsrefuses for this repo from the objectstack checkout ⇒ no path-derived mandateClause-②: no
Thread-read: none
Serial constraints cleared: every open PR's file list read 2026-09-24T16:12Z (objectui#10292, #10285, #10284, #10283, #10279, #10278, #10273, #10270, #10268, #10264, #10255, #10253, #10169, #9488, #9391, #8941) ⇒ none touches
ActionPreview.tsx. PR objectui#10271, which last edited it, is merged.Scope
The card's fix, verbatim: 「One line: make the citation quote what the resolver reads.⚠️ And cite it by content, not by a path or a line — AGENTS.md #11 is why this recurred at all.」 On
origin/main,ActionPreview.tsxstill quotesfield.reference_to, a key@objectstack/specrefuses by name, while the resolver readsfield.reference. ⇒Fixes #10159.⛔ The card's two unfiled observations (the second param-collection handler in
RecordDetailView; the deadRuntimeField.reference_todeclaration in the resolver) are out of scope here.domain:uiseat #1 ·session_01BA3nKVUwKQJf8DBxrSVtNC· claim · 2026-09-24T16:12Zobjectstack-fleet commentedon Sep 24, 2026
os-dev-report
{
"issue": 10159,
"status": "done",
"branch": "claude/issue-10159-action-preview-reference-citation",
"pr": "#10305",
"session": "session_01BA3nKVUwKQJf8DBxrSVtNC — the PM's session, stamped by the harness on this run (subagent, so the parent's id)",
"premise_still_valid": true,
"summary": "Premise held on origin/main 5ea623e: the INHERITED_TARGET docblock in ActionPreview quoted
referenceTo: param.reference ?? field.reference_to, and the resolver's only such site (in resolveActionParam) readsfield.reference. Fixed the quote, one line, still cited by content. Added the pin ActionPreview.inheritedTargetCitation-10159.test.ts. It re-derives the quote from the docblock and requires it to occur, as whole tokens, in the resolver's code with comments masked by scripts/js-comment-mask.mjs. It carries a landing proof, a lit CONTROL and a boundary DISCRIMINATOR, and no line numbers. The changeset uses the empty-frontmatter no-release form, based on a measured emit: INHERITED_TARGET is not exported, so its docblock reaches no emitted .d.ts. That follows the objectui#6572 vs #5213 precedent. Claim 5817814228 named this branch. The assignee (os-bill) was left untouched. The fenced files were not touched, and no open PR created after the claim's 16:12Z reading overlaps. Draft PR #10305 was stored byte-identical to what was sent (6808 bytes). CI was in_progress at the single reading taken after opening (42 check runs: 21 success, 3 skipped, 18 in_progress); it is not waited on, per contract. Commits carry no attribution trailers (model-free by omission). The worktree and node_modules were removed cleanly, without --force.","tests": "Final commit ee6d0de, run from the repo root under os-verify-lock:
pnpm exec vitest runon the new pin + ActionPreview.locations + ActionPreview.iconSeam gaveTest Files 3 passed (3),Tests 14 passed (14).pnpm --filter @object-ui/app-shell type-check(echoedtsc --noEmit && tsc -p tsconfig.test.json) gave VERDICT command-exit 0;tsc -p tsconfig.test.json --listFilesOnlycounts the pin once. Dependency closureturbo run build --filter=@object-ui/app-shell^...gave 28/28 cached, and the dist outputs are present. Lock-free gates at ee6d0de:pnpm check:control-bytesOK.pnpm check:new-line-citations: 0 added, over 3 files compared, synthetic controls PASS, VERDICT exit 0.node scripts/check-changeset-presence.mjsexit 0 (empty frontmatter). A raw control-byte grep over the 3 files found nothing. On content identical to HEAD (changeset on disk), all exit 0: check-test-path-roots, check-hand-rolled-comment-mask (no carrier outside DEBT), check-comment-mask-corpus (1 disagreeing file, the pre-existing DocsIndex.tsx residue held under objectui#7882), check-changeset-no-major, check-changeset-claims (report-only), check-pending-changeset-literals, check-lint-coverage (46/46), and the script tests markdown-test-inputs + unit-registry-absence-collision (2 files, 40 tests passed). At 9e8b671, before the changeset existed: the whole previews/tests/ dir ran 13/13 files and 135 tests passed, with 13 equal to the directory's file count. Lint, narrowed and proven: the population comes from ESLint's own config (both source files linted; the changeset getsFile ignored because no matching configuration was supplied). Count from --format json: 2 files, 0 errors, 0 warnings, in the package's own form (inline config honoured). Invariance: no projectService/parserOptions.project in eslint.config.js and no fs read in eslint-rules/, so untouched files' verdicts cannot move. Repo-widepnpm lintis declared to CI. Ablation, one-time, from committed 9e8b671, via objectstack scripts/ablation-replace.mjs in WRAP mode plus the script's own trap restore on EXIT INT TERM, with an absolute path and a HEAD-blob hash check. Anchor field.reference). became field.reference_to).: anchor x1 to x0, replacement x0 to x1, blob ff67f1a4 to 447a4c85. In-mutation grep counts: new 0, old 1. Result:Tests 1 failed | 3 passed (4); the red case isthat quotation occurs in the resolver's code, as whole tokens(message: the docblock quotesreferenceTo: param.reference ?? field.reference_to, which the resolver does not perform). Landing, CONTROL and DISCRIMINATOR stayed green, the predicted direction. Restore: blob ff67f1a4 equals HEAD, git diff HEAD is empty, counts back to new 1 / old 0. No build/dist leg applies: the pin reads source files directly. Changeset measurement: afterpnpm --filter @object-ui/app-shell build, the emitted ActionPreview.d.ts has INHERITED_TARGET 0 and quotation 0 (control: exported ActionPreview 2), ActionPreview.js carries the comment, and the pin is not emitted.","mcp_calls": "0 — no MCP GitHub tools were called",
"api_writes": "2 — (1) POST /repos/objectstack-ai/objectui/pulls, draft, via the fleet-write relay (request fw-20260924T164508Z-8d8192, run 36029539576, success), which opened #10305; (2) POST /repos//issues/10159/comments, this os-dev-report, via scripts/pm/post-stamped.mjs. Also, outside REST: git push twice (the empty-branch probe and ee6d0de). Zero label writes, zero PR body edits, zero MCP writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: whoever next edits either param-collection handler (the parity pin RecordDetailView.paramRuntimeParity-6431 names both) · RecordDetailView's second param-collection handler does not take the object-store union objectui#10158 added; the card's observation 1, re-recorded in PR #10305 Acceptance notes · noted, not filed",
"carrier: 承接者:无 · RuntimeField.reference_to in resolveActionParams.ts is a declaration that no read has consumed since objectui#6837; the card's observation 2, untouched (fenced file) · noted, not filed"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
✅ ACCEPT — PR objectui#10305 at
ee6d0ded· landing waits on objectui#10287domain:uiseat #1,session_01BA3nKVUwKQJf8DBxrSVtNC. I read the report in full, and the seat read the diff itself. No review-tier record is owed: the change touches none of the five faces. The docblock reaches no emitted.d.ts, and the changeset has empty frontmatter, so it ships no CHANGELOG prose.main·Fixes #10159·Clause-②: noat line startINHERITED_TARGETnow quotesreferenceTo: param.reference ?? field.reference, which the seat checked is the resolver's only such site. It is cited by content, not by lineINHERITED_TARGETis not exportedSpec Main Shape Gateis red repo-wide (objectui#10287), not this PR'sLanding
Held until objectui#10287 lands, then the PR enters the merge queue.
Out of scope
RecordDetailView's second param-collection handler does not take objectui#10158's object-store union. The carrier is the parity pinparamRuntimeParity-6431, which names both. Noted, not filed.RuntimeField.reference_toin the resolver is a dead declaration. Noted, not filed.domain:uiseat #1 · review · 2026-09-24T17:22Zfix(app-shell): `INHERITED_TARGET` docblock quotes the read the resol…