Skip to content

feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription - #29499

Merged
objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/project-thread-ejw6q8
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/project-thread-ejw6q8

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread

Fixes #29007

Clause-②: no (narrowing)
Metadata-protocol: narrowed

维护者速读

  1. 对象定义里再写 titleFormat,保存、发布、恢复和 os validate 都会直接拒绝,并提示改用 nameField。
  2. 已存的旧对象照常读取和展示,不做任何数据转换;只有下次保存时才会被要求改掉。
  3. 记录标题的取法不变:先看 nameField,没有就按原规则推导,titleFormat 一直没生效,现在只是不再假装接受。
  4. 平台自带的 68 个系统对象已去掉 titleFormat;其中 3 个补上了本来就在用的标题字段,用户看到的标题不变。
  5. 这是破坏性变更(BREAKING),升级指南已登记迁移说明,dogfood 全量回归已跑。
  6. 草稿保存仍会落库但标记为无效、无法发布;是否连草稿也拒绝,留作待定问题。

What changes

Ruling of record 6574393684, letter B: titleFormat is refused, not deleted and not honoured.

  • One judge at every door. title-format-retired moves out of the advisory validateRecordTitle into a new gating registry rule, validateTitleFormatRetired (packages/lint/src/validate-record-title.ts, registered in authoring-rules.ts with surfaces: CLI_AND_RUNTIME, runtimeTypes: ['object']). The registry is what os validate, os build, os lint and the runtime publish gate already run, so the CLI and the metadata save gate (422 INVALID_METADATA on an active save, a draft promotion and a restore) refuse with the same finding. The message and the fix line are byte-identical to the existing prescription; no new wording. validateRecordTitle now reports title-unresolvable only.
  • Schema. object.zod.ts: the titleFormat describe gains one sentence (refused at the metadata save gate and by os validate; a stored object that carries it still parses and reads). The key stays in the schema; no conversion drops it; provisionPrimary, console ordering and ADR-0079 D3/D9 are untouched.
  • ADR-0087. New D3 semantic entry object-title-format-refused (packages/spec/src/migrations/entries/semantic/18.object-title-format-refused.ts) with the replacement, reason and acceptance criteria; the changeset registers it.
  • Every code-shipped hit moves to nameField. 68 system objects across platform-objects, plugin-approvals, plugin-audit, plugin-security, plugin-sharing, plugin-webhooks, service-automation, service-mailbox, service-messaging, service-realtime and service-storage drop titleFormat. 65 already declared the nameField that titles them. sys_attachment (file_name), sys_audience_binding_suggestion (permission_set_name) and sys_notification_template (subject) now declare the field the registry already stamped, so every record title reads as before. Comments that described the template were rewritten in place. No example or template in the repo declared it.
  • Docs. data-modeling/objects.mdx, schema-design.mdx, frontend/building-crud-app.mdx, docs/notes/crm-development-standards.mdx; references regenerated; four CLI transcripts now print "author-time rules (62)" (deployment/cli.mdx, deployment/validating-metadata.mdx, getting-started/build-with-claude-code.mdx, ui/react-pages.mdx).
  • Liveness. packages/spec/liveness/sharing_rule.json: the name note no longer cites titleFormat; the label evidence now cites the list view columns and sort keys.

Forced test edits

These tests read X.titleFormat from the shipped object to prove a formula matched the old template. The template no longer ships, so each file now keeps the retired template text in a local RETIRED_TITLE_TEMPLATES map and reads RETIRED_TITLE_TEMPLATES[X.name]; the assertions are otherwise unchanged:

  • packages/platform-objects/src/identity/identity-display-title.test.ts
  • packages/plugins/plugin-approvals/src/sys-approval-delegation-display-title.test.ts
  • packages/plugins/plugin-approvals/src/sys-approval-display-title.test.ts (one comment adjusted)
  • packages/plugins/plugin-security/src/objects/sys-security-assignment-display-title.test.ts
  • packages/services/service-automation/src/sys-automation-run-display-title.test.ts
  • packages/services/service-messaging/src/objects/http-delivery-display-title.test.ts
  • packages/services/service-messaging/src/objects/notification-display-title.test.ts
  • packages/services/service-realtime/src/objects/sys-presence-display-title.test.ts

packages/plugins/plugin-approvals/src/sys-approval-request-title.integration.test.ts asserted the shipped template; it now asserts titleFormat is undefined on the shipped object (test renamed accordingly).

