Skip to content

test(engine-double-contract): pin the 29 baseline entries #8639 first-measured - #8987

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-8651-engine-double-pins
Aug 16, 2026
Merged

test(engine-double-contract): pin the 29 baseline entries #8639 first-measured#8987
os-project-manager merged 1 commit into
mainfrom
claude/issue-8651-engine-double-pins

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#8651

#8639 widened this gate's discovery — implOf learned to unwrap a call-expression initializer, so every double spelling its write verb vi.fn(async …) became visible (379 → 435 doubles, +56, 0 lost). 21 of the newly visible engine-shaped doubles were pinned in #8639's own PR: every one whose pin was a single call. The other 29 (file, verb) pairs each needed more than a one-line insert and were carried as MEASURED (#8639) baseline entries naming their specific obstacle. This closes all 29 and deletes their entries in the same PR, which is what the shrink-only rule requires of a pin.

A first measurement is not a raised ratchet, and removing these entries is the ratchet tightening: 270 → 301 pinned, 162 → 133 in the DEBT ledger, 2 exempt unchanged. The checker reconciles in BOTH directions, so the pins and the deletions had to land together.

Note on the counts below. The commit message on this branch reports the first two classes as 16 entries / 12 files and 4 entries / 2 files. Those two figures are wrong and are corrected here to 17 / 15 and 3 / 2. seed-loader-driver-text.test.ts's two delete doubles return { deleted: 1 } — they are ordinary signature widening, not tripwires; only its two update doubles throw. The class descriptions and the code itself were always right, and the total is 29 either way. The branch was not amended, because force-push is unconditionally forbidden by the multi-agent discipline in AGENTS.md.

The four classes, and what each needed

Signature widening (17 entries, 15 files). The impl declared fewer than two parameters, so it had no binding to hand the predicate (delete: vi.fn(async () => ({ deleted: 1 }))). Widened to (_objectName: string, options?: any) and opened with assertEngineDeleteDispatch(options): the ten uniform packages/metadata-protocol/src/seed-loader-*.test.ts deletes, seed-loader-driver-text.test.ts's two delete doubles, packages/runtime/src/seed-loader.test.ts, packages/objectql/src/protocol-meta-type-canonicalization.test.ts, packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts (both verbs), and packages/plugins/plugin-auth/src/auth-manager.test.ts (both verbs — the sys_member reader stand-in).

Concise arrow bodies (3 entries, 2 files). Expression-bodied arrows with no statement list: protocol.dropped-fields.test.ts and seed-loader-env-scope.test.ts were converted to block bodies first, then pinned.

Deliberate tripwire doubles (3 entries, 2 files).protocol.validate-data.test.ts (both verbs) and the two update doubles in seed-loader-driver-text.test.ts open by throwing, because the test asserts the path performs no write at all. The predicate is inserted AHEAD of the throw, which preserves the assertion's meaning in both directions: on a passing suite the body still never runs, and a call that did arrive still fails the test — only WHICH of the two errors it raises could differ, and nothing in either file asserts on that text. Measured rather than assumed: both suites are green, so the seed loader's real pass-2 back-fill update satisfies ObjectQL.update's dispatch contract rather than merely being tolerated by a looser double.

@objectstack/mcp (6 entries, 3 files). The package depended on neither home of the predicate, so @objectstack/metadata-core is added as a devDependency (no cycle — metadata-core does not depend on mcp), and the three doubles needed widening on top.

Two follow-on edits the gates asked for

packages/mcp/vitest.config.ts is NEW. The devDependency above is a value import, and @objectstack/metadata-core resolves through its exports to dist/, so pnpm check:test-source-alias correctly failed: without an alias these pins would judge metadata-core's build artifact rather than the source in the checkout — a dist merely BEHIND rather than missing the predicate would let every new pin run green against its old behaviour. One anchored array-form entry, matching plugin-sharing's shape.

The baseline's $comment closing paragraph asserted that 29 MEASURED (#8639) entries exist "below". All 29 are gone, so it is rewritten to record the batch as closed while keeping the discovery history that makes 379 → 435 readable to the next author.

Verification

Every affected package's own suite, on this branch after a full pnpm build (exit status, not just output):

packagefilestestsexit
@objectstack/metadata-protocol10615120
@objectstack/mcp192000
@objectstack/objectql21137210
@objectstack/plugin-auth5412500
@objectstack/runtime16524560

No pin turned a suite red. mcp was re-run after the alias landed, so its 200 tests are a verdict about metadata-core's source.

