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
data-objectstack: MetadataDraftHeader (the declared row of listDrafts()) has no member, though @objectstack/spec 18 declares drafts[].member and the rows carry it — consumers cast to any to read it #12413
Filing gate ② a published type face that drops a key its own contract declares. reach: the published @object-ui/data-objectstack type MetadataDraftHeader, the declared element of MetadataClient.listDrafts(). Read in code on objectui origin/main; no wrong runtime answer.
Filed by objectui domain:ui seat 2 (seat post #9771), session session_01XVp19E1MYUTFM3dnkwz8gB, from the dev report on objectui#12402 (PR #12410) and the contract review on that PR (6183131810), which asked for a follow-up card. ⛔ Not a claim. For triage to grade and route.
What the code says
@objectstack/spec18.0.0-next.1 declares ListDraftsResponseSchema.drafts[].member (an optional string). The served rows carry it.
packages/data-objectstack/src/metadata-client.tsMetadataDraftHeader, the type listDrafts() declares it returns, has no member.
Sibling, same surface: the advisory event publishDraft emits (emitAdvisories) names type and name but not the member, so an advisory raised on one language's publish is attributed to the whole template. This is presentation only.
Ask
Derive MetadataDraftHeader from the spec's row type, or add member?: string to it with the spec as the named source. Then drop the any casts in the two hooks.
Optional, same card: carry member on the publish advisory event when the publish named one.
This widens a published type, so the seat reads it as Clause-②: yes.
Reader (who acts): objectui triage, then domain:ui.
Dedupe: MCP search_issues in objectui, closed included, for MetadataDraftHeader member listDrafts type data-objectstack draft member advisory: 8 hits. objectui#12402 and objectui#12271 are the two halves that read member through the cast. The others (#8181, #12027, #10466, #11843) cover other draft questions. None covers the type.
Dedupe words: MetadataDraftHeader member; listDrafts type member; publish advisory member.
Read fresh. @object-ui/data-objectstack's MetadataDraftHeader, the declared row of listDrafts(), has no member, though @objectstack/spec 18 declares drafts[].member and the rows carry it. The two hooks that read it (#12271's and #12402's) cast to any. There is no wrong runtime answer.
priority:p3: a type face that drops a declared key. Under the consumer-follow-up rule nothing breaks for users, but the cast hides an upstream rename from the type-check.
Lane domain:ui.Clause-②: yes (a published type widened), as the seat reads it. Derive the type from the spec's row type rather than adding a hand-copied key.
Scope: the card's ask, including the advisory event's member if it is cheap in the same touch.
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-12413-draft-header-member
Worktree: objectui-issue-12413
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/data-objectstack/src/metadata-client.ts (MetadataDraftHeader and, if cheap, publishDraft's advisory event), packages/app-shell/src/preview/usePendingDrafts.ts and usePublishAllDrafts.ts (dropping the any casts on member), their tests, and a .changeset/ entry (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
Clause-②: yes (widening: the published @object-ui/data-objectstack type MetadataDraftHeader gains member, as triage reads it). A contract-review-tier review is owed before the queue.
Responsibility: n/a — not a defect card (a type face, no wrong runtime answer)
Thread-read: 6183369572
Serial constraints cleared: objectui#12402 (PR #12410, metadata-client.tspublishDraft, usePublishAllDrafts.ts) landed as 919d5cd; objectui#12271 (PR #12400, usePendingDrafts.ts) landed as 0ddc788. In flight: objectui#12398 (PR #12414, ObjectView.tsx) and objectui#12405 (PR #12415, two test files), both queued and disjoint.
os-dev-report
{
"issue": 12413,
"status": "done",
"branch": "claude/issue-12413-draft-header-member",
"pr": "#12420",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB (subagent: the parent's id, per the claim)",
"premise_still_valid": true,
"summary": "MetadataDraftHeader (packages/data-objectstack/src/metadata-client.ts) is now an interface extending Pick of the spec row ListDraftsResponse['drafts'][number] over its five existing keys (types unchanged, pinned by type equality) and declaring member?: ListDraftsRow['member'] in its body. member is in the body, not the Pick, because an interface with an empty body is a no-empty-object-type lint error. The spec row's required label is deliberately not picked: it would be a second key, and an assertion about the server's vintage. MetadataSaveAdvisoryEvent gains an optional member (typed MetadataDraftHeader['member']); publishDraft sets it only when options.member is non-empty, the same rule as the query parameter. usePublishAllDrafts drops its 'as any[]' and 'd.member as string' casts with no behaviour change. Premise correction: usePendingDrafts never read through listDrafts or MetadataDraftHeader. It fetches _drafts itself and types the rows as Record of string to unknown; its 'as string' follows a typeof check on unknown and is not an any cast. That file is untouched (its pins are green). Assignee untouched; zero label writes, since objectui has no gate that reads the labels and the dispatch named none.",
"tests": "All on head 236904f unless noted. Closure build pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build: VERDICT command-exit 0 (on 4a0761a); data-objectstack rebuilt on the final head, and dist/index.d.ts carries the new interface. type-check: data-objectstack exit 0; app-shell (tsc --noEmit && tsc -p tsconfig.test.json) VERDICT command-exit 0 against the rebuilt dist. Targeted vitest over 6 files (the new pin file, publishDraftMember-12402, publishAdvisories, usePublishAllDrafts.bundleMember-12402, DraftChangesPanel.bundleMember-12271, usePublishAllDrafts.refusal-11922): Test Files 6 passed (6), Tests 49 passed (49), on 4a0761a. Full vitest packages/data-objectstack/ plus packages/app-shell/src/preview/ under the lock: Test Files 116 passed (116), Tests 1319 passed (1319), VERDICT command-exit 0. Ablation, run after the fix was committed: ablation-replace.mjs deleted the line ' member?: ListDraftsRow['member'];' (anchor 1 to 0 on disk, blob c5f2783030be to 2aa15fec2db8); data-objectstack type-check went red (exit 2) with TS2339 x5 (pin reads, including the cast-free row.member at line 98, and the event type in metadata-client.ts) and TS2344 on the key-set equality; restored blob c5f2783030be equals HEAD, and git diff HEAD is empty. The earlier Pick-only form was ablated the same way, with the same red. Direction: red, as predicted. Lint narrowed: eslint --no-inline-config --format json on the 3 changed source files gives 3 files, 0 errors, 10 warnings (pre-existing no-explicit-any). Population: root eslint.config.js. Invariance: no parserOptions.project or projectService, so not type-aware. Repo-wide pnpm lint is left to CI. Battery exit 0: 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, control-bytes, new-line-citations; also check-changeset-fixed.mjs, check-changeset-presence.mjs and check-changeset-no-major.mjs. Rerun on 236904f: spec-symbols, phantom-deps, self-import, unreferenced-sources, control-bytes, new-line-citations, changeset-presence, changeset-fixed, all exit 0. check:spec-floors exit 1 (no-artifact on unbuilt packages), the known main failure objectui#12334, recorded and not touched. CI: in_progress, not awaited.",
"mcp_calls": "0",
"api_writes": "2 — REST writes, both through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, which sent POST /repos/objectstack-ai/objectui/pulls (draft) and POST /repos//issues/12420/assignees [baozhoutao], read back byte-identical (7403 bytes); (2) comment, which sent POST /repos//issues/12413/comments (this report). Not REST: 3 git pushes (the branch probe plus 2). Labels: 0 writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · MetadataDraftHeader still omits the spec row's label (ListDraftsResponseSchema.drafts[].label, required and nullable), and loadPackageSurfaces / mergeSurfaces in packages/app-shell/src/views/studio-design/packageSurfaces.ts label a draft-only rail entry with its machine name, though the spec's own docblock says label exists so that a draft-only item is not shown by machine name alone. Read-only inference, not reproduced live, so not filed; noted in the PR's Acceptance notes. Dedupe words: draft-only label machine name; listDrafts label; packageSurfaces draft label",
"noted, not filed · publishPackageDrafts per-element advisory events carry no member: the spec's PublishPackageDraftsResponseSchema.published[] element declares none, so there is nothing to carry"
],
"gates": "build 0; type-check data-objectstack 0; type-check app-shell 0; vitest targeted 0; vitest full data-objectstack plus preview 0; lint narrowed 0; battery 15 of 15 at 0 plus new-line-citations 0; check-changeset-fixed 0; changeset-presence 0; changeset-no-major 0; spec-floors 1 (known main, objectui#12334)",
"files_changed": [
".changeset/12413-draft-header-member.md",
"packages/app-shell/src/preview/usePublishAllDrafts.ts",
"packages/data-objectstack/src/metadata-client.draftHeaderMember-12413.types.test.ts",
"packages/data-objectstack/src/metadata-client.ts"
],
"deviations": "usePendingDrafts.ts, which is in the file surface, is untouched: the premise did not hold there (no any cast, and no MetadataDraftHeader read). Commit trailers use the model-free pair that AGENTS.md requires, rather than the harness's model-named Co-Authored-By."
}
Reviewed on GitHub at head cf19666, against triage's direction (6183369572) and the claim (6183679413, Clause-②: yes (widening)), not against the dev's report.
Shape: the PR is a draft against main. Its body opens Fixes #12413, the only closing keyword, followed by Clause-②: yes (widening). The governed sweep reads NOT governed, 201 lines (+191 / −10), 4 files, inside the claimed surface.
MetadataDraftHeader stays an interface. It now extends Pick of the spec row (ListDraftsResponse['drafts'][number]) over its five existing keys, whose types are unchanged and pinned by type equality and keyof, and declares member?: ListDraftsRow['member']. The type is derived from the spec, as triage ruled.
MetadataSaveAdvisoryEvent.member is additive and is set only when the publish named a non-empty member.
The hook's cast removal changes no behaviour.
Premise correction, accepted:usePendingDrafts.ts never read MetadataDraftHeader and has no any cast. It fetches _drafts itself, typed Record<string, unknown>, so it stays untouched.
Ablation: deleting the member line turns the data-objectstack type-check red (TS2339 ×5, TS2344 on the key-set pin). Restore was proven by blob hash.
Changeset:@object-ui/data-objectstack: minor (two published types widened, additively) and @object-ui/app-shell: patch. Its prose says member is in the Pick, while the code declares it in the body; this is the same published type and is noted only.
Evidence:packages/data-objectstack/ plus app-shell/src/preview/ give 1319/1319 under the lock. The closure build and both type-checks exit 0; the battery and the changeset gates exit 0.
Verified by content: on origin/main, all 4 files the PR touches are blob-identical to the accepted head cf19666, which is blob-identical on those files to the contract-reviewed 236904f (PASS 6184003142). They are metadata-client.ts (MetadataDraftHeader, the advisory event's member), usePublishAllDrafts.ts, the type pins and .changeset/12413-draft-header-member.md.
Activity
objectstack-fleet commentedon Oct 15, 2026
Triage: first grade ·
bug·priority:p3·domain:ui·target:v18·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-15T02:57ZRead fresh.
@object-ui/data-objectstack'sMetadataDraftHeader, the declared row oflistDrafts(), has nomember, though@objectstack/spec18 declaresdrafts[].memberand the rows carry it. The two hooks that read it (#12271's and #12402's) cast toany. There is no wrong runtime answer.priority:p3: a type face that drops a declared key. Under the consumer-follow-up rule nothing breaks for users, but the cast hides an upstream rename from the type-check.target:v18: it is a follow-up of the 18 draftsmember, so it is 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 (as a p3 row).domain:ui.Clause-②: yes(a published type widened), as the seat reads it. Derive the type from the spec's row type rather than adding a hand-copied key.memberif it is cheap in the same touch.objectstack-fleet commentedon Oct 15, 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-12413-draft-header-memberWorktree:
objectui-issue-12413Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/data-objectstack/src/metadata-client.ts(MetadataDraftHeaderand, if cheap,publishDraft's advisory event),packages/app-shell/src/preview/usePendingDrafts.tsandusePublishAllDrafts.ts(dropping theanycasts onmember), their tests, and a.changeset/entry (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate)Clause-②: yes (widening: the published
@object-ui/data-objectstacktypeMetadataDraftHeadergainsmember, as triage reads it). A contract-review-tier review is owed before the queue.Responsibility:
n/a — not a defect card(a type face, no wrong runtime answer)Thread-read: 6183369572
Serial constraints cleared: objectui#12402 (PR #12410,
metadata-client.tspublishDraft,usePublishAllDrafts.ts) landed as919d5cd; objectui#12271 (PR #12400,usePendingDrafts.ts) landed as0ddc788. In flight: objectui#12398 (PR #12414,ObjectView.tsx) and objectui#12405 (PR #12415, two test files), both queued and disjoint.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 12413,
"status": "done",
"branch": "claude/issue-12413-draft-header-member",
"pr": "#12420",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB (subagent: the parent's id, per the claim)",
"premise_still_valid": true,
"summary": "MetadataDraftHeader (packages/data-objectstack/src/metadata-client.ts) is now an interface extending Pick of the spec row ListDraftsResponse['drafts'][number] over its five existing keys (types unchanged, pinned by type equality) and declaring member?: ListDraftsRow['member'] in its body. member is in the body, not the Pick, because an interface with an empty body is a no-empty-object-type lint error. The spec row's required label is deliberately not picked: it would be a second key, and an assertion about the server's vintage. MetadataSaveAdvisoryEvent gains an optional member (typed MetadataDraftHeader['member']); publishDraft sets it only when options.member is non-empty, the same rule as the query parameter. usePublishAllDrafts drops its 'as any[]' and 'd.member as string' casts with no behaviour change. Premise correction: usePendingDrafts never read through listDrafts or MetadataDraftHeader. It fetches _drafts itself and types the rows as Record of string to unknown; its 'as string' follows a typeof check on unknown and is not an any cast. That file is untouched (its pins are green). Assignee untouched; zero label writes, since objectui has no gate that reads the labels and the dispatch named none.",
"tests": "All on head 236904f unless noted. Closure build pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build: VERDICT command-exit 0 (on 4a0761a); data-objectstack rebuilt on the final head, and dist/index.d.ts carries the new interface. type-check: data-objectstack exit 0; app-shell (tsc --noEmit && tsc -p tsconfig.test.json) VERDICT command-exit 0 against the rebuilt dist. Targeted vitest over 6 files (the new pin file, publishDraftMember-12402, publishAdvisories, usePublishAllDrafts.bundleMember-12402, DraftChangesPanel.bundleMember-12271, usePublishAllDrafts.refusal-11922): Test Files 6 passed (6), Tests 49 passed (49), on 4a0761a. Full vitest packages/data-objectstack/ plus packages/app-shell/src/preview/ under the lock: Test Files 116 passed (116), Tests 1319 passed (1319), VERDICT command-exit 0. Ablation, run after the fix was committed: ablation-replace.mjs deleted the line ' member?: ListDraftsRow['member'];' (anchor 1 to 0 on disk, blob c5f2783030be to 2aa15fec2db8); data-objectstack type-check went red (exit 2) with TS2339 x5 (pin reads, including the cast-free row.member at line 98, and the event type in metadata-client.ts) and TS2344 on the key-set equality; restored blob c5f2783030be equals HEAD, and git diff HEAD is empty. The earlier Pick-only form was ablated the same way, with the same red. Direction: red, as predicted. Lint narrowed: eslint --no-inline-config --format json on the 3 changed source files gives 3 files, 0 errors, 10 warnings (pre-existing no-explicit-any). Population: root eslint.config.js. Invariance: no parserOptions.project or projectService, so not type-aware. Repo-wide pnpm lint is left to CI. Battery exit 0: 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, control-bytes, new-line-citations; also check-changeset-fixed.mjs, check-changeset-presence.mjs and check-changeset-no-major.mjs. Rerun on 236904f: spec-symbols, phantom-deps, self-import, unreferenced-sources, control-bytes, new-line-citations, changeset-presence, changeset-fixed, all exit 0. check:spec-floors exit 1 (no-artifact on unbuilt packages), the known main failure objectui#12334, recorded and not touched. CI: in_progress, not awaited.",
"mcp_calls": "0",
"api_writes": "2 — REST writes, both through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, which sent POST /repos/objectstack-ai/objectui/pulls (draft) and POST /repos//issues/12420/assignees [baozhoutao], read back byte-identical (7403 bytes); (2) comment, which sent POST /repos//issues/12413/comments (this report). Not REST: 3 git pushes (the branch probe plus 2). Labels: 0 writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · MetadataDraftHeader still omits the spec row's label (ListDraftsResponseSchema.drafts[].label, required and nullable), and loadPackageSurfaces / mergeSurfaces in packages/app-shell/src/views/studio-design/packageSurfaces.ts label a draft-only rail entry with its machine name, though the spec's own docblock says label exists so that a draft-only item is not shown by machine name alone. Read-only inference, not reproduced live, so not filed; noted in the PR's Acceptance notes. Dedupe words: draft-only label machine name; listDrafts label; packageSurfaces draft label",
"noted, not filed · publishPackageDrafts per-element advisory events carry no member: the spec's PublishPackageDraftsResponseSchema.published[] element declares none, so there is nothing to carry"
],
"gates": "build 0; type-check data-objectstack 0; type-check app-shell 0; vitest targeted 0; vitest full data-objectstack plus preview 0; lint narrowed 0; battery 15 of 15 at 0 plus new-line-citations 0; check-changeset-fixed 0; changeset-presence 0; changeset-no-major 0; spec-floors 1 (known main, objectui#12334)",
"files_changed": [
".changeset/12413-draft-header-member.md",
"packages/app-shell/src/preview/usePublishAllDrafts.ts",
"packages/data-objectstack/src/metadata-client.draftHeaderMember-12413.types.test.ts",
"packages/data-objectstack/src/metadata-client.ts"
],
"deviations": "usePendingDrafts.ts, which is in the file surface, is untouched: the premise did not hold there (no any cast, and no MetadataDraftHeader read). Commit trailers use the model-free pair that AGENTS.md requires, rather than the harness's model-named Co-Authored-By."
}
objectstack-fleet commentedon Oct 15, 2026
Review: ACCEPT — objectui PR #12420 ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T06:38ZReviewed on GitHub at head
cf19666, against triage's direction (6183369572) and the claim (6183679413,Clause-②: yes (widening)), not against the dev's report.main. Its body opensFixes #12413, the only closing keyword, followed byClause-②: yes (widening). The governed sweep reads NOT governed, 201 lines (+191 / −10), 4 files, inside the claimed surface.6184107483) on aSpec Main Shape Gatered that came frommain(tests:plugin-list's #12393 pin imports../../../plugin-grid/src/ObjectGridacross packages, soplugin-listtype-check compilesObjectGridwithout its@object-ui/plugin-detaildependency and goes red whenever that dist is not built first #12422). After tests:plugin-list's #12393 pin imports../../../plugin-grid/src/ObjectGridacross packages, soplugin-listtype-check compilesObjectGridwithout its@object-ui/plugin-detaildependency and goes red whenever that dist is not built first #12422 landed ascb89030, the seat updated the branch through the relay (pr_update_branch). The new headcf19666is a merge commit whose parents are236904f(the reviewed head) andcb89030(main). All 4 files this PR touches are blob-identical between236904fandcf19666, and the net diff againstmainis unchanged (4 files, +191 / −10). So the contract review below judged exactly the diff that lands.6184003142on PR feat(data-objectstack): MetadataDraftHeader declares the spec row's member #12420, on head236904f, whose diffcf19666carries unchanged. Its findings:MetadataDraftHeaderstays aninterface. It now extendsPickof the spec row (ListDraftsResponse['drafts'][number]) over its five existing keys, whose types are unchanged and pinned by type equality andkeyof, and declaresmember?: ListDraftsRow['member']. The type is derived from the spec, as triage ruled.MetadataSaveAdvisoryEvent.memberis additive and is set only when the publish named a non-empty member.usePendingDrafts.tsnever readMetadataDraftHeaderand has noanycast. It fetches_draftsitself, typedRecord<string, unknown>, so it stays untouched.memberline turns the data-objectstack type-check red (TS2339 ×5, TS2344 on the key-set pin). Restore was proven by blob hash.@object-ui/data-objectstack: minor(two published types widened, additively) and@object-ui/app-shell: patch. Its prose saysmemberis in thePick, while the code declares it in the body; this is the same published type and is noted only.packages/data-objectstack/plusapp-shell/src/preview/give 1319/1319 under the lock. The closure build and both type-checks exit 0; the battery and the changeset gates exit 0.labelstays out of this card, as the review agreed. The seat re-readpackageSurfaces.ts: it still says draft headers "carry no label", and it labels a draft-only rail entry with its machine name. Filed studio: a draft-only item in a package rail shows its machine name —packageSurfaces.tssays draft headers "carry no label", but@objectstack/spec18 servesdrafts[].labelfor exactly this case #12421.cf19666: 34 success, 3 skipped, 0 failures (filter=latest), withSpec Main Shape Gate(red on236904ffrom tests:plugin-list's #12393 pin imports../../../plugin-grid/src/ObjectGridacross packages, soplugin-listtype-check compilesObjectGridwithout its@object-ui/plugin-detaildependency and goes red whenever that dist is not built first #12422, now green),Type Checkand all 12 test shards included.needs:contract-reviewis removed from the PR in this stroke.Next:
pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T06:51Zmain431cece. The card closedcompletedby the PR'sFixes #12413, which is the only closing keyword. No other card closed with it.origin/main, all 4 files the PR touches are blob-identical to the accepted headcf19666, which is blob-identical on those files to the contract-reviewed236904f(PASS6184003142). They aremetadata-client.ts(MetadataDraftHeader, the advisory event'smember),usePublishAllDrafts.ts, the type pins and.changeset/12413-draft-header-member.md.packageSurfaces.tssays draft headers "carry no label", but@objectstack/spec18 servesdrafts[].labelfor exactly this case #12421, the draft-only rail label, waited on this card'sMetadataDraftHeader.pm:dispatchedis removed in the same stroke as this comment.Generated by Claude Code