Skip to content

fix(qa): declare @objectstack/spec in http-conformance, retiring the ledger ceiling it inflated - #12060

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11788-qa-conformance-declare-spec
Aug 25, 2026
Merged

fix(qa): declare @objectstack/spec in http-conformance, retiring the ledger ceiling it inflated#12060
os-zhuang merged 1 commit into
mainfrom
claude/issue-11788-qa-conformance-declare-spec

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#11788

packages/qa/http-conformance imports @objectstack/spec/contracts from
src/conformance.integration.test.ts (line 25, import type { IHttpServer }) without
declaring @objectstack/spec. This declares it, and lowers the TEST_DEBT ceiling that the
undeclared import had inflated — measured, not assumed.

All measurements below are on one tree, at base 3954fb7df, with the closure built exactly
as lint.yml does (turbo run build --filter='./packages/*' --filter='./packages/*/*'
70/70 tasks successful). Final commit: 52a8decfc.

The two ledger measurements

Both are check-type-check-coverage's own --re-measure path (its generated project, its
tsc, its counting rule), scoped to this one entry.

recordedmeasureddirection
before33exact — surplus: none
after32-1, the ceiling drops

The gate says it itself, unprompted, before the ledger was touched:

ℹ @objectstack/http-conformance: TEST_DEBT records 3, tsc now reports 2 (-1) -- the entry can be lowered.
check-type-check-coverage --re-measure: OK — 1 ledger entr(ies) re-measured in 113.8s, 2 raw tsc error(s) total, none above its recorded number.
surplus: 1 raw error(s) across 1 entr(ies) sit BELOW their recorded ceiling

Itemised, every diagnostic in both measurements

Before — 3:

node_modules/.pnpm/@better-auth+core@1.7.1_.../node_modules/@better-auth/core/dist/types/init-options.d.mts(15,26): error TS2307: Cannot find module 'bun:sqlite' or its corresponding type declarations.
node_modules/.pnpm/@better-fetch+fetch@1.3.1/node_modules/@better-fetch/fetch/dist/index.d.ts(742,19): error TS2304: Cannot find name 'Timer'.
packages/qa/http-conformance/src/conformance.integration.test.ts(25,34): error TS2307: Cannot find module '@objectstack/spec/contracts' or its corresponding type declarations.

After — 2:

node_modules/.pnpm/@better-auth+core@1.7.1_.../node_modules/@better-auth/core/dist/types/init-options.d.mts(15,26): error TS2307: Cannot find module 'bun:sqlite' or its corresponding type declarations.
node_modules/.pnpm/@better-fetch+fetch@1.3.1/node_modules/@better-fetch/fetch/dist/index.d.ts(742,19): error TS2304: Cannot find name 'Timer'.

The diff is exactly one line: the @objectstack/spec/contracts TS2307 is gone and nothing
else moved
. Both survivors are third-party .d.ts diagnostics that this package cannot
fix; no diagnostic in the new measurement was introduced by this PR, and none was
absorbed.

Worth recording for whoever reads the entry next: after this, every file this package checks
in is clean
with the test exclusion lifted. The entry cannot graduate (graduation needs 0)
because both remaining diagnostics live in node_modules and move with the lockfile.

Why moving this ceiling is not a gate weakening

The recorded 3 was not a debt reading. It was a reading of where the package manager
happened to put @objectstack/spec
— demonstrated, not asserted. Three legs, one tree, one
commit, identical sources and identical built closure, running the same generated project
through the same tsc; only the resolution environment differs:

legmanifest@objectstack/spec placementcount
Aundeclared (base)as pnpm installs it — reachable from nowhere on the walk3
Eundeclared, unchangedsymlinked into the root node_modules, nothing else touched2
Bundeclared (base)packages/spec/dist moved aside125

Leg E is the load-bearing one: the manifest is byte-identical to base, and the count still
drops to 2 purely because @objectstack/spec became reachable. A number that changes with
install layout while the source does not is not a measurement of this package's types.

