Uh oh!
There was an error while loading. Please reload this page.
ci(scaffold-e2e): record why the unpublished-window fallback stays in the workflow, and narrow what its skip covers - #9374
Merged
os-zhuang merged 1 commit intoAug 17, 2026
Conversation
… the workflow, and stop the skip swallowing two real defects Co-Authored-By: Claude <noreply@anthropic.com>
os-zhuang
marked this pull request as ready for review
August 17, 2026 19:26
Uh oh!
There was an error while loading. Please reload this page.
os-zhuang
deleted the
claude/issue-9149-scaffold-e2e-unpublished-window
branch
August 17, 2026 19:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#9149
Workflow-only change to
.github/workflows/scaffold-e2e.yml. The shipped scaffolder is not touched — see "Scope fork" below, which the reviewer should read first.What landed
1. The designed degradation gains a recorded reason (the graded route).
The pinned-shape leg warns and skips during the unpublished-version window because the range-rewrite fallback lives in this workflow's install step, not in the scaffolder. That was tribal knowledge spread across three issues. The step's comment now states it in place: why the fallback sits here, that relocating it into the published scaffolder was considered and declined at triage on 2026-08-17 as a user-visible public-surface expansion, and that reopening it needs a decision card answering this card's three questions. The
specVersioncoupling introduced by #9264 is named there too, so a future taker inherits it instead of rediscovering it.2. The skip no longer swallows two real defects.
The registry answer was classified two ways. "npm says no version matches" and "npm could not be reached" both surface as an empty string, so a registry outage presented itself as the known window and carried the leg green. And once the skip fired, it asserted nothing at all, so a bogus tag emitted during the window was invisible.
Now three ways:
::error::— an unclassifiable answer is never evidence of the windowlatesttag must survive untouched::error::— unchanged; still the branch that catches a genuinely broken scaffolder installThe degradation itself is intact: the unpublished-version window still does not redden this leg.
Scope fork — please rule before closing
The dispatch that produced this PR framed the defect as where the fallback lives and opened the file surface to
packages/create-objectstack/src/**, suggesting the fallback be relocated into the scaffolder.The maintainer's first-touch grading on the issue (2026-08-17) says the opposite, and is quoted verbatim:
I followed the maintainer's ruling and stayed in the workflow file. Relocating would have meant writing speculative code on an explicitly-undecided public-surface question. The narrowing above is the part of the dispatch's goal — reduce the gap between what CI exercises and what a user runs — that is reachable without expanding the published surface, and it is the alternative the dispatch itself named as acceptable.
A measured correction to the dispatch's premise
The dispatch stated that a relocated fallback "must cover
specVersionalongsideengines.protocol". Measured:specVersionis advisory-only and, on this path, unread.checkSpecVersionGap(packages/cli/src/utils/spec-version.ts) documents itself as "advisory-only — it never fails a build/validate", and only fires when the declared major is older than the installed one.config.manifest.specVersion, and the blank template'sobjectstack.config.tsmanifest declares nospecVersionat all — onlyobjectstack.manifest.jsondoes, which is template-registry metadata.So the workflow fallback's asymmetry (it re-stamps
engines.protocolbut notspecVersion) is not a live defect:engines.protocolis re-stamped because the ADR-0087 D1 handshake hard-refuses the boot, andspecVersionhas no equivalent enforcement. The coupling is real for the release-time pass; it is not load-bearing for this fallback. A relocation card should still handle it, but as tidiness, not as a boot-blocker.Verification
Gate union re-run on the final commit
c9da9ca0e;dispatch-gates.mjsre-derived from the actual changed path.check:node-versioncheck:required-contextscheck:shard-attestationcheck:workflow-status-functionsnode scripts/check-shard-attestation.mjscheck:nul-bytesbash -non the extracted stepBehavioural verification of the new classifier. The classification block was extracted verbatim from the workflow (parsed out of the YAML, not retyped) and run against a stubbed
npmin four scenarios:origin/main)::error::latest16.2.0(invented)::error::::error::The two bolded rows are the previously-swallowed defects; the reverse verification ran the old block from
origin/mainagainst the same fixtures to prove the narrowing is real rather than cosmetic.Not verified locally, and it cannot be:
Scaffold E2Eis CI-only (its header declaresdispatch-gates: no-check-families) and needs a real registry, Docker and a network. The stubbed run above exercises the classification logic, not the end-to-end leg. A gate that refuses to run is not a gate that passed.Prettier: not configured and not a gate in this repo; the file fails prettier defaults identically before and after this change, so no formatting regression is introduced and the file's existing quote style is left alone.
No changeset, by the workflow's own prescription
This PR changes CI only and releases nothing, which
lint.ymlcalls "the textbookskip-changesetcase — such a PR releases nothing". Theskip-changesetlabel is applied instead of a changeset, which would otherwise fabricate a user-facing release note for a change no user can observe.Generated by Claude Code