Skip to content

fix(publish): JSR first-publish package provisioning + one-shot e2e CI + deterministic release tool#122

Merged
rickylabs merged 4 commits into
mainfrom
fix/jsr-first-publish-provisioning
Jun 25, 2026
Merged

fix(publish): JSR first-publish package provisioning + one-shot e2e CI + deterministic release tool#122
rickylabs merged 4 commits into
mainfrom
fix/jsr-first-publish-provisioning

Conversation

@rickylabs

Copy link
Copy Markdown
Owner

Summary

Fixes the first-publish JSR failure mode where every @netscript/* package must be pre-created in the JSR registry and linked to rickylabs/netscript before OIDC publish can authorize. This PR adds idempotent package provisioning, wires it into the release publish workflow before the dry-run/publish steps, and adds a deterministic GitHub Release helper so the release cut uses argv arrays instead of hand-built shell quoting.

Root Cause

The first OIDC publish failed because JSR does not auto-create packages non-interactively. OIDC publish can prove provenance, but the packages must already exist under the @netscript scope and be linked to the public GitHub repository before the first publish.

Authoritative API

Provisioning uses https://api.jsr.io with Authorization: Bearer <token> and JSON bodies:

  • GET /scopes/{scope}/packages/{package} to check existence.
  • POST /scopes/{scope}/packages with { "package": "<name>" } to create missing packages.
  • PATCH /scopes/{scope}/packages/{package} with { "githubRepository": { "owner": "rickylabs", "name": "netscript" } } to link OIDC authorization.

Already-exists and already-linked/no-op responses are treated as idempotent success.

Scope

  • Archetype / area: tooling, release workflow, JSR publish provisioning
  • Run dir: .llm/tmp/run/fix-jsr-first-publish-provisioning--e2e/

Deliverables

  • .llm/tools/jsr-provision-packages.ts: discovers all publishable members via discoverWorkspaceMembers, lists the 31 package names, no-ops without JSR_API_TOKEN, and otherwise performs GET -> optional POST -> PATCH sequentially.
  • .github/workflows/publish.yml: bumps actions/checkout to @v5, adds Ensure JSR packages exist before Publish dry-run, keeps id-token: write, and keeps publish on .llm/tools/run-publish.ts rather than bare deno publish.
  • .llm/tools/release.ts: validates --tag, workspace version equality, and non-empty notes, then runs gh release create via Deno.Command argv; --dry-run prints the exact argv without creating a release.

One-Shot Release Flow

  1. USER ACTION: mint a JSR token with @netscript package-management/full access and add it as repo secret JSR_TOKEN.
  2. Cut one GitHub Release for v0.0.1-alpha.1.
  3. The publish workflow checks out the tag with actions/checkout@v5.
  4. Ensure JSR packages exist uses JSR_TOKEN to create and link all 31 @netscript/* packages.
  5. Publish dry-run runs the existing per-member publish tool.
  6. Publish runs the existing per-member publish tool with OIDC provenance.
  7. The workflow back-annotates the GitHub Release notes with managed JSR links.

Slices

  • S1 provisioning/release workflow tooling — 3fcabc04
  • S1 harness commit tracking — b2065d91

Validation

  • deno check --unstable-kv .llm/tools/jsr-provision-packages.ts .llm/tools/release.ts — PASS.
  • deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root .llm/tools --ext ts --include '^(\\.llm/tools/(jsr-provision-packages|release)\\.ts)$' — PASS, 2 files selected, 0 findings.
  • deno lint --config /dev/null .llm/tools/jsr-provision-packages.ts .llm/tools/release.ts — PASS, checked 2 files.
  • Workflow YAML parse via deno eval --no-lock + jsr:@std/yaml — PASS.
  • Workflow scan — PASS: checkoutV4=false, checkoutV5Count=1, ensureBeforeDryRun=true, publish uses run-publish.ts, no bare deno publish workflow step.
  • env -u JSR_API_TOKEN deno run --allow-net --allow-read --allow-env .llm/tools/jsr-provision-packages.ts --dry-run — PASS, listed 31 members and printed JSR_API_TOKEN not set — skipping provisioning (assuming packages already provisioned).
  • deno run --allow-read --allow-run .llm/tools/release.ts --dry-run --tag v0.0.1-alpha.1 --notes-file <temp notes> — PASS, printed gh release create v0.0.1-alpha.1 --target main --notes-file ... --repo rickylabs/netscript --title v0.0.1-alpha.1 --prerelease.
  • deno run --allow-read --allow-run .llm/tools/release.ts --dry-run --tag v0.0.2-alpha.1 --notes-file <temp notes> — PASS, failed clearly with Release tag version 0.0.2-alpha.1 does not match workspace version 0.0.1-alpha.1.

Known Gate Notes

  • deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root .llm/tools --ext ts is blocked by unrelated pre-existing .llm/tools/fitness/check-manifest-integrity.ts errors: missing packages/fresh-ui/registry/manifest.ts and implicit-any parameters.
  • Root lint wrapper cannot lint .llm/ files because the root Deno lint config excludes .llm/; explicit deno lint --config /dev/null was used for the touched tools.

Drift / Debt

  • No architecture debt created.
  • Harness drift recorded: this was a WSL Codex implementation slice with supervisor-provided implementation authorization, so separate PLAN-EVAL was not launched in this session. Separate IMPL-EVAL remains required before merge.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [VERDICT: READY_FOR_IMPL_EVAL]

Implemented the JSR first-publish provisioning slice and pushed it to fix/jsr-first-publish-provisioning.

Scope

  • Added .llm/tools/jsr-provision-packages.ts for idempotent JSR package existence + GitHub repo linking, using discoverWorkspaceMembers.
  • Hardened .github/workflows/publish.yml: actions/checkout@v5, Ensure JSR packages exist before Publish dry-run, retained OIDC publish through .llm/tools/run-publish.ts.
  • Added .llm/tools/release.ts for deterministic gh release create argv construction and dry-run validation.
  • Recorded harness artifacts under .llm/tmp/run/fix-jsr-first-publish-provisioning--e2e/.

Commits

  • 3fcabc04fix(publish): provision jsr packages before oidc publish
  • b2065d91chore(harness): record jsr provisioning slice

Validation

  • deno check --unstable-kv .llm/tools/jsr-provision-packages.ts .llm/tools/release.ts — PASS.
  • deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root .llm/tools --ext ts --include '^(\\.llm/tools/(jsr-provision-packages|release)\\.ts)$' — PASS, 2 files selected, 0 findings.
  • deno lint --config /dev/null .llm/tools/jsr-provision-packages.ts .llm/tools/release.ts — PASS, checked 2 files.
  • Workflow YAML parse via deno eval --no-lock + jsr:@std/yaml — PASS.
  • Workflow scan — PASS: checkout v5 only, ensure-packages step precedes dry-run, publish uses run-publish.ts, OIDC permission retained.
  • No-token provisioning probe — PASS: listed all 31 packages and exited 0 with the requested skip line.
  • Release dry-run probe — PASS: printed gh release create v0.0.1-alpha.1 --target main ... --repo rickylabs/netscript --title v0.0.1-alpha.1 --prerelease.
  • Release mismatch probe — PASS: v0.0.2-alpha.1 fails with a clear workspace-version mismatch.

Gate Notes

  • Broad .llm/tools check is blocked by unrelated pre-existing .llm/tools/fitness/check-manifest-integrity.ts errors; details are in worklog.md.
  • Root lint wrapper cannot lint .llm/ because root lint config excludes it, so explicit deno lint --config /dev/null was used for touched tools.

Next

  • Run separate-session IMPL-EVAL before merge.
  • User/supervisor action before the real release: add repo secret JSR_TOKEN with @netscript package-management/full access.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [VERDICT: FOLLOW_UP_READY_FOR_IMPL_EVAL]

Applied the reviewer-requested JSR provisioning robustness fix.

Commit

  • 95f8e0f4fix(publish): avoid jsr writes when packages are linked
  • e99e51a5chore(harness): record jsr write-gating fix

What Changed

  • Public existence checks now call GET /scopes/{scope}/packages/{package} without an Authorization header.
  • The tool parses githubRepository.owner / githubRepository.name from the public package JSON and skips PATCH when the package is already linked to the target repo, case-insensitively.
  • Writes are now attempted only when needed: POST for missing packages or PATCH for missing/different repo links.
  • No-token real runs now do public GETs first and fail only if a package needs a write, with write needed but no token.
  • No-token --dry-run still exits 0 and reports intended create/link actions without writes.
  • Non-JSON response bodies are caught and converted into clean HTTP error messages instead of unhandled JSON parse failures.

Validation

  • Public shape probe: GET https://api.jsr.io/scopes/std/packages/assert returned githubRepository.owner = denoland, githubRepository.name = std.
  • deno check --unstable-kv .llm/tools/jsr-provision-packages.ts .llm/tools/release.ts — PASS.
  • deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root .llm/tools --ext ts --include '^(\\.llm/tools/(jsr-provision-packages|release)\\.ts)$' — PASS, 2 files selected, 0 findings.
  • deno lint --config /dev/null .llm/tools/jsr-provision-packages.ts .llm/tools/release.ts — PASS, checked 2 files.
  • env -u JSR_API_TOKEN deno run --allow-net --allow-read --allow-env .llm/tools/jsr-provision-packages.ts --dry-run — PASS, listed all 31 members, performed public GETs, reported each as created + would-link, and exited 0.
  • env -u JSR_API_TOKEN deno run --allow-net --allow-read --allow-env .llm/tools/jsr-provision-packages.ts — PASS for failure behavior, exited 1 with write needed but no token failures and no writes attempted.

Worklog and commits.md are updated under .llm/tmp/run/fix-jsr-first-publish-provisioning--e2e/.

@rickylabs
rickylabs merged commit cd33c37 into main Jun 25, 2026
6 checks passed
@rickylabs
rickylabs deleted the fix/jsr-first-publish-provisioning branch June 25, 2026 11:38
rickylabs added a commit that referenced this pull request Jun 28, 2026
… (#164)

* docs(release): one-shot deterministic release automation — research + plan (#147)

Folds #122 (workspace-coordinated version bump: root+members+lock),
#146 (drop --frozen rejected by Deno 2.9 deno ci), #123 (gate e2e-cli-prod
behind publish via workflow_run, no JSR race), #133 (text-import preflight gate).
Plan-only; no tooling code. Awaiting PLAN-EVAL before any implementation slice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(openhands): apply agent changes

* chore(openhands): record run trace 28304587059-1

* docs(release): PLAN-EVAL cycle-2 revision — narrow D3 + two-pass cross-line scan (#147)

Addresses PLAN-EVAL cycle-1 FAIL_PLAN (sole blocker D3). D3 now scans only
Deno.readTextFile/readFile (drops constructor false-positives) with a two-pass
cross-line resolver for the openapi.ts:29->155 break class + positive/negative
fixtures. Folds the 3 non-blocking clarifications: D4 artifact version handoff,
D5 agentic:sync-claude regen, D2 exact edit sites.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(openhands): apply agent changes

* chore(openhands): record run trace 28305083715-1

* chore(release): fix prod install args

* chore(release): add text import preflight

* chore(release): add release cut orchestrator

* chore(release): order prod e2e after publish

* docs(release): add release workflow skill

* chore(harness): finalize release automation run artifacts

* chore(openhands): apply agent changes

* chore(openhands): record run trace 28305978962-1

* chore(lock): drop spurious @std/yaml entry from IMPL-EVAL ad-hoc parse

The IMPL-EVAL evaluator ran an ad-hoc `@std/yaml parse` for workflow YAML
sanity, which leaked jsr:@std/yaml@1 into the root deno.lock. No committed
source imports @std/yaml, so the entry is unused churn. Restore deno.lock to
the IMPL HEAD (58ab73c) state. Release-automation tooling is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: OpenHands Bot <openhands@all-hands.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant