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
types: objectui validate refuses record:approvals and record:attachments, two spec-18 page blocks the default record page emits and app-shell renders — they have no AnyComponentSchema arm #12363
Filing gate ① a defect on a published face, measured.reach: the published objectui validate / validateAuthoredDocument authoring face.
Filed by objectui domain:ui seat 2 (seat post #9771), session session_01XVp19E1MYUTFM3dnkwz8gB, from an out-of-scope finding in the dev report for objectui#12342 (PR #12362). ⛔ Not a claim. For triage to grade and route.
What was measured (the dev's reading on base 065a1cf)
validateAuthoredDocument answers invalid_union at ['type'] for { type: 'record:approvals' } and for { type: 'record:attachments' }.
@objectstack/spec 18 declares both as PageComponentType members with ComponentPropsMap rows.
packages/plugin-detailbuildDefaultPageSchema emits both, and @object-ui/app-shell registers a renderer for each.
So a record page that objectui itself builds, or one an author or AI writes from the spec, is refused by the validator. Both types are still counted in the cli ratchet NAMESPACED_REFUSED_AT_TYPE (308 at base).
The precedent in flight
objectui PR #12362 (objectui#12342) gives record:approval_decision its arm while registering it:
RecordApprovalDecisionBlockSchema in @object-ui/types/zod is a strict bag restating the spec row;
it carries its TS twin, its AnyComponentSchema member and its mirror-parity pair;
each block validates with its spec-declared props;
an undeclared key is refused;
the default record page buildDefaultPageSchema emits validates whole.
Reader (who acts): the objectui lane triage routes it to. The arms live in packages/types, the stream domain:spec and domain:ui have each carried before (objectui#10872 was domain:ui).
Dedupe: MCP search_issues in objectui, closed included, for NAMESPACED_REFUSED_AT_TYPE namespaced component types refused at type arm ratchet objectui validate: 14 hits, none open, none this question. The family closure objectui#10872 is closed, with this residual left in its ratchet.
Read fresh. On objectui main, record:approvals has no arm in packages/types/src/zod, and the ratchet NAMESPACED_REFUSED_AT_TYPE is in packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts.
Scope as filed: two arms restating the spec rows, the ratchet lowered by two, and the three pins (props validate, an undeclared key refused, buildDefaultPageSchema's page validates whole).
The blocker #12342 closed completed: PR #12362 landed the record:approval_decision arm, the construction this card reuses. The grade is unchanged: p2, domain:ui. It is on #12334's pre-release list.
Claim: PM loop round 1
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-12363-approvals-attachments-arms
Worktree: objectui-issue-12363
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/types/src/zod/ (the two new block arms and AnyComponentSchema), their TS twins and mirror-parity pairs in packages/types/src/, the cli ratchet packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts, and their tests (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
Clause-②: yes — two new published arms widen objectui validate's accept set. The contract review is owed before the queue, the way objectui#12342's arm took one.
Responsibility: objectui's @object-ui/types validator refuses two spec-18 blocks | no platform path covers it: the validator is objectui's own authoring face | every author or AI validating a record page that carries the approvals or attachments block, including the default record page objectui builds
Thread-read: 6168991320
Serial constraints cleared: the predecessor objectui#12342 (PR #12362, the same construction in the same files) landed as 52d6194. The in-flight objectui#12370 bump may touch packages/types if 18.0.0-next.1 turns a types test red; whichever lands second merges main (read 2026-10-14T17:58Z).
{
"issue": 12363,
"status": "done",
"branch": "claude/issue-12363-approvals-attachments-arms",
"pr": "https://github.com/objectstack-ai/objectui/pull/12382",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB (parent's; subagent run)",
"premise_still_valid": true,
"summary": "New zod module packages/types/src/zod/record-panels.zod.ts adds RecordApprovalsBlockSchema and RecordAttachmentsBlockSchema, wired into AnyComponentSchema. Each properties bag restates its installed spec row (@objectstack/spec 18.0.0-next.0): both rows are strict and keyless, so each bag is z.strictObject({}).optional(). body/children are refused by name. The PR adds TS twins in packages/types/src/record-panels.ts (exported, plus two AnySchema members), two mirror-parity pairs (EXPECTED_MIRROR_PAIRS 196 to 198), two emit-headroom members, and lowers NAMESPACED_REFUSED_AT_TYPE 308 to 306 with a named row. Pins: per-arm bag equals the row, the node validates, undeclared keys are refused, and buildDefaultPageSchema's page validates whole on both faces. A1/A2/A3 hold. A2 has one boundary: when the host threads approvals.node (RecordDetailView passes approvals + currentUserId), the bag refuses both, because the spec row names them host runtime channels. This is the same as record:history's host entries. I pinned it as a refusal and did not widen the arm. #12370 had not landed; main moved one unrelated commit (fc211e817), so the rows were measured on next.0. Deviation: the default-page pin is a new test file in packages/plugin-detail/src/__tests__/, outside the named surface. types/cli cannot import plugin-detail (phantom-deps), and no plugin-detail source changed.",
"tests": "Head 83d91d3. vitest under the verify lock, full packages/types/ + packages/cli/ + the plugin-detail pin: 'Test Files 409 passed (409)', 'Tests 10719 passed (10719)', VERDICT command-exit 0. Earlier targeted run (6 files incl. record-approval-decision-arm-12342, zod-mirror-parity, emit-headroom, ratchet): 129 passed. type-check of @object-ui/types, @object-ui/cli and @object-ui/plugin-detail (after building the dependency closure): all 'Done', exit 0. Ablation with ablation-replace.mjs --delete on the two union members in zod/index.zod.ts: anchor 1 to 0, blob cd2ce50 to 0f4b39f, 'Test Files 3 failed (3)', 'Tests 24 failed | 50 passed (74)'. That covers the ratchet pin and row, all 4 default-page rows and the union-path arm rows; bag-vs-row rows stayed green as predicted. Restored with blob == HEAD and an empty git diff HEAD. No build leg was needed because vitest aliases @object-ui/types to src. Gates exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, registry-bare-names, control-bytes, new-line-citations (0 new citations); check-changeset-fixed/presence/no-major 0. check:spec-floors exit 1, 'The scan collapsed: 0 package(s) declare @objectstack/spec' (known objectui#12334; diff touches no dependency field). Lint narrowed to the 9 changed .ts files with eslint --format json, as the package lint scripts run it: 9 results, 0 errors, 0 warnings. With --no-inline-config: 3 findings, all on untouched lines already covered by inline disables. Not type-aware (no project/projectService in eslint.config.js), so untouched files' verdicts cannot move. Full pnpm lint belongs to CI. CI: in_progress at report time.",
"mcp_calls": "0",
"api_writes": "2 relay strokes as objectstack-fleet[bot] via fleet-write: (1) pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/12382/assignees; (2) this os-dev-report comment = POST /repos/objectstack-ai/objectui/issues/12363/comments. Plus git pushes of the branch (empty-branch probe, 2 commits). Zero label writes: objectui path labels belong to labeler.yml, and the dispatch named no label.",
"gates": {"vitest_types_cli_full": 0, "type-check_types_cli_plugin-detail": 0, "check:phantom-deps": 0, "check:self-import": 0, "check:unreferenced-sources": 0, "check:doc-example-readers": 0, "check:handler-key-reads": 0, "check:side-effects-array": 0, "check:element-data-source-declaration": 0, "check:spec-symbols": 0, "check:action-forward-parity": 0, "check:designer-field-key-parity": 0, "check:icon-record-names": 0, "check:i18n-keys": 0, "check:i18n-drift": 0, "check:i18n-designer-parity": 0, "check:registry-bare-names": 0, "check:control-bytes": 0, "check:new-line-citations": 0, "check:spec-floors": 1, "check-changeset-fixed": 0, "check-changeset-presence": 0, "check-changeset-no-major": 0, "eslint_narrowed": 0},
"files_changed": [".changeset/12363-approvals-attachments-arms.md", "packages/types/src/zod/record-panels.zod.ts", "packages/types/src/record-panels.ts", "packages/types/src/zod/index.zod.ts", "packages/types/src/index.ts", "packages/types/src/__tests__/zod-mirror-parity.test.ts", "packages/types/src/__tests__/any-component-emit-headroom-11573.test.ts", "packages/types/src/__tests__/record-panels-arms-12363.test.ts", "packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts", "packages/plugin-detail/src/__tests__/buildDefaultPageSchema.validatesWhole-12363.test.ts"],
"deviations": ["File surface: one new test file in packages/plugin-detail/src/__tests__/ carries the ruled buildDefaultPageSchema pin. No plugin-detail source changed; types/cli cannot depend on plugin-detail.", "One verify-lock attempt ended exit 99 (queue-timeout behind another seat's fields run); retried with the same slot and got the lock after 96s."],
"open_questions": [],
"out_of_scope_findings": ["Not filed, noted in PR Acceptance notes. The restated record:approvals bag loses the spec row's own unrecognized-key guidance text for approvals/currentUserId; it reports only a generic unrecognized_keys, and the arm's .describe() carries the guidance. Carrying the row's message would need @objectstack/spec/ui to export RecordApprovalsProps under a name, or the objectui#8317 boundary census to admit a ComponentPropsMap index. carrier: whoever lands the next spec bump that names the row; otherwise 承接者:无."]
}
Reviewed on GitHub at head 83d91d3, against triage's scope (6165654268) and the contract review on this head, not against the dev's report.
Shape: the PR is a draft against main. Its body opens Fixes #12363, the only closing keyword, followed by Clause-②: yes. The governed sweep reads NOT governed, 523 lines (+517 / −6).
② @object-ui/types: minor is right for two new exports and a wider accept set, with nothing removed. cli and plugin-detail are test-only.
③ Every boundary flag is answered.
Triage's scope is met:
two arms restating the spec rows (construction of objectui#12342);
NAMESPACED_REFUSED_AT_TYPE 308 → 306 with a named row;
pins: each block validates with its spec-declared props, an undeclared key is refused, and buildDefaultPageSchema's page validates whole on both faces.
A2 boundary, pinned, not widened: when the host threads approvals / currentUserId onto the node at runtime, the bag refuses both. The spec row names them host runtime channels, as with record:history's host entries. No runtime path hands that page to the validator.
Declared deviation, accepted: the default-page pin lives in packages/plugin-detail/src/__tests__/, because types / cli may not import plugin-detail (phantom-deps). No plugin-detail source changed.
Prose: the changeset matches the diff. Its body has one grammar slip ("buildDefaultPageSchema builds emits both"). It states nothing false and is not worth a cycle; it stays as written.
Acceptance note (noted, not filed): the restated record:approvals bag reports a generic unrecognized_keys where the spec row carries its own guidance text. Carrying that text needs the spec to export the row by name, or named tombstones like record:history's; the accept set is identical either way.
CI at head: 30 success, 3 skipped, 0 failures (filter=latest), all 12 test shards included.
needs:contract-review is removed in the same stroke. Next: pr_ready + automerge_enable.
Activity
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade ·
bug·priority:p2·domain:ui·area:records·target:v18·pm:blockedon #12342 · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T09:52ZRead fresh. On objectui
main,record:approvalshas no arm inpackages/types/src/zod, and the ratchetNAMESPACED_REFUSED_AT_TYPEis inpackages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts.priority:p2: the published validator refuses two spec-18 blocks that objectui itself emits and renders, so a valid record page failsobjectui validate. Pages still render, so it is not class A under the maintainer's rule of 2026-10-14. It is a consumer follow-up, listed on release(v18): objectui's first 18.x release — the syncmajor, Changesets pre mode onnext, and the two gate edits (the maintainer's ruling on #12030), after #12030 lands #12334.domain:ui, with its sibling app-shell: spec 18'srecord:approval_decisionpage block renders nothing —ApprovalDecisionRendereris written but never registered (the objectui half of spec 18's three record blocks, after #12030) #12342. That card's PR feat(app-shell): register record:approval_decision, armed in @object-ui/types (objectui#12342) #12362 (draft) builds the construction this card reuses, in the samepackages/types/src/zodfiles.Blocked-by: #12342
buildDefaultPageSchema's page validates whole).objectstack-fleet commentedon Oct 14, 2026
Unlock scan:
pm:blocked→pm:queue· #12342 closed · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T13:03ZThe blocker #12342 closed
completed: PR #12362 landed therecord:approval_decisionarm, the construction this card reuses. The grade is unchanged: p2,domain:ui. It is on #12334's pre-release list.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1
Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12363-approvals-attachments-armsWorktree:
objectui-issue-12363Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/types/src/zod/(the two new block arms andAnyComponentSchema), their TS twins and mirror-parity pairs inpackages/types/src/, the cli ratchetpackages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts, and their tests (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate)Clause-②: yes — two new published arms widen
objectui validate's accept set. The contract review is owed before the queue, the way objectui#12342's arm took one.Responsibility:
objectui's @object-ui/types validator refuses two spec-18 blocks | no platform path covers it: the validator is objectui's own authoring face | every author or AI validating a record page that carries the approvals or attachments block, including the default record page objectui buildsThread-read: 6168991320
Serial constraints cleared: the predecessor objectui#12342 (PR #12362, the same construction in the same files) landed as
52d6194. The in-flight objectui#12370 bump may touchpackages/typesif18.0.0-next.1turns a types test red; whichever lands second mergesmain(read 2026-10-14T17:58Z).Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 12363, "status": "done", "branch": "claude/issue-12363-approvals-attachments-arms", "pr": "https://github.com/objectstack-ai/objectui/pull/12382", "session": "session_01XVp19E1MYUTFM3dnkwz8gB (parent's; subagent run)", "premise_still_valid": true, "summary": "New zod module packages/types/src/zod/record-panels.zod.ts adds RecordApprovalsBlockSchema and RecordAttachmentsBlockSchema, wired into AnyComponentSchema. Each properties bag restates its installed spec row (@objectstack/spec 18.0.0-next.0): both rows are strict and keyless, so each bag is z.strictObject({}).optional(). body/children are refused by name. The PR adds TS twins in packages/types/src/record-panels.ts (exported, plus two AnySchema members), two mirror-parity pairs (EXPECTED_MIRROR_PAIRS 196 to 198), two emit-headroom members, and lowers NAMESPACED_REFUSED_AT_TYPE 308 to 306 with a named row. Pins: per-arm bag equals the row, the node validates, undeclared keys are refused, and buildDefaultPageSchema's page validates whole on both faces. A1/A2/A3 hold. A2 has one boundary: when the host threads approvals.node (RecordDetailView passes approvals + currentUserId), the bag refuses both, because the spec row names them host runtime channels. This is the same as record:history's host entries. I pinned it as a refusal and did not widen the arm. #12370 had not landed; main moved one unrelated commit (fc211e817), so the rows were measured on next.0. Deviation: the default-page pin is a new test file in packages/plugin-detail/src/__tests__/, outside the named surface. types/cli cannot import plugin-detail (phantom-deps), and no plugin-detail source changed.", "tests": "Head 83d91d3. vitest under the verify lock, full packages/types/ + packages/cli/ + the plugin-detail pin: 'Test Files 409 passed (409)', 'Tests 10719 passed (10719)', VERDICT command-exit 0. Earlier targeted run (6 files incl. record-approval-decision-arm-12342, zod-mirror-parity, emit-headroom, ratchet): 129 passed. type-check of @object-ui/types, @object-ui/cli and @object-ui/plugin-detail (after building the dependency closure): all 'Done', exit 0. Ablation with ablation-replace.mjs --delete on the two union members in zod/index.zod.ts: anchor 1 to 0, blob cd2ce50 to 0f4b39f, 'Test Files 3 failed (3)', 'Tests 24 failed | 50 passed (74)'. That covers the ratchet pin and row, all 4 default-page rows and the union-path arm rows; bag-vs-row rows stayed green as predicted. Restored with blob == HEAD and an empty git diff HEAD. No build leg was needed because vitest aliases @object-ui/types to src. Gates exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, registry-bare-names, control-bytes, new-line-citations (0 new citations); check-changeset-fixed/presence/no-major 0. check:spec-floors exit 1, 'The scan collapsed: 0 package(s) declare @objectstack/spec' (known objectui#12334; diff touches no dependency field). Lint narrowed to the 9 changed .ts files with eslint --format json, as the package lint scripts run it: 9 results, 0 errors, 0 warnings. With --no-inline-config: 3 findings, all on untouched lines already covered by inline disables. Not type-aware (no project/projectService in eslint.config.js), so untouched files' verdicts cannot move. Full pnpm lint belongs to CI. CI: in_progress at report time.", "mcp_calls": "0", "api_writes": "2 relay strokes as objectstack-fleet[bot] via fleet-write: (1) pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/12382/assignees; (2) this os-dev-report comment = POST /repos/objectstack-ai/objectui/issues/12363/comments. Plus git pushes of the branch (empty-branch probe, 2 commits). Zero label writes: objectui path labels belong to labeler.yml, and the dispatch named no label.", "gates": {"vitest_types_cli_full": 0, "type-check_types_cli_plugin-detail": 0, "check:phantom-deps": 0, "check:self-import": 0, "check:unreferenced-sources": 0, "check:doc-example-readers": 0, "check:handler-key-reads": 0, "check:side-effects-array": 0, "check:element-data-source-declaration": 0, "check:spec-symbols": 0, "check:action-forward-parity": 0, "check:designer-field-key-parity": 0, "check:icon-record-names": 0, "check:i18n-keys": 0, "check:i18n-drift": 0, "check:i18n-designer-parity": 0, "check:registry-bare-names": 0, "check:control-bytes": 0, "check:new-line-citations": 0, "check:spec-floors": 1, "check-changeset-fixed": 0, "check-changeset-presence": 0, "check-changeset-no-major": 0, "eslint_narrowed": 0}, "files_changed": [".changeset/12363-approvals-attachments-arms.md", "packages/types/src/zod/record-panels.zod.ts", "packages/types/src/record-panels.ts", "packages/types/src/zod/index.zod.ts", "packages/types/src/index.ts", "packages/types/src/__tests__/zod-mirror-parity.test.ts", "packages/types/src/__tests__/any-component-emit-headroom-11573.test.ts", "packages/types/src/__tests__/record-panels-arms-12363.test.ts", "packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts", "packages/plugin-detail/src/__tests__/buildDefaultPageSchema.validatesWhole-12363.test.ts"], "deviations": ["File surface: one new test file in packages/plugin-detail/src/__tests__/ carries the ruled buildDefaultPageSchema pin. No plugin-detail source changed; types/cli cannot depend on plugin-detail.", "One verify-lock attempt ended exit 99 (queue-timeout behind another seat's fields run); retried with the same slot and got the lock after 96s."], "open_questions": [], "out_of_scope_findings": ["Not filed, noted in PR Acceptance notes. The restated record:approvals bag loses the spec row's own unrecognized-key guidance text for approvals/currentUserId; it reports only a generic unrecognized_keys, and the arm's .describe() carries the guidance. Carrying the row's message would need @objectstack/spec/ui to export RecordApprovalsProps under a name, or the objectui#8317 boundary census to admit a ComponentPropsMap index. carrier: whoever lands the next spec bump that names the row; otherwise 承接者:无."] }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Review: ACCEPT — objectui PR #12382 ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-14T18:57ZReviewed on GitHub at head
83d91d3, against triage's scope (6165654268) and the contract review on this head, not against the dev's report.main. Its body opensFixes #12363, the only closing keyword, followed byClause-②: yes. The governed sweep reads NOT governed, 523 lines (+517 / −6).6175931173on PR feat(types): arm record:approvals and record:attachments from their spec rows (objectui#12363) #12382:Served-tier: CONTRACT_REVIEW_TIER,Head-sha83d91d37f6…(this head),Local-runs: none.record:approvalsandrecord:attachmentsare strict and keyless, so each bag isz.strictObject({}).optional(), andbody/childrenare refused by name, as on app-shell: spec 18'srecord:approval_decisionpage block renders nothing —ApprovalDecisionRendereris written but never registered (the objectui half of spec 18's three record blocks, after #12030) #12342.@object-ui/types: minoris right for two new exports and a wider accept set, with nothing removed. cli and plugin-detail are test-only.NAMESPACED_REFUSED_AT_TYPE308 → 306 with a named row;buildDefaultPageSchema's page validates whole on both faces.approvals/currentUserIdonto the node at runtime, the bag refuses both. The spec row names them host runtime channels, as withrecord:history's host entries. No runtime path hands that page to the validator.packages/plugin-detail/src/__tests__/, becausetypes/climay not import plugin-detail (phantom-deps). No plugin-detail source changed.buildDefaultPageSchemabuilds emits both"). It states nothing false and is not worth a cycle; it stays as written.record:approvalsbag reports a genericunrecognized_keyswhere the spec row carries its own guidance text. Carrying that text needs the spec to export the row by name, or named tombstones likerecord:history's; the accept set is identical either way.filter=latest), all 12 test shards included.needs:contract-reviewis removed in the same stroke. Next:pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-14T19:30Zmain2b4d3f1. The card closedcompletedby the PR'sFixes #12363, which is the only closing keyword. No other card closed with it.origin/main, all 10 files the PR touches are blob-identical to the accepted, contract-reviewed head83d91d3. They include:record-panels.zod.ts,record-panels.ts,zod/index.zod.tsandindex.ts;.changeset/12363-approvals-attachments-arms.md.pm:dispatchedis removed in the same stroke as this comment.Generated by Claude Code