Tests

  • packages/lint/src/validate-record-title.test.ts: the refusal is an error with the prescription, the envelope and controls; the explain text names the save gate and os validate.
  • packages/lint/src/runtime-gate.object-writes.test.ts: the rule is on the object door roster; an object carrying titleFormat is refused; re-saving a stored row that carries it is refused, and the healed row saves.
  • packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts: a title-format-retired case in the publish verdict table; a stored object carrying titleFormat still loads, its next save is refused 422 with the prescription, and the nameField control saves.
  • packages/cli/test/validate-title-format-retired.test.ts (new, integration): os validate --json exits 1 with title-format-retired and "migrate to nameField"; the nameField control exits 0.
  • packages/platform-objects/src/managed-api-method-affordance-sweep.test.ts: a repo-wide pin that no code-shipped object declares titleFormat, with a red fixture and a control.

Acceptance notes

  • Draft saves. Per the publish-gate contract ([runtime/metadata] 作者时规则只存在于 CLI:Studio/REST/MCP 的运行时授权面是第四扇门,26 条规则一条不跑——#4409 修完后最大的敞口 #4463 D1) a draft save is not gated: it still stores, its _diagnostics reads valid: false with this refusal, and its promotion is refused. The ruling names the save gate; I read that as the gate that already exists. Refusing drafts too would be a gate-wide change, so it is left as an open question.
  • Out of scope (governed). skills/objectstack-data/SKILL.md still calls titleFormat "Deprecated, not removed". It is a governed path, so this PR leaves it for a follow-up.
  • Still-parsed readers kept. The metadata-core FLS contract fixture and the ui renderers still read the key; the ruling keeps it parseable, so they stay.
  • Title text. Dropping a template changes only the blank-pointer fallback text on objects whose nameField value is empty; main-path titles are unchanged (measured per object).

Verification

Round 2 (head 98601175, main merged through os-regen-merge.sh). Contract review FAIL fixes: the declaration line is now Metadata-protocol: narrowed (a refused value is narrowed), and the four CLI transcripts print 62, the count check:docs-transcript-drift derives on the merged tree (#29424 landed one more rule on main). References were regenerated from the merged tree. On this head: lint, spec, platform-objects, plugin-security, service-automation, metadata-protocol and cli suites green (cli 6879 passed / 9 skipped); typecheck green for cli, lint and metadata-protocol; check:generated green; dogfood battery green (397 files passed / 3 skipped; 3277 tests passed / 28 skipped; lock VERDICT command-exit 0); dispatch-gates --ran 113 derived / 113 run / 0 NOT-MEASURED / 0 red; check-changeset-no-major --event and check-adr-0087-registration exit 0.

Round 1 readings, on head 0885931864, under os-verify-lock (slot card-29007).

  • Package suites. These were all green: lint 7834, spec 23451 (1 todo), platform-objects 1505, plugin-approvals 1381, plugin-audit, plugin-security, plugin-sharing, plugin-webhooks, service-automation, service-mailbox, service-messaging, service-realtime, service-storage, metadata-protocol and cli (6871 passed, 9 skipped, unit and integration).
  • Dogfood battery (pnpm --filter @objectstack/dogfood test): 393 files passed and 3 skipped; 3243 tests passed and 28 skipped.
  • Typecheck. run typecheck passed for all 15 touched packages, including the test layers. The cli test layer ran out of memory at the default node heap; with the CI heap (--max-old-space-size=4136) it passed.
  • Derived gates. dispatch-gates --ran reports 113 derived, 113 run, 0 NOT-MEASURED and 0 red.
    • The first pass found check:docs-transcript-drift stale: four CLI transcripts print "author-time rules (60)", and the new gating rule makes the count 61. This PR fixes those transcripts.
    • check-plugin-teardown-shape --self-test exited 3 in the shallow clone. It went green after fetching its pinned commit.
  • Clause-② and Metadata-protocol lines. These were checked offline with check-changeset-no-major.mjs --base origin/main --event against this body, which accepts no (narrowing) with narrowed (exit 0).
  • Ablation. The new rule's severity was changed from 'error' to 'warning' and the dist preflight was rerun. That turned lint red (5 tests), metadata-protocol red (2) and the cli os validate test red (1). Restoring the severity made them green again, with a clean tree and the preflight --absent check passing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ADHkmQaszscubbRkbhxD9k

The new gating rule validateTitleFormatRetired joins the registry.

Claude-Session: https://claude.ai/code/session_01ADHkmQaszscubbRkbhxD9k
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation protocol:data tests tooling labels Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 13 package(s): @objectstack/lint, @objectstack/platform-objects, @objectstack/plugin-approvals, @objectstack/plugin-audit, @objectstack/plugin-security, @objectstack/plugin-sharing, @objectstack/plugin-webhooks, @objectstack/service-automation, @objectstack/service-mailbox, @objectstack/service-messaging, @objectstack/service-realtime, @objectstack/service-storage, @objectstack/spec, touching 38 documentable anchor(s). ⚠️ 2 changed file(s) yielded no anchor (packages/lint/src/index.ts, packages/spec/liveness/sharing_rule.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/flows.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/automation/hook-bodies.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/data-modeling/field-types.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/data-modeling/formulas.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion), titleFormat (symbol, a field of const object HttpDelivery; a field of const object InboxMessage; a field of const object NotificationDelivery; a field of const object NotificationPreference; a field of const object NotificationReceipt; a field of const object NotificationTemplate; a field of const object ObjectSchemaBase, an authorable key of data/Object; a field of const object SysAccount; a field of const object SysActivity; a field of const object SysApiKey; a field of const object SysApprovalAction; a field of const object SysApprovalApprover; a field of const object SysApprovalDelegation; a field of const object SysApprovalRequest; a field of const object SysAssignmentCursor; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion; a field of const object SysAutomationRun; a field of const object SysBusinessUnit; a field of const object SysBusinessUnitMember; a field of const object SysComment; a field of const object SysDeviceCode; a field of const object SysEmail; a field of const object SysEmailTemplate; a field of const object SysExchangeRate; a field of const object SysIdentityEmail; a field of const object SysImportJob; a field of const object SysInvitation; a field of const object SysJob; a field of const object SysJobQueue; a field of const object SysJobRun; a field of const object SysMailAssociation; a field of const object SysMailMessage; a field of const object SysMailbox; a field of const object SysMember; a field of const object SysMigration; a field of const object SysMigrationJournal; a field of const object SysNotification; a field of const object SysOauthApplication; a field of const object SysOrganization; a field of const object SysPlatformSetting; a field of const object SysPresence; a field of const object SysQueue; a field of const object SysQueueMember; a field of const object SysScimConnectionBinding; a field of const object SysScimConnectionCredential; a field of const object SysScimGroup; a field of const object SysScimGroupMember; a field of const object SysScimIdentityTombstone; a field of const object SysScimProjectionGrant; a field of const object SysScimSubject; a field of const object SysScimUser; a field of const object SysSession; a field of const object SysSetting; a field of const object SysShareLink; a field of const object SysSharingRule; a field of const object SysSsoProvider; a field of const object SysTeam; a field of const object SysTeamMember; a field of const object SysTrustedKey; a field of const object SysTwoFactor; a field of const object SysUser; a field of const object SysUserPermissionSet; a field of const object SysUserPosition; a field of const object SysUserPreference; a field of const object SysVerification; a field of const object SysWebhook; a field of const object SystemFile; a field of const object SystemUploadSession))
  • content/docs/data-modeling/objects.mdx (via SysUserPermissionSet (symbol, a top-level const object), nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion), titleFormat (symbol, a field of const object HttpDelivery; a field of const object InboxMessage; a field of const object NotificationDelivery; a field of const object NotificationPreference; a field of const object NotificationReceipt; a field of const object NotificationTemplate; a field of const object ObjectSchemaBase, an authorable key of data/Object; a field of const object SysAccount; a field of const object SysActivity; a field of const object SysApiKey; a field of const object SysApprovalAction; a field of const object SysApprovalApprover; a field of const object SysApprovalDelegation; a field of const object SysApprovalRequest; a field of const object SysAssignmentCursor; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion; a field of const object SysAutomationRun; a field of const object SysBusinessUnit; a field of const object SysBusinessUnitMember; a field of const object SysComment; a field of const object SysDeviceCode; a field of const object SysEmail; a field of const object SysEmailTemplate; a field of const object SysExchangeRate; a field of const object SysIdentityEmail; a field of const object SysImportJob; a field of const object SysInvitation; a field of const object SysJob; a field of const object SysJobQueue; a field of const object SysJobRun; a field of const object SysMailAssociation; a field of const object SysMailMessage; a field of const object SysMailbox; a field of const object SysMember; a field of const object SysMigration; a field of const object SysMigrationJournal; a field of const object SysNotification; a field of const object SysOauthApplication; a field of const object SysOrganization; a field of const object SysPlatformSetting; a field of const object SysPresence; a field of const object SysQueue; a field of const object SysQueueMember; a field of const object SysScimConnectionBinding; a field of const object SysScimConnectionCredential; a field of const object SysScimGroup; a field of const object SysScimGroupMember; a field of const object SysScimIdentityTombstone; a field of const object SysScimProjectionGrant; a field of const object SysScimSubject; a field of const object SysScimUser; a field of const object SysSession; a field of const object SysSetting; a field of const object SysShareLink; a field of const object SysSharingRule; a field of const object SysSsoProvider; a field of const object SysTeam; a field of const object SysTeamMember; a field of const object SysTrustedKey; a field of const object SysTwoFactor; a field of const object SysUser; a field of const object SysUserPermissionSet; a field of const object SysUserPosition; a field of const object SysUserPreference; a field of const object SysVerification; a field of const object SysWebhook; a field of const object SystemFile; a field of const object SystemUploadSession))
  • content/docs/data-modeling/schema-design.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion), titleFormat (symbol, a field of const object HttpDelivery; a field of const object InboxMessage; a field of const object NotificationDelivery; a field of const object NotificationPreference; a field of const object NotificationReceipt; a field of const object NotificationTemplate; a field of const object ObjectSchemaBase, an authorable key of data/Object; a field of const object SysAccount; a field of const object SysActivity; a field of const object SysApiKey; a field of const object SysApprovalAction; a field of const object SysApprovalApprover; a field of const object SysApprovalDelegation; a field of const object SysApprovalRequest; a field of const object SysAssignmentCursor; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion; a field of const object SysAutomationRun; a field of const object SysBusinessUnit; a field of const object SysBusinessUnitMember; a field of const object SysComment; a field of const object SysDeviceCode; a field of const object SysEmail; a field of const object SysEmailTemplate; a field of const object SysExchangeRate; a field of const object SysIdentityEmail; a field of const object SysImportJob; a field of const object SysInvitation; a field of const object SysJob; a field of const object SysJobQueue; a field of const object SysJobRun; a field of const object SysMailAssociation; a field of const object SysMailMessage; a field of const object SysMailbox; a field of const object SysMember; a field of const object SysMigration; a field of const object SysMigrationJournal; a field of const object SysNotification; a field of const object SysOauthApplication; a field of const object SysOrganization; a field of const object SysPlatformSetting; a field of const object SysPresence; a field of const object SysQueue; a field of const object SysQueueMember; a field of const object SysScimConnectionBinding; a field of const object SysScimConnectionCredential; a field of const object SysScimGroup; a field of const object SysScimGroupMember; a field of const object SysScimIdentityTombstone; a field of const object SysScimProjectionGrant; a field of const object SysScimSubject; a field of const object SysScimUser; a field of const object SysSession; a field of const object SysSetting; a field of const object SysShareLink; a field of const object SysSharingRule; a field of const object SysSsoProvider; a field of const object SysTeam; a field of const object SysTeamMember; a field of const object SysTrustedKey; a field of const object SysTwoFactor; a field of const object SysUser; a field of const object SysUserPermissionSet; a field of const object SysUserPosition; a field of const object SysUserPreference; a field of const object SysVerification; a field of const object SysWebhook; a field of const object SystemFile; a field of const object SystemUploadSession))
  • content/docs/deployment/validating-metadata.mdx (via AUTHORING_RULES (symbol, a top-level const object), runtimeTypes (symbol, a field of const object AUTHORING_RULES))
  • content/docs/frontend/building-crud-app.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/frontend/plugins/plugin-grid.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/ui/forms.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))