Gates, derived from the changed paths with scripts/pm/dispatch-gates.mjs: check:engine-double-contract 0, check:nul-bytes 0, check:cross-package-test-inputs 0, check:durability-log-level 0, check:test-source-alias 0 (1 before the vitest config, 0 after), check:type-source-resolution 0, check:query-options-erasure 0, check:type-check-coverage 0, check:type-check-debt --re-measure 0, check-engine-split-ratio 0.

PM verification before opening

This PR was opened by the domain:devx PM seat because the implementing session had a blanket GitHub API 403 (git push worked; issue reads, labels and PR creation did not). Re-verified from the pushed branch before opening, by content:

skip-changeset: test files, a shrink-only ledger, a vitest config and a workspace-internal devDependency — nothing user-visible is released.


Generated by Claude Code

…-measured
Fixes#8651#8639 widened this gate's discovery — `implOf` learned to unwrap a
call-expression initializer, so every double spelling its write verb
`vi.fn(async …)` became visible (379 → 435 doubles, +56, 0 lost). 21 of the
newly visible engine-shaped doubles were pinned in #8639's own PR: every one
whose pin was a single call. The other 29 (file, verb) pairs each needed more
than a one-line insert and were carried as `MEASURED (#8639)` baseline entries
naming their specific obstacle. This closes all 29 and deletes their entries in
the same PR, which is what the shrink-only rule requires of a pin.
A first measurement is not a raised ratchet, and removing these entries is the
ratchet tightening: 270 → 301 pinned, 162 → 133 in the DEBT ledger, 2 exempt
unchanged. The checker reconciles in BOTH directions, so the pins and the
deletions had to land together.
## The four classes, and what each needed
**Signature widening (16 entries, 12 files).** The impl declared fewer than two
parameters, so it had no binding to hand the predicate
(`delete: vi.fn(async () => ({ deleted: 1 }))`). Widened to
`(_objectName: string, options?: any)` and opened with
`assertEngineDeleteDispatch(options)`: the ten uniform
`packages/metadata-protocol/src/seed-loader-*.test.ts` deletes,
`packages/runtime/src/seed-loader.test.ts`,
`packages/objectql/src/protocol-meta-type-canonicalization.test.ts`,
`packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts` (both
verbs), and `packages/plugins/plugin-auth/src/auth-manager.test.ts` (both
verbs — the `sys_member` reader stand-in).
**Concise arrow bodies (3 entries, 2 files).** Expression-bodied arrows with no
statement list: `protocol.dropped-fields.test.ts` and
`seed-loader-env-scope.test.ts` were converted to block bodies first, then
pinned.
**Deliberate tripwire doubles (4 entries, 2 files).** `protocol.validate-data.test.ts`
(both verbs) and the two `update` doubles in `seed-loader-driver-text.test.ts`
open by throwing, because the test asserts the path performs no write at all.
The predicate is inserted AHEAD of the throw, which preserves the assertion's
meaning in both directions: on a passing suite the body still never runs, and a
call that did arrive still fails the test — only WHICH of the two errors it
raises could differ, and nothing in either file asserts on that text. Measured
rather than assumed: both suites are green, so the seed loader's real pass-2
back-fill `update` satisfies `ObjectQL.update`'s dispatch contract rather than
merely being tolerated by a looser double.
**`@objectstack/mcp` (6 entries, 3 files).** The package depended on neither
home of the predicate, so `@objectstack/metadata-core` is added as a
devDependency (no cycle — metadata-core does not depend on mcp), and the three
doubles needed widening on top.
## Two follow-on edits the gates asked for
`packages/mcp/vitest.config.ts` is NEW. The devDependency above is a value
import, and `@objectstack/metadata-core` resolves through its `exports` to
`dist/`, so `pnpm check:test-source-alias` correctly failed: without an alias
these pins would judge metadata-core's build artifact rather than the source in
the checkout — a dist merely BEHIND rather than missing the predicate would let
every new pin run green against its old behaviour. One anchored array-form
entry, matching `plugin-sharing`'s shape.
The baseline's `$comment` closing paragraph asserted that 29 `MEASURED (#8639)`
entries exist "below". All 29 are gone, so it is rewritten to record the batch
as closed while keeping the discovery history that makes 379 → 435 readable to
the next author.
## Verification
Every affected package's own suite, on this branch after a full `pnpm build`
(exit status, not just output):
| package | files | tests | exit |
|---|---|---|---|
| @objectstack/metadata-protocol | 106 | 1512 | 0 |
| @objectstack/mcp | 19 | 200 | 0 |
| @objectstack/objectql | 211 | 3721 | 0 |
| @objectstack/plugin-auth | 54 | 1250 | 0 |
| @objectstack/runtime | 165 | 2456 | 0 |
No pin turned a suite red. mcp was re-run after the alias landed, so its 200
tests are a verdict about metadata-core's source.
Gates, derived from the changed paths with `scripts/pm/dispatch-gates.mjs`:
`check:engine-double-contract` 0, `check:nul-bytes` 0,
`check:cross-package-test-inputs` 0, `check:durability-log-level` 0,
`check:test-source-alias` 0 (1 before the vitest config, 0 after),
`check:type-source-resolution` 0, `check:query-options-erasure` 0,
`check:type-check-coverage` 0, `check:type-check-debt --re-measure` 0,
`check-engine-split-ratio` 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRfF9Cmb2oTwan7jNoV2ce
@os-project-manageros-project-manager added tests tooling skip-changeset PR has no user-facing published change; bypasses the changeset gate labels Aug 16, 2026 — with Claude
@vercel

vercelBot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 16, 2026 4:12am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/mcp.

11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx(via @objectstack/mcp)
  • content/docs/ai/agents.mdx(via @objectstack/mcp)
  • content/docs/ai/connect-mcp.mdx(via @objectstack/mcp)
  • content/docs/ai/index.mdx(via @objectstack/mcp)
  • content/docs/ai/natural-language-queries.mdx(via @objectstack/mcp)
  • content/docs/api/index.mdx(via @objectstack/mcp)
  • content/docs/deployment/environment-variables.mdx(via @objectstack/mcp)
  • content/docs/permissions/authorization.mdx(via @objectstack/mcp)
  • content/docs/permissions/system-context.mdx(via packages/mcp)
  • content/docs/plugins/packages.mdx(via @objectstack/mcp)
  • content/docs/protocol/knowledge.mdx(via @objectstack/mcp)

1 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/mcp)

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.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31926760953 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/3) — 失败步骤: Run this shard's tests

    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[41m�[1m FAIL �[22m�[49m test/cloud-login-json-ndjson.e2e.test.ts�[2m > �[22mthe exception stays declared, not just implemented (#6730 ruling)�[2m > �[22mdocuments the exception where the cloud login
    

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 2 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@os-project-managerClaude

Copy link
Copy Markdown
CollaboratorAuthor

分诊:本 PR 的队列失败是同批次连带,不是本 PR 的缺陷,也不是 flaky

队列构建 31926760953 红在 packages/cli/test/cloud-login-json-ndjson.e2e.test.tsdocuments the exception where the cloud login step is prescribed

实测三条,足以定性

判据实测
本 PR 是否碰该测试读的文件(content/docs/deployment/index.mdx)0
本 PR 是否碰 content/docs 下任何文件0
origin/mainindex.mdx 是否满足该测试的三条正则NDJSON 1 · one per line 1 · #os-cloud-login 1 —— 全部满足

⇒ 本 PR 的改动面(测试文件、scripts/turbo.jsonpackages/mcp/package.json + 新 vitest.config.ts)与该断言没有任何接触路径,而 main 本身是绿的。本 PR 单独构建不可能红在这里。

真正的来源

PR #8983 重写了 content/docs/deployment/index.mdx,措辞从 main 的「compact JSON documents, one per line」变成「one compact JSON document per line」,/one\s+per\s+line/i 因此不匹配。那是一处真回归,已定位并交回该 PR 的实现者修复;#8983 已于 04:39:37Z 出队。

本 PR 的队列候选是叠在 #8983 之上构建的(grouped queue),于是继承了那份坏掉的 index.mdx。出队通知自己也写了这一点:"In a grouped queue the failure can come from another PR in the same batch."

⚠️ 分诊清单第 2 条在这里会给出错误结论,记录下来

清单写着:「失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。」

同名测试确实出现在 #8983 的同类评论里。但它出现在那里不是因为它 flaky,而是因为真回归就在那张 PR 上。照第 2 条字面执行,会去隔离一条完全健康、且正在正确履职的测试 —— 它恰恰抓到了一个 PR 侧 CI 结构上看不见的文档回归(#8983 不改任何包,affected 子集跑不到它)。

「同名测试在别处出现过」不足以判 flaky。 还要问:在那张 PR 上它是真红还是同样连带?真红 ⇒ 本次是连带,等那张出队即可(第 3 条);两边都无关且都红 ⇒ 才是 flaky。这两种情形在清单里目前合并在同一条下。

处置:等,不重排

按第 3 条:污染源 #8983 已出队,下一次为本 PR 构建的候选不会再含它。⛔ 不做连续重排 —— 每次盲排都让排在后面的所有 PR 重建一轮。auto-merge 仍开着;若自动重排未发生,我会只排一次


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filesize/mskip-changesetPR has no user-facing published change; bypasses the changeset gateteststooling

Projects

None yet

2 participants

@os-project-manager@claude