Repository navigation
[Decision] page requires on the page kinds whose source is never compiled at save (react, full, slotted): refuse it at parse, or keep admitting a key nothing derives? #21459
Description
Ruled: 5964312254 · letter A · 2026-10-03T01:54Z
Filing gate: ② a maintainer decision, a contract-shape proposal (triage-duties.md: 「needs-user-decision = 设计卡、feature/契约形状提案」). Filed by domain:spec seat 2 (session_01YDt3PzwfrkuFzUBF89WPmM, seat post #18549), from the #20871 dev's measurement 5959538313 (option A) and contract review 5960279457, item ③. The review held that a contract-shape proposal belongs in the decision box, not in chat alone. ⛔ Not a claim. Nothing waits on this card: PR #21451 lands without it.
维护者速读
页面的 requires 字段(页面用到哪些插件)只在 html/jsx 页上有意义:平台保存时编译源码、自动算出并写入,手写的不一致会被拒。在 react、full、slotted 三种页上,平台从不计算它,只有加载时会根据它报一条警告,Studio 保存时还会把它删掉;仓内示例与应用里也没有任何一个页面手写它。A=在这三种页上解析时直接拒收(破坏性收窄,带迁移条目);B=维持现状,照收不管。要不要收窄?(是/否)
Background
- page requires, #20312 stage ③ (spec half): the liveness row flips to live, the describe and the docs state save + load, the lint reason and the ADR-0087 guide entry name the save door #20871 (PR fix(spec,lint): page
requiresis live — refused at save, reported at load #21451, in the queue) flips pagerequirestolive. On anhtml/jsxpage, on a server with the deployment's SDUI manifest, the save door stamps the compiled list and refuses a written list that disagrees. At load, a stored list naming a plugin no manifest component carries is reported, and the page is still served. - The reconciliation ledger then asked for the form-offer decision. The seat answered no offer (
5959584348), because the key's own describe says "derived from the source at save — omit it" on every kind. - The dev's measurement found the part the describe's words do not cover. On the kinds the save door never compiles, nothing derives the key, yet
PageSchemaadmits it.
Governing text:
- ADR-0080 §5 [ruled]: "Store
{ source, compiledTree, requires }— source is truth, tree is derived cache", and "requiresis inferred at parse and validated at save and load". That is the JSX-source page kind's stored shape. The ADR does not rule on the other kinds. page.zod.ts, therequiresdescribe (at PR fix(spec,lint): pagerequiresis live — refused at save, reported at load #21451's head): "derived from the source at save — omit it".- ADR-0087: the retirement and narrowing mechanism (a semantic entry, FROM/TO in the changeset).
check-prior-rulings --terms requires,page requires,sdui manifest,compiled at save,html pagenamed six ADR decisions. Each is a generic match on the wordrequires, and none rules on a page key.
Protocol declaration: PageSchema.requires: z.array(z.string()).optional() on every kind. Option A changes the protocol, and B does not.
Premises (each with its re-check, measured at origin/main b94a2a7277)
- The parse admits
requireson every kind, and no refinement ties it tokind.git grep -n "requires: z.array" origin/main -- packages/spec/src/ui/page.zod.ts→:903, 1 hit.git grep -n -E "kind: z.enum" origin/main -- packages/spec/src/ui/page.zod.ts→:839,['full', 'slotted', 'html', 'react', 'jsx'].
- Only
html/jsxare compiled at save.git grep -n "COMPILED_PAGE_KINDS" origin/main -- packages/metadata-protocol/src/runtime-authoring-gate.ts→:571new Set(['html', 'jsx']), and:634, which returns early for any other kind.
- No page-level
requiresis authored in this repo's examples or apps.git grep -n -E "^\s*requires:" origin/main -- examples packages/apps→ 3 hits, all stack-level capability lists inobjectstack.config.ts, not page bodies.
- Studio drops the key on every page save.
- objectui at the pinned
.objectui-sha89cad75d55:packages/app-shell/src/services/builtinComponents.tsxpageSaveBodydeletesrequires, registered asfromDraftfor typepagewith no kind gate.
- objectui at the pinned
- On non-compiled kinds, the only reader is the load report, a warning with the page still served:
findPageRequiresAbsentFromManifest(kind-agnostic) viareportPageRequiresAbsentAtLoad, per the measurement5959538313.
The question
On react, full and slotted pages, the platform never derives requires, Studio never keeps it, and no example writes it. Should the contract go on admitting it there?
Options
| What it does | What a customer or author sees | |
|---|---|---|
| A. Refuse at parse on non-compiled kinds | PageSchema accepts requires only when kind is html / jsx. A semantic retirement entry (ADR-0087) and a changeset with FROM/TO. A stored non-compiled page that carries the key is converted (the key dropped) or refused at its next save, whichever the entry prescribes. |
An author or AI that writes requires on a react page gets a loud refusal at save, naming the key and saying it is derived for compiled pages only. No measured author is affected (premise 3). |
| B. Keep admitting it | No change. The ledger row landed by PR #21451 already states the per-kind truth. | A requires written on a react page is accepted, only the load-time warning reads it, and Studio drops it on the next save. The author is never told the key does nothing there. |
Business meaning:
- A: a field the platform fills in is accepted only on the page types where the platform fills it in. This is like a calculated column that an import refuses to take a hand-typed value for.
- B: the form keeps a box nobody reads on three of five page types. Whatever is typed there is silently dropped the next time the page is saved in Studio.
四维分析
os-decision-facets
- ① 项目长远合理性: A 缩小契约——
requires回到 ADR-0080 定义的「编译页派生字段」本义,一个键只有一种含义;B 保留一个只在两种页上有派生者、其余三种页上无人写也无人真用的方言面,契约增生不减。 - ② 实际业务拉动: 今天无人撞上——仓内示例与应用零处页面级手写
requires(前提 3),Studio 每次保存都删掉它(前提 4);零拉动按原则默认 remove,而非 declare-and-maintain。 - ③ 防 AI 犯错: A 让 AI 在非编译页上写
requires时得到响亮拒绝;B 下 AI 写了也被接受,只得一条加载期警告、随后被 Studio 静默删除——出错时作者看不到,是静默容忍。 - ④ 创业阶段不扩散: A 删掉一个零消费的声明面,少一项永久义务;B 让每个已声明却无派生者的键继续是永久维护成本。
Prior rulings read: requires,page requires,sdui manifest,compiled at save,html page → 14 hits; ADR-0007 Decision §9, ADR-0055 Decision §3, ADR-0059 Decision §3, ADR-0066 D2, ADR-0088 Decision §1, ADR-0106 D4 (all generic matches on the word requires; the governing text is ADR-0080 §5, read above); thread: none (new card); repo: objectstack-ai/objectstack
推荐:A。 终态句:两年后 requires 应是编译型页面由平台从源码推导出的依赖清单,作者永不手写——如同打包器从 import 推导模块依赖、而不读一份手写依赖表;非编译页不存在这个键。只看①选 A;②③④ 是否翻转:否(②零拉动、③响亮拒绝、④减少义务,均同向)。回退: B(维持现状,PR #21451 落地的账本行已如实写明各页类型的真相)。置信缺口: 仓外(cloud、hotcrm 等姊妹仓)是否有页面手写 requires 未测——本会话组织级代码检索返回 403;A 落地前须由有组织级读权限的席位补测。
After the ruling
- A: a
domain:speccard, filed by the seat that reads the ruling.PageSchemarefusesrequiresunlesskindishtml/jsx, with the refusal naming the key and the compiled kinds. It carries a semantic retirement entry in the next unreleased step, with its reason and prescription, a changeset with FROM/TO, and the stored-row disposition the entry prescribes. The reconciliation ledger row's per-kind clause shrinks to the compiled kinds. objectui needs no change: Studio already drops the key. Before building, the sister repos' page bodies are measured for a hand-writtenrequires(the confidence gap above). - B: this card closes
not_planned, citing the ruling. Nothing else changes.
Related
#20871 · PR #21451 · the measurement 5959538313 · seat answer 5959584348 · reviews 5959399303 (FAIL) and 5960279457 (PASS, item ③) · ADR-0080 §5 · ADR-0087.
Dedupe: the 1,000 most recently updated issues and PRs here, open and closed, were listed by REST and grepped for page requires, requires with react page, and requires with non-compiled / slotted. 1 hit: this seat's own post #18549, which names option A as raised. No card proposes narrowing page requires by kind.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 3, 2026
Ruling: batch #270 item 2 · letter A · maintainer 「其他issue同意」 2026-10-03T01:52Z
Director seat, summon #32,
session_016tKoy8NJa35Yih1FdzrVmn. Written asobjectstack-fleet[bot]through the relay.The reading that filled the confidence gap (read this session)
There are zero page-level hand-written
requiresin cloud (c5a4c9e6cb), hotcrm (5ae524916d) and objectui (8366accd13). Everyrequires:hit is a stack-level capability list inobjectstack.config.ts, or objectui'ssdui-parsercomputing the derived list.The ruling
A:
PageSchemaacceptsrequiresonly whenkindishtmlorjsx, the kinds the save door compiles. Onreact,fullandslottedit is refused at parse, and the refusal names the key and the compiled kinds.Not taken: B. It keeps admitting a key nothing derives on three of five kinds, and Studio silently drops it.
四棱(本裁决新记录)
requires回到 ADR-0080 的本义——编译型页面由平台从源码推导的依赖清单,作者永不手写。Execution parameters
This card:
needs-user-decision→pm:queuein this act,domain:spec, and gradedpriority:p3here (zero pull). The card carries its own execution: no second card.Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
Claim: PM loop round 1
Session:
session_01YDt3PzwfrkuFzUBF89WPmMAccount:
os-tesla(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-21459-page-requires-compiled-kindsWorktree:
objectstack-issue-21459Domain:
domain:specSeat:
domain:spec#2File surface (at
origin/mainad7c351898), per the ruling record5964312254(A, 「其他issue同意」):packages/spec/src/ui/page.zod.ts,PageSchema:requiresis accepted only whenkindishtmlorjsx, the kinds the save door compiles. Onreact,fullandslottedit is refused at parse, and the refusal names the key and the compiled kinds. Therequiresdescribe is narrowed with it.migrations/registry.tsregions and the step's rationale fragment, the generated artifacts, and one changeset with FROM/TO.requires, landed by PR fix(spec,lint): pagerequiresis live — refused at save, reported at load #21451: its per-kind clause shrinks to the compiled kinds.htmlandjsxstill accepted, with the save door's compile path unchanged; a page with norequiresunchanged on every kind.metadata-protocolruntime-authoring-gate.ts) or the load report, beyond tests that pinned the old acceptance.Container & model:
M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceilingCONTRACT_REVIEW_TIER). A narrowing ofpackages/spec/src/**, so the at-tier contract review runs as a separate isolated subagent after the PR opens.Clause-②: yes (narrowing)
Thread-read: 5964312254
Serial constraints, answered: PR #21531 (#21504, ACCEPTed, landing next) also writes
ui/page.zod.ts(RETIRED_PAGE_COMPONENT_TYPES, a different region) and adds a step-18 rationale fragment and entry tomigrations/registry.ts. Fold or serial: serial, not folded. The defect shapes differ (a retired component type, a key narrowed by kind), so fold gate ① fails. The dev cuts frommainand mergesmainagain after PR #21531 lands, before opening the PR. #20234's stage 11 (seat 5, the hand-written parts ofmigrations/registry.ts) has no open PR at 2026-10-03T03:58Z; whichever lands second mergesmain. No other open PR touches these paths.Seat terms: p3, under the maintainer's 「p3 的卡也可以派了」 (
5952442849),batch 3. A contract-surface card, so it orders first among this lane's open candidates. The PR isFixes #21459.Generated by Claude Code
wip(spec): page requires only on compiled kinds — refusal, conversion…
objectstack-fleet commentedon Oct 3, 2026
os-dev-report
{ "issue": 21459, "status": "done", "branch": "claude/issue-21459-page-requires-compiled-kinds", "pr": "https://github.com/objectstack-ai/objectstack/pull/21547", "head": "e38149267c", "session": "session_01YDt3PzwfrkuFzUBF89WPmM", "premise_still_valid": true, "summary": "Ruling A is executed. PageSchema accepts `requires` only when `kind` is `html` or `jsx`. A new exported object-level check, `checkPageRequiresKind`, refuses it at `requires` on a react, full or slotted page, and on a kind-less page (whose kind defaults to full). The refusal names the key, the page's kind and the compiled kinds, and carries no tracker number. The check is chained with `.superRefine` beside `checkPageSourceCompleteness`, with the new export `COMPILED_PAGE_KINDS` as its vocabulary. The describe is narrowed, and its quoted opening sentence is kept byte-identical. The ADR-0087 kit is: D2 lossless-strip conversion `page-requires-non-compiled-kind-removed` (step 18, order 58, retiredFromLoadPath, retiredAfter 17.6.0); D3 semantic entry `page-requires-non-compiled-kind-refused` (with conversionIds); a hand-written STEP18_RATIONALE fragment (order 66); regenerated registry regions; and a minor BREAKING changeset with FROM/TO and the ADR-0087 registered marker. The liveness row and the reconciliation row shrink their per-kind clause to the compiled kinds. No runtime, objectui or skills edit. Draft PR #21547 is open. Its assignee is NOT set: the label-write was refused by the local permission classifier (see deviations).", "files_changed": [ ".changeset/21459-page-requires-compiled-kinds.md (new)", "packages/spec/src/ui/page.zod.ts (COMPILED_PAGE_KINDS, checkPageRequiresKind, superRefine chain, describe + TSDoc)", "packages/spec/src/conversions/registry.ts (D2 conversion + MAJOR_18_CONVERSIONS entry)", "packages/spec/src/migrations/entries/semantic/18.page-requires-non-compiled-kind-refused.ts (new D3 entry)", "packages/spec/src/migrations/registry.ts (rationale fragment by hand + regions by gen:migration-registry)", "packages/spec/liveness/page.json (requires row: PARSE evidence, per-kind clause, verifiedAt 2026-10-03)", "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts (row per-kind clause)", "packages/spec/src/ui/object-refinement-check-exports.test.ts (new export catalogued)", "packages/spec/src/ui/page-requires-compiled-kinds.test.ts (new pins)", "packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts (save-door refusal + stored-row load pins; tests only)", "generated by check:generated --fix: packages/spec/api-surface/ui.json, packages/spec/export-origins/ui.json, content/docs/references/ui/page.mdx" ], "line_budget": "13 files, +641 / -24 (665 changed lines) vs merge base 49161683fb; under the 5000-line human-merge threshold; no governed surface (no .claude/**, skills/**, docs/adr/**, AGENTS.md)", "census_A1": "Base c98a72d69e, re-read on the merged tree. Zero page bodies author `requires` on a non-compiled kind outside tests, and none in tests, so there is no producer. Every `requires:` hit in examples/** is a stack-level capability list: app-crm, app-showcase and app-todo objectstack.config.ts, plus prose comments naming capability tokens. packages/apps/** has 0 hits. content/docs/** has only stack-level hits plus the auto-gen references/ui/page.mdx describe row. skills/** has only stack-level hits. In tests and fixtures, the only page bodies with `requires` are the 11 htmlPage(...) sites in packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts. All are kind html, so they are still accepted, and they are the proximity scan's positive control. docs/qa/platform-checklist `fixtures.requires` is checklist prose, not a page. The CLI test templates are stack-level. No test pinned acceptance on a non-compiled kind. objectui at the .objectui-sha pin 89cad75d55 has page `requires` only on stamped html fixtures, plus one compile-only type fixture (twins-spec-by-reference-9736.test.ts:158). The main commits 1ac7308d7a and 41b13331cd add none: their one pages/index.ts edit is an action target.", "A2_default_kind": "An omitted kind parses as `full` (the PageSchema default), and the refinement runs on the parsed value. So a kind-less page carrying `requires` is refused as `kind: 'full'`, and the message adds '(`full` is also the kind of a page that omits `kind`)'. The direct call, which a .shape mirror makes with no default, reads an absent kind as full and returns the identical issue. Pinned in page-requires-compiled-kinds.test.ts and by the kind-less fixture in the exports parity matrix.", "A2_empty_array": "Measured on non-compiled kinds. At the save door, compileHtmlPage returns undefined, so findHtmlPageSourceGaps answers null and stampHtmlPageRequires returns the body unchanged. At load, findPageRequiresAbsentFromManifest answers [] for an empty list, which reports nothing. So [] had no effect anywhere. The ruling refuses the KEY ('accepts `requires` only when `kind` is `html` or `jsx`'), so [] is refused too, and the D2 conversion strips it (the fixture's team_home). Both are pinned.", "A4_disposition": "A mechanical drop, carried by a D2 conversion (page-requires-non-compiled-kind-removed, retiredFromLoadPath true, retiredAfter 17.6.0). Why it is a drop: on react, full and slotted pages nothing derived the list, no renderer read it, and the Studio page editor already drops it on every save. Its one reader was the load report's warning, so the delete loses nothing a page does. Why a conversion rather than refuse-at-next-save: a stored row at rest has no author. With the conversion it loads clean with one conversion notice. Without it, every boot would warn [metadata_spec_invalid] and badge _diagnostics on the row until someone deleted the key. An artifact built by 17.6.0 or earlier replays it too. Authored sources are still refused at parse, because the conversion is retired from the load path, and `os migrate meta --from 17` lists the edit. Measured at the real seam: loadMetaFromDb over a seeded stored react page with requires gives loaded 1, errors 0, invalid 0, one notice naming the conversion, no [page_requires_plugin_absent] line although the manifest lacks the plugin, and no [metadata_spec_invalid] line.", "A6_unreachable_reader_branches": [ "packages/metadata-protocol/src/runtime-authoring-gate.ts:616-627 findPageRequiresAbsentFromManifest, 'Kind-agnostic on purpose' (TSDoc at :610). A non-compiled page can no longer reach it: the save door's spec parse refuses the key, and at load the stored-row conversion strips it before reportPageRequiresAbsentAtLoad reads it (protocol.ts:24418 passes the converted body). Its kind-agnostic reach now serves only html/jsx rows. Follow-up candidate: the TSDoc sentence. Not changed here.", "packages/metadata-protocol/src/protocol.ts:24526 reportPageRequiresAbsentAtLoad TSDoc 'How a stored page gets here'. It is still true, but now only of html/jsx rows. Not changed.", "packages/metadata-protocol/src/runtime-authoring-gate.ts:679 and :728 were already gated to html/jsx by compileHtmlPage (:634), so nothing became unreachable there.", "objectui (pin 89cad75d55) app-shell builtinComponents.tsx pageSaveBody deletes `requires` on every kind. On non-compiled kinds that is now redundant and harmless. No objectui edit.", "No existing test pinned the old acceptance, so no test was rewritten for it." ], "A9_merge_state": "PR #21531 LANDED as 48eb9c193f. This branch merged origin/main twice through scripts/pm/os-regen-merge.sh: dafb0f6d1e after #21531, then e38149267c at 49161683fb. ui/page.zod.ts and migrations/registry.ts merged textually clean, and both rationale fragments are kept: ui-ai-chat-window-retired at 65 and this one bumped to 66 because #21531 landed first. check:migration-registry is green on the merged regions. The three os-regen artifacts both sides touched (api-surface/ui.json, export-origins/ui.json, references/ui/page.mdx) were regenerated on the merged tree in d7cd797549, and their delta vs main is exactly this PR's two exports and the describe row. Sibling entries survive with equal counts on main and head: 'ui-ai-chat-window-retired' 3, 'ui/AIChatWindowProps' 2, 'ai:chat_window' 17. None of the 10 open PRs touches page.zod.ts, migrations/registry.ts, conversions/registry.ts, liveness/page.json, the reconciliation test, the exports test or the save-door test. Main has since gained 1ac7308d7a (core) and 41b13331cd (spec view.zod.ts and examples). Neither touches a file in this diff, and this branch was NOT re-merged onto them.", "ablation": "Run through scripts/ablation-replace.mjs (WRAP mode, auto-restore) under the verify lock, from committed HEAD e38149267c. The mutation replaces the kind condition `if ((COMPILED_PAGE_KINDS as readonly string[]).includes(kind)) return;` with a bare `return;`, so the key is accepted on every kind. The source-resolved spec suites need no rebuild, so there was no dist leg. Mutation landed: anchor 1 -> 0, blob 6b13a7df8e44 -> 1fd2575e28e3, and the ABLATION-21459 marker counted 1 on disk during the run. Red leg (page-requires-compiled-kinds.test.ts + object-refinement-check-exports.test.ts): 13 failed / 174 passed. The failures are the refusal pins on react, full and slotted; the omitted-kind, empty-array, stack-door and strip-iff-refused pins; the 5 direct-call parity fixtures; and the bijection leg. The html/jsx CONTROL pins stayed green, as listed by the verbose reporter. Restore: blob == HEAD 6b13a7df8e44 and git diff HEAD empty. Green leg: 187/187.", "semver": "@objectstack/spec minor, BREAKING banner, `Clause-②: yes (narrowing)` in the changeset and at the PR body's line 2. Gate lines: check-changeset-no-major with the PR body as --event gave '✓ This diff introduces no `major` bump.' and '✓ LEVEL AXIS: this PR declares clause-② `yes (narrowing)`, and no package whose `packages/**/src/**` it moves is graded `patch`.' check-adr-0087-registration --base origin/main exited 0 with the changeset's registered marker. check-empty-changeset exited 0. No skip-changeset (spec publishes).", "tests": "All at e38149267c unless noted. (1) @objectstack/spec `vitest run --project local`: 604 files, 17888 passed, 1 todo. Run at d7cd797549; the second merge moved nothing under packages/spec or packages/metadata-protocol, checked by git diff --stat. (2) @objectstack/spec typecheck: exit 0 (tsc --noEmit + check:scripts-typecheck + check:test-typecheck, 52 files / 246 errors held). (3) @objectstack/metadata-protocol full vitest: 205 files passed, 3 skipped, 3157 tests passed. Typecheck exit 0, and --listFiles includes protocol.runtime-authoring-gate.test.ts. (4) Targeted: protocol.runtime-authoring-gate.test.ts 62/62 (6 new: the save door refuses requires on react/full/slotted/kind-less with {code: INVALID_METADATA, status: 422}, one custom issue at `requires`, no jsx-* finding, nothing persisted; the html control saves and stamps; the load pin above). The spec conversion, migration and merge-script tests passed 632/632, and the page/exports/reconciliation/migrate-sentence suites passed 360/360. (5) The ablation is above. (6) Narrowed eslint (--no-inline-config --format json) over the 8 changed .ts files found 8 files, 0 errors, 0 warnings. Population: the config's lint targets, of which all 8 files are linted, since no ignore warning was emitted. Invariance: eslint.config.mjs enables no type-aware linting (no parserOptions.project, its own header at :326-328), so the diff cannot move a verdict on an untouched file. The full `pnpm lint` is left to CI.", "gates": [ "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at e38149267c :: 116 commands; each exit code recorded to disk before reading (ran.list)", "dispatch-gates --ran ran.list :: exit 0 :: 'Run reconciliation — 116 derived, 115 run, 1 NOT-MEASURED, 0 UNRUN.'", "NOT MEASURED: pnpm check:dual-build-cjs-loads :: exit 3 :: 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/' (needs a repo-wide build of 60+ packages); declared to CI", "pnpm --filter @objectstack/spec run check:skill-examples :: first exit 3 (PREREQUISITE NOT MET, client-react dist) -> built the closure -> exit 0 :: '✅ 259 prose examples type-check across 3 surface(s)'", "pnpm check:lean-entry-closure :: first exit 3 (objectql dist) -> built -> exit 0 :: 'Admitted set held exactly (15 packages); 6 denied names absent.'", "pnpm --filter @objectstack/spec build :: exit 0 (check-dts-emitted 38/38, check-dts-references 384/384)", "pnpm --filter @objectstack/spec check:generated :: exit 0 on the merged tree (15 artifacts; it first proved api-surface, export-origins and docs stale, and --fix regenerated exactly those 3)", "check:liveness, check:migration-registry, check:spec-changes, check:upgrade-guide, check:api-surface, check:export-origins, check:docs, check:authorable-surface, check:dual-source-exports, check:exported-any, check:variant-docs, check:empty-state, check:yaml-examples :: each exit 0", "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; check-changeset-no-major --base origin/main --event (PR body) :: exit 0; check-empty-changeset --base origin/main :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0", "pnpm check:doc-authoring :: exit 0; pnpm check:nul-bytes :: exit 0; control-byte self-scan over the 13 changed files :: no hit", "pnpm check:cross-package-test-inputs, check:engine-double-contract, check:type-check-coverage, check:type-check-debt, check:query-options-erasure, check:slot-lookup, check:merge-driver, check:page-declaration-shape, check:react-page-adapter-contract :: each exit 0", "All remaining derived commands :: exit 0 (full list with codes in ran.list)" ], "deviations": [ "PR assignee NOT set. The one budgeted `node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 21547 --assign os-tesla` was refused before it ran by the local Claude Code permission classifier ([External System Writes]). Per the os-dev contract I stopped and did not re-route through curl, MCP or any other channel. The seat owes the PR assignee (os-tesla).", "Added tests in packages/metadata-protocol (protocol.runtime-authoring-gate.test.ts: the save-door refusal and the stored-row load disposition). The claim's file surface names that package only for tests that pinned old acceptance. These are new pins proving the refusal and the D2 disposition at the public door and at the real load seam. No runtime file changed.", "Exported a second new symbol, COMPILED_PAGE_KINDS, beside checkPageRequiresKind, so the check, the conversion's coupling pin and the D3 text share one vocabulary. The conversion itself spells the refused set explicitly (full, slotted, react) to avoid an import cycle through field.zod -> conversions/registry, and a test pins it equal to the kind enum minus COMPILED_PAGE_KINDS.", "Rationale fragment order bumped 65 -> 66 at the merge, because #21531 landed first at 65.", "Not re-merged onto main's two newest commits (1ac7308d7a, 41b13331cd), which arrived after the final gate union. They share no file with this diff." ], "mcp_calls": "0 — no MCP tool used", "api_writes": "2 executed relay dispatches, plus 1 write refused before sending. (1) fleet-write request fw-20261003T052302Z-2d1305 (run 37099645599, success) = pr_create POST /repos/objectstack-ai/objectstack/pulls (draft, base main) -> #21547; the relay read back 12712 bytes sent, 12712 stored. (2) This comment = POST /repos/objectstack-ai/objectstack/issues/21459/comments via post-stamped.mjs --comment=21459. Refused, nothing sent: label-write.mjs --issue 21547 --assign os-tesla (permission classifier). git push is not a REST write: 6 branch pushes.", "open_questions": [], "out_of_scope_findings": [ "carrier: objectui's next @objectstack/spec bump (the objectui seat) · noted, not filed · objectui packages/types/src/__tests__/spec-object-refinements-7715.test.ts (pin 89cad75d55) census row 'SpecPageFields -> PageNodeSchema' lists attached: ['checkPageSourceCompleteness'] and counts PageSchema's _zod.def.checks. It is designed to go red by name when the spec adds a check, so at the next spec bump it will ask for checkPageRequiresKind to be attached to PageNodeSchema (attachable: the mirror carries kind and requires) or declared notAttachable. This qualifies the ruling's 'objectui needs no change': no runtime change is needed, but one census row is. The Console Pin Gate (build-only) is unaffected. Dedupe words: checkPageRequiresKind, PageNodeSchema census, spec-object-refinements-7715.", "carrier: a follow-up touching runtime-authoring-gate.ts · noted, not filed · findPageRequiresAbsentFromManifest's TSDoc 'Kind-agnostic on purpose' (runtime-authoring-gate.ts:610) now describes a reach only html/jsx rows can use (A6). Doc drift, not a defect, so it is not filed." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
Landed: PR #21547 →
72af58c621domain:specseat 2 (session_01YDt3PzwfrkuFzUBF89WPmM), holder of claim5965316789· 2026-10-03T06:22Zrequiresonly on the compiled kinds — refused at parse on react, full and slotted pages (#21459) #21547 went through the merge queue as72af58c621, with one parent (fd5a1cd597).Fixes #21459closed this card ascompleted.e3814926: 13 of 13 files are blob-equal.5964312254).PageSchemaacceptsrequiresonly whenkindishtmlorjsx. Onreact,full,slottedand a kind-less page it is refused atrequires, by the exportedcheckPageRequiresKind.page-requires-non-compiled-kind-removed, and load clean with one notice.page-requires-non-compiled-kind-refused.@objectstack/specminorwith the BREAKING banner, published with the next Version Packages release.5966012133, and the ACCEPT is5966106123.@objectstack/specbump that resolves a release carrying this change:packages/types/src/__tests__/spec-object-refinements-7715.test.tslistsPageSchema's attached checks by name and will ask forcheckPageRequiresKind. Attach it toPageNodeSchema, whose mirror carrieskindandrequires, or declare it not attachable. Studio's save already drops the key, so no runtime change is owed.findPageRequiresAbsentFromManifest's TSDoc ("kind-agnostic on purpose",runtime-authoring-gate.ts:610) rides the next PR that edits that file.pm:dispatchedcomes off in this act.Generated by Claude Code
feat(spec)!: page `requires` only on the compiled kinds — refused at …
fix(spec): the protocol 16 → 17 conversion summaries and three descri…
feat(spec)!: eight list members of object-grid, object-kanban and obj…