Skip to content

feat(spec): one override declaration for code and Studio, with the .custom pairing helpers and the closed overridable-type list (ADR-0146) - #28467

Merged
objectstack-fleet[bot] merged 18 commits into
mainfrom
claude/issue-28404-override-declaration
Oct 31, 2026
Merged

objectstack-fleet[bot] merged 18 commits into
mainfrom
claude/issue-28404-override-declaration

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

🤖 Generated with Claude Code

https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V

Fixes #28404

Clause-②: yes (widening)
Metadata-protocol: added

维护者速读

  • 改了什么:spec 里新增「覆盖声明」overrides: { package, basedOn },加在 13 种可覆盖的元数据上;另加 .custom 配对包的命名、命名空间、依赖范围规则,可覆盖类型的封闭清单,__c 扩展字段后缀和基础字段可改的显示属性白名单。
  • 为什么改:开发者在仓库里写 hotcrm.custom,管理员在 Studio 里定制,两边要写出同一份声明,后面的写入关、读取、导出和 os validate 才能读同一样东西,不会各自拼一套「这一项覆盖了 HotCRM 的哪一项」。
  • 风险与回滚:只是新增可选字段、常量和纯函数,没有任何入口开始按它放行或拒绝;现有元数据不受影响。回滚就是 revert 本 PR。
  • 先看:① packages/spec/src/kernel/customization-package.ts 的 OVERRIDE_TYPE_CLASSIFICATION(哪些类型能覆盖,有 4 个待您定);② customizationNamespace(基础命名空间超过 13 个字符就没有配对命名空间);③ packages/spec/src/data/field-customization.ts 的白名单。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run src/kernel/override-declaration.test.ts src/kernel/customization-package.test.ts src/data/field-customization.test.ts,预期三个文件全绿。
  • 需要你做的:无。下面 "For the maintainer" 的 7 条您已同意(2026-10-31 20:44Z「同意」);契约复审 PASS、CI 全绿后由席位落地。

For the maintainer