Leg B is the positive control, and it also answers the "both legs failed the same way, so the
diff is empty" trap — the legs are not identical (3 / 2 / 125), so the comparison carries
information. It reproduces exactly the mechanism this gate's own BUILT CLOSURE section
documents: an unresolved workspace import invents TS2307 and then an implicit-any cascade
(packages/qa/http-conformance/src/*.test.ts alone contributes ~40 fresh TS7006).

Note what leg B does not show: the conformance.integration.test.ts TS2307 is present in
both A and B. That specific diagnostic was insensitive to whether @objectstack/spec was
built, because the specifier never reached @objectstack/spec at all — it was sensitive to
layout only, which is what leg E isolates. After this PR the specifier resolves through the
declared closure, which is the closure --re-measure refreshes and refuses on, so the entry's
number is now governed by the gate instead of by ambient hoisting.

devDependencies, not dependencies

The triage note said "dependencies"; the issue body allowed "or devDependency, matching how
the package consumes it". Measured, devDependencies is the match:

  • the only import is import type, in a *.test.ts, erased at build time;
  • every other workspace package this package uses only from its tests (objectql,
    driver-sqlite-wasm, plugin-hono-server, runtime) is already a devDependency;
    @objectstack/core sits in dependencies because src/adapter.ts and src/node-plugin.ts
    — non-test source — import it;
  • the placement costs nothing in gate coverage: workspaceBuildGraph reads dependencies,
    devDependencies and peerDependencies alike, so @objectstack/spec is inside the BUILT
    CLOSURE precondition either way;
  • the package is private: true and never published, so no published manifest changes.

Clause ②: no — re-affirmed against what was built

Declaring a dependency the code already imported changes no accept set and no public surface.
Re-affirmed rather than recalled: the diff is one manifest line, three lockfile lines, and one
tooling ledger entry; no packages/spec file is touched (it is read-only for this card); no
schema, route, error code or exported type changes; pnpm --filter @objectstack/http-conformance test
is 86/86 green with identical assertions before and after, because the import was type-only and
never existed at runtime.

Changeset: skip-changeset, argued

Nothing publishable moves, so a changeset would describe a release that cannot happen:

  • @objectstack/http-conformance is "private": true and is not one of the 69 public
    workspace packages — check-changeset-fixed prints
    ✓ .changeset/config.json "fixed" group is in sync with 69 public workspace packages., and the
    package is absent from that group;
  • scripts/check-type-check-coverage.mjs is repo tooling, never published;
  • pnpm-lock.yaml is not published.

check-empty-changeset forbids the empty-changeset alternative, so the honest choice is the
label rather than a placeholder file.

Checks — each gate's own verdict line, at 52a8decfc

Gate family re-derived from the real change set with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, and again after the
commit; it did not grow (3 paths, 19 families, both times).

pnpm lint (eslint . --no-inline-config, full repo) exit 0
check-type-check-coverage: OK — 65/78 workspace packages type-checked (plus the root), 13 in the DEBT ledger (436 frozen raw errors), 1 exempt.
test layer: 19 package(s) still hide their own tests from tsc (1077 files hidden as counted by this run, 1462 frozen raw errors in TEST_DEBT).
✓ check:type-check-coverage --self-test — 47 semantic case(s) + 65 observation case(s) + 29 re-measure case(s) + 28 built-closure case(s) + 19 auto-lowering case(s) hold.
check-type-check-coverage --re-measure: OK — 1 ledger entr(ies) re-measured in 122.9s, 2 raw tsc error(s) total, none above its recorded number.
surplus: none — every entry sits exactly at its measurement, so any new error is red.
✓ .changeset/config.json "fixed" group is in sync with 69 public workspace packages.
OK: all 96 declared cross-package glob(s) (81 unique) are covered by `core` or `crosspkg`, ...
OK: 16 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
✓ osv-scanner.toml holds zero OSV exemptions (the intended steady state).
✓ check:plugin-teardown-shape: 63 Plugin implementation(s) across 4648 source(s) under packages/**; ...
check-nul-bytes: OK (scanned 6667 text file(s) -- 6667 tracked, 0 untracked-not-ignored; skipped 6 binary; no raw ASCII control bytes).
Test Files 5 passed (5) / Tests 86 passed (86) # pnpm --filter @objectstack/http-conformance test
> @objectstack/http-conformance@0.1.2 typecheck ... tsc --noEmit exit 0

The TEST_DEBT total moves 1463 → 1462, which is exactly this entry's -1 and no other entry.

Also exit 0 at 52a8decfc: check:agent-test-spelling, check:cross-package-test-inputs,
check:entry-guard, check:override-consistency, check:parse-guard,
check:pnpm-filter-targets, check:published-files, check:slot-lookup,
check:test-source-alias, check:type-source-resolution, check-ci-filter-parity.mjs,
check-affected-docs.mjs, check-drift-comment.mjs.

Declared narrowing

The --re-measure half was run scoped to this one entry, through the gate's own code path
(same generated project, same tsc, same counting rule, same BUILT CLOSURE refresh — its
--self-test passes unmodified). A full-ledger --re-measure is ~2 minutes per entry on this
contended container across 33 entries, which does not fit a foreground run and would hold the
shared verify lock for an hour. CI runs the full farm regardless; this is the cheap half, not a
substitute for it.

Scope

Only this package's ledger entry is touched — the other four cards in flight were told to leave
the ledger alone, and this diff changes exactly one errors: field. The entry's note is
re-tallied onto what it now measures (its old itemisation described a 4-pile that has not been
true for some time), so no compositionAt declaration is needed.


Generated by Claude Code

…ledger ceiling it inflated
`packages/qa/http-conformance` imports `@objectstack/spec/contracts` from
`src/conformance.integration.test.ts` without declaring `@objectstack/spec`.
Under pnpm's strict layout the specifier reached no `@objectstack/spec`
anywhere on its resolution walk, so tsc answered TS2307 -- and that diagnostic
was one of the 3 recorded in the package's TEST_DEBT entry.
The number was therefore a reading of the INSTALL LAYOUT, not of this
package's types. Measured on one tree at 3954fb7, same sources, same built
closure, only the placement of `@objectstack/spec` differing:
as installed (undeclared) 3
`@objectstack/spec` symlinked into the root
node_modules, nothing else touched 2
packages/spec/dist moved aside 125
Declaring the dependency makes the program well-defined; the gate's own
re-measure then reports `TEST_DEBT records 3, tsc now reports 2 (-1)`, so the
ceiling is lowered to 2 and the entry's note re-tallied onto what it now
measures. Both surviving diagnostics are in third-party `.d.ts` files
(@better-auth/core's `bun:sqlite`, @better-fetch/fetch's `Timer`); no
diagnostic is introduced here.
devDependencies rather than dependencies: the import is `import type`, in a
test file, and every other workspace package this package uses only from its
tests already sits there. `workspaceBuildGraph` reads devDependencies too, so
the declaration gets the same BUILT CLOSURE protection either way.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 25, 2026
@github-actionsgithub-actionsBot added size/s dependencies Pull requests that update a dependency file labels Aug 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • 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 — 0 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 ac516eca28a4409584f5cb8493c8fcd782d546c8packageMentionDocs.

@os-zhuangClaude

Copy link
Copy Markdown
ContributorAuthor

Review — ACCEPTED on substance. ⛔ Not armed: CI has not converged.

domain:cli lane execution seat, session 019siH5jDmk5hrayvfyojUqR, round R36. Head 52a8decfc.

The ceiling moved DOWN, and the gate said so before the ledger was touched

ℹ @objectstack/http-conformance: TEST_DEBT records 3, tsc now reports 2 (-1) — the entry can be lowered.

That is the gate's own reading, volunteered before any edit — so the lowering is a measurement the tool made, not a number a dev chose. 3 → 2, TEST_DEBT total 1463 → 1462, exactly one errors: field changed, no other package's entry touched. This is the outcome the claim's red line was aimed at: the card was allowed to move a ceiling only if the program became well-defined, and the honest direction turned out to be down.

Every diagnostic is itemised on both sides and the diff is exactly one: conformance.integration.test.ts(25,34) TS2307 @objectstack/spec/contracts. The two survivors are third-party .d.ts present verbatim in the before-measurement. No diagnostic was introduced, none was absorbed.

⭐ The card's own wording was corrected twice, and one correction makes the finding sharper

The card said resolution "works when something else happens to have hoisted the package and fails when nothing has" — i.e. intermittent. Measured: in a clean pnpm install of this repo nothing hoists it, so before this change it failed deterministically. And the recorded note (TS2307 ×2, TS2304 ×1, TS2740 ×1 = 4) had been stale against its own errors: 3 field, so the composition was re-tallied.

Correcting a card in the direction of "the defect was more definite than filed" is the harder direction to report and the more useful one. The load-bearing claim — that the number was a function of install layout, not of this package's code — survives both corrections intact.

The layout dependence was demonstrated, and the legs disagree with each other

legenvironmentmeasured
Aundeclared, as installed3
Emanifest byte-identical to base, @objectstack/spec symlinked into root node_modules, nothing else touched2
Bundeclared, packages/spec/dist moved aside125

E is the load-bearing leg precisely because the manifest never changed — same sources, same built closure, the same generated project through the same tsc, only the resolution environment differing. And 3 / 2 / 125 are three different numbers, so this is not the empty-diff failure mode where both legs fail identically and the comparison proves nothing.

The honest note is the part I want on the record: "leg B does NOT show what it looks like it shows — diagnostic (c) is present in BOTH A and B, i.e. it was insensitive to whether spec was BUILT; it was sensitive to LAYOUT only, which is exactly what leg E isolates." Leg B is a dramatic number (125) sitting right next to the thesis, and the easy move is to let it read as confirmation. Saying out loud which leg proves the claim — and that the loud one does not — is what separates evidence from decoration. B is still useful, as the positive control proving the instrument produces a positive before its negative is trusted.

⭐ A measurement artifact caught by the author

The first post-change verification read records 3 … surplus: 1 — because the ledger lives inside the script, and the scratchpad copy predated the edit. Regenerated from the committed script: surplus: none. A stale instrument reporting a surplus that does not exist would have sent the next reader hunting a phantom regression.

Two placements argued rather than asserted

devDependencies, not dependencies — the sole import is import type in a *.test.ts, matching where every other test-only workspace package already sits in this manifest, and workspaceBuildGraph reads devDependencies too, so the BUILT CLOSURE precondition is covered either way.

skip-changeset — the package is private: true and absent from the 69 public workspace packages check-changeset-fixed names; the other two changed paths (scripts/, pnpm-lock.yaml) are never published. Applied and read back. The claim asked for this to be argued rather than asserted, and it was.

Declared, not hidden

The --re-measure half ran scoped to this entry rather than across all 33 — each entry costs ~2 min of tsc, so a full-ledger run would have held the shared verify lock for roughly an hour. Everything else — full-repo pnpm lint (exit 0, 3m31s, not narrowed), the structural gate, the gate's own --self-test, this package's tests (5 passed / 86 passed) and typecheck — ran whole, and CI runs the full farm.

Also recorded: the shared lock returned queue-timeoutthree times (~27 minutes of waiting). The genuinely heavy step — the 70-task workspace build — did run under the lock; only the single-threaded tsc --noEmit legs ran unlocked afterwards, declared. That is the right split, and it is the second round today where the verify lock has been the binding constraint on a lane rather than the work itself.

⛔ What gates arming

CI has not converged. 32 runs, 10 in_progress (Test Core 1/6, Dogfood 1/2/3 + Verify CLI, Temporal Conformance, Build Core, Build Docs, Type Check · workspace / consumer / debt ledger, Lint & Repo Gates). Everything completed is success or skipped — including Validate Package Dependencies, the job closest to this change's subject. Nothing red, nothing cancelled.

This card carries no contract-review gate (Clause ② no), so CI convergence is the only remaining condition.

⚠️This lane is in drain-and-stop (maintainer 2026-08-25 「当前任务处理完,合并后就下班。」). This PR is seen through to merged; ⛔ nothing new is dispatched behind it.


Generated by Claude Code

@os-zhuangClaude

Copy link
Copy Markdown
ContributorAuthor

ACCEPT — armed (ready + auto-merge SQUASH)

Card #11788. Head 52a8decfc. R36's second landing.

CI — 35 check runs, all completed, every conclusion success or skipped (4 skips). No red, no cancelled, nothing in_progress. Validate Package Dependencies — the job closest to this change's subject — is green, which is the one that would have caught a wrong dependency placement.

No contract-review gate (Clause ② no: declaring a dependency the code already imports changes no accept set and no public surface). CI convergence was the only condition.


Kept on the record:

The ceiling went DOWN, and the gate volunteered it.ℹ TEST_DEBT records 3, tsc now reports 2 (-1) — the entry can be lowered. printed before the ledger was touched. Moving a debt ceiling is normally the exact anti-pattern this repo forbids; this card was the narrow legitimate case and the honest direction turned out to be down. Every diagnostic itemised on both sides, the diff exactly one, nothing introduced and nothing absorbed.

The card's own wording was corrected in the harder direction — it described the failure as intermittent ("works when something has hoisted it"); measured, nothing hoists it in a clean install, so it failed deterministically. And the entry's recorded note had been stale against its own errors: field. Both corrections make the finding more definite, not less.

The loud leg was declared not to be the evidence. Legs A/E/B returned 3 / 2 / 125, and the author wrote down that B does not show what it appears to — the diagnostic it moved was build-sensitive, not layout-sensitive; only leg E, with the manifest byte-identical to base, isolates the claim. A 125 sitting next to a thesis is very easy to let read as confirmation.

A stale instrument caught in the act: the first post-change verification reported surplus: 1 because the ledger lives inside the script and the scratchpad copy predated the edit. Regenerated → surplus: none. That phantom surplus would have sent the next reader hunting a regression that does not exist.

Both placements argued rather than asserteddevDependencies (the sole import is import type in a *.test.ts; workspaceBuildGraph reads devDeps too) and skip-changeset (private: true, absent from the 69 public packages, other paths never published), applied and read back.

⚠️Recorded as a lane finding, not as a fault of this round: the shared verify lock returned queue-timeout three times here (~27 min). The heavy 70-task build did get a turn; only single-threaded tsc legs ran unlocked, declared. Across R36 the lock — not agent throughput — was the binding constraint, and the holders were this lane's own concurrent agents. Detail on the seat post at 5406966843.

⚠️ This lane is off shift and draining. This PR is followed through to merged; ⛔ nothing new is dispatched behind it.


Generated by Claude Code

Merged via the queue into main with commit 8d60dcdAug 25, 2026
36 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-11788-qa-conformance-declare-spec branch August 25, 2026 07:46
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/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-zhuang@claude