ci(publish): real-publish-equivalent preflight (no more half-releases)#141
Merged
Conversation
`deno publish --dry-run` is a confirmed blind spot: it can pass while the REAL publish module-graph build rejects a module. That is exactly how the alpha.5 release half-published (text-import graph-build rejection surfaced only at real publish, after dry-run was green), uploading a partial set. Add a `preflight` publish mode that runs the actual `deno publish` (not --dry-run) with a deliberately invalid token, so it builds every member's publish graph in the real code path and then stops at the auth boundary before any upload. Classification: - reached auth boundary (invalidBearerToken) -> PASS (full graph built) - exit 0 (all already published, registry skip) -> PASS (no-op) - any other nonzero (graph/check error) -> FAIL (would half-publish) Wire a "Publish preflight" CI step between dry-run and Publish, so a real graph/check failure reds the job before the real Publish step runs. The preflight never uploads (the token is invalid by design). Validated locally across all three branches: already-published no-op PASS, unpublished-version real-graph-build -> auth-boundary PASS (all 31 members incl. fresh-ui), and an injected missing-module graph error -> FAIL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
rickylabs
added a commit
that referenced
this pull request
Jun 26, 2026
…to 0.0.1-alpha.6 (#142) Revert the #139 string-const asset embedding and return to `with { type: 'text' }` imports in the generated barrels (cli/fresh-ui/plugin) — text imports keep the asset content in the module graph so it resolves over https from JSR, and are the cleaner mechanism. They are runtime-stable in Deno 2.8+ and the real publish-graph build accepts them (verified locally and in CI on Deno 2.9.0). The #141 publish preflight is kept: it runs the real `deno publish` graph build (no upload) before the Publish step, so if the text-import graph build is ever rejected the job reds before any upload — no half-publish. The alpha.5 text-import rejection was not reproducible locally or in CI on the same Deno 2.9.0. Bump 0.0.1-alpha.5 -> 0.0.1-alpha.6 across all workspace members, the root deno.json, and the deno.lock @netscript range mirror. Gates: check:assets-barrel (deterministic regen) PASS; local publish preflight (real graph build over all 31 members incl. fresh-ui + plugin text imports) PASS. Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 26, 2026
rickylabs
added a commit
that referenced
this pull request
Jun 27, 2026
Composes the four alpha.11 fix-train slices: A (root --version + write-free --dry-run via DryRunFileSystemAdapter), B (scaffold type-soundness), C (--cache/--cache-backend + interactive init via PromptPort), E (plain GET /health + service-health e2e probe). Init conflict resolved keeping both A+C behaviors. Composed scaffold.runtime e2e 48/0. IMPL-EVAL PASS (OpenHands qwen3.7-max, separate session): no userland leak, no unauthorized casts, minimal lock churn. Integrates #156 #157 #158 #159. Refs #141 #153.
rickylabs
added a commit
that referenced
this pull request
Jun 27, 2026
* docs(harness): alpha.11 fix-train plan + research (Storefront Ch.1 blockers) PLAN-EVAL deliverable for the alpha.11 fix-train (#141) addressing the Storefront Ch.1 eye-test blockers (#153). Six slices: A CLI-core (F-3/F-4), B scaffold type-soundness (F-15), C interactive-init + cache feature (F-11, new public surface), D doc-truth alignment driven by the e2e (F-6/F-8/F-12), E service health + e2e :3001 coverage (F-14/F-13), F install pin + alpha banner (F-1). Grounded by two code-truth scouts: F-6 is a doc fix not a code reorder (db commands self-provision Aspire via DbOperationRunner); F-13 is diagnosed by a new e2e service-health probe; interactive init reuses the dormant PromptPort/CliffyPrompt adapter (init = first consumer). Plan artifacts only; no framework source. Implementation follows on PLAN-EVAL PASS via WSL Codex daemon-attached slices. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * alpha.11 fix-train: PLAN-EVAL verdict — PASS (with advisories) - Slice decomposition, dependency order, lane split, gate set, debt list all sound. - F-6 disposition (db self-provisions Aspire via DbOperationRunner.executeDetached) confirmed; doc fix only, not code reorder. - F-14 advisory: defineService().withHealth() is already wired (current main); Slice E's template work is verify-only — only the new :3001 e2e probe is required. - F-15a/b: template-rewrite preferred over SDK widening (getQueryState exists on the underlying @tanstack/query-core 5.101.0). - F-15c: publish-only drift disposition is correct; self-resolves on republish. - Slice C public surface (--cache/--cache-backend) is contract-first and doctrine-conformant; --ci/--yes escape hatches preserve CI non-interactive. - Gate set: scoped check/lint/fmt + deno task test + deno doc --lint on changed public exports + full e2e:cli scaffold.runtime with new :3001 probe. Co-authored-by: openhands <openhands@all-hands.dev> * alpha.11 fix-train: PLAN-EVAL trace metadata (run-28284573816-1, verdict=PASS) Co-authored-by: openhands <openhands@all-hands.dev> * chore(openhands): record run trace 28284573816-1 --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: openhands <openhands@all-hands.dev>
rickylabs
added a commit
that referenced
this pull request
Jun 27, 2026
…realignment (#162) * docs(cli-reference): document alpha.11 init surface — cache + interactive + version Lane D (doc-truth align) commit 1: add the new `netscript init` surface introduced by the alpha.11 fix-train (PR #160) to the scaffold reference. - `--cache` / `--no-cache` (default on) + `--cache-backend redis|garnet|deno-kv` (default redis; redis/garnet are Aspire container resources, deno-kv is app-level/no container). - Interactive-vs-non-interactive callout: TTY prompts for omitted options incl. the two cache questions; `--yes`/`--ci` skip prompts; defaults = Postgres-ready workspace + Redis cache. - `netscript --version` prints the installed CLI version. Grounded against integration/alpha11-fixtrain init-command.ts + cache-backend.ts. Docs-only; lands as a separate docs PR. Refs #141 #153. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * docs(alpha11): replace invalid `aspire run` with `aspire start` across published docs `aspire run` is not a valid Aspire CLI command (the CLI has `aspire start`); Run-1 eye-test blocker F-12 confirmed it orphans the scaffolded AppHost on Windows. Sweeps all 61 published pages (tutorials, capabilities, how-to, explanation, landing, cli-reference) to `aspire start`. Internal `_plan/` worklogs left untouched. 1:1 string swap, no other content change. Refs #141 #153 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * docs(alpha11): pin CLI install/invoke to the alpha release train (F-1) Bare `jsr:@netscript/cli` resolves to JSR `latest`, which is null while the package is prerelease-only — so every unpinned `deno install`/`deno x` in the docs dead-ends at "no matching version" (Run-1 eye-test blocker F-1). Pin all 20 occurrences to the dynamic `{{ releaseSpecifier }}` (= `@<releaseVersion>`, sourced from packages/cli/deno.json), so published docs always show the exact current alpha pin and self-advance on each release bump. Plain fences/prose use `{{ releaseSpecifier }}`; comp-tag JS string args use `" + releaseSpecifier + "` concatenation to avoid nested-`{{}}` parse breaks. Lume build verified green (306 files, exit 0). Refs #141 #153 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * docs(alpha11): realign cache docs to multi-backend capability (redis default) Present the scaffold cache as a multi-backend capability across the site: `redis` is the default backend everywhere; `garnet` and `deno-kv` are first-class alternatives selectable via `--cache-backend`. Garnet is kept only where shown as an explicit alternative backend choice, and real symbols (createGarnetListTransport, Cache.<backend> keys, GARNET_URI/REDIS_URI) are preserved. - 45 docs files realigned (concepts, cli-reference, glossary, explanation/*, capabilities/*, how-to/*, tutorials/*, index/why/quickstart). - aspire-resource-graph diagram: add the default Redis cache resource node and wiring; SVG regenerated (byte-clean, single-diagram delta). - quickstart bare `netscript init` now passes `--db postgres` to match the tutorial stack. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * docs(alpha11): present the database as polyglot (postgres default; mysql/mssql/sqlite via --db) Mirror the cache multi-backend realignment for the database. NetScript scaffolds a Prisma-backed database for four engines chosen at scaffold time with `--db`: postgres | mysql | mssql | sqlite. Postgres stays the recommended default (every tutorial uses `--db postgres`); mysql/mssql/sqlite are first-class alternatives. postgres/mysql/mssql provision an Aspire container resource; sqlite is file-backed with no container. This is enrichment, not replacement: wherever the docs presented Postgres as the sole app database (monolithic framing), add concise polyglot framing or — on the anchor pages (database, cli-reference, glossary, use-a-second-database, database-migration) — a richer backend/--db passage with the sqlite no-container caveat. Tutorials keep every `--db postgres` command verbatim and gain one swap-engine note near the first scaffold step. Rule-C kept untouched (engine-specific by design, not the app-DB-engine choice): Postgres-as-subsystem backends (queue provider FOR UPDATE SKIP LOCKED / advisory locks, saga/durable stores), connection-string mechanics (DATABASE_URL / POSTGRES_URI), Prisma provider literals, engine-specific paths, and the runtime second-datasource adapter barrel (which ships postgres/mssql/mysql only — no sqlite adapter was fabricated). - 27 docs files realigned (capabilities/*, cli-reference, glossary, explanation/*, how-to/*, tutorials/*, concepts/index/why/quickstart). - Lume build: green (306 files). No diagram sources changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * docs(alpha11): note Prisma-backed subsystems follow the scaffolded DB engine (not Postgres-only) A file-grounded subsystem audit showed the saga `prisma` store and the better-auth backend are NOT Postgres-specific — both persist through the project's Prisma client, so they follow whichever engine was scaffolded with `--db` (Postgres by default; mysql / mssql / sqlite all work). The docs presented them as "Postgres" stores, implying a hard coupling that does not exist. Add concise polyglot framing at the definitional points only: - capabilities/durable-sagas.md — `prisma` store backend + trait-matrix row. - explanation/durability-model.md — `prisma` store row + "choosing kv vs prisma". - capabilities/auth.md — better-auth tables provisioning note. - how-to/add-authentication.md — auth.prisma aggregation line + table caption. Deliberately left unchanged (genuinely engine-specific, per the same audit): - The queue PostgreSQL provider — hard-tied to Postgres (`FOR UPDATE SKIP LOCKED`, `JSONB`, `TIMESTAMPTZ`, raw `$N` SQL); a polyglot queue is real engineering (SQLite infeasible) and is tracked as backlog, not a doc framing. - The durable-streams service's Postgres/Redis dependency line (service infra, accurate by default). Lume build: green (306 files). No diagram sources changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct * chore(openhands): record run trace 28300391133-1 --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: OpenHands Bot <openhands@all-hands.dev>
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 free
to 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.
Real-publish-equivalent preflight — never half-release again
deno publish --dry-runis a confirmed blind spot: it can pass while the real publish module-graph build rejects a module. That is exactly how alpha.5 half-published — the text-import graph-build rejection surfaced only at real publish (after dry-run was green), so a partial member set uploaded before the run errored.This adds a preflight that exercises the real publish code path but cannot upload.
How it works
A new
preflightmode inpublish-workspace.tsruns the actualdeno publish(not--dry-run) with a deliberately invalid token (--token … --no-provenance).deno publishbuilds the full combined module graph for every workspace member first, then hits auth — so an invalid token lets the graph build run for real and stops at the auth boundary before any upload.Classification:
invalidBearerToken)CI wiring
publish.ymlgains aPublish preflight (real graph build, no upload)step between Publish dry-run and Publish. A real graph/check failure now reds the job before the real Publish step runs, so a release can never half-publish. The step never uploads (the token is invalid by design); it adds no secret dependency.Validation (local, Deno 2.9.0)
All three classification branches exercised end-to-end:
@netscript/fresh-ui, stopped at the auth boundary → PASS, exit 0.deno check✓ ·deno fmt --check✓ ·deno lint✓ (tools clean).Closes the
deno publish --dry-runblind spot recorded in the JSR publish dry-run blind-spots note.🤖 Generated with Claude Code