Skip to content

[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

@objectstack-fleet

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

Governing text:

  • ADR-0080 §5 [ruled]: "Store { source, compiledTree, requires } — source is truth, tree is derived cache", and "requires is 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, the requires describe (at PR fix(spec,lint): page requires is 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 page named six ADR decisions. Each is a generic match on the word requires, 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)

  1. The parse admits requires on every kind, and no refinement ties it to kind.
    • 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'].
  2. Only html / jsx are compiled at save.
    • git grep -n "COMPILED_PAGE_KINDS" origin/main -- packages/metadata-protocol/src/runtime-authoring-gate.ts → :571 new Set(['html', 'jsx']), and :634, which returns early for any other kind.
  3. No page-level requires is 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 in objectstack.config.ts, not page bodies.
  4. Studio drops the key on every page save.
    • objectui at the pinned .objectui-sha 89cad75d55: packages/app-shell/src/services/builtinComponents.tsx pageSaveBody deletes requires, registered as fromDraft for type page with no kind gate.
  5. On non-compiled kinds, the only reader is the load report, a warning with the page still served: findPageRequiresAbsentFromManifest (kind-agnostic) via reportPageRequiresAbsentAtLoad, per the measurement 5959538313.

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:spec card, filed by the seat that reads the ruling. PageSchema refuses requires unless kind is html / 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-written requires (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

  1. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #270 item 2 · letter A · maintainer 「其他issue同意」 2026-10-03T01:52Z

    Director seat, summon #32, session_016tKoy8NJa35Yih1FdzrVmn. Written as objectstack-fleet[bot] through the relay.

    • How it was ruled. Batch 🔗 Broken links detected in documentation #270 was presented in the live director chat with this card's options A and B. The director recommended A, with fallback B, and filled the card's confidence gap (below). The maintainer answered 「其他issue同意」.
    • The freshness gate: this card has no comment.

    The reading that filled the confidence gap (read this session)

    There are zero page-level hand-written requires in cloud (c5a4c9e6cb), hotcrm (5ae524916d) and objectui (8366accd13). Every requires: hit is a stack-level capability list in objectstack.config.ts, or objectui's sdui-parser computing the derived list.

    The ruling

    A: PageSchema accepts requires only when kind is html or jsx, the kinds the save door compiles. On react, full and slotted it is refused at parse, and the refusal names the key and the compiled kinds.

    • It carries a semantic retirement entry (ADR-0087) in the next unreleased step, with its reason and prescription, and a changeset with FROM/TO.
    • A stored non-compiled page carrying the key gets whatever disposition the entry prescribes.
    • The reconciliation ledger row's per-kind clause shrinks to the compiled kinds. objectui needs no change, because Studio already drops the key.

    Not taken: B. It keeps admitting a key nothing derives on three of five kinds, and Studio silently drops it.

    四棱(本裁决新记录)

    • ① 长远:requires 回到 ADR-0080 的本义——编译型页面由平台从源码推导的依赖清单,作者永不手写。
    • ② 拉动:零(四仓页面级手写 0 处)。
    • ③ 防 AI:写错得到响亮拒收,而不是被接受后静默删除。
    • ④ 不扩散:删掉一个零消费的声明面。
    • 只看①选 A;②③④ 是否翻转:否。

    Execution parameters

    This card: needs-user-decision → pm:queue in this act, domain:spec, and graded priority:p3 here (zero pull). The card carries its own execution: no second card.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01YDt3PzwfrkuFzUBF89WPmM
    Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-21459-page-requires-compiled-kinds
    Worktree: objectstack-issue-21459
    Domain: domain:spec
    Seat: domain:spec#2
    File surface (at origin/main ad7c351898), per the ruling record 5964312254 (A, 「其他issue同意」):

    • packages/spec/src/ui/page.zod.ts, PageSchema: requires is accepted only when kind is html or jsx, the kinds the save door compiles. On react, full and slotted it is refused at parse, and the refusal names the key and the compiled kinds. The requires describe is narrowed with it.
    • The retirement kit (ADR-0087): a semantic entry in the next unreleased step, with its reason and prescription, and the stored-row disposition that entry prescribes for a stored non-compiled page carrying the key. A D2 conversion is added only if that disposition is a mechanical drop. The regenerated migrations/registry.ts regions and the step's rationale fragment, the generated artifacts, and one changeset with FROM/TO.
    • The reconciliation ledger row for page requires, landed by PR fix(spec,lint): page requires is live — refused at save, reported at load #21451: its per-kind clause shrinks to the compiled kinds.
    • Pins: the refusal on each of the three non-compiled kinds, by name and path; html and jsx still accepted, with the save door's compile path unchanged; a page with no requires unchanged on every kind.
    • ⛔ No objectui edit (the ruling: Studio already drops the key). ⛔ No change to the save door (metadata-protocol runtime-authoring-gate.ts) or the load report, beyond tests that pinned the old acceptance.
    • Stop on breach and explain in the report.

    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling CONTRACT_REVIEW_TIER). A narrowing of packages/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 to migrations/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 from main and merges main again after PR #21531 lands, before opening the PR. #20234's stage 11 (seat 5, the hand-written parts of migrations/registry.ts) has no open PR at 2026-10-03T03:58Z; whichever lands second merges main. 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 is Fixes #21459.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  4. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21547 → 72af58c621

    domain:spec seat 2 (session_01YDt3PzwfrkuFzUBF89WPmM), holder of claim 5965316789 · 2026-10-03T06:22Z

    • Landed: PR feat(spec)!: page requires only on the compiled kinds — refused at parse on react, full and slotted pages (#21459) #21547 went through the merge queue as 72af58c621, with one parent (fd5a1cd597). Fixes #21459 closed this card as completed.
    • Blob check against the ACCEPTed head e3814926: 13 of 13 files are blob-equal.
    • Delivered: ruling A (5964312254).
      • PageSchema accepts requires only when kind is html or jsx. On react, full, slotted and a kind-less page it is refused at requires, by the exported checkPageRequiresKind.
      • Stored rows on those kinds lose the key through the D2 conversion page-requires-non-compiled-kind-removed, and load clean with one notice.
      • The D3 entry is page-requires-non-compiled-kind-refused.
      • Release: @objectstack/spec minor with the BREAKING banner, published with the next Version Packages release.
      • The review is 5966012133, and the ACCEPT is 5966106123.
    • For objectui, at the @objectstack/spec bump that resolves a release carrying this change: packages/types/src/__tests__/spec-object-refinements-7715.test.ts lists PageSchema's attached checks by name and will ask for checkPageRequiresKind. Attach it to PageNodeSchema, whose mirror carries kind and requires, or declare it not attachable. Studio's save already drops the key, so no runtime change is owed.
    • Carried: findPageRequiresAbsentFromManifest's TSDoc ("kind-agnostic on purpose", runtime-authoring-gate.ts:610) rides the next PR that edits that file.
    • pm:dispatched comes off in this act.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions