Skip to content

fix(spec,cli): govern the QA testing domain and enforce TestSuiteSchema at the os test load site (#6247) - #7255

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6247-qa-testing-enforce
Aug 10, 2026
Merged

fix(spec,cli): govern the QA testing domain and enforce TestSuiteSchema at the os test load site (#6247)#7255
os-zhuang merged 2 commits into
mainfrom
claude/issue-6247-qa-testing-enforce

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Executes the standing maintainer ruling on #6247, verbatim:

Maintainer ruling (2026-08-08): Option A — enforce. The 2026-08-07 retire ruling is withdrawn.

The earlier retire ruling rested on a "zero runtime consumers" reading that the sweep dev's pre-flight gate falsified: the original grep scanned only *Schema identifiers and missed type-name consumers. The actual state is a complete execution chain (packages/core/src/qa/runner.ts TestRunner, http-adapter.ts action switch, published through core's index) plus the shipped CLI command os test with public docs. Per ADR-0049 enforce-or-remove: when the evidence flips, the leg flips with it.

Scope (option A per the 2026-08-08 04:36Z re-ruling request):

  • Add the packages/spec/liveness/qa.json ledger entry.
  • Replace the type-assertion load site in the CLI test command (currently a JSON.parse cast straight to QA.TestSuite) with a real TestSuiteSchema.parse(), plus pin.

⚠️ The 2026-08-07 retire ruling is WITHDRAWN — do not resurrect it. The issue thread flips mid-way: comment 5219849000 (2026-08-07) ruled retire, and comment 5225532429 (2026-08-08, quoted above) withdrew it in favour of enforce. The operative ruling is the last one. Nothing in this PR removes any part of the QA surface, and a review comment asking why the domain wasn't retired is answered here rather than in the thread.


Premise re-measurement (fresh origin/main @ f40c5b4)

Every premise the ruling rests on was re-measured in a clean worktree before any edit:

Premise Measured Result
No packages/spec/liveness/qa.json exists ls packages/spec/liveness/ — 29 ledgers, no qa.json ✅ holds
The CLI load site still carries the cast + TODO packages/cli/src/commands/test.ts:98JSON.parse(content) as QA.TestSuite; // Should validate with Zod ✅ holds
The runner reads suite/scenario/step fields packages/core/src/qa/runner.ts:27, 41, 62, 86, 101, 112, 118, 125 ✅ holds
The adapter switches on action.type = TestActionTypeSchema values packages/core/src/qa/http-adapter.ts:21-38 ✅ holds
Published via export * as QA packages/core/src/index.ts:25 ✅ holds
Driven by the shipped os test command packages/cli/src/commands/test.ts, content/docs/deployment/cli.mdx:987,1012-1020, packages/cli/README.md:104 ✅ holds (docs path is deployment/cli.mdx, not references/cli.mdx as the re-ruling request cited — same content, same line numbers)
qa is not a registered metadata type absent from listMetadataTypeSchemaTypes(); the gate reports no ungoverned entry for it ✅ holds → needs the SPEC_ONLY_SCHEMAS route, like query / webhook / validation

The whole finding turns on one thing worth repeating: the original grep scanned *Schema identifiers, and every consumer in this domain reads the TYPE names (QA.TestSuite, QA.TestScenario, QA.TestStep, QA.TestAction, QA.TestAssertion). The full reference set is four files and the search matched none of them. The evidenceScope section of the liveness README already says no amount of specifier matching is sufficient for a negative claim (#4895 case 4); this is the same lesson one level over, for identifier matching.

Changes

File Change
packages/spec/liveness/qa.json new — the ledger. 9 verdicts at the gate's granularity: 4 live with file:line evidence into the runner, 5 dead. scenarios is DRILLED via children, so no undrilled-containers.baseline.json row is needed.
packages/spec/scripts/liveness/check-liveness.mts qa added to GOVERNED + SPEC_ONLY_SCHEMAS (TestSuiteSchema), with the rationale comment the other three overrides carry. Without this the ledger file would be inertloadLedger is only called for governed types, so an ungoverned qa.json would be documentation nothing checks, which is the exact sin the issue reports.
packages/cli/src/commands/test.ts loadTestSuite()TestSuiteSchema.safeParse at the load boundary, replacing the cast. Bad JSON and schema failures both throw an error naming the file, listing the issues and quoting the expected shape. Wired ahead of the run branch so a refusal is reported as a refusal, not as a run failure; a broken suite is one failed suite, not a dead command.
packages/cli/test/qa-suite-schema-load.test.ts new — the pin (6 cases).
packages/spec/liveness/README.md qa row in the state table + heading count.
.changeset/qa-testing-liveness-enforce.md one non-major changeset (spec minor, cli patch).

What the ledger actually says

live (4): scenarios.id, scenarios.setup, scenarios.steps, scenarios.teardown — each citing the runner line that reads it.

dead (5), measured, not assumed:

  • name (suite) — runSuite touches only suite.scenarios; the CLI prints path.basename(file). The file name is the suite identity today.
  • scenarios.name — its describe() says "Scenario name for test reports" and no report carries it: TestResult has scenarioId and no name field. An author who writes a careful name and a terse id gets the terse one in every failure line.
  • scenarios.description — docs-shaped, kept (ADR-0033), same disposition as flow.description.
  • scenarios.tags — promises "Tags for filtering and categorization" and nothing filters: os test has exactly two flags (--url, --token). Enforce-or-remove worklist.
  • scenarios.requires — declares params / plugins preconditions nothing checks. A suite naming an absent plugin runs anyway and fails later as an unexplained HTTP error. Enforce-or-remove worklist.

Three deliberate calls a reviewer should check rather than skim:

  1. No authorWarn anywhere, on purpose. tags and requires are exactly the misleading shape the flag exists for — but the author-side lint (packages/lint/src/lint-liveness-properties.ts) walks stack collections (stack.flows, stack.views, …) and a QA suite is a loose file in no stack. Marking them would produce a warning nothing can emit: a silent no-op inside the mechanism built to catch silent no-ops. Recorded as _authorWarnSkipped in the file note, with the correction carried in each row's note instead.
  2. Step / action / assertion keys sit below the gate's one-level walk. They were measured in the same pass and are recorded in the scenarios.setup note rather than fanned into rows the gate would never check — the query precedent for sub-walk verdicts. Two value-level gaps are noted there and are loud, not silent (run_script has no adapter branch → throws; not_contains/gt/gte/lt/lte/error → throw "Unknown assertion operator"), so neither changes a key verdict — the api.json type precedent.
  3. evidenceScope: "in-repo" on every row. Honest rather than optimistic: objectui was not walked. The structural argument for why that is sufficient here — the surface is a JSON file read by an oclif command in a Node process, with no renderer path to reach it — is stated in the ledger, not assumed.

Reverse verification — direction predicted first

Predicted before running: the reject pins must be RED against the cast (a type assertion checks nothing at runtime, so every malformed document loads fine), and the valid-suite pin must be GREEN in both states (proving the RED is caused by the defect, not by the harness).

Pin Pre-change (cast) Post-change (safeParse)
loads a valid suite unchanged ✅ pass ✅ pass
refuses a suite with no scenarios fail — loaded silently ✅ pass
refuses a misspelled steps key fail — loaded silently ✅ pass
refuses an unknown action.type fail — loaded silently ✅ pass
names the file, the issues, the shape fail — no error raised at all ✅ pass
refuses invalid JSON naming the file fail — bare Unexpected end of JSON input ✅ pass

Measured, not asserted: 5 failed | 1 passed (6) before, 6 passed (6) after. To take the pre-change measurement against the real defect rather than a missing import, the loader was first extracted with the cast body preserved verbatim, the pin run, then the body swapped for the parse — so the only variable between the two runs is JSON.parse(…) as QA.TestSuite versus TestSuiteSchema.safeParse(…).

Each rejected shape is one the cast really shipped, which is why the pin uses these three and not synthetic garbage:

  • missing scenariosTypeError inside TestRunner.runSuite, attributed to the runner with no idea which file it came from;
  • misspelled steps → the scenario reports PASSED having executed nothing (the dangerous one: indistinguishable from green in CI);
  • bad action.type → survives load and runner, dies in the adapter's default: branch mid-run, after earlier steps have already written records.

End-to-end smoke through the built CLI, since the pin covers the loader and not the loop wiring:

📄 Running suite: broken.test.json
qa/broken.test.json is not a valid Quality Protocol suite (TestSuiteSchema):
  ✗ scenarios.0.steps: Invalid input: expected array, received undefined
  Expected shape: { "name": string, "scenarios": [ { "id", "name", "steps": [ { "name", "action": { "type", "target" } } ] } ] }
  Reference: content/docs/references/qa/testing.mdx
-------------------------------------
FAILED: 1 scenarios failed. 0 passed.     → exit 1

Gates

Gate Result
check:liveness ✅ green — qa 9 classified (dead 5, live 4); 349/349 repo-local evidence paths resolve; no orphan rows, no undeclared container inheritance
check:empty-state ✅ green — all classified (1 closed, 2 open, 4 output, 9 scope)
check:generated All 11 generated artifacts are up to date (spec built first, per #7122)
liveness gate self-tests (scripts/liveness/*.test.ts) ✅ 8 files / 143 tests
@objectstack/spec tests ✅ 360 files / 9397 tests
@objectstack/core tests ✅ 28 files / 524 tests
@objectstack/cli tests ✅ 106 files / 1145 tests (incl. the 6 new pins)
typecheck (spec, cli, core) ✅ clean, incl. check:scripts-typecheck and check:test-typecheck

Two suites failed on the first pass for an environmental reason and are recorded rather than quietly re-run: core (1 file) and cli (76 files) could not resolve unbuilt workspace packages (@objectstack/metadata-core, @objectstack/lint, @objectstack/runtime, …). Both are green after pnpm build; neither failure touched any file in this diff. Heavy runs held /tmp/os-heavy-verify.lock; no wait was observed.

Dual-snapshot: not applicable — no package exports change. The gate agrees: check:api-surface and check:export-origins are green with no regeneration. TestSuiteSchema was already exported from @objectstack/spec/qa; this PR adds its first parse call site.

Special-inspection items

  1. GOVERNED + SPEC_ONLY_SCHEMAS is load-bearing, not incidental. Dropping qa.json into packages/spec/liveness/ alone would produce a file nothing reads. Please confirm you agree qa belongs on the spec-only route (it is a file surface an author writes, like query is a request surface a caller writes) rather than being registered as a metadata type — registering it would switch on Studio CRUD and saveMetaItem overlay acceptance for a type that has no business there.
  2. The authorWarn omission (point 1 above) — the strongest candidate for a reviewer disagreeing. The alternative is registering a qa collection in the lint's TYPE_COLLECTIONS, which would be false: there is no stack.qa.
  3. result.data as QA.TestSuite in the loader is a narrowing cast between zod's input and output types of the same schema (the exported QA.TestSuite is z.input<…>), not a re-introduction of the unchecked assertion — the value has been parsed by then. Flagging it because it looks like the thing this PR removes.
  4. Out-of-scope discoveries, filed separately rather than fixed here: the contains assertion silently PASSES when the actual value is neither an array nor a string (runner.ts:171-177) — the one genuinely silent path in the assertion engine; and the liveness README's state table has no rows for the already-governed api / capability types. The README heading now says 30 with a short note admitting the table carries 28, rather than back-filling two Notes cells from changes somebody else measured.

Closes #6247


Generated by Claude Code

…ma at the `os test` load site (#6247)

#6247 filed `packages/spec/src/qa/testing.zod.ts` as declared-but-inert on a
grep that scanned only `*Schema` identifiers. Every consumer here reads the
TYPE names (`QA.TestSuite`, `QA.TestStep`, `QA.TestAction`), so the search
matched nothing and a complete execution chain read as zero consumers: core's
`TestRunner` + `HttpTestAdapter` (whose `action.type` switch labels ARE the
`TestActionTypeSchema` values), published through `export * as QA`, driven by
the shipped, documented CLI command `os test`. The 2026-08-07 retire ruling
rested on that reading and was withdrawn on 2026-08-08 in favour of enforce.

The real gap was narrower and genuine: the type was the contract and the schema
had no `parse` site anywhere, so `os test` loaded suites with
`JSON.parse(content) as QA.TestSuite` beside the author's own
`// Should validate with Zod`.

- `packages/spec/liveness/qa.json` — seed the ledger, governed via the same
  `SPEC_ONLY_SCHEMAS` override as `query`/`webhook`/`validation` (a QA suite is
  an authored file, not stack metadata). 4 live rows with file:line evidence
  into the runner, 5 dead recorded honestly; step/action/assertion keys sit
  below the one-level walk and are measured in the notes rather than fanned into
  rows the gate would not check. No `authorWarn` anywhere, deliberately: the
  lint walks stack collections and a QA suite belongs to no stack, so the flag
  would be a silent no-op inside the mechanism built to catch silent no-ops.
- `packages/cli/src/commands/test.ts` — `loadTestSuite()` parses with
  `TestSuiteSchema.safeParse` at the load boundary and refuses a bad suite
  there, naming the file, listing the issues and quoting the expected shape. A
  refusal counts as one failed suite instead of killing the run.
- pin `packages/cli/test/qa-suite-schema-load.test.ts` — the three shapes the
  cast admitted (missing `scenarios` → TypeError inside the runner; misspelled
  `steps` → scenario reports PASSED having executed nothing; bad `action.type`
  → dies mid-run after earlier steps wrote records) are now refused at load.

Closes #6247

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Up7rAGwREEy754haLKVtZH
@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 10, 2026 4:02am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via packages/cli, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/cli, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via packages/cli, @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/permissions/system-context.mdx (via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

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

  • content/docs/releases/implementation-status.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

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.

#6247)

The load-site parse is user-visible behaviour: a suite that does not match
`TestSuiteSchema` is now refused before it runs, named, and counted as one
failed suite while the rest of the glob continues. The `os test` section
listed the flags and said nothing about what happens to a bad file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Up7rAGwREEy754haLKVtZH
@os-zhuang
os-zhuang marked this pull request as ready for review August 10, 2026 04:55
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

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

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

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

    �[41m�[1m FAIL �[22m�[49m src/metadata-repository-fs-dot-root.test.ts�[2m > �[22mMetadataManager ← FileSystemRepository under `.objectstack/metadata` (#7150)�[2m > �[22man out-of-process write reaches
    

历史信号:

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

分诊清单:

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

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

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Queue ejection triaged: not this PR — it is the known watcher flake, #7282. Checklist item 2, not item 1. Recording the measurement rather than re-queueing blindly, since every blind re-queue rebuilds everything behind it.

The failure. Queue run 31357039709, Test Core (1/3):

FAIL src/metadata-repository-fs-dot-root.test.ts
  > an out-of-process write reaches subscribe() in the dot-rooted layout   25541ms
AssertionError: expected [] to have a length of 1 but got +0   (line 94)

Why it cannot be this PR.

Check Result
Does this PR touch packages/metadata / metadata-fs / anything they import? No. The diff is 7 files: the spec liveness ledger + gate script, the CLI test command + its pin, the liveness README, a CLI doc paragraph, a changeset. Nothing reads a liveness ledger except the gate and packages/lint.
Did the failing test even exist at this PR's base? No. packages/metadata/src/metadata-repository-fs-dot-root.test.ts was added by 684ab22 (#7208), which landed on main after this branch was cut at f40c5b4.
Does it reproduce on pristine main? No — origin/main @ 89470f7 in a clean worktree: 5/5 green for that file alone, 3/3 green for the full packages/metadata suite (30 files / 593 tests).
Does the branch conflict with current main? No — git merge-tree against 89470f7 is clean.

What this ejection adds to #7282, which already diagnosed this family as "the event is suppressed, not late" — this is a fourth occurrence and it sharpens two of that issue's open points, so I've posted the detail there:

Not re-queueing on my own initiative, per the triage bot's guidance: nothing in this PR changed, so a re-queue is a coin flip on the same flake rather than a fix. Re-queue whenever convenient — the checks all passed on the PR-side run (26 checks, 25 success + 1 skipped) and the branch is conflict-free. I'll keep watching and will re-triage if the next attempt fails on a different signature.


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.

spec(qa): TestScenarioSchema/TestSuiteSchema are declared-but-inert — no runtime consumer, no liveness ledger

2 participants