⛔ 5 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v13.mdx (via SysUserPosition (symbol, a top-level const object))
  • content/docs/releases/v16.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/releases/v17/17-0.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion), titleFormat (symbol, a field of const object HttpDelivery; a field of const object InboxMessage; a field of const object NotificationDelivery; a field of const object NotificationPreference; a field of const object NotificationReceipt; a field of const object NotificationTemplate; a field of const object ObjectSchemaBase, an authorable key of data/Object; a field of const object SysAccount; a field of const object SysActivity; a field of const object SysApiKey; a field of const object SysApprovalAction; a field of const object SysApprovalApprover; a field of const object SysApprovalDelegation; a field of const object SysApprovalRequest; a field of const object SysAssignmentCursor; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion; a field of const object SysAutomationRun; a field of const object SysBusinessUnit; a field of const object SysBusinessUnitMember; a field of const object SysComment; a field of const object SysDeviceCode; a field of const object SysEmail; a field of const object SysEmailTemplate; a field of const object SysExchangeRate; a field of const object SysIdentityEmail; a field of const object SysImportJob; a field of const object SysInvitation; a field of const object SysJob; a field of const object SysJobQueue; a field of const object SysJobRun; a field of const object SysMailAssociation; a field of const object SysMailMessage; a field of const object SysMailbox; a field of const object SysMember; a field of const object SysMigration; a field of const object SysMigrationJournal; a field of const object SysNotification; a field of const object SysOauthApplication; a field of const object SysOrganization; a field of const object SysPlatformSetting; a field of const object SysPresence; a field of const object SysQueue; a field of const object SysQueueMember; a field of const object SysScimConnectionBinding; a field of const object SysScimConnectionCredential; a field of const object SysScimGroup; a field of const object SysScimGroupMember; a field of const object SysScimIdentityTombstone; a field of const object SysScimProjectionGrant; a field of const object SysScimSubject; a field of const object SysScimUser; a field of const object SysSession; a field of const object SysSetting; a field of const object SysShareLink; a field of const object SysSharingRule; a field of const object SysSsoProvider; a field of const object SysTeam; a field of const object SysTeamMember; a field of const object SysTrustedKey; a field of const object SysTwoFactor; a field of const object SysUser; a field of const object SysUserPermissionSet; a field of const object SysUserPosition; a field of const object SysUserPreference; a field of const object SysVerification; a field of const object SysWebhook; a field of const object SystemFile; a field of const object SystemUploadSession))
  • content/docs/releases/v17/17-2.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))
  • content/docs/releases/v18/18-1.mdx (via nameField (symbol, a field of const object NotificationTemplate; a field of const object SysAttachment; a field of const object SysAudienceBindingSuggestion))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 changed file(s) yielded no anchor (packages/lint/src/index.ts, packages/spec/liveness/sharing_rule.json) — pages documenting those are invisible to this run
  • 7 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 216 client-bound route-ledger rows — the other 156 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 156: 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; 101 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 — 176 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 dbca3ef034537269cef482b342aa4ba7169dfe42 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from f27464b7de65d55c42ed0195f42a3b346a38dc48 — the merge of head 63417d56d5216bbcf5dc0355fbe4915aad2f7dc5 into base dbca3ef034537269cef482b342aa4ba7169dfe42, 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 f27464b7de65d55c42ed0195f42a3b346a38dc48 && git checkout f27464b7de65d55c42ed0195f42a3b346a38dc48
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin dbca3ef034537269cef482b342aa4ba7169dfe42 63417d56d5216bbcf5dc0355fbe4915aad2f7dc5 && git checkout -B drift-repro dbca3ef034537269cef482b342aa4ba7169dfe42 && git merge --no-ff 63417d56d5216bbcf5dc0355fbe4915aad2f7dc5