ADR-0146 does not decide these. Ruled 2026-10-31 20:44Z: the maintainer agreed to all seven as built (「同意」), together with the follow-ups recorded after the list:

  1. Namespace past 13 characters. customizationNamespace(baseNs) answers <base_ns>_custom; a base namespace longer than 13 characters gets no pair namespace ({ ok: false, reason: 'base_namespace_too_long' }) and the ensure door will refuse that base with a sentence. No truncation, no hashing. Nothing in the repository is affected today (the longest base namespace is feature_flags, 13).
  2. seed — runtime-creatable and shipped by packages, so D2's first sentence admits it, but ADR-0126 §3 puts it outside ("one-shot"). Classified excluded, basis adr_0126_one_shot (ruled).
  3. datasource — the same reading (ADR-0126 §3: "origin-gated"); D2 names it on neither side. Classified excluded, basis setup_owned_connection (ADR-0146 D1 gives datasources to Setup; ADR-0126 §3 origin-gated; ruled). The card's census listed four undecided types and missed this one: its registry entry is the only multi-line entry, which a line-wise reading cannot see (the registry's own comment warns about this).
  4. tool and skill — behavioural (ADR-0126 §3 pre-charts them for Regime C), with no ledger switch and no D9-style conditions written for them. Classified excluded, basis behavioural_switch_first: action's path, the ledger switch first and an override door later (ruled).
  5. external_catalog — decided by D2's first sentence (packages never ship one), classified excluded, basis not_package_shipped. Listed so you can confirm the reading.
  6. Prerelease base versions. customizationDependencyRange('2.0.0-beta.1') answers ^2 (the major of the numeric core, the ADR's words read literally). The ADR-0141 D2 install check cannot read a prerelease installed version, so a pair whose base sits at a prerelease is re-installable once the base reaches a release of that major.
  7. basedOn is required inside the block. The ADR's shape names both keys; the PR requires both to be non-empty strings when overrides is present.

Follow-ups the ruling also agreed:

What changes

  • overrides: { package, basedOn } (packages/spec/src/kernel/override-declaration.zod.ts, OverrideDeclarationFields): one closed field set, spread on the 13 types OVERRIDE_TYPE_CLASSIFICATION classifies overridable: view (the ViewItem record and the flattened overlay; not the defineView container, see the acceptance notes), dashboard, report, translation (the item), email_template, page, app, dataset, doc, book, mapping, flow, action. It is a separate spread, not part of MetadataProtectionFields: that envelope is spread into excluded types and is what registration and clone strip as loader-stamped state. package refuses a .custom id. basedOn's .describe() says it is recorded and never judged.
  • Pairing helpers (packages/spec/src/kernel/customization-package.ts): CUSTOMIZATION_PACKAGE_SUFFIX, customizationPackageId, customizationBasePackageId, isCustomizationPackage, isCustomizationPairOf (ruling A: only the paired <base>.custom declares), customizationNamespace, customizationDependencyRange. Each derivation answers { ok: true, value } or { ok: false, reason }. Dotted ids are covered. The namespace answer is judged against ManifestSchema.shape.namespace and the id against MANIFEST_ID_PATTERN, so the helpers restate neither grammar.
  • The closed type list: OVERRIDE_TYPE_CLASSIFICATION is total over MetadataType at compile time and pinned to DEFAULT_METADATA_TYPE_REGISTRY in both directions by a test. object is extend_only; permission, position, capability are excluded (D6); the code-only types are excluded; flow and action carry their D9 conditions as data. OVERRIDABLE_METADATA_TYPES, getOverrideTypeClassification, isOverridableMetadataType read it.
  • __c and the display whitelist (packages/spec/src/data/field-customization.ts): EXTENSION_FIELD_SUFFIX, isExtensionFieldName, BASE_FIELD_DISPLAY_WHITELIST = field label, description, inlineHelpText, placeholder, and option label, each measured against D10's test. Only the class D10 names; other display-only keys may pass the same test and enter by decision.
  • The per-field patch slot on ObjectExtensionSchema rides N-23a. A slot that the merge (mergeObjectDefinitions) does not apply would be an authorable key that nothing reads, so it lands together with that merge.
  • Liveness rows (planned) for overrides on the 12 ledgers that walk it, and the count shards; the llms.txt schema counts (kernel 31, total 213); regenerated spec artefacts.
  • The served /meta/types property counts in packages/metadata-protocol/src/protocol.meta-types-degenerate-derivation.test.ts move by one on the seven overridable types that suite pins (action, app, dashboard, dataset, flow, page, report); the excluded types keep theirs (seat commit e55a4e7c6b, after Test Core (7/8) went red on e0253ce45c).
  • Ledger rows in two existing pins the key reaches: a root omit row for overrides on the eight types with a hand-written metadata form (metadata-form-zod-reconciliation.test.ts; Studio writes the declaration on a customization, so no hand-filled control is offered while it is planned), and a noReader row for flow.overrides in the flows translation face.

Tests

  • packages/spec/src/kernel/override-declaration.test.ts: the shape accepts and refuses (missing, empty, unknown key, .custom package); every overridable type keeps overrides through its metadata schema (the save door's parse) and refuses a malformed block; the excluded types with a create seed refuse the key by name; defineStack() (strict) keeps it on all 11 item collections; the export's viewItems: channel keeps it for a ViewItem and an overlay.
  • packages/spec/src/kernel/customization-package.test.ts: table tests for the id helpers (dotted ids, a pair of a pair, a dependent package that is not the pair), the namespace (13 and 14 characters, pinned against the grammar), the range, and the type list pinned to the registry.
  • packages/spec/src/data/field-customization.test.ts: every whitelist member exists on FieldSchema (or its option schema) and takes text; none is in the structural list, and every structural key named is a real FieldSchema key.
  • packages/runtime/src/domains/packages-export-override-declaration.test.ts: GET /packages/<base>.custom/export carries overrides on a flow and a view item and strips provenance; both re-parse with the block intact.
  • Full @objectstack/spec suite on e0253ce45c: 865 files passed, 24491 tests passed, 1 todo. An earlier run named three existing pins the key reaches (the form reconciliation, the flows translation face, the description renderer's level-1 count); they are recorded in their ledgers above and the module header opens at level 2.
  • Reverse check: with the spread removed from flow.zod.ts, the strict defineStack() in the first file refuses overrides on flows.0 and the file goes red; restored from HEAD.

Acceptance notes

  • view via defineStack() and translation via the stack. The stack authors views as defineView containers (views:) and translations as locale bundles (translations:); both are aggregates that are expanded or merged into items at load. The declaration is on the item shapes the view and translation metadata types parse, so it survives the metadata save and the export, but a repository author cannot write it through those two stack collections today. Whether a container-level declaration fans out to its expanded items is a loader decision for the read and Studio cards, not taken here.
  • The export skips emailTemplates (assemblePackageManifest excludes it with datasources), so an overriding email template in .custom does not travel through GET /packages/:id/export today. Pre-existing; the effective-read card carries it.
  • The app schema now carries the landing refinement from main (feat(spec): an app can name a landing per audience with landing #28449); the override spread sits inside it, resolved in the merge.
  • No view liveness row: the view ledger governs the defineView container (ViewSchema), which does not carry the key.

Verification

Independent review: none run (quota); the PR waits for the seat's contract-review hand-off.

Gates (head e0253ce45c): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 112 commands. All 112 ran in one pass and exited 0, each exit code recorded before any pipe. --ran reconciliation: 112 derived, 112 run, 0 not measured, 0 unrun. The full farm is CI's.

Also run:

  • pnpm --filter @objectstack/spec check:generated: all 14 artefacts current after regeneration on each merge.
  • pnpm --filter @objectstack/spec typecheck: exit 0.
  • pnpm --filter @objectstack/runtime typecheck: exit 0.
  • The runtime export test: 3 of 3 passed, on 0f9936f445. The later merge brought only the app landing, components and docs.

Earlier passes found two real fixes, both in this PR: the llms.txt schema counts, and the three ledger pins. Gates that refused with exit 3 because a prerequisite build was missing were re-run after the build and are not counted as passes.


Generated by Claude Code

claude added 13 commits October 31, 2026 14:56
…e overridable-type list, the __c reservation and the display whitelist

ADR-0146 D2, D3, D6, D9, D10: one Zod field set overrides { package, basedOn }
spread on the thirteen overridable types; the pair's id, namespace and
dependency-range helpers; the closed classification of every registry type;
the __c suffix and the base-field display-property whitelist.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…n, not a refinement

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…the new tests

Regenerated skill references, api-surface, export-origins, declaration-map,
reference docs, the strictness-ledger counts and the authorable surface for
the override declaration and the pairing helpers. The two new test files now
pass the test typecheck without a debt entry.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
The merged tree's reference docs and authorable surface are regenerated in
this commit (the merge took them without a text merge).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
The kernel domain now holds 31 schema modules and the package 213.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
… ledgers

The full spec suite named three pins the new key reaches:

- the metadata form reconciliation: `overrides` is accepted by eight schemas
  whose hand-written forms do not offer it. Each gets a root ledger row: the
  declaration is `planned` and Studio writes it on a customization, so a
  hand-filled control is not how it is authored.
- the flows translation face: `flow.overrides` is a base package id and a
  version, never drawn for a person running the flow.
- the description renderer's count of level-1 module openers: the new
  module's header now opens at level 2, so the count stands.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
Takes the sibling spec cards that landed since the last merge; the generated
artefacts are regenerated from the merged tree in the next commit.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
Takes the sibling spec cards that landed since the last merge (resolving
the app schema: the override spread now sits inside the landing refinement);
the generated
artefacts are regenerated from the merged tree in the next commit.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 84 documentable anchor(s). ⚠️ 39 changed file(s) yielded no anchor (packages/spec/api-surface/data.json, packages/spec/api-surface/kernel.json, packages/spec/authorable-surface/api.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

22 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 5e706e7a9e938925de326ed52b6d65475f43d095.

⛔ 10 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 39 changed file(s) yielded no anchor (packages/spec/api-surface/data.json, packages/spec/api-surface/kernel.json, packages/spec/authorable-surface/api.json, …) — pages documenting those are invisible to this run
  • 34 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 212 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5e706e7a9e938925de326ed52b6d65475f43d095 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from bfbecfe77b5507f481e0fbe0095956fca7b57e52 — the merge of head 743ac88b6ce187f37978cf549c3b63288a31d7b5 into base 5e706e7a9e938925de326ed52b6d65475f43d095, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin bfbecfe77b5507f481e0fbe0095956fca7b57e52 && git checkout bfbecfe77b5507f481e0fbe0095956fca7b57e52
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5e706e7a9e938925de326ed52b6d65475f43d095 743ac88b6ce187f37978cf549c3b63288a31d7b5 && git checkout -B drift-repro 5e706e7a9e938925de326ed52b6d65475f43d095 && git merge --no-ff 743ac88b6ce187f37978cf549c3b63288a31d7b5

node scripts/docs-audit/affected-docs.mjs --json 5e706e7a9e938925de326ed52b6d65475f43d095

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5e706e7a9e938925de326ed52b6d65475f43d095 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

维护者速读(席位终稿 · head e0253ce4)

  • 改了什么: 规格里有了统一的“覆盖声明” overrides: { package, basedOn },13 种元数据(视图、仪表盘、报表、页面、应用、流程、动作等)可以带上它,意思是“这一项整体替换 HotCRM 的同名项”。另外定下了配对定制包的规则:hotcrm 的定制包叫 hotcrm.custom,命名空间 hotcrm_custom,依赖 ^主版本;哪些类型能覆盖是一张封闭清单;扩展字段用 __c 结尾;基础字段只允许改标签、说明、帮助文字、占位符和选项标签这几项显示属性。
  • 为什么改: 开发者在仓库里写的 hotcrm.custom 和管理员在 Studio 里做的定制,要落成同一份声明,后面的写入关、读取、导出和卸载才会读同一个东西。
  • 风险与回滚: 只加可选字段、常量和纯函数,还没有任何入口按它放行或拒绝,现有元数据不受影响。回退本 PR 即可。
  • 先看: packages/spec/src/kernel/customization-package.ts(类型清单和命名空间规则)、packages/spec/src/data/field-customization.ts(显示属性白名单)。
  • 两分钟验证: pnpm --filter @objectstack/spec exec vitest run src/kernel/override-declaration.test.ts src/kernel/customization-package.test.ts src/data/field-customization.test.ts,三个文件全绿。
  • 需要你做的: 确认 PR 正文 "For the maintainer" 的 7 条(主要是:基础命名空间超过 13 个字符时不给定制包;seed、datasource、tool、skill 暂不允许覆盖)。确认之前不落地。

席位意见: ACCEPT(车道部分)。7 条都选了可以以后放宽的一侧:超长命名空间直接拒绝而不截断,4 个没定的类型先不允许覆盖。以后改成允许不会破坏已存的数据,反过来就会。

席位核对 · ACCEPT (lane part) · card #28404 (epic #28236 N-08) · 2026-10-31T20:25Z

  1. 形态: 88 files, +1912 / −21 at head e0253ce45c, draft, Fixes #28404, Clause-②: yes (widening) / Metadata-protocol: added, changeset .changeset/28404-override-declaration.md (@objectstack/spec minor). check-governed-merges.mjs --pr 28467: NOT governed (the two skills/**/references/_index.md hits are pure regenerations, lifted). Tier S.
  2. 前提实测: holds. The seat read override-declaration.zod.ts (a leaf module importing only zod and strictObject, to avoid the manifest/app schema cycle), customizationNamespace (missing → base_namespace_missing; over MAX_CUSTOMIZATION_BASE_NAMESPACE_LENGTH = 13 → base_namespace_too_long; the pair judged against ManifestSchema.shape.namespace, so no grammar is restated), the range table (^<major> of the numeric core; 0.x → ^0) and OVERRIDE_TYPE_CLASSIFICATION (one table, total over MetadataType, pinned both ways to DEFAULT_METADATA_TYPE_REGISTRY). overrides is a separate spread, not part of MetadataProtectionFields, so excluded types do not gain it and registration/clone do not strip it as loader state.
  3. 门禁 check-runs: on e0253ce45c CI is running (13 success, 7 skipped, 22 in progress at 2026-10-31T20:25Z); the seat re-reads every check before any landing stroke. Dev: dispatch-gates --commands 112 derived, 112 run, all exit 0; --ran 112 of 112. Full spec suite 865 files / 24491 tests; spec and runtime typecheck 0; runtime export test 3/3. Two gate reds fixed in the branch (check:llms-txt counts; three existing pins given ledger rows). A reverse check (spread removed from flow.zod.ts) turns the strict defineStack() test red. os-dev-report 6548679183.
  4. 接受的偏差:
    • The file surface grew past the claim: 12 liveness ledgers (planned rows), llms.txt, two existing spec ledgers (metadata-form-zod-reconciliation, flows-translation-face) and a new runtime test. Each one was forced by a gate or a pin.
    • The per-field patch slot on ObjectExtensionSchema rides N-23a, as the order allowed: a slot the merge does not read would be an authorable key that nothing reads.
    • view and translation carry the key on their item shapes only: the defineView containers and locale bundles in defineStack() cannot carry it. Whether a container-level declaration fans out is a loader decision for the read and Studio cards.
    • basedOn required inside the block (both keys non-empty). This is maintainer item 7.
  5. 范围外去向: the export skips emailTemplates (pre-existing, before this PR) → the effective-read card N-10; cloning an overriding .custom flow copies overrides → N-21; container fan-out → the read and Studio children of [Epic] Package-level override: every customization of an installed package lives in its paired <base>.custom package, one declared override shared by code and Studio (supersedes #28130) #28236. All are carried by existing epic children, so no new card is filed. Skills-docs: none owed yet: no door reads the declaration, so the skill lands with the write gate and read doors.
  6. 落地条款: Tier S path. Owed before any landing stroke: the maintainer's confirmation of the 7 "For the maintainer" items (a changed answer means a new head and a delta review); green CI on the landing head; a same-shape CONTRACT_REVIEW_TIER PASS (packages/spec/src/** non-test). This seat cannot serve that tier now and hands the review over below.

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head e0253ce
Thread-read: none

…property pins

The override declaration adds one top-level property to `action`, `app`,
`dashboard`, `dataset`, `flow`, `page` and `report`; the degenerate-derivation
suite pins each served count, so each moves by one and the `action` sample
names the new key. The excluded types keep their counts.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Head moved by a seat test fix · 2026-10-31T20:44Z · e0253ce45c42f6688e112e25a7eed70b16de77c7 → e55a4e7c6bfc8691a20fa79031d88d083e14c2d4

Test Core (7/8) was red on e0253ce4. The cause was @objectstack/metadata-protocol#test, in src/protocol.meta-types-degenerate-derivation.test.ts, which pins each served /meta/types top-level property count. overrides adds one property to each overridable type in that table: action 50 → 51, app 23 → 24, dashboard 20 → 21, dataset 16 → 17, flow 22 → 23, page 26 → 27, report 23 → 24. The excluded types (agent, field, hook, object, position, skill, tool) keep their counts, which also confirms that the separate spread did not leak. The action live sample now names overrides.

The fix is one test file, with one dated comment on each pin. Seat-local: that file 18/18 (7 red before the fix). The dev's gate battery did not derive this package's suite, so CI is the first run of it. No other check was red on e0253ce4.

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head e55a4e7 · supersedes the hand-off on e0253ce (no review was claimed on it)
Thread-read: none

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-claim: session_01L9qibw58ehQ2gRHP2h2Puz · head e0253ce45c42f6688e112e25a7eed70b16de77c7 · 2026-10-31T20:47Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-hold: session_01L9qibw58ehQ2gRHP2h2Puz · head e0253ce · Test Core 7/8 red: seven /meta/types count pins in metadata-protocol are one short of the new key · until a green head

Claim 6548930392 stands; no record on this head (a PASS is never written on a red head). Read in full at 2026-10-31T20:50Z: card #28404 (claim 6544804569, dev report 6548679183), the seat hand-off 6548702768, the PR body, the diff (88 files, +1912/−21 against merge-base 80a9f99, merge-tree clean; every hand-written spec hunk, tests by case, generated files by count), ADR-0146 D2 / D3 / D6 / D9 / D10 and its "Decided here" list on origin/main, the cited main symbols (MANIFEST_ID_PATTERN L360, the manifest namespace grammar L564 {1,19} = 20 chars so 13 + _custom is the limit, SEMVER_2_0_0_VERSION_PATTERN L97 group 1 = major, Object.keys(MetadataProtectionFields) at the registration and clone strip sites), check-runs: 50 latest-per-name, 37 success + 11 skipped, 2 failed (Test Core, Test Core 7/8).

  • The red: @objectstack/metadata-protocol pnpm run test exited 1 (job 124647708200): src/protocol.meta-types-degenerate-derivation.test.ts L262 (action top-level count 50, served 51) and L376 (the control table: app 23 → 24, report 23 → 24, dashboard 20 → 21, dataset 16 → 17, flow 22 → 23, page 26 → 27). Each is the new overrides key reaching /meta/types. The pins are stale, not the shape: add one to each of the seven and a [#28404] n → n+1: overrides note in the style of the [#28022] line above the table. metadata-protocol is outside the PR's own suite list (spec full, spec + runtime typecheck); a new spec key reaches that package's count pins on every such card.
  • Contract content reads clean on this head, to be recorded on the next green one: overrides: { package, basedOn } is a closed shape (aliases named, package refuses a .custom id by a published pattern, basedOn min(1) and described as recorded, never judged), spread as OverrideDeclarationFields on exactly the thirteen D2 types (view item + flattened overlay, dashboard, report, translation item, email_template, page, app, dataset, doc, book, mapping, flow, action) and kept apart from MetadataProtectionFields so the registration and clone strips never drop it; the pairing helpers answer discriminated results and judge the namespace against ManifestSchema.shape.namespace and the id against MANIFEST_ID_PATTERN (no restated grammar); OVERRIDE_TYPE_CLASSIFICATION is total over MetadataType (satisfies) and pinned to the registry both ways, with D6 (permission, position, capability), D10 (object extend-only), the code-only types and the D9 conditions as the ADR words them (flow: four; action: the ledger switch plus 1–3); BASE_FIELD_DISPLAY_WHITELIST is the class D10 names (label, description, inlineHelpText, placeholder, option label), each measured against FieldSchema by test. Declarations Clause-②: yes (widening) + Metadata-protocol: added, @objectstack/spec minor: right for an optional new key and new exports.
  • The seven "For the maintainer" items are each the reversible side (no pair namespace past 13 characters rather than a truncation; seed, datasource, tool, skill excluded as undecided; external_catalog not_package_shipped; ^<major> of the numeric core for a prerelease; both keys required inside the block). None is a contract defect; the seat made their confirmation a landing condition, and a changed answer is a new head and a delta.
  • Tier: skills/** is touched only by four one-line references/_index.md regenerations. CI's Governed Surface Queue Guard is green on this head, and the seat's check-governed-merges run read the paths lifted; in this container the generator's own --check exited 254 (no build), so the lane did not reproduce the lift and reads the guard's verdict instead. If a human reads them as governed, os-zhuang or hotlong Approve is owed; otherwise Tier S.

Owner: domain:spec#4 (marchtian, session_017ihL2fi9zfJhUTubyJYb6V, another project: this note is the signal). On the next head the lane re-claims and records the delta.

…ation and `basedOn`

The maintainer agreed the seven open points on #28404. Two wording changes
follow from that ruling:

- `OVERRIDE_TYPE_CLASSIFICATION`: `seed`, `datasource`, `tool` and `skill`
  stay `excluded`, but on a decided basis instead of `undecided`.
  `adr_0126_one_shot` (seed), `setup_owned_connection` (datasource: ADR-0146
  D1 plus ADR-0126 §3 origin-gated) and `behavioural_switch_first` (tool,
  skill: action's path). The `undecided` basis is gone, and a test pins that
  no row carries it.
- `overrides.basedOn` records the base package's `manifest.version` the
  override was taken from, not a history version of the item. It is still
  recorded and never judged.

Reference pages regenerated.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract review (delta)

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 743ac88b6ce187f37978cf549c3b63288a31d7b5
Local-runs: none
Scope: the delta from the reviewed head d548ee9c (PASS (delta) 6549858395) to 743ac88b, one merge commit of origin/main after the queue dequeued the PR on #28446's landing (seat hand-off 6550043450; claim 6550135975). Tier unchanged: the four skills/*/references/_index.md lines are byte-identical to the reviewed head; no docs/adr/** file in the PR.
Inputs: git log d548ee9c..743ac88b (main's #28465, #28446, #28474 and the merge), the PR-only interdiff (this PR's diff against its own merge-base before 9b1dc992 and after 5e706e7a, hunk headers ignored: content/docs/references/index.mdx schema count 1577 → 1578 in the description and the Total row, plus the Integration row's 22 → 23 context line that #28446 added and this PR does not touch; nothing else of the PR's own change moved), merge-tree against origin/main clean, check-runs (read 2026-10-31T23:06Z: all 50 latest-per-name check-runs completed, 39 success + 11 skipped, none failed, none running) — 50 checks.

Delta judgment

Implemented-by: claude/issue-28404-override-declaration
Reviewed-by: triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

VERDICT: PASS (delta)

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Landing stroke (re-arm after the 22:28Z MERGE_CONFLICT dequeue) · 2026-10-31T23:07Z · head 743ac88b6ce187f37978cf549c3b63288a31d7b5.

  • Contract review: PASS 6549440881 (862035aa), delta PASS 6549858395 (d548ee9c) and delta PASS 6550365351 on this head. Each delta is a merge of main only. No must-fix was raised.
  • Maintainer: 田騏 agreed to the seven ruled points (6549129352). In this project's thread at 2026-10-31 22:41Z they also wrote 「28467 我批准了,契约复审通过就可以合并了」, and os-zhuang APPROVED the PR (5725295353).
  • Checks on this head: 55 completed, 42 success, 13 skipped, 0 failed. check-expected-skips.mjs --pr 28467 is OK. mergeable_state is clean. needs:contract-review comes off.
  • The seat re-arms auto-merge.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

⛔ The scheduled full run is red after this PR landed: p0 #28491 · 2026-11-01T00:54Z

This PR's landing ba0084e4 added overrides to ActionSchema. ui/packages/core/src/actions/__tests__/actionKeys.pin.test.ts:140 now reads missing: ['overrides']. The ui shards did not run on this PR's diff (the #28220 gap), so main pushes read green while every ui-touching queue group fails it.

Landing seat (domain:spec#4) or domain:ui: claim #28491 this round. The stop-bleed is one inventory entry for overrides in ui/packages/core/src/actions/actionKeys.ts.


Generated by Claude Code

This was referenced Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants