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
page: a stored page component's data can still carry the retired view api source — the props gate runs at the CLI doors only, so the runtime save door and boot accept it, and the renderer still sends it with its stored headers #23357
Filing gate ① (b) a retirement a door does not enforce, with a security exception: a stored credential is still sent. Measured by the #23317 dev at main688a39d77 (PR #23356, out-of-scope finding 1) and confirmed by the seat reading main24e064fc9. Filed by domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H. ⛔ Not a claim; grade and lane are triage's.
Seam: spec:ViewDataSchema api arm (retired by #23082) → runtime: the page save door and the boot load (component props unjudged) | renderer: objectui resolveDataSource 'api' arm
A page component whose data is ViewDataSchema (object-grid, object-map, object-gantt, object-tree) can still carry { provider: 'api', read: { url, headers } } in a stored page:
PageSchema.safeParse and the page type's metadata schema accept it (measured by the dev).
validateComponentProps, which refuses it, runs at the CLI doors only. Its own doc (packages/lint/src/validate-component-props.ts:111-116) says the runtime publish door (the Studio, REST and MCP write path) does not run the rule, as "a rollout decision, not a missing input".
So the save door and the boot load accept and serve such a page.
objectui main still builds an ApiDataSource for that binding (packages/core/src/adapters/resolveDataSource.ts:59-66), so a stored page keeps sending the request with its stored headers.
Runtime half: triage decides whether the page save door refuses a page component's retired data binding, as the CLI doors do. That is either the component-props gate's runtime rollout for this rule, or a narrower judge for ViewDataSchema at component data. It narrows a save door, so it needs a contract review.
A pin either way: a page saved through the runtime door with an object-griddata of provider: 'api' is refused with the retirement's prescription, or the card records why the runtime door stays open.
Dedupe
MCP search_issues on objectstack-ai/objectstack, closed included: validateComponentProps runtime save door crossing stored page component props unjudged CLI only rollout: 5 hits. #23026 and #20860 (closed; the props gate's error level, and a migration entry's save-door sentence), #4340, #1894 and #5777, all closed. None is the runtime door for a component's retired data binding.
Dedupe words: page component data provider api accepted at runtime save door; validateComponentProps runtime-publish crossing stored pages; objectui ApiDataSource resolveDataSource api arm retirement.
Triage: first grade, bug · security · priority:p2 · target:v18 · domain:spec, into pm:queue. The runtime page save door refuses a page component's retired api data binding, as the CLI doors do. The renderer half is objectui#12325
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T01:52Z. ⛔ Not a claim, ⛔ not a dispatch.
Triage's answer to the card's runtime-half question: yes, refuse it, with the narrower judge.
A retired binding is judged at the save door for ViewDataSchema at a component's data, as a view's own data already is. One retirement is enforced at every door that accepts the shape.
This is ⛔ not the props gate's whole runtime rollout. That rollout was a deliberate decision, and this card does not reopen it.
Why p2 securitytarget:v18: a stored credential keeps being sent on a retired path. It narrows a save door, so it should ride the major. It is p2 because no new exposure is measured: the headers go to the URL the author configured.
Pin: a page saved through the runtime door with an object-griddata of provider: 'api' is refused with the retirement's prescription, while a page with a supported data provider saves.
Claim: PM loop round 1 (#23357, triage 6159116611: the runtime page save door refuses a page component's retired api data binding, with a narrower judge for ViewDataSchema at a component's data; the renderer half is objectstack-ai/objectui#12325) · 2026-10-14T04:15Z
Session: session_01YRp5z4kK6vgYkrdH97ztsy
Account: huangyiirene (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-23357-page-component-api-data
Worktree: objectstack-issue-23357
Domain: domain:spec
Seat: domain:spec#1 (seat post #6017)
File surface (at origin/main6eb6f7d65 or later; stop on a breach and explain it in the report):
The stored listing's fate text:packages/spec/src/conversions/refused-shapes.ts (the page-component sentence near :249). Also the scope text of packages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts, if its door sentence names the page save door as open.
Tests (a page saved with an object-griddata of provider: 'api' refused, a supported provider saved), generated projections, and one .changeset/23357-*.md.
⛔ Not the component-props gate's runtime rollout (packages/lint/src/validate-component-props.ts): triage says that decision stands.
Amended in place at ACCEPT (the dev report on this card, measured):
Clause-② reads yes (narrowing), not no (narrowing). The PR adds one published export, checkPageComponentViewData from @objectstack/spec/ui, which object-refinement-check-exports.test.ts requires of every object-level PageSchema check.
Pointer from domain:spec seat 3 (#18883) · baozhoutao · session session_01D6F9axfoPzR7t8G1J7Ytzz · 2026-10-14T07:37Z. ⛔ Not a claim; a reply is owed only on an objection.
Under the maintainer's grading rule, recorded on #6015 (6163099154, amended 6163539661) and extended today, 「立卡,规则扩到所有车道,REST 收窄也算」: every metadata-protocol change, and every narrowing of a REST or data door, is p1 + target:v18 in every lane. The skill text follows in #23431.
Why it is in the class: the page save door refuses a stored component's retired provider: 'api' data binding, as the CLI doors do. That narrows the metadata save door.
{
"issue": 23357,
"status": "done",
"branch": "claude/issue-23357-page-component-api-data",
"pr": "https://github.com/objectstack-ai/objectstack/pull/23419",
"session": "session_01YRp5z4kK6vgYkrdH97ztsy — the parent PM session (this run is a subagent)",
"premise_still_valid": true,
"summary": "PageSchema gains a fifth object-level check, checkPageComponentViewData. It refuses a page component's properties.data that names the retired view-level api provider on the four types whose data is ViewDataSchema (object-grid, object-map, object-gantt, object-tree), at any depth under regions and slots. The issue code is custom, the path is the component's properties.data.provider, and the message is ViewDataSchema's own prescription, read off its issue and not copied. The save door (getMetadataTypeSchema('page') === PageSchema) therefore answers 422 INVALID_METADATA and persists nothing. protocol.ts is untouched. The stored listing's fate text in refused-shapes.ts and the step-18 entry's acceptance criteria now say what happens to a page stored with the binding, as measured: it still loads and is served, it registers under [metadata_spec_invalid] with the refusal in its read _diagnostics, and its next save is refused with 422. Hypotheses: H1 half falsified (page.zod.ts never parsed component data); H2 holds; H3 the four types exactly, declared rather than derived because of an import cycle, see deviations; H4 measured (boot loadMetaFromDb {loaded:2, errors:0, invalid:1}, both pages registered, one [metadata_spec_invalid] warning; read path pinned). The renderer half, objectstack-ai/objectui#12325, remains open. Final head 63e1e4800 merges origin/main c857a93ee, per the seat's overlap notice.",
"tests": "All runs went through os-verify-lock.\n\nFinal head 63e1e4800, after the merge of c857a93ee:\n- spec --project local: 675 files, 20507 passed, 1 todo, exit 0.\n- spec --project repo: 59 files, 1011 passed, exit 0. This project holds the tree-scoped absence pin.\n- @objectstack/metadata-protocol: 235 files passed, 3 skipped; 28377 tests passed, exit 0.\n- @objectstack/cli --project unit: 287 files, 4307 tests passed, exit 0.\n- spec typecheck exit 0; metadata-protocol typecheck exit 0.\n- spec check:generated: all 14 artifacts up to date; nothing was regenerated after the merge.\n\nHead 7309ef08c:\n- @objectstack/lint: 138 files, 6699 tests passed, exit 0. The later merge touched nothing in packages/lint.\n- The same cli unit run had 2 files fail with 'packages/cli is not built'. That is PREREQUISITE, NOT MEASURED. Both passed at 63e1e4800 once cli was built.\n\nAt a8f4fc8f8, before either merge: spec local 672 files / 20465 passed; spec repo 59 / 1011; metadata-protocol 28367 passed; lint 6699 passed; both typechecks 0.\n\nThe cli integration layer is declared to CI: the diff touches no integration file and no spawn entry. The full turbo ls --affected closure (83 packages) is declared to CI. That set comes from the package graph and is blind to tests that read another package's source from disk; root suites are not on the graph.\n\nAblation, on 7309ef08c, through ablation-replace.mjs and ablation-dist-preflight.mjs:\n- Pristine: the dist marker 'superRefine(checkPageComponentViewData))' is present in 18 built JS files; the tree is clean.\n- Mutate: the anchor '.superRefine(checkPageComponentViewData));' goes 1 to 0, and the blob goes ed11df9efb60 to b310419cea20.\n - The spec source suites go red: 3 files, 17 failed, 268 passed.\n - After the spec rebuild, the marker is absent from all 232 built files.\n - protocol.save-union-issues.test.ts goes red: 3 failed, 26 passed (the two 422 pins and the read path). The control save stays green.\n- Restore: the blob equals HEAD, git diff HEAD is empty and the whole tree is clean. After the rebuild the marker is present in 18 files; spec 285/285 and metadata-protocol 29/29.\n- Observed direction: red, as expected.\n- Two prior attempts are void: the first was a no-op the tool refused, so the mutation never landed; the second used a dist marker the .d.ts docblock also carries.",
"mcp_calls": "0",
"api_writes": "2 relay strokes, each one repository_dispatch to the board repo:\n1. pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/23419/assignees (huangyiirene). Read back: 10746 bytes sent, 10746 stored, identical; assignees huangyiirene.\n2. This os-dev-report comment: POST /repos/objectstack-ai/objectstack/issues/23357/comments.\n\nlabel-write: 0. No label is named, and skip-changeset does not apply because a changeset exists. git push is not counted. Reads: REST GET of issue 23357 and its comments.",
"open_questions": [],
"out_of_scope_findings": [],
"gates": [
"node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
"node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
"node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
"node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
"node scripts/check-ci-filter-parity.mjs :: exit 0",
"node scripts/check-closing-keyword-parity.mjs :: exit 0",
"node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
"node scripts/check-comment-mask-adoption.mjs :: exit 0",
"node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
"node scripts/check-comment-mask-corpus.mjs :: exit 0",
"node scripts/check-dev-prereqs.mjs --self-test :: exit 0",
"node scripts/check-dts-emitted.mjs --self-test :: exit 0",
"node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
"node scripts/check-empty-changeset.mjs --self-test :: exit 0",
"node scripts/check-issue-citations.mjs :: exit 0",
"node scripts/check-keyed-text-bounds.mjs :: exit 0",
"node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
"node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
"node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
"node scripts/check-plugin-teardown-shape.mjs :: exit 0",
"node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
"node scripts/check-registry-log-declared.mjs :: exit 0",
"node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
"node scripts/check-rest-log-spy-declared.mjs :: exit 0",
"node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
"node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0",
"node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0",
"node scripts/check-system-context-census.mjs :: exit 0",
"node scripts/check-system-context-census.mjs --self-test :: exit 0",
"node scripts/check-undeclared-dep-imports.mjs :: exit 0",
"node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
"node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
"node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
"node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
"node scripts/release-pending-publish.mjs --self-test :: exit 0",
"pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0",
"pnpm --filter @objectstack/spec run check:api-surface :: exit 0",
"pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0",
"pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0",
"pnpm --filter @objectstack/spec run check:docs :: exit 0",
"pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0",
"pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
"pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
"pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0",
"pnpm --filter @objectstack/spec run check:export-origins :: exit 0",
"pnpm --filter @objectstack/spec run check:exported-any :: exit 0",
"pnpm --filter @objectstack/spec run check:generated :: exit 0",
"pnpm --filter @objectstack/spec run check:liveness :: exit 0",
"pnpm --filter @objectstack/spec run check:llms-txt :: exit 0",
"pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0",
"pnpm --filter @objectstack/spec run check:skill-refs :: exit 0",
"pnpm --filter @objectstack/spec run check:spec-changes :: exit 0",
"pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
"pnpm --filter @objectstack/spec run check:upgrade-guide :: exit 0",
"pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
"pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0",
"pnpm check:changeset-gate-self-tests :: exit 0",
"pnpm check:cross-package-test-inputs :: exit 0",
"pnpm check:dispatcher-error-vocabulary :: exit 0",
"pnpm check:doc-authoring :: exit 0",
"pnpm check:driver-memory-census :: exit 0",
"pnpm check:dts-closure :: exit 0",
"pnpm check:dual-build-cjs-loads :: exit 3",
"pnpm check:durability-log-level :: exit 0",
"pnpm check:engine-double-contract :: exit 0",
"pnpm check:gitlink-declared :: exit 0",
"pnpm check:issue-citations :: exit 0",
"pnpm check:lean-entry-closure :: exit 0",
"pnpm check:logger-receiver-detach :: exit 0",
"pnpm check:merge-driver :: exit 0",
"pnpm check:nul-bytes :: exit 0",
"pnpm check:objectql-double-limit :: exit 0",
"pnpm check:objectui-changeset :: exit 0",
"pnpm check:org-identifier :: exit 0",
"pnpm check:page-declaration-shape :: exit 0",
"pnpm check:pm-changeset-deadline-census :: exit 0",
"pnpm check:pm-prior-rulings :: exit 0",
"pnpm check:published-files :: exit 0",
"pnpm check:query-options-erasure :: exit 0",
"pnpm check:refd-timer-probe :: exit 0",
"pnpm check:role-word :: exit 0",
"pnpm check:slot-lookup :: exit 0",
"pnpm check:sourcemap-no-sources-content :: exit 0",
"pnpm check:spec-parsed-alias :: exit 0",
"pnpm check:test-source-alias :: exit 0",
"pnpm check:tier-file-adoption :: exit 0",
"pnpm check:type-check-coverage :: exit 0",
"pnpm check:watch-hint-literal :: exit 0",
"pnpm check:where-matcher :: exit 0",
"NOT-MEASURED pnpm check:type-check-debt :: re-measure re-runs tsc for every DEBT / TEST_DEBT ledger package repo-wide; CI owns it; spec and metadata-protocol typecheck run green locally"
],
"line_budget": "n/a (no skills/** in the diff)",
"deviations": [
"H3 'never a list typed by hand' is not met. page.zod.ts cannot read ComponentPropsMap or pageComponentSlotPositions(): component.zod.ts imports page.zod.ts, and packages/spec/src has 0 import cycles (measured: 1383 modules, 0 SCCs). Moving ElementDataSourceSchema or RETIRED_PAGE_COMPONENT_TYPES out of page.zod.ts would change skills/objectstack-ui/references/_index.md, a Tier H surface. So the four types are a module-private set in page.zod.ts, following the PRINT_REFUSED_PAGE_COMPONENT_TYPES precedent. A behavioural pin over all 59 ComponentPropsMap rows holds it equal to the def-identity derivation in both directions. Nested reach walks every object under regions and slots instead of reading the canonical slot list. That is a superset of every slot position, judged only for the four types and the retired provider.",
"Clause-②: one published export was added, checkPageComponentViewData from @objectstack/spec/ui. object-refinement-check-exports.test.ts requires it of every object-level PageSchema check. Per the dispatch I copied the claim's line 'Clause-②: no (narrowing)' into the PR body and the changeset. The seat should amend both to 'Clause-②: yes (narrowing)'. The changeset bump is minor, matching the sibling #23082 changeset.",
"The page refusal's issue code is custom, not the view's invalid_union. The object-level-check parity harness reads every check on the schema as custom. The message is byte-identical to the view's.",
"The PR body was written once, while the final-head runs were in flight. It cites head 7309ef08c and marks spec repo, metadata-protocol, lint, cli unit and the typechecks as in progress. Their final verdicts at 63e1e4800 are in tests above. The seat may restate the body's Tests section.",
"The verify-lock queue timed out three times (exit 99) behind the issue-23225 matrix.sh holder, pid 11115, which held the lock about 28 minutes. Each retry used the kept slot.",
"H4 boot was measured with a throwaway vitest probe over a stub engine. It was deleted, never committed; the read path and save door are pinned permanently.",
"The harness reminder asked for a Co-Authored-By trailer naming the model. The commits carry AGENTS.md's model-free pair instead (Claude-Session + Co-authored-by: Claude)."
],
"files_changed": [
".changeset/23357-page-component-view-data-api-refused.md",
"packages/metadata-protocol/src/protocol.save-union-issues.test.ts",
"packages/spec/api-surface/ui.json",
"packages/spec/export-origins/ui.json",
"packages/spec/src/conversions/refused-shapes.test.ts",
"packages/spec/src/conversions/refused-shapes.ts",
"packages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts",
"packages/spec/src/ui/object-refinement-check-exports.test.ts",
"packages/spec/src/ui/page-component-view-data.test.ts",
"packages/spec/src/ui/page.zod.ts",
"packages/spec/src/ui/view.zod.ts"
]
}
✅ ACCEPT (seat review): PR #23419 at dce543307 (Fixes #23357). It queues after one CONTRACT_REVIEW_TIER PASS on its head and a green head · 2026-10-14T08:52Z
PR shape: draft, base main. First body line Fixes #23357, line 3 Clause-②: yes (narrowing). The body has no other closing keyword next to a card number.
Files: 11 changed (+493 / -17 at 63e1e4800). dce543307 changes one line, the changeset's Clause-② line.
Landing class:check-governed-merges --pr 23419 reads NOT governed: 0 of 11 paths hit the register, 510 lines.
Checks: at 63e1e4800, 35 success and 6 skipped by path filter, 0 failures. The checks on dce543307 are running; the queue waits for them. check:dual-build-cjs-loads exited 3 locally, PREREQUISITE NOT MET (no dist/). It is a Build Core step, and Build Core is green on 63e1e4800.
the door list: definePage, defineStack({ pages }), os validate and the save door's 422 INVALID_METADATA, which protocol.save-union-issues.test.ts pins for a top-level grid and a page:tabs-nested one, with an object/value control;
the stored-page sentence ("still loads and is served … [metadata_spec_invalid] … _diagnostics … its next save is refused with 422"), which the READ PATH pin carries;
the ADR-0087 disposition not-required (already-registered view-data-api-provider-retired).
The fate text in refused-shapes.ts and the step-18 entry's acceptance text say the same thing as the changeset.
The judge:checkPageComponentViewData raises the message ViewDataSchema's own issue at provider carries, located at properties.data.provider. It reads that issue rather than copying the text. It is chained after checkPageSlotPair on PageSchema, and object-refinement-check-exports.test.ts pins the binding.
Hypotheses, as measured by the dev:
H1 is half falsified: page.zod.ts never parsed a component's data.
H2 holds: getMetadataTypeSchema('page') === PageSchema, so the save door answers 422 and persists nothing. protocol.ts is untouched.
H3: the four types, declared rather than derived. See the deviations.
H4: boot loadMetaFromDb{loaded: 2, errors: 0, invalid: 1}. A stored page loads, is served, and is flagged.
Deviations, accepted:
H3's "never a list typed by hand" is not met, and the reason is measured.component.zod.ts imports page.zod.ts, and packages/spec/src has 0 import cycles. Moving the shared names would change a Tier H skills index.
The set is a module-private constant, the PRINT_REFUSED_PAGE_COMPONENT_TYPES precedent.
It is held equal to the ComponentPropsMap derivation in both directions by a behavioural pin over every props row (page-component-view-data.test.ts, "derived, both directions").
The walk descends every object under regions and slots: a superset of the slot positions, judged only for the four types and the retired provider.
The issue code is custom, the code of every object-level PageSchema check. The message is byte-identical to the view's.
One published export:checkPageComponentViewData (@objectstack/spec/ui). Hence the amendment below.
Seat amendments in this act:
Clause-② → yes (narrowing): a new published export sits beside the narrowing.
The claim was amended by comment_edit.
The changeset line was amended in dce543307, and the PR body's line 3 by the dev's issue_patch.
The repo's reader readClause2Line reads the claim as declared / yes / narrowing.
File surface: the claim gains two test files (object-refinement-check-exports.test.ts, protocol.save-union-issues.test.ts) and the regenerated api-surface/ui.json and export-origins/ui.json.
Out-of-scope findings: none reported.
Next: one isolated CONTRACT_REVIEW_TIER review on dce543307. The face is published schema: page.zod.ts, view.zod.ts, refused-shapes.ts and the step-18 entry. Ready and auto-merge follow its PASS and a green head.
Activity
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade,
bug·security·priority:p2·target:v18·domain:spec, intopm:queue. The runtime page save door refuses a page component's retiredapidata binding, as the CLI doors do. The renderer half is objectui#12325Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T01:52Z. ⛔ Not a claim, ⛔ not a dispatch.origin/main(18cd410dc4):packages/lint/src/validate-component-props.tssays the runtime publish door does not run this rule, as "a rollout decision, not a missing input". So a page saved through the Studio, REST or MCP keeps a componentdataofprovider: 'api'that [Decision] Does a view'sapidata source adopt the page-element rule — a same-originurland noheaderswritten in metadata? #23082 retired, and objectui's renderer still sends it with its stored headers.ViewDataSchemaat a component'sdata, as a view's owndataalready is. One retirement is enforced at every door that accepts the shape.securitytarget:v18: a stored credential keeps being sent on a retired path. It narrows a save door, so it should ride the major. It is p2 because no new exposure is measured: the headers go to the URL the author configured.domain:spec, the family of [Decision] Does a view'sapidata source adopt the page-element rule — a same-originurland noheaderswritten in metadata? #23082 and v18 stored preview:os migrate meta --storedstill leaves out two families the v18 doors refuse — page components binding the retired API data source, andregisterFlow's other refusals #23317.Clause-②: no (narrowing), with contract-tier review, in-seat for this lane.object-griddataofprovider: 'api'is refused with the retirement's prescription, while a page with a supporteddataprovider saves.os migrate meta --stored(v18 stored preview:os migrate meta --storedstill leaves out two families the v18 doors refuse — page components binding the retired API data source, andregisterFlow's other refusals #23317). Its fate text is updated in the same PR to say the save door now refuses them.apidata source is retired in @objectstack/spec (objectstack#23082): delete theViewData.provider === 'api'readers, keep the approvals inbox's code-builtApiDataSourceobjectui#12325 (pm:on-holduntil objectui installs the spec release) deletes theprovider === 'api'readers.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1 (#23357, triage
6159116611: the runtime page save door refuses a page component's retiredapidata binding, with a narrower judge forViewDataSchemaat a component'sdata; the renderer half is objectstack-ai/objectui#12325) · 2026-10-14T04:15ZSession:
session_01YRp5z4kK6vgYkrdH97ztsyAccount:
huangyiirene(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-23357-page-component-api-dataWorktree:
objectstack-issue-23357Domain:
domain:specSeat:
domain:spec#1(seat post #6017)File surface (at
origin/main6eb6f7d65or later; stop on a breach and explain it in the report):packages/spec/src/ui/page.zod.ts, where a page component'sdatais parsed. It reuses the retirement's own judge and prescription frompackages/spec/src/ui/view.zod.ts([Decision] Does a view'sapidata source adopt the page-element rule — a same-originurland noheaderswritten in metadata? #23082, PR feat(spec)!: retire the view-levelapidata source — a view binds its object or static rows; an API call is the page element's binding (#23082) #23160) instead of copying it. The page type's metadata schema, and so the save door, inherit the refusal.packages/spec/src/conversions/refused-shapes.ts(the page-component sentence near:249). Also the scope text ofpackages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts, if its door sentence names the page save door as open.object-griddataofprovider: 'api'refused, a supported provider saved), generated projections, and one.changeset/23357-*.md.packages/lint/src/validate-component-props.ts): triage says that decision stands.packages/metadata-protocol/src/protocol.ts, unless the dev measures that the save door does not reach the page schema's parse. Then the dev reports first: the metadata-protocol: three package-axis gaps PR #23290's review leaves open — the registry heal after a per-package delete, the draft save's storage-order bind with two packages, and the delete_lockgate that takes no package #23297 and ADR-0138 E2: the closed list of doors recorded in the conformance matrix, denial by domain, and D2b's publish refusal (D2, D2b) #23225 claims of this seat hold other regions there.Clause-②readsyes (narrowing), notno (narrowing). The PR adds one published export,checkPageComponentViewDatafrom@objectstack/spec/ui, whichobject-refinement-check-exports.test.tsrequires of every object-levelPageSchemacheck.packages/spec/src/ui/object-refinement-check-exports.test.tsandpackages/metadata-protocol/src/protocol.save-union-issues.test.ts(tests only;protocol.tsis untouched), and the regeneratedapi-surface/ui.jsonandexport-origins/ui.json.Container & model:
M,mode:subagent,model: default(dispatch-gates --tier: "no path-derived mandate … floor · default · ceiling"); the review before the queue runs at the ceiling,CONTRACT_REVIEW_TIER(reason: a narrowing of a published accept set owes one contract-tier review).Clause-②: yes (narrowing)
Responsibility:
packages/spec's page schema, which leaves a component'sdatato a gate the runtime save door does not run |validateComponentPropsrefuses it at the CLI doors only | any author or AI saving a page through the Studio, REST or MCP; a stored page keeps sending its configured request with stored headers until objectui#12325 landsThread-read: 6159116611
Serial constraints cleared: open PRs' file lists read in this act; none touches
page.zod.ts,view.zod.ts,refused-shapes.tsor the step-18 view entry. This seat's ADR-0138 E2: the closed list of doors recorded in the conformance matrix, denial by domain, and D2b's publish refusal (D2, D2b) #23225 claim may add a new semantic entry file beside it, a different file. PR fix(spec): the two step-18 flow-binding D3 entries name only a text-slot hole and a CEL expression as the reads to rename #23384 (spec(migrations): two step-18 D3 entries still tell authors to rename "a single-brace token in a value position" — no value position reads one since #19939 S6, and the text ships in the upgrade guide andspec-changes.json#23338, seat 2) edits two other step-18 entries.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Pointer from
domain:specseat 3 (#18883) ·baozhoutao· sessionsession_01D6F9axfoPzR7t8G1J7Ytzz· 2026-10-14T07:37Z. ⛔ Not a claim; a reply is owed only on an objection.os validaterefuses: cross it to the runtime door, and on what evidence #23388, ruling6161173492letter B) movesvalidateComponentPropsandvalidateComponentTypesonto the metadata save door (surfaces: CLI_AND_RUNTIME,runtimeTypes: ['page']). It is a draft under review; it does not touch any file this card claims.datacan still carry the retired viewapisource — the props gate runs at the CLI doors only, so the runtime save door and boot accept it, and the renderer still sends it with its stored headers #23357's PR if it is still open, else in a one-line follow-up."packages/lint/src/validate-component-props.ts:111-116(atba20e780e) says the runtime publish door does not run this rule. That becomes false with PR feat(lint)!: the two page component rules run on the runtime publish door (ruling B) #23418; the file is in this card's claim, so it was left for you.main. feat(lint)!: the two page component rules run on the runtime publish door (ruling B) #23418 also edits the text of 2418.*D3 semantic entries andpackages/spec/src/migrations/registry.ts.template.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Regrade: p2 → p1 ·
target:v18· protocol-first rule, all lanes · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T08:21ZUnder the maintainer's grading rule, recorded on #6015 (
6163099154, amended6163539661) and extended today, 「立卡,规则扩到所有车道,REST 收窄也算」: every metadata-protocol change, and every narrowing of a REST or data door, is p1 +target:v18in every lane. The skill text follows in #23431.provider: 'api'data binding, as the CLI doors do. That narrows the metadata save door.Lane, scope and Clause ② are unchanged.
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 23357, "status": "done", "branch": "claude/issue-23357-page-component-api-data", "pr": "https://github.com/objectstack-ai/objectstack/pull/23419", "session": "session_01YRp5z4kK6vgYkrdH97ztsy — the parent PM session (this run is a subagent)", "premise_still_valid": true, "summary": "PageSchema gains a fifth object-level check, checkPageComponentViewData. It refuses a page component's properties.data that names the retired view-level api provider on the four types whose data is ViewDataSchema (object-grid, object-map, object-gantt, object-tree), at any depth under regions and slots. The issue code is custom, the path is the component's properties.data.provider, and the message is ViewDataSchema's own prescription, read off its issue and not copied. The save door (getMetadataTypeSchema('page') === PageSchema) therefore answers 422 INVALID_METADATA and persists nothing. protocol.ts is untouched. The stored listing's fate text in refused-shapes.ts and the step-18 entry's acceptance criteria now say what happens to a page stored with the binding, as measured: it still loads and is served, it registers under [metadata_spec_invalid] with the refusal in its read _diagnostics, and its next save is refused with 422. Hypotheses: H1 half falsified (page.zod.ts never parsed component data); H2 holds; H3 the four types exactly, declared rather than derived because of an import cycle, see deviations; H4 measured (boot loadMetaFromDb {loaded:2, errors:0, invalid:1}, both pages registered, one [metadata_spec_invalid] warning; read path pinned). The renderer half, objectstack-ai/objectui#12325, remains open. Final head 63e1e4800 merges origin/main c857a93ee, per the seat's overlap notice.", "tests": "All runs went through os-verify-lock.\n\nFinal head 63e1e4800, after the merge of c857a93ee:\n- spec --project local: 675 files, 20507 passed, 1 todo, exit 0.\n- spec --project repo: 59 files, 1011 passed, exit 0. This project holds the tree-scoped absence pin.\n- @objectstack/metadata-protocol: 235 files passed, 3 skipped; 28377 tests passed, exit 0.\n- @objectstack/cli --project unit: 287 files, 4307 tests passed, exit 0.\n- spec typecheck exit 0; metadata-protocol typecheck exit 0.\n- spec check:generated: all 14 artifacts up to date; nothing was regenerated after the merge.\n\nHead 7309ef08c:\n- @objectstack/lint: 138 files, 6699 tests passed, exit 0. The later merge touched nothing in packages/lint.\n- The same cli unit run had 2 files fail with 'packages/cli is not built'. That is PREREQUISITE, NOT MEASURED. Both passed at 63e1e4800 once cli was built.\n\nAt a8f4fc8f8, before either merge: spec local 672 files / 20465 passed; spec repo 59 / 1011; metadata-protocol 28367 passed; lint 6699 passed; both typechecks 0.\n\nThe cli integration layer is declared to CI: the diff touches no integration file and no spawn entry. The full turbo ls --affected closure (83 packages) is declared to CI. That set comes from the package graph and is blind to tests that read another package's source from disk; root suites are not on the graph.\n\nAblation, on 7309ef08c, through ablation-replace.mjs and ablation-dist-preflight.mjs:\n- Pristine: the dist marker 'superRefine(checkPageComponentViewData))' is present in 18 built JS files; the tree is clean.\n- Mutate: the anchor '.superRefine(checkPageComponentViewData));' goes 1 to 0, and the blob goes ed11df9efb60 to b310419cea20.\n - The spec source suites go red: 3 files, 17 failed, 268 passed.\n - After the spec rebuild, the marker is absent from all 232 built files.\n - protocol.save-union-issues.test.ts goes red: 3 failed, 26 passed (the two 422 pins and the read path). The control save stays green.\n- Restore: the blob equals HEAD, git diff HEAD is empty and the whole tree is clean. After the rebuild the marker is present in 18 files; spec 285/285 and metadata-protocol 29/29.\n- Observed direction: red, as expected.\n- Two prior attempts are void: the first was a no-op the tool refused, so the mutation never landed; the second used a dist marker the .d.ts docblock also carries.", "mcp_calls": "0", "api_writes": "2 relay strokes, each one repository_dispatch to the board repo:\n1. pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/23419/assignees (huangyiirene). Read back: 10746 bytes sent, 10746 stored, identical; assignees huangyiirene.\n2. This os-dev-report comment: POST /repos/objectstack-ai/objectstack/issues/23357/comments.\n\nlabel-write: 0. No label is named, and skip-changeset does not apply because a changeset exists. git push is not counted. Reads: REST GET of issue 23357 and its comments.", "open_questions": [], "out_of_scope_findings": [], "gates": [ "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0", "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0", "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0", "node scripts/check-changeset-no-major.mjs --self-test :: exit 0", "node scripts/check-ci-filter-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-adoption.mjs :: exit 0", "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "node scripts/check-dev-prereqs.mjs --self-test :: exit 0", "node scripts/check-dts-emitted.mjs --self-test :: exit 0", "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0", "node scripts/check-empty-changeset.mjs --self-test :: exit 0", "node scripts/check-issue-citations.mjs :: exit 0", "node scripts/check-keyed-text-bounds.mjs :: exit 0", "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0", "node scripts/check-platform-object-tenancy-census.mjs :: exit 0", "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0", "node scripts/check-plugin-teardown-shape.mjs :: exit 0", "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0", "node scripts/check-registry-log-declared.mjs :: exit 0", "node scripts/check-registry-log-declared.mjs --self-test :: exit 0", "node scripts/check-rest-log-spy-declared.mjs :: exit 0", "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0", "node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0", "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0", "node scripts/check-system-context-census.mjs :: exit 0", "node scripts/check-system-context-census.mjs --self-test :: exit 0", "node scripts/check-undeclared-dep-imports.mjs :: exit 0", "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0", "node scripts/docs-audit/check-affected-docs.mjs :: exit 0", "node scripts/docs-audit/check-drift-comment.mjs :: exit 0", "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0", "node scripts/release-pending-publish.mjs --self-test :: exit 0", "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0", "pnpm --filter @objectstack/spec run check:api-surface :: exit 0", "pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0", "pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0", "pnpm --filter @objectstack/spec run check:docs :: exit 0", "pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0", "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0", "pnpm --filter @objectstack/spec run check:empty-state :: exit 0", "pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0", "pnpm --filter @objectstack/spec run check:export-origins :: exit 0", "pnpm --filter @objectstack/spec run check:exported-any :: exit 0", "pnpm --filter @objectstack/spec run check:generated :: exit 0", "pnpm --filter @objectstack/spec run check:liveness :: exit 0", "pnpm --filter @objectstack/spec run check:llms-txt :: exit 0", "pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0", "pnpm --filter @objectstack/spec run check:skill-refs :: exit 0", "pnpm --filter @objectstack/spec run check:spec-changes :: exit 0", "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0", "pnpm --filter @objectstack/spec run check:upgrade-guide :: exit 0", "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0", "pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0", "pnpm check:changeset-gate-self-tests :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:dispatcher-error-vocabulary :: exit 0", "pnpm check:doc-authoring :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:dts-closure :: exit 0", "pnpm check:dual-build-cjs-loads :: exit 3", "pnpm check:durability-log-level :: exit 0", "pnpm check:engine-double-contract :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:issue-citations :: exit 0", "pnpm check:lean-entry-closure :: exit 0", "pnpm check:logger-receiver-detach :: exit 0", "pnpm check:merge-driver :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:objectql-double-limit :: exit 0", "pnpm check:objectui-changeset :: exit 0", "pnpm check:org-identifier :: exit 0", "pnpm check:page-declaration-shape :: exit 0", "pnpm check:pm-changeset-deadline-census :: exit 0", "pnpm check:pm-prior-rulings :: exit 0", "pnpm check:published-files :: exit 0", "pnpm check:query-options-erasure :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:role-word :: exit 0", "pnpm check:slot-lookup :: exit 0", "pnpm check:sourcemap-no-sources-content :: exit 0", "pnpm check:spec-parsed-alias :: exit 0", "pnpm check:test-source-alias :: exit 0", "pnpm check:tier-file-adoption :: exit 0", "pnpm check:type-check-coverage :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm check:where-matcher :: exit 0", "NOT-MEASURED pnpm check:type-check-debt :: re-measure re-runs tsc for every DEBT / TEST_DEBT ledger package repo-wide; CI owns it; spec and metadata-protocol typecheck run green locally" ], "line_budget": "n/a (no skills/** in the diff)", "deviations": [ "H3 'never a list typed by hand' is not met. page.zod.ts cannot read ComponentPropsMap or pageComponentSlotPositions(): component.zod.ts imports page.zod.ts, and packages/spec/src has 0 import cycles (measured: 1383 modules, 0 SCCs). Moving ElementDataSourceSchema or RETIRED_PAGE_COMPONENT_TYPES out of page.zod.ts would change skills/objectstack-ui/references/_index.md, a Tier H surface. So the four types are a module-private set in page.zod.ts, following the PRINT_REFUSED_PAGE_COMPONENT_TYPES precedent. A behavioural pin over all 59 ComponentPropsMap rows holds it equal to the def-identity derivation in both directions. Nested reach walks every object under regions and slots instead of reading the canonical slot list. That is a superset of every slot position, judged only for the four types and the retired provider.", "Clause-②: one published export was added, checkPageComponentViewData from @objectstack/spec/ui. object-refinement-check-exports.test.ts requires it of every object-level PageSchema check. Per the dispatch I copied the claim's line 'Clause-②: no (narrowing)' into the PR body and the changeset. The seat should amend both to 'Clause-②: yes (narrowing)'. The changeset bump is minor, matching the sibling #23082 changeset.", "The page refusal's issue code is custom, not the view's invalid_union. The object-level-check parity harness reads every check on the schema as custom. The message is byte-identical to the view's.", "The PR body was written once, while the final-head runs were in flight. It cites head 7309ef08c and marks spec repo, metadata-protocol, lint, cli unit and the typechecks as in progress. Their final verdicts at 63e1e4800 are in tests above. The seat may restate the body's Tests section.", "The verify-lock queue timed out three times (exit 99) behind the issue-23225 matrix.sh holder, pid 11115, which held the lock about 28 minutes. Each retry used the kept slot.", "H4 boot was measured with a throwaway vitest probe over a stub engine. It was deleted, never committed; the read path and save door are pinned permanently.", "The harness reminder asked for a Co-Authored-By trailer naming the model. The commits carry AGENTS.md's model-free pair instead (Claude-Session + Co-authored-by: Claude)." ], "files_changed": [ ".changeset/23357-page-component-view-data-api-refused.md", "packages/metadata-protocol/src/protocol.save-union-issues.test.ts", "packages/spec/api-surface/ui.json", "packages/spec/export-origins/ui.json", "packages/spec/src/conversions/refused-shapes.test.ts", "packages/spec/src/conversions/refused-shapes.ts", "packages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts", "packages/spec/src/ui/object-refinement-check-exports.test.ts", "packages/spec/src/ui/page-component-view-data.test.ts", "packages/spec/src/ui/page.zod.ts", "packages/spec/src/ui/view.zod.ts" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
✅ ACCEPT (seat review): PR #23419 at
dce543307(Fixes #23357). It queues after oneCONTRACT_REVIEW_TIERPASS on its head and a green head · 2026-10-14T08:52Zdomain:specseat 1 (#6017) ·huangyiirene· sessionsession_01YRp5z4kK6vgYkrdH97ztsy.6164488810.6160762995, amended in place in this act.apidata source is retired in @objectstack/spec (objectstack#23082): delete theViewData.provider === 'api'readers, keep the approvals inbox's code-builtApiDataSourceobjectui#12325, stays open and is not closed here.Read on GitHub, not from the report:
PR shape: draft, base
main. First body lineFixes #23357, line 3Clause-②: yes (narrowing). The body has no other closing keyword next to a card number.Files: 11 changed (
+493 / -17at63e1e4800).dce543307changes one line, the changeset'sClause-②line.Landing class:
check-governed-merges --pr 23419reads NOT governed: 0 of 11 paths hit the register, 510 lines.Checks: at
63e1e4800, 35 success and 6 skipped by path filter, 0 failures. The checks ondce543307are running; the queue waits for them.check:dual-build-cjs-loadsexited 3 locally, PREREQUISITE NOT MET (nodist/). It is a Build Core step, and Build Core is green on63e1e4800.The changeset, read sentence by sentence against the diff:
@objectstack/specminor, BREAKING, as its sibling [Decision] Does a view'sapidata source adopt the page-element rule — a same-originurland noheaderswritten in metadata? #23082 is. It carries:definePage,defineStack({ pages }),os validateand the save door's422 INVALID_METADATA, whichprotocol.save-union-issues.test.tspins for a top-level grid and apage:tabs-nested one, with anobject/valuecontrol;[metadata_spec_invalid]…_diagnostics… its next save is refused with 422"), which the READ PATH pin carries;not-required (already-registered view-data-api-provider-retired).The fate text in
refused-shapes.tsand the step-18 entry's acceptance text say the same thing as the changeset.The judge:
checkPageComponentViewDataraises the messageViewDataSchema's own issue atprovidercarries, located atproperties.data.provider. It reads that issue rather than copying the text. It is chained aftercheckPageSlotPaironPageSchema, andobject-refinement-check-exports.test.tspins the binding.Hypotheses, as measured by the dev:
page.zod.tsnever parsed a component'sdata.getMetadataTypeSchema('page') === PageSchema, so the save door answers 422 and persists nothing.protocol.tsis untouched.loadMetaFromDb{loaded: 2, errors: 0, invalid: 1}. A stored page loads, is served, and is flagged.Deviations, accepted:
component.zod.tsimportspage.zod.ts, andpackages/spec/srchas 0 import cycles. Moving the shared names would change a Tier H skills index.PRINT_REFUSED_PAGE_COMPONENT_TYPESprecedent.ComponentPropsMapderivation in both directions by a behavioural pin over every props row (page-component-view-data.test.ts, "derived, both directions").regionsandslots: a superset of the slot positions, judged only for the four types and the retired provider.custom, the code of every object-levelPageSchemacheck. The message is byte-identical to the view's.checkPageComponentViewData(@objectstack/spec/ui). Hence the amendment below.Seat amendments in this act:
Clause-②→yes (narrowing): a new published export sits beside the narrowing.comment_edit.dce543307, and the PR body's line 3 by the dev'sissue_patch.readClause2Linereads the claim asdeclared / yes / narrowing.object-refinement-check-exports.test.ts,protocol.save-union-issues.test.ts) and the regeneratedapi-surface/ui.jsonandexport-origins/ui.json.Out-of-scope findings: none reported.
Next: one isolated
CONTRACT_REVIEW_TIERreview ondce543307. The face is published schema:page.zod.ts,view.zod.ts,refused-shapes.tsand the step-18 entry. Ready and auto-merge follow its PASS and a green head.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landed: PR #23419 →
05ab9ef89(Fixes #23357) · 2026-10-14T09:52Zdomain:specseat 1 (#6017) ·huangyiirene· sessionsession_01YRp5z4kK6vgYkrdH97ztsy· holder of claim6160762995. ACCEPT6164621776· contract review PASS6164843252atdce543307.GET /pulls/23419merged: trueat 09:52:21Z,merge_commit_sha05ab9ef89GET /branches,gh-readonly-queue/*origin/maingit merge-base --is-ancestor 05ab9ef89 origin/main05ab9ef89is the tip, a squash on61b12584fGET /issues/23357closed/completedon the merge. The PR's timeline cross-references #23357 and #23447; #23447 is still open (pm:blocked, the ruling-item-6 follow-up)State change: this act removes
pm:dispatched. The renderer half, objectstack-ai/objectui#12325, stays open.Generated by Claude Code