node scripts/docs-audit/affected-docs.mjs --json dbca3ef034537269cef482b342aa4ba7169dfe42

⚠️ 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 dbca3ef034537269cef482b342aa4ba7169dfe42 → 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#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Head-sha: 08859318 · read 2026-11-02T16:38Z

维护者速读

席位意见:可落地,等契约复审。

席位核对 — ACCEPT · domain:spec#1 · head 08859318

  1. Shape: draft, base main, Fixes #29007, Clause-②: no (narrowing) / Metadata-protocol: semantic in the body and the changeset. 101 files, +728/-273. Not governed (check-governed-merges --branch: 101 checked, no hit).
  2. Ruling: director 6574393684 letter B (「454 同意」) rules the refusal at the save gate and os validate, with the existing prescription. The key still parses on read, is neither honoured nor deleted, and gets no conversion.
  3. Surface: inside claim 6578956474's named doors. The refusal is one gating registry rule, title-format-retired (CLI_AND_RUNTIME, object), which os validate, build, lint and the save gate all run. The 68 system objects drop the key, as the claim's "every titleFormat hit" asks. The PR body names the nine forced test edits; the 60 → 61 author-time rule count appears in four doc transcripts. All are accepted.
  4. Open questions, the seat's answers:
  5. Not touched: skills/objectstack-data/SKILL.md:90 still says "Deprecated, not removed". It is a governed path, so it is left for a governed follow-up.
  6. Readings (dev, on 08859318):
    • 15 package suites and typecheck green (cli 6871 tests).
    • Dogfood 393 files / 3243 tests, exit 0.
    • 113/113 derived gates run, 0 red.
    • Offline level gate accepted.
    • Ablation red in lint (5), metadata-protocol (2) and cli (1), then restored.
  7. Landing: a narrowing on the published-schema face, so one CONTRACT_REVIEW_TIER review by the seat (claim line follows). After a PASS and green CI, the seat readies and queues.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Contract-review-claim: session_01ADHkmPi25XXKx92Xmg4viS · head 0885931 · 2026-11-02T16:39Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Contract review (delta) · head 9860117 · 2026-11-02T19:32Z

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 986011757d558c62c70f162fd458051c51c3fc3c
Local-runs: none
Scope: delta 0885931864..986011757d — the merge of origin/main (9b05a3b42e, via os-regen-merge.sh), 75c2ac28a8 (regenerated references), 324dfa2614 (changeset kind line), 986011757d (transcripts 62) + packages/lint/src/authoring-rules.ts (read at merge base, head and current origin/main), .changeset/29007-object-title-format-refused.md, the four CLI transcript .mdx files, the PR body as served

