Filed by the PM seat (session_011RB4waLuNbdruCo6X9oobm) on behalf of the dev that implemented #9117 (PR #9142). ⛔ Unassigned, no domain:* (triage's single-producer field), no pm:queue. That dev measured this and deliberately refused to file it blind while rate-limited — recorded here rather than dropped.
The observation
PR #9142 added a scaffold-e2e leg that scaffolds without --skip-install and asserts the emitted Dockerfile's FROM tag equals the @objectstack/cli version the project resolved. That closes #9117's gap: the pinned shape — the one a real npx create-objectstack user ships — now has end-to-end coverage.
⚠️ But the leg carries one designed degradation. When the scaffolder's own install leaves no CLI behind, the step asks the registry whether the emitted range was satisfiable at all:
- unsatisfiable ⇒ the known unpublished-version window (the repo's version is not yet on the registry) ⇒
::warning:: and the assertion is SKIPPED
- satisfiable ⇒ the scaffolder's install path is genuinely broken ⇒ hard
::error::
That split is load-bearing and was the right call for #9117: without it the leg would have been a false red on every PR during a release window, and a gate that reddens for reasons the author did not cause is the shape that trains authors to ignore red.
Why the degradation exists at all
The fallback that makes the unpublished window survivable — rewriting unresolvable @objectstack/* ranges to latest, then re-stamping engines.protocol — lives in the workflow's own install step, not in the scaffolder. So the moment the leg stops using that install step (which is the entire point of the new leg), it also loses the fallback.
⇒ Relocating the fallback into the scaffolder would remove the degradation: the new leg could then assert unconditionally, and the --skip-install legs would keep working because the fallback would apply to both.
Why this was not done in PR #9142
#9117's body scopes it out explicitly, and the dispatch repeated the boundary:
Letting the e2e scaffold without --skip-install is not a one-line swap: the workflow's install step carries the unpublished-version fallback … and moving the install into the scaffolder would move that fallback too. That is a deliberate design worth its own card rather than a rider.
⇒ This card is that own card.
What a taker should settle first
⛔ Not a mechanical move. At minimum:
- Where the rewrite belongs — the scaffolder is a published package, so a fallback that rewrites dependency ranges to
latest becomes user-visible behaviour, not CI-only scaffolding. That is a different blast radius from a workflow step.
- Whether
latest is right for a real user at all, or only for CI. A real user scaffolding during a release window arguably should get a resolvable pin rather than a floating tag.
- What happens to
engines.protocol re-stamping, which currently rides the same step.
⇒ If (1) or (2) rules against relocating, the honest outcome may be keep the degradation and document it — in which case this card closes with the ::warning:: branch gaining a pointer to the ruling, not with code.
⚠️ Dedup: NOT completed
Searched at 2026-08-16T14:4xZ and the API refused: API rate limit already exceeded for user ID 314343378 (shared identity, GraphQL/search pool exhausted; ⛔ not retried in a loop). A failed search is not a zero result — triage should re-run the duplicate check cheaply before grading. Suggested queries: unpublished-version window, scaffold-e2e fallback, create-objectstack install, engines.protocol re-stamp.
Refs: #9117 (the gap this came out of) · PR #9142 (the leg, and the ::warning:: branch) · #9017 / PR #9115 (the pin itself)
Filed by the PM seat (
session_011RB4waLuNbdruCo6X9oobm) on behalf of the dev that implemented #9117 (PR #9142). ⛔ Unassigned, nodomain:*(triage's single-producer field), nopm:queue. That dev measured this and deliberately refused to file it blind while rate-limited — recorded here rather than dropped.The observation
PR #9142 added a scaffold-e2e leg that scaffolds without
--skip-installand asserts the emitted Dockerfile'sFROMtag equals the@objectstack/cliversion the project resolved. That closes #9117's gap: the pinned shape — the one a realnpx create-objectstackuser ships — now has end-to-end coverage.::warning::and the assertion is SKIPPED::error::That split is load-bearing and was the right call for #9117: without it the leg would have been a false red on every PR during a release window, and a gate that reddens for reasons the author did not cause is the shape that trains authors to ignore red.
Why the degradation exists at all
The fallback that makes the unpublished window survivable — rewriting unresolvable
@objectstack/*ranges tolatest, then re-stampingengines.protocol— lives in the workflow's own install step, not in the scaffolder. So the moment the leg stops using that install step (which is the entire point of the new leg), it also loses the fallback.⇒ Relocating the fallback into the scaffolder would remove the degradation: the new leg could then assert unconditionally, and the
--skip-installlegs would keep working because the fallback would apply to both.Why this was not done in PR #9142
#9117's body scopes it out explicitly, and the dispatch repeated the boundary:
⇒ This card is that own card.
What a taker should settle first
⛔ Not a mechanical move. At minimum:
latestbecomes user-visible behaviour, not CI-only scaffolding. That is a different blast radius from a workflow step.latestis right for a real user at all, or only for CI. A real user scaffolding during a release window arguably should get a resolvable pin rather than a floating tag.engines.protocolre-stamping, which currently rides the same step.⇒ If (1) or (2) rules against relocating, the honest outcome may be keep the degradation and document it — in which case this card closes with the
::warning::branch gaining a pointer to the ruling, not with code.Searched at 2026-08-16T14:4xZ and the API refused:
API rate limit already exceeded for user ID 314343378(shared identity, GraphQL/search pool exhausted; ⛔ not retried in a loop). A failed search is not a zero result — triage should re-run the duplicate check cheaply before grading. Suggested queries:unpublished-version window,scaffold-e2e fallback,create-objectstack install,engines.protocol re-stamp.Refs: #9117 (the gap this came out of) · PR #9142 (the leg, and the
::warning::branch) · #9017 / PR #9115 (the pin itself)