Skip to content

fix(cli)!: os build refuses a field the __c extension-field reservation refuses, as os validate does (#28727) - #28757

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-0fsk8u
Nov 1, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-0fsk8u

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread

Fixes #28727

Clause-②: no (narrowing)
os build used to emit dist/objectstack.json for a package source whose field breaks the __c reservation; it now refuses that build. The spelling it newly refuses has a measured count of 0 on this base (below). No packages/spec/** or packages/metadata-protocol/** file is touched; no schema, type, export or error code moves.

Metadata-protocol: none
What a metadata author can write is unchanged at every metadata door: the save, restore and publish doors, os validate and the marketplace install already refuse the same fields with the same judge since #28564 (PR #28724). This only moves the same verdict to the build, as #28643 (PR #28681) did for the override write gate, which declared the same pair.

Skills-docs: none — no file under skills/** teaches a field spelled with the __c suffix or what os build refuses for one (git grep of the suffix over skills/** on this base: 0 hits); the objectstack-data skill's "Object Extension Model" section names no field spelling, so it stays true.

维护者速读

  • 改了什么:os build 现在和 os validate 一样检查 __c 扩展字段后缀(ADR-0146 D10)。普通包里出现 x__c 字段、或 .custom 配对包的扩展字段不带 __c,构建直接失败(退出码 1),dist/ 里什么都不写。
  • 为什么改:metadata-protocol + cli + install-local: __c extension fields only in a .custom package — refused at save/publish/restore, os validate, both install doors and duplicate #28564 让保存/发布/安装/os validate 都拒这两种写法,唯独 os build 还会产出一个到处都会被拒的产物。现在发货的那道门当场拒,和 fix(cli): os build runs the override write gate os validate runs #28681 对覆盖声明门做的事一样。
  • 风险与回滚:同一个判官、同一条遍历(findExtensionFieldSuffixRefusals),没有第二份拼写;新拒的拼法在本基点上实测 0 个字段名。回滚即 revert,无数据迁移。
  • 先看:packages/cli/src/commands/compile.ts 的 3b-iii-bis 一段(紧跟覆盖声明门,在任何产物写入之前);packages/cli/test/validate-build-gate-parity.test.ts 的台账行搬家。
  • 两分钟验证:pnpm --filter @objectstack/cli exec vitest run test/build-extension-field-suffix.test.ts,预期 Tests 4 passed (4)。
  • 需要你做的:无,席位落地(合同审查后)。

What changes

  • packages/cli/src/commands/compile.ts: step 3b-iii-bis calls findExtensionFieldSuffixRefusals (utils/extension-field-suffix.ts, over @objectstack/metadata-protocol's judgeExtensionFieldSuffix), the call os validate makes at its step 3a-iv. It sits right after fix(cli): os build runs the override write gate os validate runs #28681's override gate (3b-iii) and ahead of every artifact write, so a refused build writes nothing to dist/. Same package-id reading as validate: each packages[] entry under its own id, else the stack under manifest.id; a stack naming no id is not judged. Faces: --json answers this command's failure envelope (success: false, errors = the rows os validate --json carries), the text face prints os validate's heading and bullet rows; exit 1 in both. No second walk, and neither the suffix nor the pair rule is spelled here.
  • packages/cli/test/validate-build-gate-parity.test.ts: the findExtensionFieldSuffixRefusals row leaves VALIDATE_ONLY_GATES for SHARED_NON_REGISTRY_GATES, with its reason; the ledger is {} again and its docblock now names the three rows it has held and closed.
  • .changeset/28727-build-extension-field-suffix.md: @objectstack/cli patch, both declaration lines, BREAKING banner and the ADR-0087 not-required (no-migration-prescription) disposition.

Tests

  • New packages/cli/test/build-extension-field-suffix.test.ts (4, unit tier; os build and os validate run in-process, the recipe of build-override-declarations.test.ts):
    • case (a), a plain package's own object field x__c, and case (b), the com.acme.crm.custom pair extending crm_account with a plain region: os build --json exits as os validate --json does (1), errors deep-equals validate's rows for the same config (anti-vacuity: exactly one VALIDATION_ERROR row with the expected rule and path), and dist/ does not exist afterwards;
    • the text face of case (b) exits 1 and prints validate's refusal block verbatim, with no "Build complete";
    • CONTROL: the pair extending with region__c validates clean and builds, the artifact carrying region__c.
  • Red on base: compile.ts restored to db357f6d (tests kept): 4 failed / 32 passed across the new file and the parity file (the three build pins with expected +0 to be 1, and the parity pin "compile.ts no longer calls findExtensionFieldSuffixRefusals"); the control stays green. Restore proved by git diff HEAD empty and the blob equal to HEAD's.
  • Ablation (scripts/ablation-replace.mjs, anchor hit once, blob 8f239dd8 to 7cc70658): the compile call replaced by an empty row list: 4 failed / 32 passed, the same four pins. Restore: blob equal to HEAD (8f239dd8), git diff HEAD empty. The command runs from src (the test imports ../src/commands/compile), so no dist/ sits on the path.

Acceptance notes

Verification

Run on 4eb1b66430 (base db357f6d; origin/main has since moved by 8 commits, none touching this diff's files; not merged, see the deviation below). Each test command under os-verify-lock (VERDICT command-exit 0).

  • Build: pnpm --filter '@objectstack/cli...' build exit 0; the dogfood closure pnpm --filter '@objectstack/dogfood^...' build exit 0.
  • @objectstack/cli unit tier (vitest run --project unit): Test Files 366 passed (366); Tests 5180 passed (5180). The new file is unit tier (in-process, no spawn); the integration tier is declared to CI (no integration-tier file or spawn entry is touched).
  • pnpm --filter @objectstack/cli typecheck: exit 0 (check:test-typecheck: OK).
  • eslint --no-inline-config packages/cli: exit 0.
  • Dogfood battery (pnpm --filter @objectstack/dogfood test, owed by the narrowing arm): Test Files 374 passed, 3 skipped (377); Tests 3034 passed, 28 skipped (3062).
  • Derived gates (dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 61 families, each exit captured before any pipe), reconciled: ✓ dispatch-gates --ran: 61 derived famil(ies) accounted for — 61 run, 0 NOT-MEASURED (a DERIVED zero — all 61 recorded an exit code and none of them is 3). check:i18n-coverage first read 3 (@objectstack/connector-slack had no build output in this worktree) and read 0 after building it: OK (14 config(s), 527 baselined untranslated string(s), none new).
  • Count (the narrowing's migration note): git grep -nE "[a-z0-9]__c\b" over examples/**, packages/*/src/**, skills/**, tests excluded, at origin/main db357f6d: 8 hits, all doc comments (protocol-extension-field-suffix.ts, field-customization.ts, object.zod.ts, validation.zod.ts); 0 field names.
  • Deviation: origin/main was not merged before opening. The 8 incoming commits touch none of the four files here; in packages/cli they change only src/utils/override-declarations.test.ts. CI's merge-group run judges the joint tree; the serial merge with feat(objectql): an object extension's fieldPatches relabels the vendor field on every read, refused at install and os validate when it names nothing (#28565) #28728 stays owed by whichever lands second.

Generated by Claude Code

…ion refuses, as os validate does

compile.ts makes the call validate.ts makes (findExtensionFieldSuffixRefusals,
over metadata-protocol's judgeExtensionFieldSuffix), beside the override gate
and ahead of every artifact write, with validate's refusal text and exit 1 in
both output modes. The parity ledger's VALIDATE_ONLY_GATES row moves to the
shared set and the ledger is empty again.

Claude-Session: https://claude.ai/code/session_01FEkQ5oPz5wWFMzWjTGyVUb
Co-Authored-By: Claude <noreply@anthropic.com>
…he reservation refuses it

Claude-Session: https://claude.ai/code/session_01FEkQ5oPz5wWFMzWjTGyVUb
Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Nov 1, 2026
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

18 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 706ac52d570096a47b64283e970bc1a8e569bc91.

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

What this run could not see

Coarse fallback — 35 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 706ac52d570096a47b64283e970bc1a8e569bc91 → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 706ac52d570096a47b64283e970bc1a8e569bc91

⚠️ 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 706ac52d570096a47b64283e970bc1a8e569bc91 → 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:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 4eb1b66430056ed39d280b49c5b494b9c5c582ff
Local-runs: none
Scope: packages/cli/src/commands/compile.ts, packages/cli/test/build-extension-field-suffix.test.ts, packages/cli/test/validate-build-gate-parity.test.ts + packages/cli/src/commands/validate.ts (step 3a-iv, the call and both faces the build now mirrors), packages/cli/src/utils/extension-field-suffix.ts (the walk), packages/cli/src/utils/artifact-packages.ts (artifactPackages, the id rule the walk reads), packages/metadata-protocol/src/protocol-extension-field-suffix.ts (judgeExtensionFieldSuffix, the one judge), packages/spec/src/data/field-customization.ts (isExtensionFieldName), packages/spec/src/kernel/customization-package.ts (isCustomizationPackage), docs/adr/0146-…md §D10 (the published rule), packages/cli/test/build-override-declarations.test.ts (the recipe the new test copies), packages/cli/test/helpers/define-stack-fixture.ts, skills/objectstack-data/SKILL.md §Object Extension Model (the Skills-docs claim). Not reviewed: .changeset/28727-build-extension-field-suffix.md (prose face; its declaration lines are read under ②).

Inputs: card #28727 (body, claim 6560789923, os-dev-report 6561648987); PR #28757 body, file list, git diff db357f6d..4eb1b664; the head's 48 check-runs — 37 success, 11 skipped, 0 failures (Test Core ×9, TypeScript Type Check, Lint & Repo Gates, Check Changeset, Governed Surface Queue Guard, PR-body guards, Dogfood Regression Gate, Build Core all green).

① Derived judgments

  1. Accept set of os build narrows — a stack whose field breaks the __c reservation (case (a) reserved_outside_pair: a __c field on a non-.custom package's own object or extension; case (b) unsuffixed_in_pair: an unsuffixed objectExtensions[].fields key of a .custom pair) now exits 1 and writes nothing. Right. The call is findExtensionFieldSuffixRefusals(result.data) at compile.ts step 3b-iii-bis, the same symbol validate.ts calls at 3a-iv over the same parsed result.data (both commands parse the lowered stack with ObjectStackDefinitionSchema.safeParse); neither the suffix nor the pair rule is spelled in compile.ts.
  2. Position — 3b-iii-bis sits at compile.ts:809–837, directly after the override gate (3b-iii, :778) and ahead of every write: the first fs.writeFileSync in the command is the opt-in access-matrix snapshot at 3e (:1004), cleanupOldRuntimeBundles is at :1262/:1273, the artifact write at :1292. The output directory is not created before the gate (the new test's dist/-absent pin is green in Test Core). Right.
  3. Faces — --json: this command's envelope { success: false, errors, warnings, conversions } (the override gate's shape, :796), errors being the rows validate's --json carries (the new test pins deep equality). Text: printError heading and printBulletList rows string-identical to validate.ts:714–718. Right; no second wording.
  4. Package-id reading — the walk hands each packages[] entry under artifactPackages' id (manifest.id, else name, else packages[N]) and the bare stack under manifest.id; a bare stack with no id is not judged (the judge returns [] for a non-string id). This is the walk validate.ts already runs, unchanged by the diff, so build ≡ validate on which packages are judged. Right (noting the PR body's "a stack naming no id is not judged" holds for the bare stack only; a packages[] entry falls back to its name — pre-existing, shared, not a divergence).
  5. Parity ledger — findExtensionFieldSuffixRefusals moves from VALIDATE_ONLY_GATES to SHARED_NON_REGISTRY_GATES; the ledger is {}; the docblock's row history is rewritten (three rows closed). Right — the pin every VALIDATE_ONLY_GATES entry is still validate-only (:1172) would otherwise red on the compile call, and both commands run %s (:929) now holds the build to it.
  6. Public surface — no export, type, schema, error code or spec key moves; packages/spec/** and packages/metadata-protocol/** untouched, as the card's claim forbade. os lint calls neither this gate nor the override gate on main; the parity contract is compile ↔ validate, and this diff leaves lint as it was. Right; nothing further implied.

② Semver level

.changeset/28727-build-extension-field-suffix.md: '@objectstack/cli': patch, line-initial Clause-②: no (narrowing) and Metadata-protocol: none, a BREAKING banner, exactly one adr-0087: not-required (no-migration-prescription) marker (no-migration-prescription is in CATEGORIES of scripts/check-adr-0087-registration.mjs; Check Changeset and the ADR-0087 registration gate are green). The PR body carries the same two line-initial declarations.

③ Boundary flags

  • open_questions: [] — none to answer.
  • Deviation 1 (origin/main not merged): verified — git diff --stat db357f6d..origin/main (5493b884) over the four files and validate.ts is empty; PR feat(objectql): an object extension's fieldPatches relabels the vendor field on every read, refused at install and os validate when it names nothing (#28565) #28728 (the same parity file) is still open, so the ruling-5 serial merge stays owed by whichever lands second. Not a blocker for this record.
  • Deviation 2 (three pushes): a budget note, not a contract matter.
  • Deviation 3 (count re-measured): verified — git grep -nE "[a-z0-9]__c\b" at db357f6d over examples/**, packages/*/src/**, skills/**, tests excluded: 8 hits, all doc comments, 0 field names. The PR measured case (a) only; I measured case (b): no .custom manifest id exists in examples/** or packages/*/src/** at the base (examples/app-showcase is com.example.showcase), so the unsuffixed-in-pair case also narrows on a count of 0.
  • Skills-docs: none: verified — 0 __c hits under skills/**; skills/objectstack-data/SKILL.md §Object Extension Model names no field spelling and stays true.
  • Acceptance note (text face verbatim): verified against validate.ts:712–718 — same heading, same row format, same noun/remedy.

④ Design judgment

The narrowing, read against the published spec on main: ADR-0146 D10 declares the __c reservation refused "at publish, at os validate and at the install door … so a vendor artifact that ships one is refused on entry". Emitting an artifact every door refuses is not a capability D10 declares to the build's consumer; the parity file's own contract ("os validate is the READ-ONLY SUPERSET of the gates os build runs") and its #28564 ledger row ("a real gap in the build's direction, reported and not closed") name the pre-diff state as a gap. The diff makes the spec's own refusal real at the shipping door, one judge, one walk, no re-spelling; it takes nothing away that any door delivered. Not a consumer-side narrowing of a declared capability.

Attempts to break it:

  • A write before the gate? None — see ①.2.
  • Build judging a different package set than validate? Same walk, same artifactPackages id rule, same result.data; a .custom pair's own objects and extensions of them are skipped by the judge at both doors.
  • A false refusal on the tree? The dogfood battery and Test Core are green; both case counts are 0 at base.
  • A face drift? Text strings identical; --json envelope is the command's own, with validate's rows.

Findings:

  • should-fix — build-extension-field-suffix.test.ts copies the in-process run/json helpers verbatim from build-override-declarations.test.ts (two copies at head). The parity file's own doctrine is one source per sentence; hoist the helper into packages/cli/test/helpers/ on the next touch of either file. Not a contract defect; no verdict weight.
  • must-fix — none.

Implemented-by: claude/project-thread-0fsk8u
Reviewed-by: session_01R1q2xdtYgU6FKrZ7LgjPCC

VERDICT: PASS


Generated by Claude Code

@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-01T18:12Z

Head 4eb1b664, report 6561648987 (on #28727), claim 6560789923. Clause-②: no (narrowing): the contract review owed at CONTRACT_REVIEW_TIER is on this head, 6561884162, PASS, with no must-fix.

item reading
Shape Draft, base main, Fixes #28727. 4 files (+244 / −16): compile.ts, the new build-extension-field-suffix.test.ts, the parity ledger, and one changeset (@objectstack/cli patch, BREAKING banner, ADR-0087 not-required (no-migration-prescription)). Metadata-protocol: none. No packages/spec/**, no packages/metadata-protocol/**, no gate.
Rule os build step 3b-iii-bis calls findExtensionFieldSuffixRefusals, the same walk os validate runs. It sits right after #28681's override gate and ahead of every write. Both faces match validate's. VALIDATE_ONLY_GATES is {} again.
Evidence CI green on head 4eb1b664 (filter=latest: 35 success, 13 skipped, 0 failed). The report shows 4 red on base and green on head, an ablation restored clean, the cli suite and dogfood green, and 61 derived gates with 0 NOT-MEASURED. Measured count: 0 for case (a) by the dev, and 0 for case (b) by the reviewer.
Follow-ups The review's one should-fix is test-helper duplication with build-override-declarations.test.ts. It is to be hoisted on the next touch of either file, carries no contract weight, and does not move this head. Serial: seat 5's PR #28728 (#28565) touches the same parity file; whichever lands second merges origin/main once (order ruling 5). This head is mergeable_state: clean.
Landing 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, with the contract review PASS on this head and 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 18:13
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 1, 2026 18:14
…E_ONLY_GATES row beside the __c judge's move to the shared set

Claude-Session: https://claude.ai/code/session_01FEkQ5oPz5wWFMzWjTGyVUb
Co-Authored-By: Claude <noreply@anthropic.com>
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 1, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

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

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: b36743d69ac312520f08eeb822628036ee86b2b7
Local-runs: none
Scope: packages/cli/src/commands/compile.ts, packages/cli/test/build-extension-field-suffix.test.ts, packages/cli/test/validate-build-gate-parity.test.ts + packages/cli/src/commands/validate.ts (steps 3a-iv and the new 3a-v, the second being what the kept ledger row claims about the build), packages/cli/src/utils/field-patch-targets.ts (findFieldPatchTargetRefusals, the #28565 walk the kept row names), packages/cli/src/utils/extension-field-suffix.ts (the walk the moved row names). Not reviewed: .changeset/28727-build-extension-field-suffix.md (prose face; byte-identical to the head already judged, re-read under ②).

Delta record, following 6561884162 (PASS on 4eb1b664, merge base db357f6d). The new head is one commit on top of that head: a merge of origin/main at 706ac52d (first parent 4eb1b664, second parent 706ac52d, which is an ancestor of origin/main), resolving the one conflict in the parity file against PR #28728 (#28565). The new merge base is 706ac52d. Everything 6561884162 judged that the merge did not touch stands as written there and is not re-argued here.

Inputs: card #28727 (body, claim 6560789923, os-dev-report 6561648987; no later comment); PR #28757 body, file list (still the same 4 files, +244/−14), commit list; the merge commit b36743d6; the interdiff diff (git diff db357f6d 4eb1b664 -- the 4 files) (git diff 706ac52d b36743d6 -- the 4 files); git diff db357f6d 706ac52d over the cited code; the head's 48 check-runs, all completed — 35 success, 13 skipped, 0 failed, 0 in progress (Test Core ×9, TypeScript Type Check, Lint & Repo Gates, Check Changeset, Governed Surface Queue Guard, PR-body guards, Dogfood Regression Gate, Build Core all green).

① Derived judgments

  1. What the merge changed in the PR's diff — the parity file only. The interdiff is empty for compile.ts, build-extension-field-suffix.test.ts and the changeset (git diff 4eb1b664 b36743d6 over those three is empty), and git diff --stat 706ac52d b36743d6 lists exactly the PR's 4 files, so the merge carries nothing of its own outside them. In the parity file two things differ from the previously judged diff: VALIDATE_ONLY_GATES is no longer {} but holds objectql: an object extension's display patch is carried and applied by mergeObjectDefinitions; a patch naming a missing field or option is refused at install and validate #28565's findFieldPatchTargetRefusals row (main's row, kept verbatim), and the docblock reads "It holds one today, findFieldPatchTargetRefusals (objectql: an object extension's display patch is carried and applied by mergeObjectDefinitions; a patch naming a missing field or option is refused at install and validate #28565), whose card did not name the build" instead of "It holds none today". The metadata-protocol + cli + install-local: __c extension fields only in a .custom package — refused at save/publish/restore, os validate, both install doors and duplicate #28564 row is still deleted and the findExtensionFieldSuffixRefusals row still sits in SHARED_NON_REGISTRY_GATES with its reason. Right — this is the order-ruling-5 resolution the claim and the previous record named as owed by whichever landed second: both rows kept, neither reworded.
  2. The ledger stays true on the head, both rows. findFieldPatchTargetRefusals is imported and called in validate.ts only (:83, :732, step 3a-v); compile.ts neither imports nor calls it (git grep over packages/cli/src at the head: validate.ts, the walk and its unit test, nothing in compile.ts). findExtensionFieldSuffixRefusals is called by both (compile.ts :824, validate.ts :703). The pins hold each row mechanically: both commands run %s (:936) for the shared row and every VALIDATE_ONLY_GATES entry is still validate-only (:1179, pruned both ways — red if validate.ts drops the call, red if compile.ts gains it) for the kept row; Test Core is green on the merged tree. The docblock's row history ("Three rows … moved … holds one today") is accurate against the sets beneath it. Right.
  3. Accept set of os build — unchanged by the merge. compile.ts at b36743d6 is byte-identical to 4eb1b664's; 3b-iii-bis still sits after the override gate (3b-iii, :778) and ahead of every write, calling the same walk over the same result.data. The build still does not run 3a-v (field-patch targets): that is the kept ledger row, a build-side gap objectql: an object extension's display patch is carried and applied by mergeObjectDefinitions; a patch naming a missing field or option is refused at install and validate #28565's card reported and did not close, outside this card's wanted list and honestly recorded. Nothing in this delta widens or narrows beyond what 6561884162 judged.
  4. Faces — still identical. The only cited code that moved between the two merge bases is validate.ts (+32: the 3a-v import and block, inserted after 3a-iv); the 3a-iv block itself is untouched, and at the head compile.ts :830–:835 and validate.ts :716–:721 carry the same printError heading and the same printBulletList row format, noun and remedy. The --json rows are validate's rows as before. The walk, artifact-packages.ts, the protocol judge, field-customization.ts, customization-package.ts, the fixture helper and the recipe test did not move between bases.
  5. Public surface — still none moved: no packages/spec/**, no packages/metadata-protocol/**, no export, type, schema or error code in the diff against 706ac52d.

② Semver level

.changeset/28727-build-extension-field-suffix.md is byte-identical to the head already judged: '@objectstack/cli': patch, line-initial Clause-②: no (narrowing) and Metadata-protocol: none, the BREAKING banner, one adr-0087: not-required (no-migration-prescription) marker; Check Changeset is green on the merged tree. The PR body's two line-initial declarations are unchanged. The merge adds no second changeset and no second narrowing. Level, Metadata-protocol: none and the no (narrowing) arm: unchanged, still right.

③ Boundary flags

④ Design judgment

The narrowing itself is the one 6561884162 judged — the build making D10's refusal real at the shipping door with one judge and one walk — and the merge leaves it as it was. The merge resolution had one design choice, how to hold two independent ledger moves in one file, and it took the right one: keep main's row as main wrote it, keep this PR's move as this PR wrote it, rewrite only the docblock's row count. A reader of the parity file on the merged tree sees an accurate history (three closed, one open) and the open row names the exact gap the build still carries.

Attempts to break it:

Findings:

  • should-fix — the two stale sentences in the PR body named under ③; a one-line edit of the body ("merged origin/main at 706ac52d in b36743d6, both ledger rows kept") on the next body touch. No verdict weight.
  • should-fix (carried from 6561884162) — the duplicated in-process run/json helpers between build-extension-field-suffix.test.ts and build-override-declarations.test.ts; hoist on the next touch of either. Unchanged by the merge.
  • must-fix — none.

Implemented-by: claude/project-thread-0fsk8u
Reviewed-by: session_01R1q2xdtYgU6FKrZ7LgjPCC

VERDICT: PASS


Generated by Claude Code

@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-01T18:43Z

Head b36743d6. This supersedes ACCEPT 6561895882 on 4eb1b664. The new head is the order-ruling-5 merge of origin/main carrying #28728 (#28565).

When the merge pushed, auto-merge was still on from the earlier arm, so the queue took b36743d6 before a record stood on it. The seat disabled auto-merge to pull it out. The delta contract review 6562245843 (CONTRACT_REVIEW_TIER) is now on this head, PASS, with no must-fix:

CI is green on b36743d6 (35 success, 13 skipped, 0 failed), and the PR is mergeable_state: clean. The review's should-fix (two stale PR-body sentences about the merge) is prose and does not move the head. The test-helper hoist is carried as before.

Landing: 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z). Auto-merge is re-enabled through the relay.


Generated by Claude Code

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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli: os build does not run the __c extension-field judge that os validate runs (#28564 follow-up)

1 participant