Round-1 record: record.md on 0885931864, FAIL on two must-fixes (A: transcripts stale against main; B: Metadata-protocol: narrowed). This record judges the fixes and the merge; the round-1 judgments on the narrowing itself are unchanged by this delta and are not re-argued.

① Derived judgments

Branch delta integrity — intact. Round-1 delta (925e86070c...0885931864) and round-2 delta (86d36e9974...986011757d, the new merge base) carry the same 101-file list; a per-file comparison of the hunks (headers and index lines stripped) differs in exactly five files: the changeset and the four transcripts, i.e. the two fixes. content/docs/references/data/object.mdx and references/system/migration.mdx were regenerated from the merged tree (75c2ac28a8, +8/−4) and their branch-attributable hunks are byte-equal to round 1; the extra lines are main-side describe changes the regeneration absorbed. The merge commit brings 281 main-side files and drops or alters no branch change.

(A) Transcripts — correct on the head, stale against main again. Measured by counting name: entries inside AUTHORING_RULES (every entry's commands includes validate, so authoringRulesFor('validate').length equals the entry count): merge base 86d36e9974 = 61, head = 62, and the four transcripts on the head read 62 (deployment/cli.mdx:774, deployment/validating-metadata.mdx:763, getting-started/build-with-claude-code.mdx:313, ui/react-pages.mdx:407). The drift gate (check:docs-transcript-drift, lint.yml job Type Check · workspace) is green on this head. But origin/main (ebbb5b8867) has since landed #29495 (7f368f56ec, validateFlowRegionShape) with its own 61 → 62 edit to the same four lines: main = 62 rules / transcripts 62; head = 62 / 62; the merged tree = 63 rules (union of the two added names) while the three-way merge of identical textual edits leaves the transcripts at 62. The gate runs on merge_group, so the queue reds the merge result exactly as in round 1. MUST-FIX A′: merge origin/main once more and set the four transcripts to 63 — or to whatever the union count is at the moment of the merge — and queue immediately. This is the same race twice in one day: four hand-written literals that every rule-adding PR edits; a card on the gate (regenerate the count in the queue leg, or stop printing a literal) is owed, not this PR's.

(B) Kind line — half landed. .changeset/29007-object-title-format-refused.md:20 now reads Metadata-protocol: narrowed beside Clause-②: no (narrowing) and the registered object-title-format-refused marker. The PR body as served on 986011757d still reads Metadata-protocol: semantic, and its Verification bullet still says the offline gate "accepts no (narrowing) with semantic". The level gate reads the kind from the PR body ("declared ONCE, FOR THE PR — a PR-body line"), so the declaration of record is still the wrong one; no gate cross-checks the body line against the changeset line (the "disagree" refusal is declaration-vs-level, not body-vs-changeset), which is why Check Changeset is green either way. MUST-FIX B (remaining): patch the PR body to Metadata-protocol: narrowed and reword the Verification bullet; the dev reports this as owed.

② Semver level

  • no (narrowing) + narrowed is the enforce pair in check-changeset-no-major.mjs (:2048 refuses narrowed only without the arm; :3737/:3747 pin it at minor): thirteen packages at minor stay consistent with the new kind. For check-adr-0087-registration.mjs the changeset now carries signals (2) **BREAKING, (3) !, (4) the arm and (5) narrowed, all answered by the one registered disposition that resolves to entries/semantic/18.object-title-format-refused.ts (the ADR-0087 category is unchanged and correct). Check Changeset, Lint · PM dispatch-gates, Governed Surface Queue Guard green on the head.

③ Boundary flags

  • Check-runs on 986011757d at reading: 65 runs, all completed, every one success or skipped (Test Core 8/8, Test UI 16/16, Type Check UI/workspace/source/consumer/debt, Build Core/Docs/UI, Live E2E UI, Build & E2E UI, Lint lanes, Dogfood Regression Gate, Spec property liveness, Check Changeset). Green on the head; the merge-group result is what A′ is about.
  • Governed surfaces: none in the delta; the merge touched .github/, skills/ or docs/adr/ only as main-side content.
  • Dev-reported local greens (check:generated, 7 suites + typecheck, dogfood battery, 100/113 derived gates with 0 red) are consistent with the CI reading; not relied on.
  • Still owed from round 1, unchanged: a Tier H follow-up for skills/objectstack-data/SKILL.md:90 / skills/objectstack-formula/SKILL.md:444 (filed, not "noted"), and a one-line ADR-0079 D3 amendment citing ruling 6574393684. Non-blocking.

④ Design judgment

  • The merge was made the mechanized way (os-regen-merge.sh: main's side of every os-regen path both sides moved, then the chain regenerated), and the regenerated references show only main-side additions beside the branch's sentence — the right outcome for a describe change riding a moving main. Nothing new to judge on the schema, the rule or the doors.

Implemented-by: claude/project-thread-ejw6q8
Reviewed-by: session_01ADHkmPi25XXKx92Xmg4viS

VERDICT: FAIL

Must-fix before a PASS record: (A′) re-merge origin/main (now ebbb5b8867, carrying #29495's validateFlowRegionShape) and set the four CLI transcripts to the merged tree's count, 63 as of this reading, then queue at once; (B) the PR body still declares Metadata-protocol: semantic — patch it to narrowed (and its Verification bullet) so the body matches the changeset. The branch delta is otherwise unchanged and intact, and every check on the head is green.


Seat addendum · 2026-11-02T19:32Z. The seat re-read B after this record was written. The PR body as served now reads Metadata-protocol: narrowed (line 7), and its round-2 Verification block cites no (narrowing) with narrowed. B is closed.

A′ is the only open item, and it is a main race, not a branch defect. The dev re-merges origin/main and sets the four transcripts to the count measured on the merged tree. The seat treats that head as merge-only. It carries this review forward once check:docs-transcript-drift and the lint suite are green on the head, and queues it right away so main cannot move the count again.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Merge-only head 63417d56 · 2026-11-02T19:42Z. This closes A′ of the round-2 delta review.

  • Merge. The dev merged origin/main dbca3ef0 with os-regen-merge.sh. Main's feat(lint)!: os lint refuses a flow region the engine refuses to register (flow-region-shape-invalid) #29495 (validateFlowRegionShape) is now in the tree. The dev regenerated the references from the merged tree in their own commit (90d6dcc).
  • Transcripts. The dev rebuilt the cli closure (lint included). check:docs-transcript-drift measures 63 on the merged tree, and the four transcripts now print 63. The check is green.
  • B was closed in the review addendum, since the body reads Metadata-protocol: narrowed.

The branch delta is otherwise unchanged, so the seat carries the CONTRACT_REVIEW_TIER review forward to this head as PASS. It readies and queues now, so the rule count cannot move again on main. The PR's own CI and the merge-group CI are the gate for the suites the dev is still running.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 19:44
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 2, 2026 19:44
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant