Skip to content

fix(metadata-protocol): the sealed-overlay boot report no longer counts a served .custom override (#28771) - #28801

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-jqgfyc
Nov 1, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-jqgfyc

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

Fixes #28771

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:启动时的 [metadata_sealed_overlay_unserved] 告警不再把基础包在 BASE.custom 里声明的覆盖算作「没有读取会返回它」的行,也就不再让运维删掉这份正在生效的定制。真正没被返回的行照旧上报,附带补救办法。
  • 为什么改:service-automation: a declared override in <base>.custom is the packaged flow — armed over the code package, rebound in one reload, one ledger switch #28412 之后,这份覆盖会被返回,流程还会被挂载,但启动告警仍然把它算进去,并建议「删除存储行」。照做会让租户悄悄回到基础流程。
  • 风险与回滚:低。只改一条启动日志里统计哪些行;判定用唯一的 isServedOverrideRowOf,看存储的 package_id 列,不看正文 _packageId。加载、返回、挂载都不变。回滚即还原本 PR。
  • 先看:packages/metadata-protocol/src/protocol.ts 的 loadMetaFromDb,即 sealedOverlays.push 前多出的一个条件。
  • 两分钟验证:pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.reads-environment-only.test.ts,预期 27/27 通过。
  • 需要你做的:无,席位落地。

What changes

loadMetaFromDb collects the rows it hands to reportSealedOverlayRows, the census behind [metadata_sealed_overlay_unserved]. It now skips a row that the one served-override predicate admits: isServedOverrideRowOf(record, packagedArtifactOwner(type, name)), judged on the row's own package_id column, never on a body's _packageId. Since #28412 the shipping package's declared BASE.custom override is served, and for a flow it is armed, so the line's "No read serves them … delete the stored row" was a destructive remedy aimed at a working row.

Only the census changes. The object skip just below it, the hydration and what is served or armed are all untouched. Every row no rule serves is still reported with both remedies, and the count goes down by exactly the served rows.

⛔ No packages/spec/**, no new export, no new error code and no new gate. Clause-② measured: no. It is a boot log line only: no served value, no export and no accept-set change. Metadata-protocol: none.

Tests

New cases, red first on main, ablation

There are 7 new cases in metadata-protocol protocol.reads-environment-only.test.ts, section 3 (the boot report). They use the file's environment-kernel harness and loadMetaFromDb, with a packaged flow artifact:

  • a boot holding only the declared override prints no sealed-overlay line;
  • the override plus a legacy package-less row reports the legacy row alone ("1 active environment sys_metadata row(s)", flow×1 (managed_flow), both remedies);
  • controls, each still reported: the legacy row alone; the pair's undeclared row; a dependent package's declaration; a package-less row whose body stamps the pair and declares the override (binding, not stamp).

Red first: protocol.ts was restored to main d9c4cdc4 (the suite imports the source, so there is no dist step). Result: Tests 2 failed | 25 passed (27):

  • × a boot holding only the declared override prints no sealed-overlay line, because it printed "flow×1 (managed_flow) … delete the stored row";
  • × … reports the legacy row alone, because it counted "2 … flow×2 (managed_flow, managed_flow)".

Restore: git checkout HEAD --, blob equal to HEAD, git diff HEAD empty, porcelain empty.

Ablation: ablation-replace.mjs made the exclusion always false (anchor && !isServedOverrideRowOf(, 1 marker on disk). Result: the same two cases red, Tests 2 failed | 25 passed (27). Restore: ok restored: blob == HEAD … git diff HEAD is empty, marker count 0, porcelain empty.

Full suites, typecheck, lint, gates

All on head c3a0c542:

  • metadata-protocol full suite, under the verify lock: Test Files 295 passed | 4 skipped (299), Tests 22065 passed | 26 skipped (22091).
  • service-automation full suite, under the verify lock: Test Files 254 passed (254), Tests 3269 passed (3269).
  • tsc --noEmit -p packages/metadata-protocol: exit 0. eslint --no-inline-config packages/metadata-protocol: exit 0.
  • Derived gate list (dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 61 families): each was run with its exit code captured before any pipe, and all exited 0. --ran: 61 derived, 61 run, 0 NOT-MEASURED, 0 UNRUN. check-nul-bytes: exit 0.
  • Dogfood battery: not owed (no ! in the title, and no (narrowing) arm).

Acceptance notes

  • The served-override predicate is asked with the loader's set's owner (packagedArtifactOwner), the same owner the reads use. A row that overlays sealed content of a name no package ships never enters this census at all.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FEkQ5oTRCUNQ4EA3YV84sZ

… a served .custom override

The boot census behind [metadata_sealed_overlay_unserved] counted the
shipping package's declared .custom override with the unserved rows, so
the line said no read serves it and prescribed deleting the stored row,
the live customization. The census now skips a row isServedOverrideRowOf
admits on its package_id column. Unserved rows, the legacy package-less
row a declared override shadows included, are still reported with their
remedies. What the boot loads, serves and arms is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • 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 — 10 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 0aaad18fc052326bc78378ead5f7e789f64e072d → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 0aaad18fc052326bc78378ead5f7e789f64e072d

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

席位核对 · ACCEPT · domain:server seat 1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC · 2026-11-01T21:02Z

Head c3a0c542, report 6563611182 (on #28771), claim 6563067638. Clause-②: no, with no arm: no contract review is owed. The seat read the diff itself.

item reading
Shape Draft, base main, Fixes #28771. 3 files (+79 / −1): one condition in loadMetaFromDb's sealed-overlay census (protocol.ts), 7 new cases in protocol.reads-environment-only.test.ts, and a @objectstack/metadata-protocol patch changeset. Metadata-protocol: none. No export, no packages/spec/**, no gate.
Rule A row joins the census only when isServedOverrideRowOf(record, packagedArtifactOwner(...)) does not admit it. That is the one served-override predicate, on the row's package_id column. What the loop loads, serves or arms is unchanged (the push sits beside the existing host-code-datasource skip). Unserved rows, the legacy row #28717 leaves shadowed included, keep their remedies.
Evidence CI green on head c3a0c542 (filter=latest: 35 success, 13 skipped, 0 failed). The report shows 2 red on main (the override-only boot said "delete the stored row", and the override-plus-legacy boot counted 2), green on head, an ablation restored clean, the metadata-protocol and service-automation suites green, and 61/61 derived gates.
Landing 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, with every check green or an expected skip.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 1, 2026 21:03
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit 70bf434 Nov 1, 2026
49 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-jqgfyc branch November 1, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

metadata-protocol: the boot's metadata_sealed_overlay_unserved line counts a served .custom flow override and tells the operator to delete it

1 participant