Skip to content

test(cli): drive the two new --json members and align the noise-budget scaffold with the workspace protocol (nightly tiers) - #22699

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-22622-nightly-tiers-red
Oct 10, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-22622-nightly-tiers-red

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #22622
Clause-②: no
Two nightly-tier CLI test files change and nothing else: no accepted input, key, export or error code moves, and nothing publishes.

Two independent reds on the nightly tiers, both in domain:cli. Both are fixed inside the nightly tests, following the seat's review 6099406666 on #22622. Nothing else changes:

  • the family-roster check;
  • the noise budget and every assertion in that file;
  • the create-objectstack template, the version-time stamp (scripts/sync-template-versions.mjs) and their tests, which are byte-for-byte as main has them.

(a) Both reds, reproduced before any fix

Base 9646991283, OS_TEST_TIERS=nightly, --project integration, through the verify lock: Tests 2 failed | 51 passed (53).

  • json-stdout-purity.e2e.test.ts, is exactly the set listed here: expected [ 'meta resync', …(17) ] to deeply equal [ 'meta resync', …(15) ], with + "migrate organization-ownership" and + "migrate security-catalog-overlays". migrate organization-ownership came from PR feat(cli): os migrate organization-ownership — the ADR-0131 D10 inventory and the read-only ceremony plan (C7a) #22643, after the nightly that filed the card. The members were taken from discoverFamily()'s output.
  • serve-boot-diagnostics-noise-budget.e2e.test.ts, highlights the dead button once…: expected 0 to be greater than 0 at :176. The boot printed ✗ package 'com.example.support-desk' targets protocol ^17 (engines.protocol) but this runtime is protocol 18.0.0. This is a major-version break. Run: objectstack migrate meta --from 17. That is a refusal, so no Boot diagnostics block is printed at all.

After, on 3d63ed7db5: Test Files 2 passed (2), Tests 59 passed (59). That is 53, plus 3 cases for each of the two new members.

Failure 1: the two new --json members are driven

FAMILY gains both members, each in its bare form. The CLI was first run against the purity fixture to see each one's face:

  • migrate organization-ownership shows its refusal face. Over a database with none of the platform tables it prints {"error":"plan_refused","reason":"not-an-objectstack-database",…} and exits 1. The JSON is emitted after stack.shutdown(), and no plan file is written.
  • migrate security-catalog-overlays shows its read-only preview: listed: 0, exit 0. There is no sys_metadata hydration and nothing is deleted.

Both print all three boot diagnostics on stderr. The discovery and the toEqual roster check are untouched.

Failure 2: the noise-budget e2e aligns the pair it boots

(b) What the version-time stamp writes

Measured read-only at 9646991283:

  • changeset status --output (pre.json is {"mode":"pre","tag":"next"}) gives @objectstack/spec major 17.7.0 -> 18.0.0-next.0 and create-objectstack major 17.7.0 -> 18.0.0-next.0 (the fixed group).
  • loadScaffolderVersion() on 18.0.0-next.0 gives {"version":"18.0.0-next.0","major":"18","range":"^18.0.0"}. So the version pass stamps engines: { protocol: '^18' } into the released template.

Triage's "every project that v18's create-objectstack scaffolds would boot with the protocol-gap warning" is false. No released v18 scaffold carries the gap. PR #22215's changeset says the same ("the template keeps '^17' until the version pass stamps it").

The red is main's pre-mode window: packages at 17.7.0, PROTOCOL_VERSION at 18.0.0. Only an in-repo pairing sees it: a published-line scaffold booted on the workspace runtime with nothing installed.

Round 1 changed the product side, and CI falsified that

Round 1 (bff640d98) stamped the template's engines.protocol from PROTOCOL_VERSION's major. On that head, Scaffold with repo dist (scaffold-e2e.yml, job 1) went red: "package 'com.example.e2e-app' targets protocol ^18 (engines.protocol) but this runtime is protocol 17.0.0".

