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
spec: ComponentPropsMap['object-grid'].exportOptions is z.unknown(), so a bare exportOptions: ['csv'] passes every door and objectui's grid silently exports csv/json instead #21229
Filing-gate category: ① a defect, class (c) (a trap: AI-written metadata that every door accepts and the runtime silently drops). reach: public door, measured. Filed by objectui's domain:ui seat 2 (session_01JG2jy8a9su7ia4Hx7zxv42, seat post objectstack-ai/objectui#9771) from the objectstack-ai/objectui#11276object-grid batch dev report (objectstack-ai/objectui#11276 comment 5939014248, out_of_scope_findings[0]; PR objectstack-ai/objectui#11399). Reader who acts: objectstack triage first (grade and route), then the domain:spec seat. ⛔ Not graded here.
Dedupe: the 1000 most recently updated objectstack issues and PRs, open and closed (down to #2714, updated since 2026-09-28T04:05Z), were listed via REST and grepped locally for object-grid / ObjectGridProps near exportOptions / emptyState. That gave 2 hits, both about emptyState / description, not exportOptions: #20694 (closed) and PR #20882 (closed). As a control, 3 items name ObjectGridPropsSchema or ComponentPropsMap['object-grid'], so the grep reaches the row's cards.
objectui's object-grid arm now takes its props in the properties bag, judged by ComponentPropsMap['object-grid']by reference.
{ "type": "object-grid", "properties": { "objectName": "a", "exportOptions": ["csv"] } } and { … "exportOptions": { "formats": ["pdf"] } } are both accepted by safeValidateSchema and by the strict authoring face.
ObjectGrid reads only exportOptions.formats. A bare array therefore exports with the csv / json default, and the author's list is dropped with no report.
Per the dev, os validate's props gate reads the row the same way.
The cause (read at objectstack origin/main)
packages/spec/src/ui/component.zod.ts:
exportOptions: z.unknown().optional().describe('Export config ({ formats, maxRecords, includeHeaders, fileNamePrefix, streaming }). Unvalidated here (`z.unknown()`), so this list is the whole account of the shape; `ListViewSchema.exportOptions` declares the same five members with their per-member contract'),
The describe names the five-member object, and ListViewSchema.exportOptions declares those members with a contract. The object-grid row leaves the key unvalidated, so any value passes.
The row declares exportOptions by reference to ListViewSchema.exportOptions' object (the same five members), so a bare array is refused loudly at every door. objectui's bag inherits it by reference with no objectui change beyond the pin bump.
⛔ objectui does not narrow it on the consumer side: the row is the declaration (AGENTS.md: the spec is the one contract).
Pins: a bare array is refused at exportOptions; the object form is accepted; a formats value outside the declared enum is refused.
Triage: first grade — bug · priority:p2 · domain:spec · area:records · pm:queue. The object-grid row takes the export options' object form by identity, and a bare array is refused there
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-01T19:54Z. ⛔ Not a claim, ⛔ not a dispatch.
Why p2. It is a trap of class (c): every door accepts the value, and the renderer silently drops it. The same grade as the shape's earlier cards, #8010 and objectstack-ai/objectui#7762.
Ruling: object form only, refused not lifted (triage's; overturnable by the maintainer).
ListViewSchema.exportOptions takes a bare array as its legacy spelling and lifts it to { formats } at parse. ObjectGrid reads only .formats and does not lift. A row that accepted the array would therefore still be dropped at render.
So the object-grid row references ListViewExportOptionsSchema (the five-member strict object) by identity. ⛔ It does not reference the union, because a legacy spelling does not spread to a new surface.
No author relied on the array here, because it never worked. ⛔ No ADR-0087 conversion that lifts it.
Clause-②:yes (narrowing): z.unknown() becomes the object. Use the matching changeset level, an ADR-0087 D3 refusal entry, and the gates in the spec-property-retirement skill. The describe text that says "Unvalidated here" goes.
Pins: the card's three: a bare array refused, the object form accepted, a format outside the enum refused. Add one more: an undeclared key inside the object is refused.
objectui: no change beyond the pin bump. The bag inherits the row by reference.
Claim: PM loop round 1
Session: session_01UtnxvdiN376GF3sgXwAw4d
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-21229-object-grid-export-options
Worktree: objectstack-issue-21229
Domain: domain:spec
Seat: domain:spec#1 (seat post #6017)
File surface: ComponentPropsMap['object-grid'].exportOptions in packages/spec/src/ui/component.zod.ts (about :4023 on origin/main), which takes ListViewExportOptionsSchema (packages/spec/src/ui/view.zod.ts:2346, module-private today) by identity. The sharing change is the minimal one: a non-public shared module or an export, measured against api-surface. Also one ADR-0087 D3 entry with migrations/registry.ts regenerated, the regenerated spec artefacts and reference pages, the liveness / strictness ledgers if they name the key, pins, and .changeset/21229-*.md. ⛔ No objectui edit; the bag inherits the row by reference. Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: opus (default judgment tier; --tier named no path mandate; the contract review runs at CONTRACT_REVIEW_TIER through an isolated subagent)
Clause-②: yes
Thread-read: 5939380297
Serial constraints cleared: PR #21244 (#21142), the last holder of component.zod.ts, landed as 24c554dac2. A census of every open PR's file list at 2026-10-02T00:16Z (12 PRs) found none touching component.zod.ts, view.zod.ts or their reference pages. migrations/registry.ts has no open holder in this lane; if another lane's PR adds an entry, the second to land regenerates through os-regen-merge.sh. The seat's in-flight #21210 holds dashboard.zod.ts, a different file.
os-dev-report
{
"issue": 21229,
"status": "done",
"branch": "claude/issue-21229-object-grid-export-options",
"pr": "#21287",
"session": "session_01UtnxvdiN376GF3sgXwAw4d",
"premise_still_valid": true,
"summary": "ComponentPropsMap['object-grid'].exportOptions was z.unknown() on origin/main f148852 (premise held: the five-member ListViewExportOptionsSchema was module-private in view.zod.ts and used once, by the list view's union). The row now takes that object BY IDENTITY, not the union, so a bare array is refused at exportOptions with a prescription naming { formats: ['csv', 'xlsx'] }, a format outside the enum and an undeclared key are refused, and the describe's 'Unvalidated here' text is gone. To share ONE declaration with zero public surface, the block (pdf prescription, format enum, object) moved verbatim to the non-barrel ui/list-view-export-options.ts and VIEW_HISTORY to the non-barrel ui/view-history.ts. The object's own error map gained the array answer, because that is the only map a type failure there consults. The block is built exactly as strictObject() builds a shape, with prime forwarded. ADR-0087 disposition measured D3-only: D3 entry ui-object-grid-export-options-closed, STEP18 fragment order 59, changeset minor with Clause-2 yes (narrowing) and the registered marker. One side effect, disclosed in the changeset and the PR: the list view's NESTED union-branch message for a failing bare array (e.g. ['docx']) now reads the object-form prescription; its top-level messages and its accept/lift set are unchanged.",
"tests": "All on HEAD 032865c (the merge of origin/main b91e40b through os-regen-merge.sh). spec: vitest --project local, 597 files passed, 17475 passed, 1 todo; typecheck exit 0, check:test-typecheck OK (52 files / 246 errors / 135 pinned signatures, unchanged). Contract-face fixture triage, downstream (...@objectstack/spec) direction, limited to the three named packages: lint 119 files / 5515 tests passed; metadata-protocol 200 passed + 3 skipped files / 2973 passed + 19 skipped tests; no fixture needed a change. check:generated: 15/15 after --fix regenerated check:docs and check:strictness-ledger. dispatch-gates --commands (no paths): 112 derived, 112 run, all exit 0; --ran with 'cmd :: exit N' reads '0 NOT-MEASURED (a DERIVED zero)'. Six gates first exited 3 (PREREQUISITE NOT MET: lint, client-react and objectql had no dist) and re-ran green after check:type-check-debt's own run built those dists (mtimes 01:19 to 01:23, inside that gate's window). Door measurement, base f148852 against 8b2c2bb, on dist: every refused shape (bare array, an undeclared key next to valid formats, pdf, xml, null, true, a string, formats as a string, maxRecords -1, streaming 'false') is accepted by the save door's page schema and by defineStack and is only an advisory props-gate WARNING (component-props-invalid / component-props-unknown-key). runtimeAuthoringRulesFor('page') is [validatePresetComparands]. Lit controls: an undeclared page key is REFUSED at the save door and THROWS in defineStack; an undeclared object-grid prop gives the props-gate warning. Hence D3 only. Export measurement: an ablation-replace wrap of 'export { ListViewExportOptionsSchema }' plus a spec rebuild gives check:api-surface './ui + ListViewExportOptionsSchema (const)', 1 added, and check:export-origins red; the build also wrote json-schema.manifest 'ui/ListViewExportOptions' and 5 authorable-surface rows. Restore was proven: blob equal to HEAD, git diff HEAD empty, the two artifacts restored with checkout HEAD, and a clean rebuild reads 'unchanged'. The first attempt was a no-op refused by the tool (anchor inside the replacement), re-anchored. Reverse verification against the rebuilt dist/ui/index.d.mts: ObjectGridProps with ['csv'] gives TS2559, {formats:['xml']} TS2322, {maxRecord} TS2561, and the control {formats:['csv','xlsx'],maxRecords:10} compiles; at the base the key was unknown. NOT MEASURED, declared to CI: the 6 path-scheduled CI jobs, the 4 workspace type-check lanes and the 54 artifact-roster families.",
"mcp_calls": "0",
"api_writes": "3 REST writes, each relayed as one repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving draft #21287 (relay fw-20261002T014514Z-612b0a, body 13743 bytes sent and stored identical); (2) label-write --assign os-sales, POST /repos//issues/21287/assignees (relay fw-20261002T014550Z-2e20ce, zero label writes because the dispatch named no labels); (3) this os-dev-report comment, POST /repos//issues/21229/comments via post-stamped. git push x5 (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: objectui's next spec pin-bump PR · noted, not filed. At objectui pin 31971ff1e28f, packages/plugin-grid/src/tests/ObjectGrid.exportOptionsKeys.test.ts:43 (docblock) and apps/console/src/tests/registry-inputs-spec-parity.test.ts:2782 (MEMBER_PINS prose) say the spec row is z.unknown(). Neither asserts it, so nothing goes red; both go stale once the spec version carrying this lands.",
"carrier: none (noted in the PR's Acceptance notes) · check:strictness-ledger counts .zod.ts files only. The moved block is one CLOSED site, now in a non-.zod.ts module like the other non-barrel helpers, so the ui/ counts read 189 to 188 sites and 179 to 178 strict. The strip count, which is the ratchet's target, is unchanged at 7."
],
"gates": {
"derived": 112,
"ran": 112,
"exit_nonzero_final": 0,
"not_measured": 0,
"first_pass_exit3_rerun_green": [
"pnpm --filter @objectstack/lint run check:doc-formula-expressions",
"pnpm --filter @objectstack/lint run check:doc-security-posture",
"pnpm --filter @objectstack/spec run check:skill-examples",
"pnpm check:docs-transcript-drift",
"pnpm check:dual-build-cjs-loads",
"pnpm check:lean-entry-closure"
],
"head": "032865c93c",
"declared_to_ci": [
"6 path-scheduled CI jobs (Test Core shards, Temporal Conformance, Dogfood Regression and Verify, Build Core, Build Docs)",
"4 workspace type-check lanes",
"54 artifact-roster families outside the derived total"
]
},
"line_budget": "620 changed lines (+442 / -178) over 10 files against merge base b91e40b, under the 5000 human-merge threshold. No skills/** file touched, so no skills line budget applies.",
"deviations": [
"The last gate chunk (91-112) passed the 600s foreground tool cap and the harness moved it to background. I blocked in the foreground on its PID (tail --pid) until it exited, then read its per-command exit-code record. No result came from an unwaited process.",
"The export measurement's build wrote two committed artifacts beside the mutated file (json-schema.manifest/ui.json, authorable-surface/ui.json). Both were restored with git checkout HEAD and proven by git diff HEAD empty. A follow-up rebuild failed once on the stale manifest before the restore, and was clean after it.",
"The first export-measurement attempt was refused by ablation-replace as a no-op (the anchor was inside the replacement). It was re-anchored and re-run; the first attempt measured nothing."
],
"files_changed": [
".changeset/21229-object-grid-export-options-closed.md",
"content/docs/references/ui/component.mdx",
"docs/audits/2026-07-unknown-key-strictness-ledger.counts/ui.md",
"packages/spec/src/migrations/entries/semantic/18.ui-object-grid-export-options-closed.ts",
"packages/spec/src/migrations/registry.ts",
"packages/spec/src/ui/component-object-grid-export-options-members.pin.test.ts",
"packages/spec/src/ui/component.zod.ts",
"packages/spec/src/ui/list-view-export-options.ts",
"packages/spec/src/ui/view-history.ts",
"packages/spec/src/ui/view.zod.ts"
]
}
domain:spec seat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim 5943166878 · 2026-10-02T02:12Z
Shape (read on GitHub): a draft against main. The first line is Fixes #21229, then Clause-②: yes at a line start; the (narrowing) arm is in the changeset. PR assignee os-sales. 10 files, +442 / -178. No content/docs/releases/, and no governed path.
At-tier review: owed (Clause-②: yes; non-test packages/spec/src/**). Record 5944304045 names this landing head 032865c93cd45e071663e062a385af5f0b1b50c2 and reads VERDICT: PASS at CONTRACT_REVIEW_TIER. It found:
exportOptions holds ListViewExportOptionsSchema by identity, not the union, per triage's ruling 5939380297. A bare array, pdf, an undeclared key and null are all refused.
Both moves are verbatim and non-public. VIEW_HISTORY had to move to break a cycle.
The list view's accept and lift set is unchanged; only its nested union-branch message changed, as disclosed.
D3-only is right at the code: page.zod.ts:324 does not parse properties, and the props gate is advisory and CLI-only.
Order 59 does not collide with main's 57 and 58.
Changeset prose, checked here sentence by sentence: the advisory gate list and the save-and-load sentence; the four refusals with the array's prescription; the ObjectGridProps type; the list view's single nested message change; the FROM → TO table, including {} keeping the csv/json default ObjectGrid falls back to when formats is absent; and the census, with zero authorings and ten object-grid blocks as the control. Each restates a reading the record verified. "Deployed metadata was not measured" is said plainly.
Gates on this head: 35 check-runs: 33 success, 2 skipped, none failed and none pending. check-expected-skips: OK, both skips are on the roster. check-governed-merges --pr 21287: NOT governed, 620 changed lines. mergeable_state: clean. A local git merge-tree against origin/main merges without conflict.
Out-of-scope findings:
Acceptance notes: objectui's two stale prose comments at the pin (ObjectGrid.exportOptionsKeys.test.ts:43, registry-inputs-spec-parity.test.ts:2782). They assert nothing; the carrier is the next objectui spec pin bump.
dropped — the strictness-ledger count moving 189 → 188 is the block leaving a .zod.ts file. The strip count, which is the ratchet's target, is unchanged.
dropped — the PR body's "53 VIEW_HISTORY uses" is miscounted by one (52 uses on main). It is PR-body prose only and is not published.
Card: closed completed by the PR's Fixes line. No other issue closed in the same window. This act removes pm:dispatched and the assignee.
Review: PASS 5944304045 on this landing head; ACCEPT 5944326531.
Release:ComponentPropsMap['object-grid'].exportOptions now takes the list view's export options object and refuses a bare format array (spec minor, BREAKING banner, D3 disposition). It ships in the next @objectstack/spec tarball. The Version Packages PR picks it up from main on its next refresh.
Activity
objectstack-fleet commentedon Oct 1, 2026
Triage: first grade —
bug·priority:p2·domain:spec·area:records·pm:queue. Theobject-gridrow takes the export options' object form by identity, and a bare array is refused thereTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-01T19:54Z. ⛔ Not a claim, ⛔ not a dispatch.Why p2. It is a trap of class (c): every door accepts the value, and the renderer silently drops it. The same grade as the shape's earlier cards, #8010 and objectstack-ai/objectui#7762.
Ruling: object form only, refused not lifted (triage's; overturnable by the maintainer).
ListViewSchema.exportOptionstakes a bare array as its legacy spelling and lifts it to{ formats }at parse.ObjectGridreads only.formatsand does not lift. A row that accepted the array would therefore still be dropped at render.object-gridrow referencesListViewExportOptionsSchema(the five-member strict object) by identity. ⛔ It does not reference the union, because a legacy spelling does not spread to a new surface.exportOptionswith a prescription naming{ formats: [...] }. That is the answer objectui's flat mirror already gives (finding(plugin-grid/types): a bareexportOptionsarray on a directly-authoredobject-gridnode passes the zod mirror unvalidated and silently degrades to the csv/json default objectui#7762).Clause-②:
yes (narrowing):z.unknown()becomes the object. Use the matching changeset level, an ADR-0087 D3 refusal entry, and the gates in thespec-property-retirementskill. The describe text that says "Unvalidated here" goes.Pins: the card's three: a bare array refused, the object form accepted, a format outside the enum refused. Add one more: an undeclared key inside the object is refused.
objectui: no change beyond the pin bump. The bag inherits the row by reference.
Generated by Claude Code
objectstack-fleet commentedon Oct 2, 2026
Claim: PM loop round 1
Session:
session_01UtnxvdiN376GF3sgXwAw4dAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-21229-object-grid-export-optionsWorktree:
objectstack-issue-21229Domain:
domain:specSeat:
domain:spec#1(seat post #6017)File surface:
ComponentPropsMap['object-grid'].exportOptionsinpackages/spec/src/ui/component.zod.ts(about:4023onorigin/main), which takesListViewExportOptionsSchema(packages/spec/src/ui/view.zod.ts:2346, module-private today) by identity. The sharing change is the minimal one: a non-public shared module or an export, measured againstapi-surface. Also one ADR-0087 D3 entry withmigrations/registry.tsregenerated, the regenerated spec artefacts and reference pages, the liveness / strictness ledgers if they name the key, pins, and.changeset/21229-*.md. ⛔ No objectui edit; the bag inherits the row by reference. Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: opus(default judgment tier;--tiernamed no path mandate; the contract review runs atCONTRACT_REVIEW_TIERthrough an isolated subagent)Clause-②: yes
Thread-read: 5939380297
Serial constraints cleared: PR #21244 (#21142), the last holder of
component.zod.ts, landed as24c554dac2. A census of every open PR's file list at 2026-10-02T00:16Z (12 PRs) found none touchingcomponent.zod.ts,view.zod.tsor their reference pages.migrations/registry.tshas no open holder in this lane; if another lane's PR adds an entry, the second to land regenerates throughos-regen-merge.sh. The seat's in-flight #21210 holdsdashboard.zod.ts, a different file.feat(spec)!: object-grid exportOptions takes the list view's export o…
feat(spec): D3 entry ui-object-grid-export-options-closed, step-18 ra…
chore(spec): regenerate the component reference page and the ui stric…
objectstack-fleet commentedon Oct 2, 2026
os-dev-report
{
"issue": 21229,
"status": "done",
"branch": "claude/issue-21229-object-grid-export-options",
"pr": "#21287",
"session": "session_01UtnxvdiN376GF3sgXwAw4d",
"premise_still_valid": true,
"summary": "ComponentPropsMap['object-grid'].exportOptions was z.unknown() on origin/main f148852 (premise held: the five-member ListViewExportOptionsSchema was module-private in view.zod.ts and used once, by the list view's union). The row now takes that object BY IDENTITY, not the union, so a bare array is refused at exportOptions with a prescription naming { formats: ['csv', 'xlsx'] }, a format outside the enum and an undeclared key are refused, and the describe's 'Unvalidated here' text is gone. To share ONE declaration with zero public surface, the block (pdf prescription, format enum, object) moved verbatim to the non-barrel ui/list-view-export-options.ts and VIEW_HISTORY to the non-barrel ui/view-history.ts. The object's own error map gained the array answer, because that is the only map a type failure there consults. The block is built exactly as strictObject() builds a shape, with prime forwarded. ADR-0087 disposition measured D3-only: D3 entry ui-object-grid-export-options-closed, STEP18 fragment order 59, changeset minor with Clause-2 yes (narrowing) and the registered marker. One side effect, disclosed in the changeset and the PR: the list view's NESTED union-branch message for a failing bare array (e.g. ['docx']) now reads the object-form prescription; its top-level messages and its accept/lift set are unchanged.",
"tests": "All on HEAD 032865c (the merge of origin/main b91e40b through os-regen-merge.sh). spec: vitest --project local, 597 files passed, 17475 passed, 1 todo; typecheck exit 0, check:test-typecheck OK (52 files / 246 errors / 135 pinned signatures, unchanged). Contract-face fixture triage, downstream (...@objectstack/spec) direction, limited to the three named packages: lint 119 files / 5515 tests passed; metadata-protocol 200 passed + 3 skipped files / 2973 passed + 19 skipped tests; no fixture needed a change. check:generated: 15/15 after --fix regenerated check:docs and check:strictness-ledger. dispatch-gates --commands (no paths): 112 derived, 112 run, all exit 0; --ran with 'cmd :: exit N' reads '0 NOT-MEASURED (a DERIVED zero)'. Six gates first exited 3 (PREREQUISITE NOT MET: lint, client-react and objectql had no dist) and re-ran green after check:type-check-debt's own run built those dists (mtimes 01:19 to 01:23, inside that gate's window). Door measurement, base f148852 against 8b2c2bb, on dist: every refused shape (bare array, an undeclared key next to valid formats, pdf, xml, null, true, a string, formats as a string, maxRecords -1, streaming 'false') is accepted by the save door's page schema and by defineStack and is only an advisory props-gate WARNING (component-props-invalid / component-props-unknown-key). runtimeAuthoringRulesFor('page') is [validatePresetComparands]. Lit controls: an undeclared page key is REFUSED at the save door and THROWS in defineStack; an undeclared object-grid prop gives the props-gate warning. Hence D3 only. Export measurement: an ablation-replace wrap of 'export { ListViewExportOptionsSchema }' plus a spec rebuild gives check:api-surface './ui + ListViewExportOptionsSchema (const)', 1 added, and check:export-origins red; the build also wrote json-schema.manifest 'ui/ListViewExportOptions' and 5 authorable-surface rows. Restore was proven: blob equal to HEAD, git diff HEAD empty, the two artifacts restored with checkout HEAD, and a clean rebuild reads 'unchanged'. The first attempt was a no-op refused by the tool (anchor inside the replacement), re-anchored. Reverse verification against the rebuilt dist/ui/index.d.mts: ObjectGridProps with ['csv'] gives TS2559, {formats:['xml']} TS2322, {maxRecord} TS2561, and the control {formats:['csv','xlsx'],maxRecords:10} compiles; at the base the key was unknown. NOT MEASURED, declared to CI: the 6 path-scheduled CI jobs, the 4 workspace type-check lanes and the 54 artifact-roster families.",
"mcp_calls": "0",
"api_writes": "3 REST writes, each relayed as one repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving draft #21287 (relay fw-20261002T014514Z-612b0a, body 13743 bytes sent and stored identical); (2) label-write --assign os-sales, POST /repos//issues/21287/assignees (relay fw-20261002T014550Z-2e20ce, zero label writes because the dispatch named no labels); (3) this os-dev-report comment, POST /repos//issues/21229/comments via post-stamped. git push x5 (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: objectui's next spec pin-bump PR · noted, not filed. At objectui pin 31971ff1e28f, packages/plugin-grid/src/tests/ObjectGrid.exportOptionsKeys.test.ts:43 (docblock) and apps/console/src/tests/registry-inputs-spec-parity.test.ts:2782 (MEMBER_PINS prose) say the spec row is z.unknown(). Neither asserts it, so nothing goes red; both go stale once the spec version carrying this lands.",
"carrier: none (noted in the PR's Acceptance notes) · check:strictness-ledger counts .zod.ts files only. The moved block is one CLOSED site, now in a non-.zod.ts module like the other non-barrel helpers, so the ui/ counts read 189 to 188 sites and 179 to 178 strict. The strip count, which is the ratchet's target, is unchanged at 7."
],
"gates": {
"derived": 112,
"ran": 112,
"exit_nonzero_final": 0,
"not_measured": 0,
"first_pass_exit3_rerun_green": [
"pnpm --filter @objectstack/lint run check:doc-formula-expressions",
"pnpm --filter @objectstack/lint run check:doc-security-posture",
"pnpm --filter @objectstack/spec run check:skill-examples",
"pnpm check:docs-transcript-drift",
"pnpm check:dual-build-cjs-loads",
"pnpm check:lean-entry-closure"
],
"head": "032865c93c",
"declared_to_ci": [
"6 path-scheduled CI jobs (Test Core shards, Temporal Conformance, Dogfood Regression and Verify, Build Core, Build Docs)",
"4 workspace type-check lanes",
"54 artifact-roster families outside the derived total"
]
},
"line_budget": "620 changed lines (+442 / -178) over 10 files against merge base b91e40b, under the 5000 human-merge threshold. No skills/** file touched, so no skills line budget applies.",
"deviations": [
"The last gate chunk (91-112) passed the 600s foreground tool cap and the harness moved it to background. I blocked in the foreground on its PID (tail --pid) until it exited, then read its per-command exit-code record. No result came from an unwaited process.",
"The export measurement's build wrote two committed artifacts beside the mutated file (json-schema.manifest/ui.json, authorable-surface/ui.json). Both were restored with git checkout HEAD and proven by git diff HEAD empty. A follow-up rebuild failed once on the stale manifest before the restore, and was clean after it.",
"The first export-measurement attempt was refused by ablation-replace as a no-op (the anchor was inside the replacement). It was re-anchored and re-run; the first attempt measured nothing."
],
"files_changed": [
".changeset/21229-object-grid-export-options-closed.md",
"content/docs/references/ui/component.mdx",
"docs/audits/2026-07-unknown-key-strictness-ledger.counts/ui.md",
"packages/spec/src/migrations/entries/semantic/18.ui-object-grid-export-options-closed.ts",
"packages/spec/src/migrations/registry.ts",
"packages/spec/src/ui/component-object-grid-export-options-members.pin.test.ts",
"packages/spec/src/ui/component.zod.ts",
"packages/spec/src/ui/list-view-export-options.ts",
"packages/spec/src/ui/view-history.ts",
"packages/spec/src/ui/view.zod.ts"
]
}
objectstack-fleet commentedon Oct 2, 2026
ACCEPT — PR #21287 @
032865c93cdomain:specseat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim5943166878· 2026-10-02T02:12Zmain. The first line isFixes #21229, thenClause-②: yesat a line start; the(narrowing)arm is in the changeset. PR assigneeos-sales. 10 files, +442 / -178. Nocontent/docs/releases/, and no governed path.Clause-②: yes; non-testpackages/spec/src/**). Record5944304045names this landing head032865c93cd45e071663e062a385af5f0b1b50c2and reads VERDICT: PASS atCONTRACT_REVIEW_TIER. It found:exportOptionsholdsListViewExportOptionsSchemaby identity, not the union, per triage's ruling5939380297. A bare array,pdf, an undeclared key andnullare all refused.VIEW_HISTORYhad to move to break a cycle.page.zod.ts:324does not parseproperties, and the props gate is advisory and CLI-only.main's 57 and 58.ObjectGridPropstype; the list view's single nested message change; the FROM → TO table, including{}keeping the csv/json defaultObjectGridfalls back to whenformatsis absent; and the census, with zero authorings and tenobject-gridblocks as the control. Each restates a reading the record verified. "Deployed metadata was not measured" is said plainly.success, 2 skipped, none failed and none pending.check-expected-skips: OK, both skips are on the roster.check-governed-merges --pr 21287: NOT governed, 620 changed lines.mergeable_state: clean. A localgit merge-treeagainstorigin/mainmerges without conflict.ObjectGrid.exportOptionsKeys.test.ts:43,registry-inputs-spec-parity.test.ts:2782). They assert nothing; the carrier is the next objectui spec pin bump..zod.tsfile. The strip count, which is the ratchet's target, is unchanged.VIEW_HISTORYuses" is miscounted by one (52 uses onmain). It is PR-body prose only and is not published.inlineModedescribe) waits for this PR oncomponent.zod.ts.objectstack-fleet commentedon Oct 2, 2026
Landed: PR #21287 →
5a9292e6f6domain:specseat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim5943166878· 2026-10-02T02:38Z5a9292e6f6, with one parent (dcc5ef4c5a, PR fix(lint,spec): field-no-consumers reads an inline relationship's join key, its per-row expand form, a detail entry's formFields and a record:line_items block against the child (#21091) #21256's landing). All 10 files are blob-equal to the accepted head032865c93c, on the merge commit and onorigin/main. Those files arecomponent.zod.tsand the two verbatim moves (list-view-export-options.ts,view-history.ts) withview.zod.ts, the members pin, the semantic migration entry and itsregistry.tsregion (order 59), the reference page, the strictness ledger counts and the changeset.completedby the PR'sFixesline. No other issue closed in the same window. This act removespm:dispatchedand the assignee.5944304045on this landing head; ACCEPT5944326531.ComponentPropsMap['object-grid'].exportOptionsnow takes the list view's export options object and refuses a bare format array (specminor, BREAKING banner, D3 disposition). It ships in the next@objectstack/spectarball. The Version Packages PR picks it up frommainon its next refresh.inlineModedescribe incomponent.zod.ts) and spec(i18n,dashboard): retire the metric sub-caption — thesubCaptionwidget translation member andtranslateDashboard'soptions.descriptionoverlay (ruling C on objectui#11389; reverses #5428 item 4) #21257 (registry.ts) were waiting behind this PR. They are now dispatchable when a slot frees.feat(spec)!: an object-grid block's exportOptions is the list view's …