Skip to content

fix(cli): resolve packages[] at the four config-load boundaries and the gates that key off config.objects - #15228

Merged
hotlong merged 3 commits into
mainfrom
claude/issue-15006-cli-config-load-boundaries
Sep 4, 2026
Merged

fix(cli): resolve packages[] at the four config-load boundaries and the gates that key off config.objects#15228
hotlong merged 3 commits into
mainfrom
claude/issue-15006-cli-config-load-boundaries

Conversation

@hotlong

@hotlong hotlong commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15006

Reader program 3/4 of the ADR-0130 D4 option-B ruling (#14512 comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card: no command emits anything different, composeStacks and packages/spec/src/stack.zod.ts are untouched.

What was broken

@objectstack/cli holds four independent config-load boundaries, and every read of a package-owned collection behind them was an inline expression against the FLATTENED top level. A stack that carries each definition once under packages[] reached those expressions with the key simply absent — and nothing threw.

Site before What an option-B stack got
ObjectQL engine auto-registration serve.ts:2632 if (config.objects && !hasObjectQL) no query engine, boot reports healthy
Storage-driver auto-registration serve.ts:2669 if (!hasDriver && config.objects) no storage driver, same silence
i18n service auto-registration serve.ts:2976-2995 REST i18n routes absent
readArtifactObjects() dev.ts:653-666 inventory permanently empty; every recompile reads all-green
union author-time rule run compile.ts:344 rules judge an empty stack; os build publishes green
configHasMetadata, twice — serve.ts:2802 and os migrate's own second loadConfig at schema-migration-plugins.ts:1094 measured: does not losemanifest is an envelope key

Nothing between the artifact and the two serve.ts gates could notice the loss: standalone-stack.ts:785 omits the objects key entirely when the array is absent (not []), and mergeBootConfig is a plain spread.

The seam

packages/cli/src/utils/stack-collections.ts — one module, one resolution rule, seven exports. Two properties make it safe to land:

  1. Every predicate starts from the expression it replaced. if (stack.objects) return true; is byte-identical to the old gate; packages[] is consulted only where the old read already returned nothing. So no stack that boots or builds today can take a different branch. That ordering is load-bearing, not stylistic: config.objects is truthy for an EMPTY array, so a stack declaring objects: [] gets an engine today. Re-expressing the gate as resolve(...).length > 0 would have quietly stopped doing that — reintroducing "boots with no query engine" in a different case. Pinned in stack-collections.test.ts.
  2. It is CALLABLE. That is the other half of the card. The reader program 1/4 — the option-B acceptance probe: a two-package fixture booted through every entry path with the flattened collections absent #15004 probe could not reach an expression inside an oclif command body, which is exactly why these four sites sat outside its 24-row ledger (reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006 comment 5530257178). The probe now calls the DECISION each command makes — the whole gate, plugin duck-typing included, because what silently fails is the decision and not the count.

Package order comes from resolveArtifactPackageOrder (@objectstack/core, #14643) — never re-derived. Its ADR-0112 refusal for a malformed packages is deliberately not swallowed: it is reachable only once the caller's own expression has come back falsy, i.e. only on the shape that boots silently broken today.

The package-owned collection key set the os build fold needs is derivedObjectStackDefinitionSchemaAssembledPackageBodySchema, the same reconciliation packages/spec/src/assembled-package-body.test.ts performs — never hand-listed, so a collection family added to the stack schema next month joins the fold without anyone remembering to. (#14877 would let it read that set as an export instead.)

The ledger: 24 rows, unchanged. Zero deleted, zero added.

No OPTION_B_LOSSES row was deleted or added. That is the correct outcome and worth stating plainly, because "which rows did you delete" is the usual question for this program:

Six new rows enter the probe. Five were RED before this change and are GREEN after, so none enters the ledger; the sixth was green in both shapes and stays green.

Reverse verification — the new rows are a measurement, not decoration

Committed first (38d97fb90), then ablated with a trap-restored script using absolute paths. The mutation removes the option-B leg at one anchor (packageBodies returns []), and was confirmed on disk before the run: injected marker occurrences 1, blob a85e9f16… different from the HEAD blob 2577e5d5…. No rebuild is in the path — the pin reaches this module by RELATIVE path from inside @objectstack/cli (test/fixtures up to ../../src/utils), so vitest transforms the source and no dist/ copy participates.

Ablated pin: 1 failed | 6 passed. The one failure is THE PIN, naming exactly the five rows this change fixes:

A subsystem lost a collection that the ledger does not carry …
  B1 · cli dev artifact object inventory (readArtifactObjects recompile diff) · objects
  B2 · cli serve ObjectQL engine auto-registration gate (from source) · objects
  B2 · cli serve i18n service auto-registration gate (from source) · translations
  B2 · cli serve storage-driver auto-registration gate (from source) · objects
  B3 · cli build union author-time rule input (os build) · every package-owned collection
…
  LOST     B2 · cli serve ObjectQL engine auto-registration gate (from source) · objects = NO QUERY ENGINE registered
  LOST     B2 · cli serve storage-driver auto-registration gate (from source) · objects = NO STORAGE DRIVER registered
  present  B2/B4 · cli AppPlugin wrap gate (configHasMetadata — serve and migrate) · … = AppPlugin wrap composed
  LOST     B2 · cli serve i18n service auto-registration gate (from source) · translations = NO i18n plugin — REST i18n routes absent
  LOST     B1 · cli dev artifact object inventory (readArtifactObjects recompile diff) · objects = 0
  LOST     B3 · cli build union author-time rule input (os build) · every package-owned collection = 0

In that SAME run the additive BASELINE, the packages[] anti-vacuity CONTROL, the shape-derivation test, the phantom-ledger test, the five-boundary test and the new #15006 representation test all passed — which is what makes the red a discrimination rather than a broken fixture. Restore proved by an empty git diff HEAD and a blob hash byte-identical to HEAD.

One site deliberately NOT fixed

plugins and devPlugins are package-owned collections by the same derivation every row here uses, and serve.ts:2622 / schema-migration-plugins.ts:1082 read them off the top level only. The mechanical repair is wrong there: packages[i].manifest.plugins in a JSON artifact is inert data where kernel.use() needs a live instance, and whether a live-object collection belongs in the package-owned key set at all is a packages/spec question upstream of every reader in this program. Filed as #15219, named in the pin's header, and left alone here. The zoo declares no plugins, so no probe row covers it — adding one would pin a shape that may be about to change.

Docs drift — hand-read, not anchor-listed

The drift bot reports 1 package, 22 documentable anchors, 40 hand-written pages, 5 release-owned pages. Re-derived on this worktree: 45 pages, the same split.

The 5 release-owned pages (releases/v12, v13, v14, v16, v17) are untouched and stay untouched. Release notes are written centrally at release time; this PR's input to them is its changeset.

The bot's own note says an anchor list cannot reach a page that states a rule by its inputs, because such a page shares no identifier with the emitter. This diff changes exactly that kind of rule — "whether config.objects exists decides if the engine and driver auto-register" — so the rule-restating pages were read by hand, searched by the rule's INPUTS across all of content/docs minus releases/: auto-register / automatically registers, config.objects, top-level objects, I18nServicePlugin + translations, author-time rules, packages[] / multi-package, recompil.

Page What it states Verdict
plugins/index.mdx:238 os dev on a minimal config auto-registers ObjectQL, the default datasource, AppPlugin, HonoServer and the REST API still true — that config declares top-level objects, and the first clause of both gates is byte-identical to the expression it replaced
deployment/cli.mdx:206-208 tier presets gate optional plugin auto-registration; "any plugin already present in config.plugins always wins" still true — the already-composed check moved into the seam unchanged, both halves of it
data-modeling/drivers.mdx:55 the driver KIND is inferred by the CLI from the URL scheme untouched — resolveDriverType is not in this diff; what moved is the gate on whether to build one at all, which no page states
kernel/services-checklist.mdx:428 DevPlugin auto-wires I18nServicePlugin when the stack declares translations true, and NOT this diff — that is @objectstack/plugin-dev's own reader, already filed as a site of #15210
getting-started/examples.mdx:352-432 a project compiles to one artifact carrying packages[]; registration order is topological from dependencies, never array order still true, and this diff honours it — the fold reads resolveArtifactPackageOrder, the same topological order this page describes
deployment/cli.mdx:456, deployment/validating-metadata.mdx:558, ui/react-pages.mdx:380, getting-started/build-with-claude-code.mdx:266 transcripts printing → Running author-time rules (41)... still true — the count is authoringRulesFor('build').length, untouched, and the fold changes the rules' INPUT, not the table or the step line
protocol/kernel/plugin-spec.mdx:187,652 a package manifest declares its objects through top-level globs authoring-time, upstream of every reader here

No page is falsified, and the reason is a property rather than an inspection: this change is strictly additive on every shape the platform emits today. Each predicate's first clause is the expression it replaced, and authoringRuleUnionStack returns the stack BY IDENTITY whenever the top level carries its collections — measured on the acceptance fixture and on the real build-multi-package-artifact / compile-artifact-packages e2e runs. Behaviour moves only on the option-B shape, which nothing emits yet and which no page documents.

Verification

All at dbe2fa58a (final commit). Gate family re-derived there with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands — identical to the earlier derivation: 9 paths, 46 runnable commands — and the union re-run whole on that head.

Run Reading
gate family 46 of 46 exit 0. Named because they were PREREQUISITE NOT MET on an earlier pass and are MEASURED here: check:i18nOK (9 package(s) — all bundles in sync, no undeclared authoring keys); check:i18n-coverageOK (13 config(s), 691 baselined untranslated string(s), none new); check:dual-build-cjs-loadsOK — 102 published require entry point(s) across 66 package(s) load
ratchets check:type-check-debtOK — 16 ledger entr(ies) re-measured in 223.4s, 207 raw tsc error(s) total, none above its recorded number, surplus: none. check:type-check-coverageOK — 73/79 workspace packages type-checked. check:type-source-resolutionOK — 120 tsc program(s) across 78 packages scanned. check:test-source-aliasOK — 72 packages with tests scanned
pnpm --filter @objectstack/cli typecheck exit 0; check:test-typecheck reports 3 file(s) / 28 error(s) / 6 pinned signature(s) — byte-identical to the committed test-typecheck-debt.json, so zero new diagnostics. tsc --noEmit --listFiles confirms both new files are in the program (1 hit each), so "typecheck is clean" is a statement ABOUT them
the suites this diff reaches Test Files 8 passed (8) / Tests 75 passed (75) — the seam's contract, merge-boot-config, the acceptance pin, authoring-rule-command-parity, compile-artifact-packages.e2e, build-multi-package-artifact.e2e, format-zod-union, hook-body-build-reach.e2e. Plus a second targeted run over the units for the edited command files — Test Files 8 passed (8) / Tests 83 passed (83): serve-automation-shadowing, serve-i18n-load-diagnostic, serve-driver-banner, serve-host-config-security-registrar.pin, serve-settings-ordering.pin, database-driver-flag-derivation, dev-default-db, graft-runtime-hooks
roster gates my paths sit inside check-stack-collection-maps (8 enumerations reconciled against the schema), check-changeset-fixed, check:authz-resolver, check:error-code-casing, check:filter-alias-parity, check:swallow-census-controls — all exit 0. Named because dispatch-gates scores them "silent" on a roster, which is a fact about a list rather than a clearance

Every exit code above was captured before any pipe.

Declared narrowing. The whole 224-file @objectstack/cli suite was started and deliberately terminated at 34 minutes (SUITE_EXIT=130), because it was holding the shared verification lock with a sibling agent queued behind it. Its partial output named two failures — format-zod-union.test.ts (1) and hook-body-build-reach.e2e.test.ts (2) — with file durations of 666s and 747s against 120s per-test timeouts, i.e. timeout signatures rather than assertions. Both files pass in the targeted runs above, so the classification is contention, not this diff. CI runs the suite whole regardless.

⚠️ One reading was thrown away rather than reported: a first typecheck returned TS7016 for @objectstack/client, whose dist/index.d.ts was being rewritten at that instant by check:type-check-debt's own build closure running unlocked beside it. The file was present, and re-measured, typecheck is clean. Recorded because it is the same shape as #15042 (a package's .d.ts "vanishing" after a green build) and offers that card a concrete cause: a concurrent rebuild in the same worktree, read through tsup's non-atomic write window.

The B2/B3/B4 shared-helper question, measured rather than assumed

The card left open whether the three config loads can collapse into one helper (serve.ts calls bundleRequire; compile.ts:211 and schema-migration-plugins.ts:1083 call loadConfig). Measured: the loaders are not the problem and were not touched. All three load an ordinary module and hand its export on unchanged — the collection loss is in the READERS each of them then drives, which is what this PR moved. That refactor stays unmade and out of this card.


🤖 Generated with Claude Code

https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m

… the gates that key off `config.objects`

The CLI holds four independent config-load boundaries, and every read of a
package-owned collection behind them was an inline expression against the
flattened top level. A stack carrying each definition once under `packages[]`
reached those expressions with the key absent, and nothing threw: `os serve`
booted with no query engine and no storage driver, its i18n plugin never
registered, `os dev`'s recompile inventory went permanently empty, and `os
build`'s union author-time rule run judged an empty stack and published green.

One seam (`utils/stack-collections.ts`) now answers all of them, in
`resolveArtifactPackageOrder`'s dependency order. Each predicate starts from the
expression it replaced, so every stack that boots or builds today takes the
identical branch — including one declaring an empty `objects: []` — and
`packages[]` is consulted only where the old read returned nothing.

Being callable is the other half of the point: the #15004 acceptance probe could
not reach an expression inside an oclif command body, which is why these four
sites sat outside its ledger. The probe now carries a row per site that calls the
decision each command makes.

No command emits anything different. `OPTION_B_LOSSES` is unchanged at 24 rows:
none of them names a cli reader.

Part of #15006

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
…eaves alone

`plugins` / `devPlugins` are package-owned collections that `serve.ts` and
`schema-migration-plugins.ts` read off the top level only, and the mechanical
repair is wrong there: `packages[i].manifest.plugins` in a JSON artifact is inert
data where `kernel.use()` needs a live instance. Whether a live-object collection
belongs in the package-owned key set at all is a `packages/spec` question
upstream of every reader in this program, so the pin's header points at #15219
instead of at this card's report.

Part of #15006

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
…lection key

`resolveArtifactPackageOrder` parses every `packages[]` entry whole, and the
`os build` union fold asks about all 37 package-owned collections — so the first
cut ran that parse 38 times per build, and the `AppPlugin` wrap gate ran it four
times per boot. The bodies are resolved once and handed to `collectFrom`, which
is the only shape that changed; every answer is identical.

Also corrects the probe's note: six rows enter, not four. The two beyond the
card's named sites are the reads sitting beside them on the same boundaries —
the `AppPlugin` wrap gate, which measured does NOT lose, and the i18n
auto-registration gate, which does.

Part of #15006

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
@github-actions github-actions Bot added the size/l label Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

40 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 9c1bcda382067e75e2d69f11086d6c986ccb987a.

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

What this run could not see
  • 3 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 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.

Coarse fallback — 22 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 9c1bcda382067e75e2d69f11086d6c986ccb987apackageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 9c1bcda382067e75e2d69f11086d6c986ccb987a

⚠️ 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 9c1bcda382067e75e2d69f11086d6c986ccb987a → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026

hotlong commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

复审 PASS —— 三个 open question 全裁给实施席;另有两处它自己发现的东西,比卡面要求的更进一步

PM 席(epic #14122,session session_01UHvF5hyiZjnCyExFnfQB8m)。同会话披露:本 PR 由我派发,这是同会话复审,不是独立复审。

三条硬约束逐条核过(读 diff,不是只看 pin 绿)

  1. OPTION_B_LOSSES 逐字节相同——零增零删。 我把 main 与本 PR 的台账数组整段 diff 过,无差异。集合相等断言、各子系统断言、夹具都没动。探针文件的 +65 全部是新增测量行 + 注释重写
  2. artifact 仍 additive。 composeStackspackages/spec/src/stack.zod.ts、任何命令的输出都没动;折叠出的 stack 是规则的输入,到不了任何写入方。
  3. 五个红转绿的站点都是真修好的。 新接缝 packages/cli/src/utils/stack-collections.ts 把决策本身导出(不只是集合读取),探针的行调用命令真正做的那个判断,不是照抄它。

两处比卡面要求更进一步的东西,记下来

一、空数组的陷阱。 每个谓词先答调用方的原始表达式,只在它 falsy 时才查 packages[]。理由写在实现里:config.objects空数组是 truthy,若把门重写成 resolve(...).length > 0,一个声明 objects: [] 的 stack 就不再注册引擎——恰好引入这张卡要消除的那个故障。这个坑很细,机械修复必踩。

二、它补上了探针设计里我没想到的一个洞。 新加的 #15006 — the four cli reads ... are each represented 测试,理由是原话:

the pin asserts set EQUALITY against the ledger, so a row that stopped being measured while it was GREEN would take nothing red with it.

对。集合相等保护「还在丢的」和「刚修好的」,但一个绿着的行被悄悄移除测量,集合依然相等,pin 不会红。这是我在定探针验收时漏掉的失效模式,它自己发现并用 toContain 堵上了。

它也把「⛔ 不得用 config.objects 断言充数」这条禁令保留并搬到新行旁边,而不是随着「已覆盖」把它删掉——下一个人还会读到。

Open question 1 —— 零删台账行:裁 A,零是正确答案

24 行里没有一行是 cli 读取方,全是 @objectstack/runtime@objectstack/plugin-security 的。cli 自己的读从来不在台账里,正因为探针够不着它们——这恰恰是评论 5530257178 存在的理由。

⛔ 选项 B(删 B1 · createStandaloneStack surfaced objects,因为它的标签点了这两个门)被拒绝是对的,而且拒绝的依据是测量而非读法:option-B 产物下 createStandaloneStack 的结果键只有 ["api","manifest","plugins"],既没 objects 也没 packages,所以 cli 侧任何接缝都解析不了 runtime 从没 surface 的东西。删一个自己没修的读取方的行,正是我反复警告的「人为对齐台账」——它没上钩。那行是 #15005 的。

Open question 2 —— 多做的两处(i18n 门 + configHasMetadata):裁 A,保留

i18n 门确实会丢(实测:additive true、option-B false),且就在卡面站点表里。configHasMetadata 不丢(manifest 是信封键,活下来了),但它是 AppPlugin 之后读取的每个集合的总闸,是 B4(os migrate 自己的第二个 loadConfig)唯一的读取方,而且此前是两份会漂移的拷贝、它们自己的注释还说是同一个谓词。选 B 会让 B4 连一个可调用的读取方都没有,os migrate 就继续留在所有探针之外——这个程序反复重新发现的正是这种缺口。

Open question 3 —— 没花调用直读 #14512 那三条评论:裁 A,可接受

主动 flag 而不是埋掉,这点先记一功。实质理由成立:零配额通道探测过且够不着(323KB 载荷 0 命中),三条评论的内容已逐行转写在它读全了的卡面上,并且用更强的来源交叉核对过——#15210 的按形状扫描后出于两次枚举,且按形状而非按包名搜索。补这一次调用改变不了任何已落地的东西。

#15219:故意不修,判断正确

plugins / devPlugins 按同一套推导也是 package-owned 集合,却只从顶层读。它没有机械修复,理由是:产物路径上 packages[i].manifest.plugins惰性 JSON,而调用点 kernel.use() 期待的是活的插件实例——照搬其他站点的修法会把「静默跳过」变成「启动时注册垃圾」。修复比缺陷更糟,这种时候停手并另立卡是对的。它还指出真正的问题在上游:一个装活对象的集合到底该不该进 package-owned 键集,那是 packages/specCOMPOSE_KEY_DISPOSITIONS 决定。

其余核过

  • 46/46 门禁 exit 0,且三条此前 PREREQUISITE NOT MET 的在构建闭包就绪后重测为 MEASURED 并通过,而不是留着当「不算失败」。
  • 消融验证:明确陈述重建不在解析路径上(pin 以相对路径直达 src,vitest 转译源码,dist 不参与)——这是容易搞错且必须说清的一点。消融后只有 pin 一个失败且点名五行,同一轮里 baseline、anti-vacuity control、形状推导、幻影台账、五边界等测试全绿——这才使那个红是区分度而非夹具坏了。恢复以空 git diff HEAD 与 blob 逐字节相同证明。
  • 申明的收窄诚实:224 文件的 cli 全套跑了 34 分钟被主动终止(持共享验证锁、有兄弟排队),部分输出里两个文件的失败是 666s/747s 对 120s 超时的超时签名而非断言失败,且两文件在定向运行中都过 —— 分类为争用而非本 diff。
  • 丢掉了一次假测量而不是上报:TS7016(@objectstack/clientdist/index.d.ts 正被并发重建改写),重测干净,并把成因作为 [finding] @objectstack/service-cluster's dist/*.d.ts vanished AFTER its own build reported 3/3 declared declaration file(s) present — a downstream typecheck then failed TS7016 against a package that had built green #15042候选(那张卡的成因明说未确立)而非新立卡。

CI 在报告时的状态未收敛。全绿后我翻 ready。⛔ 不 approve、不挂 auto-merge。


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 4, 2026 07:03
@hotlong
hotlong added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 1226f2e Sep 4, 2026
38 checks passed
@hotlong
hotlong deleted the claude/issue-15006-cli-config-load-boundaries branch September 4, 2026 09:01
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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects

2 participants