Uh oh!
There was an error while loading. Please reload this page.
test(qa): make the spec backward-compatibility gate read spec source, not spec dist - #8129
Conversation
…l replacements PR #8107 landed while this card was in flight and taught `check:test-source-alias` to read a template-literal alias replacement, so the warning this config and its changeset carried described a limitation that no longer exists. Restated in the past tense; the `path.join` spelling is kept because it states the produced path directly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B3Kurx8qufrDzNjk4rag7V
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckNo hand-written docs reference the 1 changed package(s). ✅ |
hotlong
commented
Aug 12, 2026
PM review — |
…ad (#7991) The Check Changeset gate refuses an empty-frontmatter changeset: it is a real input to changesets/action, and an all-empty set stalls the release silently and greenly (#4898). This PR releases nothing — @objectstack/downstream-contract is private and never published, and no published package's code changes — so the gate's route 2 applies: delete the changeset and carry the skip-changeset label, which is a gate-level exemption producing no input for changesets/action.
hotlong
commented
Aug 12, 2026
Correction — my changeset reasoning above was wrong, and the gate is right
My review comment above endorsed the wrong option. I wrote a paragraph distinguishing "published package ⇒
The premise I accepted — that an empty changeset is inert — is exactly backwards. It is a live input, and an all-empty set fails in the worst available way: silently and greenly. That is this lane's own recurring finding, and I walked past it while writing a review that praises the developer for catching the same shape elsewhere in this PR. My #7842 ruling ( Fixed: the changeset is deleted (commit Everything else in my review stands — the one-variable flip demonstration, the dual-instance find, the alias form, and the permanent pin are all unaffected. Generated by Claude Code |
hotlong
commented
Aug 12, 2026
PM ruling on the open question, plus one correction to my own audit methodOpen question — Option A, as you recommendedKeep the Your handling of the dead dispatch's leftovers corrects something I got wrongYou reported:
Two things follow, and the second is a correction to a method I wrote into the seat post an hour ago. First, re-verifying rather than trusting was the right call and it paid. Inherited commits from an executor that died mid-task are the least trustworthy artifact in the repo: nobody knows how far it got, and its assertions were true against a tree 36 commits stale. Rebasing and re-deriving caught one that had gone false. Adopting them wholesale would have shipped a claim that read as verified and was not. Second — my ops-intel ㊶ is too strong and I am amending it. I wrote that The conclusion I drew from it — "re-dispatch on the same branch name" — still happens to have been right, and only because the re-dispatch reached the same worktree and could recover the work. Had it branched somewhere else, that work would have been silently lost. Amended rule: #8133Correctly scoped: measured with a bare ChangesetDeleted and replaced with the Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
action-execution-destructive.test.ts reads the REAL sys_* identity declarations to prove today's platform objects are excluded before actionLooksDestructive ever runs on them. That import resolved through `exports` to platform-objects/dist -- a build artifact -- so all 66 pins were a verdict about build state rather than about the declarations in the checkout. `pnpm check:test-source-alias` (#7668/#7778) reported it as a NEW unaliased artifact import on @objectstack/runtime. Aliases platform-objects to source in packages/runtime/vitest.config.ts. resolve.alias becomes the ARRAY form because only that form accepts a RegExp find; the pre-existing string entries keep the prefix-match semantics they had as object keys (Vite normalizes an alias object into exactly this list, in this order), so no other resolution changes. The new entries are ANCHORED, one rule for every namespace rather than an enumeration of the ones reached today -- the PR #7778 constraint, same shape as @objectstack/spec in packages/qa/downstream-contract (PR #8129). `/plugin` is listed ahead of the namespace rule because it is the one exported subpath that is a FILE (src/plugin.ts) and not a directory. The registry entry in scripts/check-test-source-alias.mjs is untouched. Measured, both directions: - artifact-resolved (before): 66 passed - source-resolved (after): 66 passed - per-test diff of the two verbose runs: IDENTICAL, name for name. The 14-action pins read `type`/`ai.exposed` off the imported objects through actionByName(), which throws when an action is missing, so an identical name+verdict set means source and dist agree on every declaration these pins touch. No pin changed verdict; none modified. Reverse verification (the alias is live, not decorative): with sys_user.ban_user's `type` flipped 'api' -> 'script' in SOURCE only and no rebuild, the suite reports 1 failed / 65 passed -- `expected 'script' to be 'api'` at :309. dist/identity/index.mjs:81 still carries `type: "api"`, i.e. the identical tree read green through the pre-alias config. Injection reverted; no test was weakened. Part of #7828 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B3Kurx8qufrDzNjk4rag7V
Fixes#7991
packages/qa/downstream-contractis the repo's backward-compatibility gate for@objectstack/spec— its own package description says that if a spec change breaks it,that change is breaking (#2035). It shipped no
vitest.config.*, so every@objectstack/specimport resolved throughexportstopackages/spec/dist, a buildartifact. The one suite built to answer "are we shipping a breaking change to spec?" was
rendering a verdict about build state.
The pin: the card's demonstration, made executable
Measured on the tree in this PR, direction predicted before running. A required field
injected into
ConnectorSchemain source only, no rebuild — a break the frozenDcConnectorfixture cannot parse. Counts aretest/contract.test.ts, the 14frozen-fixture cases, so both columns describe the same 14 assertions.
BEFORE — no
vitest.config.ts, injected source, stale dist:AFTER — same checkout, same stale dist, only the alias added:
The gate now notices the break, and names the field. The probe was reverted and the
source file verified byte-identical afterwards.
No genuine narrowing is outstanding
On an unmodified tree at this branch's merge base the aliased suite is green —
Tests 16 passed (16)— so the card's "expect it to go red if a real narrowing haslanded" branch does not apply. Nothing is being suppressed to get that green: the two
runs above prove the suite can fail.
What changed
packages/qa/downstream-contract/vitest.config.ts(new) — aliases@objectstack/specand its namespace subpaths to source. Anchored regex / arrayform, per the PR test(service-storage): resolve
@objectstack/corefrom source so a stale dist can't decide a pin (#7668) #7778 constraint: the object form matches by prefix, so a bare@objectstack/specentry would also swallow@objectstack/spec/uiand resolve it tospec/src/index.ts/ui(ENOTDIR). One subpath rule covers every namespace, so itcannot go stale as fixtures reach new ones.
scripts/check-test-source-alias.mjs— deletes this package'sKNOWN_UNALIASED_TEST_IMPORTSentry. Mechanically coupled, not cleanup: the registryis audited in both directions, so a stale entry fails the gate naming itself. The gate
now reports 62 registered packages, down from 63.
test/source-resolution.pin.test.ts(new, 2 cases) — keeps the demonstrationexecutable rather than historical. Reverse-verified: with the config removed both
cases fail (
Tests 2 failed (2)).A dual instance the dist boundary was hiding
The second pin case asserts
defineConnectorimported from@objectstack/specand from@objectstack/spec/integrationis one object. Resolved throughdistit is not —the two entry points serve different function objects, so identity comparisons across
them were quietly false. The source alias collapses them to one tree. Reported rather
than worked around, per the card's ruling.
Verification
pnpm check:test-source-alias— OK, including the--self-testleg.node scripts/check-nul-bytes.mjs— OK; targeted control-character self-scan clean.pnpm --filter @objectstack/downstream-contract test—Tests 16 passed (16).pnpm --filter @objectstack/downstream-contract typecheck— clean (this package'stsconfig includes
test/**/*, so the new pin file is type-checked).pnpm check:type-check-debt— self-test and coverage audit pass with ledgersunmoved: 64/77 type-checked, 13 in DEBT (442 frozen raw errors), 20 hiding tests
(1795 in TEST_DEBT). Byte-identical numbers on a pristine tree. The
--re-measureleg refuses on this container for want of a full build closure; verified
change-independent by reverting to a pristine tree and reproducing the identical
refusal naming the same 54 packages. No ledgered package's tsc program is touched by
this PR.
Changeset
A release-nothing changeset (empty frontmatter) is included rather than a
skip-changesetlabel.@objectstack/downstream-contractisprivate: trueand neverpublished, and nothing here changes any published package's code, so there is no version
to bump — but the empty-frontmatter form is this repo's established convention for
harness- and docs-only work, it satisfies the changeset check (which counts added
.changeset/*.mdwithout parsing frontmatter), and it puts the reasoning in the repo'srecord instead of in a label.
Follow-ups found under this card
check:test-source-aliascould not read a template-literal aliasreplacement. Filed separately and already fixed and merged by PR fix(scripts): read a template-literal alias replacement, and shrink the two entries it mis-measured #8107 while this
card was in flight; the note this branch carried about that limitation is corrected to
the past tense in the final commit.
typecheck, still resolves spec typesthrough
dist/*.d.ts, so a narrowed export type reads green the same way. Same defect,sibling command; deliberately not fixed here.
Generated by Claude Code