That gate guards the path a user takes. It scaffolds with the repo-built scaffolder and installs @objectstack/* from the registry (^17.0.0, so protocol 17). On that path a template's range must match the protocol of the packages it installs, which is the package major. The sync script and the template-consistency ratchet already enforce exactly that on main.

Commit 60fa01c7a7 removes round 1's product-side change:

  • templates/blank/objectstack.config.ts, template-consistency.test.ts, template-version-stamps.test.ts and scripts/sync-template-versions.mjs are back at their main blobs (6308f29e, d32c819c, 48ba146e, f7704db8, all equal at base and origin/main);
  • the create-objectstack changeset is deleted.

This round: the setup aligns the pair it boots

This follows the seat's verification-strategy ruling in 6099406666.

After scaffolding, and before the fixture files are written, alignProtocolRange() rewrites the scaffold's engines.protocol to '^' + PROTOCOL_MAJOR. PROTOCOL_MAJOR is read from @objectstack/spec/kernel, the workspace spec this file boots, the same import other CLI e2e files use.

  • Only the major's digits are rewritten. When the majors agree, the scaffold is left byte-for-byte as written, and the helper does not write the file at all.
    • Measured on the template: at '^17' (the window) the hash moves 684e38ed0d1a → 5d6e6468255e, and only the engines line differs.
    • At '^18' (majors agree) the hash stays 5d6e6468255e → 5d6e6468255e, byte-identical.
  • A missing stamp throws in beforeAll. A template that stops declaring the key fails this file loudly instead of skipping the alignment.
  • Why a direct rewrite of the one key, and not objectstack migrate meta --from 17 --write. The --write command is the step the refusal prescribes, and it was measured first. On a scaffold under packages/cli/node_modules/ it exited 0 with not written [outside-project] and left the config unchanged. The codemod refuses any file whose real path has a node_modules segment (authored-source-codemod.ts, the outside-project refusal). This project has to live under this package's node_modules so that its imports resolve to workspace copies.
  • What stays the same: the noise budget, all three assertions, and the ticket object and actions. Once the version pass lands, the window closes and the alignment becomes a no-op.

Ablations

Both ran through scripts/ablation-replace.mjs in wrap mode on committed trees, under the verify lock. Each restore was proven by blob equal to HEAD and an empty git diff HEAD. Neither subject resolves through dist/: the FAMILY and the setup live in the test files.

Mutation Anchor Result
alignProtocolRange(join(dir, 'objectstack.config.ts')); deleted from the setup x1 → x0, blob 058fbecec7dc → bfedb0522aa5 noise-budget red with the original refusal: ✗ package 'com.example.support-desk' targets protocol ^17 … this runtime is protocol 18.0.0 …, expected 0 to be greater than 0, 1 failed and 2 passed. After the restore to blob 058fbecec7dc: 3 passed.
'migrate security-catalog-overlays': [], deleted from FAMILY (round 1, same blob as now) x1 → x0, blob 698034ba9bcb → 5dfe8780897a roster pin red: expected [ 'meta resync', …(17) ] to deeply equal [ 'meta resync', …(16) ], + "migrate security-catalog-overlays"

Tests (on 3d63ed7db5)

  • Nightly tier (OS_TEST_TIERS=nightly, --project integration, verify lock): the two card files, 59 passed.
  • create-objectstack: suite 17 files and 254 tests passed. pnpm check:template-version-sync is green with 40 assertions, the same count as on main. Both are unchanged, because this diff does not touch the package or the script.
  • @objectstack/cli:
    • unit layer: 279 files and 4126 tests passed;
    • typecheck (tsc --noEmit plus check:test-typecheck) is OK, and tsconfig.test.json's --listFiles includes both edited files.
  • Changeset: node scripts/check-empty-changeset.mjs --base origin/main exits 0. It reports no empty-frontmatter changeset added and no merge-base changeset modified or deleted.
  • Gates: dispatch-gates --commands (no paths) derived 50 commands from the 2-file change set. --ran reports 50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero: every command recorded exit 0. check:type-check-debt and check:dual-build-cjs-loads ran last, after every locked suite.
    • dispatch-gates noted that the tree is behind origin/main: 6 derived-from files changed there (ci.yml, check-shard-attestation.mjs and the fleet-write relay scripts).
    • No conflict exists, so per the round's direction there was no merge. CI judges the merge ref.
  • Lint, proven narrowing:
    1. Population is read from ESLint's own config: both changed files return results with no "File ignored".
    2. File count is from --format json: 2 results, 0 errors, 0 warnings.
    3. Invariance: eslint.config.mjs enables no type-aware linting, and this diff touches neither the config nor a baseline it reads.

Changeset

Nothing publishes: @objectstack/cli ships dist, README.md and CHANGELOG.md, and this diff is two test/ files. By the repo's rule this PR takes the skip-changeset label. An empty-frontmatter changeset would be the risky path that check:empty-changeset refuses. The seat applies the label.

Acceptance notes

  • objectstack migrate meta --write on a project whose path has a node_modules segment says the literal is in …/objectstack.config.ts, outside the project at …, although the file is inside the project. The real cause is the node_modules segment rule. Only a test layout reaches it, so this is a wording polish, not a finding. No carrier.
  • Version Packages PR chore: version packages #21988 was last refreshed on 2026-10-08T06:19Z, before pre mode was entered (a87d8be29). This is release-lane state, recorded as a reading, ⛔ not acted on.

Generated by Claude Code

…dout-purity family

The family-roster pin in json-stdout-purity.e2e.test.ts discovered
`migrate organization-ownership` and `migrate security-catalog-overlays`
(both boot the shared stack and declare --json) while FAMILY drove
neither. Each is now driven in its bare form: the ownership plan's
refusal face over a database with no platform tables, and the overlay
step's read-only preview. The roster check itself is unchanged.

Claude-Session: https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS
Co-authored-by: Claude <noreply@anthropic.com>
…ROTOCOL_VERSION's major

sync-template-versions.mjs stamped engines.protocol from create-objectstack's
own package major, though its header says the key carries the PROTOCOL
major. In Changesets pre mode the protocol moves ahead of the version pass
(packages 17.7.0 beside PROTOCOL_VERSION 18.0.0), so the blank template
kept '^17' and a project scaffolded from main was refused at the protocol
handshake on boot.

- The stamp now reads the protocol major from PROTOCOL_VERSION's declaration
  (source text, the expression check-changeset-no-major.mjs reads it with);
  specVersion and the @objectstack/* ranges keep the package range. An
  unreadable declaration is a hard failure, never a fall-back.
- The blank template is re-stamped by the script: '^18'.
- template-consistency.test.ts judges engines.protocol against PROTOCOL_MAJOR
  (spec source, via the existing vitest alias), not the package major.
- The self-test's fixtures carry a package major (42) and a protocol major
  (43) that differ; Control I and Control J pin the two sources and the hard
  failure. template-version-stamps.test.ts's fixture gains the same split.

Claude-Session: https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 10, 2026
@github-actions

github-actions Bot commented Oct 10, 2026 •

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

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 1bb1da1bcbedffaef5e54b9e96aace17bb5a6a55 → packageMentionDocs.

…and their tests as main has them

The Scaffold E2E gate (repo-built scaffolder, registry-installed
@objectstack/* at ^17.0.0) refused a template declaring engines.protocol
'^18': a template's range must match the protocol of the packages it
installs, which is the package major the sync script and the
template-consistency ratchet already enforce. The skew the nightly hit is
the in-repo pairing of a published-line scaffold with the workspace
runtime during the pre-mode window, so the alignment moves into that
test's setup. Restores the four files to their blobs on main and drops
the create-objectstack changeset.

Claude-Session: https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS
Co-authored-by: Claude <noreply@anthropic.com>
…l with the runtime it boots

The file scaffolds the blank starter and boots it against the workspace
runtime without an install. In a Changesets pre-mode window the workspace
protocol (18) is ahead of the published line the template stamps (^17), so
the handshake refused the pair before any boot diagnostic was printed and
the budget assertion read an empty block. The setup now rewrites the one
key to '^' + PROTOCOL_MAJOR of the workspace spec, digits only, so it leaves
the scaffold byte-for-byte as written when the majors agree. A direct
rewrite rather than `migrate meta --write`: that codemod refuses files under
a node_modules segment, where this project lives. Budget, assertions and
fixture objects and actions are unchanged.

Claude-Session: https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s and removed size/m labels Oct 10, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 10, 2026
@objectstack-fleet objectstack-fleet Bot changed the title fix(create-objectstack,cli): stamp engines.protocol from PROTOCOL_VERSION and drive the two new --json members (nightly tiers) test(cli): drive the two new --json members and align the noise-budget scaffold with the workspace protocol (nightly tiers) Oct 10, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 10, 2026 16:30
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 10, 2026 16:30
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 10, 2026
Merged via the queue into main with commit d8830c2 Oct 10, 2026
53 of 54 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22622-nightly-tiers-red branch October 10, 2026 16:49
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/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nightly-tiers: red on main

2 participants