From fd52b997ab27ec66671e5421d60eb27d7029c574 Mon Sep 17 00:00:00 2001 From: lzrs Date: Tue, 28 Jul 2026 11:11:09 -0700 Subject: [PATCH 1/6] sdg(phase-2): draft patch 0001-npm-publishing (Bug Report, Proposed) Triage of the npm-publishing seed: SPEC.md exists and the change requires no SPEC.md update (distribution is not part of the product contract), so this is a bug-classified patch. Substance: first publish of @modularcloud/xspec, standing automated releases from main, release logic recorded in DEVOPS.md, concise manual checklist for Developer-credential steps. Co-Authored-By: Claude Fable 5 --- specs/patches/0001-npm-publishing.md | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 specs/patches/0001-npm-publishing.md diff --git a/specs/patches/0001-npm-publishing.md b/specs/patches/0001-npm-publishing.md new file mode 100644 index 0000000..f987866 --- /dev/null +++ b/specs/patches/0001-npm-publishing.md @@ -0,0 +1,38 @@ +# Patch 0001 — npm publishing + +- **Type:** Bug Report +- **Stage:** Proposed +- **Origin:** Developer seed, 2026-07-28 (written on Developer's behalf by Liaison) + +## Motivation + +The xspec product is complete and green on `main` of its dedicated repository (`modularcloud/xspec`), but it has never been distributed. The initial build's release was deliberately deferred by Developer decision — `specs/DEVOPS.md` records the deferral and the release-candidate commit — because the work then lived in the SDG process repository rather than the product's own. The product has since been relocated to this repository. Developer has now authorized and requested distribution: a first publish, plus a standing automated release path so distribution never lags `main` again. + +## Change requested + +1. **First publish.** The product is published to the public npm registry under the package name `@modularcloud/xspec`, from the `main` branch as it stands. Publishing changes nothing about product behavior: what is published is the product as already specified and implemented. +2. **Standing automated releases.** Going forward, every change that lands on the `main` branch of this repository is automatically released to npm, without Developer involvement per release. Each release carries a version greater than every previously published version, and a release happens only from a green build (per the standing DEVOPS rule: never release with red CI). +3. **Release logic recorded in `specs/DEVOPS.md`.** The standing release procedure above becomes part of `specs/DEVOPS.md`, the document PROCESS.md designates as owning how and when release, merge, and deploy actions happen. DEVOPS.md's description of the deferred initial-build release in the old repository is superseded by the reality that this repository is now the product's home. +4. **Concise manual checklist.** Everything that genuinely requires Developer's own accounts or credentials — npm organization access for the `modularcloud` scope, publish credentials, repository secrets, and similar — is collected into one concise checklist handed to Developer at the end. Everything that does not require Developer's credentials is done automatically by the process. + +## Developer's working instructions (archival, from the seed) + +- The process should do as much as possible automatically. Whatever genuinely requires Developer's own accounts or credentials (npm organization access, publish credentials, repository secrets, and similar) must be collected into a concise manual checklist and handed to Developer at the end. +- Publish from the `main` branch as it stands. Unrelated uncommitted docs work-in-progress in the local checkout is to be disregarded: leave it on disk, never commit it, never delete it; base all work on `origin/main`. + +Archival observation from triage (not a prescription): the repository's package metadata predates the relocation — it names the package `xspec` (unscoped) and points at the old `modularcloud/sdg-claude` repository — so the published artifact's metadata will need to correctly identify the package as `@modularcloud/xspec` and this repository as its home. + +## Classification rationale + +- **No changes to `SPEC.md`.** SPEC.md defines product behavior through its complete interface — the `xspec` command-line executable, the `xspec.config.ts` configuration, the source-file syntax, the generated TypeScript modules, and the files xspec writes to the workspace. The distribution channel is not part of that contract, and no product behavior changes here. Per PROCESS.md, a patch that does not require changes to `SPEC.md` is classified as a bug. +- **No test harness update is targeted, and no changes to `TEST-SPEC.md` (or `CERTIFICATIONS.md`) are necessary.** There is no product misbehavior for the harness to catch: this patch introduces no product change and reports no defect. Its substance is release machinery, which PROCESS.md places under `DEVOPS.md` and the Release phase. + +## Considerations for refinement + +- The versioning policy for automated releases: how the strictly increasing version of each `main` release is determined, and what version the first publish carries — specified behaviorally, without prescribing tooling. Developer's instruction is maximal automation, so the policy must not require Developer involvement per release. +- The release gate: whether anything beyond green CI must hold before an automated release proceeds. +- The exact boundary of the manual checklist: which one-time setup actions can be prepared by the process versus which require Developer's own accounts, so the checklist stays minimal. + +## Stage history + +- 2026-07-28 — **Proposed**. Drafted from the Developer seed during triage. From aec65ee4ca21d5a313b52768b30f5040226da126 Mon Sep 17 00:00:00 2001 From: lzrs Date: Tue, 28 Jul 2026 11:26:18 -0700 Subject: [PATCH 2/6] sdg(liaison): update PHILOSOPHY.md --- specs/PHILOSOPHY.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/specs/PHILOSOPHY.md b/specs/PHILOSOPHY.md index c8c730d..2fa277d 100644 --- a/specs/PHILOSOPHY.md +++ b/specs/PHILOSOPHY.md @@ -8,4 +8,8 @@ IMPORTANT: This file may only be edited and interpreted by Liaison. Only Liaison - sdg-claude is the home of the SDG process only — it "describes the process being run and is not supposed to be the xspec home" (Developer, 2026-07-17). Products built by the process belong in their own repositories. The xspec initial build landed here by accident; Developer's plan: finish the initial-build PR as-is on this repo, then Developer personally relocates the work to a dedicated xspec repo ("i will switch it over"). Consequences while this run finishes: PR #1 deliberately stays merge-conflicted with main (specs/GOALS.md) and unmerged — that state is intended, never a defect to fix or re-raise; no actor merges main into the branch or edits GOALS.md; and since a conflicted PR can never produce pull_request-event CI runs, every green-CI requirement of this run is observed via CI runs on the branch head instead (equivalent evidence: same workflow, same tree — the merge ref it forgoes is with a main this work is leaving anyway). Channel ruling (2026-07-17): workflow_dispatch is unavailable — the GitHub integration token lacks Actions write (403 "Resource not accessible by integration", proven twice) — so the sanctioned channel is push-triggered runs: ci.yml's `push:` trigger amended to include `sdg/initial-build` (agent-owned Phase 8 scaffold, editable without approval; agents have pushed workflow-file changes successfully, so the push credential carries workflow scope). Evaluation frame at every gate is per-job, never the run-level composite: at Phase 9, harness-self green is the required signal while suite-linux/suite-windows are expected red (composite "failure" is the expected shape); from Phase 10's completion, all legs must be green. General rule: when a CI observation channel is closed by integration permissions, prefer amending agent-owned scaffold (e.g. workflow triggers) over asking Developer for UI actions or permission grants — Developer delegates tooling choices and has asked for zero process friction while this run finishes. At run completion, the closing report to Developer should note the branch is ready for the switch-over. - Release ruling for the xspec initial build (2026-07-25, derived from the 2026-07-17 wrong-repo decision): "release" on this repo means no external artifacts at all — no merge (impossible and forbidden), no version tags, no GitHub Release, no package publishing. An xspec version tag or Release on sdg-claude would brand the process repo as the product's home, exactly what Developer said it is not; and publishing needs credentials and authorization never granted. The released state is the green branch head itself (the final commit with all CI jobs green); actual distribution — tagging, npm publish, repo setup — happens after Developer personally relocates the work to the dedicated xspec repo, from that repo. General rule: release actions that create external artifacts (tags, GitHub Releases, package publishes) always require explicit Developer authorization; absent one, DEVOPS.md defaults to deferral and the completion report names the exact commit that constitutes the release candidate. - The xspec relocation is process-executed at Developer's explicit instruction (2026-07-25), superseding the "Developer personally relocates" plan in the two bullets above; this instruction is the external-artifact authorization DEVOPS.md requires. Sequence: (1) the existing unrelated modularcloud/xspec is renamed to modularcloud/cspec to free the name — a GitHub owner-settings action only Developer can perform, since the session toolset has no repository-rename capability; (2) once the name is free, the process creates a fresh modularcloud/xspec and pushes the finished `sdg/initial-build` branch — full history, complete tree (product, harness, specs, process scaffold, CI) — as the new repository's default branch `main`, so future xspec runs are governed by the SDG process from the product's own home per DEVOPS.md's future-runs flow. sdg-claude and PR #1 are left exactly as they stand; closing PR #1 afterward is Developer's call, never the process's initiative. General rule: repository renames and repository creation in the modularcloud org are Developer-performed — the GitHub integration cannot create org repositories (403 "Resource not accessible by integration" on POST /orgs/modularcloud/repos, proven 2026-07-27) — while pushes are process-performed once the target repo exists and is in session scope (add_repo with push access). Redirect hazard, observed 2026-07-27: after a rename, GitHub leaves a redirect on the freed name until a new repo claims it, and add_repo/git resolve straight through that redirect — so before pushing to a just-freed name, verify the resolved target is the intended new repo (e.g. its branch listing), and never push through a rename redirect: it would land on the renamed old repo. +- npm distribution is authorized (Developer, 2026-07-28): publish the product as `@modularcloud/xspec` from the relocated product repo, and set up automated publishing so changes on `main` release to npm going forward. This is the explicit external-artifact authorization the 2026-07-25 release ruling required, and it is standing: once the automated path exists, publishes triggered by it need no fresh per-release approval. Steps needing Developer's own accounts (npm org access, publish credentials, repo secrets) remain Developer-performed — consistent with the proven pattern that org-level GitHub/npm account actions are Developer's, pushes and repo-side wiring are the process's. +- Developer's default working mode for operational setup (stated 2026-07-28): "do as much for me as you can and then let me know what i need to do manually" — automate everything the process can, then hand Developer one concise checklist of only the steps requiring their accounts/credentials, rather than asking permission step-by-step along the way. +- Developer does docs/README/website work outside the SDG process on `claude/*` branches and merges it to `main` directly (first: modularcloud/xspec PR #1, merged 2026-07-27). Such branches and any related working-tree WIP are Developer's space: SDG agents never fold them into SDG commits, never clean them up, and never re-raise them as anomalies. Ruling 2026-07-28 ("disregard work in progress, just publish main branch"): when unrelated local WIP sits in the checkout, ignore it — leave it on disk, never commit it, never delete it — and base all process work on `origin/main` (using a clean worktree or equivalent if the dirty checkout blocks branch mechanics). +- Operational and infrastructure setup work is not a patch in Developer's eyes: "this is not intended to be a patch, its just a one off set up task" (2026-07-28, correcting the npm-publishing work after triage drafted a Bug Report patch for it). Work whose substance is release/deploy/distribution machinery with zero product-behavior change routes as one-off release/devops execution under DEVOPS.md — not through the patch pipeline — and any patch artifacts created by such a misclassification are retired, not refined. Reserve the patch taxonomy for changes to specified product behavior (IP) or to the harness's ability to catch defects (Bug Report). - Refinement loops that plateau are closed by valve ruling, not run to a spontaneous clean round (first applied 2026-07-10, TEST-SPEC.md at iteration 12 of the xspec initial build). Plateau markers: each fresh review yields only one or two genuine but ever-narrower findings, nothing is re-litigated or reversed, and the upstream documents are already converged. Closure shape: one final iteration whose Driver applies what is necessary and then HALTs, with escape hatches for blocking upstream problems or an indefensible late discovery; residual gaps are deliberately left to the downstream problems-file net, which finds them with implementation eyes when they actually matter. Basis: Developer's revealed preference for bounded forward progress over open-ended polishing (bare "continue" nudges, cost sensitivity shown by the 2026-07-09 credits outage, full delegation of process judgment). From 799177a817dc16233151f8de9366cc9dc8d622e1 Mon Sep 17 00:00:00 2001 From: lzrs Date: Tue, 28 Jul 2026 11:34:21 -0700 Subject: [PATCH 3/6] =?UTF-8?q?sdg(phase-11):=20retire=20patch=200001=20?= =?UTF-8?q?=E2=80=94=20npm=20publishing=20is=20release=20work,=20not=20a?= =?UTF-8?q?=20patch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Developer ruling (2026-07-28): the npm-publishing request is a one-off release/setup task, not a patch — it changes no product behavior and its substance is release machinery owned by DEVOPS.md. The patch document is therefore retired unmerged; its content remains in git history (fd52b99). The release setup itself follows on this branch under Phase 11 authority. Co-Authored-By: Claude Fable 5 --- specs/patches/0001-npm-publishing.md | 38 ---------------------------- 1 file changed, 38 deletions(-) delete mode 100644 specs/patches/0001-npm-publishing.md diff --git a/specs/patches/0001-npm-publishing.md b/specs/patches/0001-npm-publishing.md deleted file mode 100644 index f987866..0000000 --- a/specs/patches/0001-npm-publishing.md +++ /dev/null @@ -1,38 +0,0 @@ -# Patch 0001 — npm publishing - -- **Type:** Bug Report -- **Stage:** Proposed -- **Origin:** Developer seed, 2026-07-28 (written on Developer's behalf by Liaison) - -## Motivation - -The xspec product is complete and green on `main` of its dedicated repository (`modularcloud/xspec`), but it has never been distributed. The initial build's release was deliberately deferred by Developer decision — `specs/DEVOPS.md` records the deferral and the release-candidate commit — because the work then lived in the SDG process repository rather than the product's own. The product has since been relocated to this repository. Developer has now authorized and requested distribution: a first publish, plus a standing automated release path so distribution never lags `main` again. - -## Change requested - -1. **First publish.** The product is published to the public npm registry under the package name `@modularcloud/xspec`, from the `main` branch as it stands. Publishing changes nothing about product behavior: what is published is the product as already specified and implemented. -2. **Standing automated releases.** Going forward, every change that lands on the `main` branch of this repository is automatically released to npm, without Developer involvement per release. Each release carries a version greater than every previously published version, and a release happens only from a green build (per the standing DEVOPS rule: never release with red CI). -3. **Release logic recorded in `specs/DEVOPS.md`.** The standing release procedure above becomes part of `specs/DEVOPS.md`, the document PROCESS.md designates as owning how and when release, merge, and deploy actions happen. DEVOPS.md's description of the deferred initial-build release in the old repository is superseded by the reality that this repository is now the product's home. -4. **Concise manual checklist.** Everything that genuinely requires Developer's own accounts or credentials — npm organization access for the `modularcloud` scope, publish credentials, repository secrets, and similar — is collected into one concise checklist handed to Developer at the end. Everything that does not require Developer's credentials is done automatically by the process. - -## Developer's working instructions (archival, from the seed) - -- The process should do as much as possible automatically. Whatever genuinely requires Developer's own accounts or credentials (npm organization access, publish credentials, repository secrets, and similar) must be collected into a concise manual checklist and handed to Developer at the end. -- Publish from the `main` branch as it stands. Unrelated uncommitted docs work-in-progress in the local checkout is to be disregarded: leave it on disk, never commit it, never delete it; base all work on `origin/main`. - -Archival observation from triage (not a prescription): the repository's package metadata predates the relocation — it names the package `xspec` (unscoped) and points at the old `modularcloud/sdg-claude` repository — so the published artifact's metadata will need to correctly identify the package as `@modularcloud/xspec` and this repository as its home. - -## Classification rationale - -- **No changes to `SPEC.md`.** SPEC.md defines product behavior through its complete interface — the `xspec` command-line executable, the `xspec.config.ts` configuration, the source-file syntax, the generated TypeScript modules, and the files xspec writes to the workspace. The distribution channel is not part of that contract, and no product behavior changes here. Per PROCESS.md, a patch that does not require changes to `SPEC.md` is classified as a bug. -- **No test harness update is targeted, and no changes to `TEST-SPEC.md` (or `CERTIFICATIONS.md`) are necessary.** There is no product misbehavior for the harness to catch: this patch introduces no product change and reports no defect. Its substance is release machinery, which PROCESS.md places under `DEVOPS.md` and the Release phase. - -## Considerations for refinement - -- The versioning policy for automated releases: how the strictly increasing version of each `main` release is determined, and what version the first publish carries — specified behaviorally, without prescribing tooling. Developer's instruction is maximal automation, so the policy must not require Developer involvement per release. -- The release gate: whether anything beyond green CI must hold before an automated release proceeds. -- The exact boundary of the manual checklist: which one-time setup actions can be prepared by the process versus which require Developer's own accounts, so the checklist stays minimal. - -## Stage history - -- 2026-07-28 — **Proposed**. Drafted from the Developer seed during triage. From 8e95079fd2cb3bf4981655c8b14ec3400706a709 Mon Sep 17 00:00:00 2001 From: lzrs Date: Tue, 28 Jul 2026 11:35:38 -0700 Subject: [PATCH 4/6] sdg(phase-11): identify the package as @modularcloud/xspec, homed in this repository The metadata predated the product's relocation: it named the package xspec (unscoped) and pointed at the retired modularcloud/sdg-claude repository. The published artifact must identify as @modularcloud/xspec with modularcloud/xspec as its home, so: scoped name, repository/ homepage/bugs URLs to this repository, public access for the scoped package, a user-facing description and keywords, and version 0.1.0 as the first-release baseline. Product behavior is unchanged; the tarball remains dist-only (npm pack --dry-run: 151 files). Co-Authored-By: Claude Fable 5 --- package-lock.json | 8 ++++---- package.json | 24 ++++++++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b39bdea..070d781 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "xspec", - "version": "0.0.0", + "name": "@modularcloud/xspec", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "xspec", - "version": "0.0.0", + "name": "@modularcloud/xspec", + "version": "0.1.0", "license": "MIT", "dependencies": { "acorn": "^8.17.0", diff --git a/package.json b/package.json index fab30c8..9242ff9 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,27 @@ { - "name": "xspec", - "version": "0.0.0", - "description": "xspec — the product program of this repository; the test harness under test/ is a separate program.", + "name": "@modularcloud/xspec", + "version": "0.1.0", + "description": "Requirement traceability for specifications written in MDX: typed spec modules, reference validation, dependency policy, coverage, impact analysis, and staged reviews.", "license": "MIT", "repository": { "type": "git", - "url": "git+https://github.com/modularcloud/sdg-claude.git" + "url": "git+https://github.com/modularcloud/xspec.git" + }, + "homepage": "https://github.com/modularcloud/xspec#readme", + "bugs": { + "url": "https://github.com/modularcloud/xspec/issues" + }, + "keywords": [ + "specification", + "requirements", + "traceability", + "mdx", + "typescript", + "coverage", + "spec-driven" + ], + "publishConfig": { + "access": "public" }, "type": "module", "engines": { From f6b617ad7350dfc7343fedcbedfb1799be38d766 Mon Sep 17 00:00:00 2001 From: lzrs Date: Tue, 28 Jul 2026 11:36:22 -0700 Subject: [PATCH 5/6] sdg(phase-11): add the standing npm release workflow Every push to main whose CI run concludes green is published to the public npm registry as @modularcloud/xspec and tagged vX.Y.Z, with no human involvement per release. The Release workflow triggers on CI completion for main pushes (the never-release-with-red-CI rule enforced mechanically), checks out exactly the commit CI validated, and computes a strictly increasing version via .github/scripts/next-version.mjs: package.json's version when it exceeds the latest published version (deliberate bumps land as ordinary package.json changes), otherwise the latest published version patch-incremented. Publishing authenticates with the NPM_TOKEN repository secret and attaches npm provenance; a missing secret fails the run loudly with instructions rather than silently skipping the release. Co-Authored-By: Claude Fable 5 --- .github/scripts/next-version.mjs | 34 +++++++++++++ .github/workflows/release.yml | 85 ++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 .github/scripts/next-version.mjs create mode 100644 .github/workflows/release.yml diff --git a/.github/scripts/next-version.mjs b/.github/scripts/next-version.mjs new file mode 100644 index 0000000..d3f7346 --- /dev/null +++ b/.github/scripts/next-version.mjs @@ -0,0 +1,34 @@ +// Compute the next release version (DEVOPS.md — npm releases, standing +// procedure). Usage: +// +// node .github/scripts/next-version.mjs [latest-published] +// +// Prints the version to publish: +// +// - the baseline (package.json's version) when nothing is published yet or +// the baseline is greater than the latest published version — this is how +// a deliberate minor/major bump landed on main takes effect; +// - otherwise the latest published version with its patch component +// incremented. +// +// Either way the result is strictly greater than every previously published +// version. Only plain x.y.z versions are accepted; anything else (prerelease +// tags, garbage from a failed registry lookup) fails loudly rather than +// publishing a surprise. + +const [baseline, latest] = process.argv.slice(2); + +const parse = (v) => { + const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(v ?? ""); + if (!m) throw new Error(`next-version: not a plain x.y.z version: ${JSON.stringify(v)}`); + return m.slice(1).map(Number); +}; + +const b = parse(baseline); +if (!latest) { + console.log(baseline); +} else { + const l = parse(latest); + const gt = b[0] !== l[0] ? b[0] > l[0] : b[1] !== l[1] ? b[1] > l[1] : b[2] > l[2]; + console.log(gt ? baseline : `${l[0]}.${l[1]}.${l[2] + 1}`); +} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c9996d1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,85 @@ +# Automated npm releases (DEVOPS.md — npm releases, standing procedure). +# +# Every push to main whose CI run is green is published to the public npm +# registry as @modularcloud/xspec, with a strictly increasing version, and the +# released commit is tagged vX.Y.Z. No human is involved per release. +# +# Trigger completion of the CI workflow for a push to main. Publishing +# hangs off CI's own result, so the never-release-with-red-CI +# rule is enforced mechanically, and the job checks out exactly +# the commit CI validated (workflow_run.head_sha). +# Version next-version.mjs: package.json's version when it is greater +# than the latest published version (deliberate bumps land on +# main as ordinary package.json changes), else latest published +# with the patch component incremented. The registry and the +# vX.Y.Z tags are the record of released versions; the bump is +# not committed back to main. +# Credential the NPM_TOKEN repository secret (granular npm automation +# token). Missing secret fails loudly with instructions — a +# release is never silently skipped. Re-running a failed run is +# safe: the registry refuses to republish an existing version. +name: Release + +on: + workflow_run: + workflows: [CI] + types: [completed] + branches: [main] + +permissions: + contents: write + id-token: write + +# Queue releases rather than cancelling one mid-publish. +concurrency: + group: npm-release + cancel-in-progress: false + +jobs: + publish: + name: Publish @modularcloud/xspec to npm + runs-on: ubuntu-24.04 + timeout-minutes: 15 + if: >- + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + github.event.workflow_run.head_branch == 'main' + steps: + - name: Require the NPM_TOKEN repository secret + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if [ -z "$NPM_TOKEN" ]; then + echo "::error::The NPM_TOKEN repository secret is not set, so this green main commit was NOT published. Complete the one-time setup in specs/DEVOPS.md (npm releases — credentials), then re-run this workflow run to publish this commit." + exit 1 + fi + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.workflow_run.head_sha }} + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + registry-url: https://registry.npmjs.org + - run: npm ci + - name: Build the product + run: npm run build + - name: Compute the release version (strictly increasing) + id: version + run: | + NAME="$(node -p "require('./package.json').name")" + BASELINE="$(node -p "require('./package.json').version")" + LATEST="$(npm view "$NAME" version 2>/dev/null || true)" + NEXT="$(node .github/scripts/next-version.mjs "$BASELINE" "$LATEST")" + echo "Package $NAME — baseline $BASELINE, latest published ${LATEST:-}, releasing $NEXT" + echo "next=$NEXT" >> "$GITHUB_OUTPUT" + - name: Publish to npm + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + npm version "${{ steps.version.outputs.next }}" --no-git-tag-version + npm publish --provenance --access public + - name: Tag the released commit + run: | + git tag "v${{ steps.version.outputs.next }}" "${{ github.event.workflow_run.head_sha }}" + git push origin "v${{ steps.version.outputs.next }}" From cd0165d4f126a00da9363e218019e91d2ebb6ca1 Mon Sep 17 00:00:00 2001 From: lzrs Date: Tue, 28 Jul 2026 11:37:00 -0700 Subject: [PATCH 6/6] sdg(phase-11): record the standing npm release procedure in DEVOPS.md Supersedes the deferred-release section written when the product lived in modularcloud/sdg-claude: this repository is now the product's home, so that deferral (and release candidate 9316048) is history, kept as a one-line note. Records the standing Developer authorization of 2026-07-28 for npm publishes and release tags, the automated release procedure (trigger, gate, versioning, tags, credentials model, failure handling), and the resulting Release-phase flow for future patches: merge on green, automation does the rest. Co-Authored-By: Claude Fable 5 --- specs/DEVOPS.md | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/specs/DEVOPS.md b/specs/DEVOPS.md index 9ea9243..8cd43d6 100644 --- a/specs/DEVOPS.md +++ b/specs/DEVOPS.md @@ -6,27 +6,26 @@ This document defines how release, merge, and deploy actions are performed for t - Never merge with red CI. A release candidate is a commit at which the full test suite and every CI job are green. - Never rewrite pushed history. Ordinary commits only. -- External release artifacts — version tags, GitHub Releases, package publishes, deploys — always require explicit Developer authorization. Absent that authorization, the default is deferral: take no external action and record the release candidate instead. +- External release artifacts require explicit Developer authorization. Two standing authorizations exist, granted by Developer on 2026-07-28: publishing `@modularcloud/xspec` to the public npm registry from green `main` commits of this repository, and the `vX.Y.Z` git tags marking those publishes. Any other kind of external artifact (deploys, GitHub Releases, publishes elsewhere) still requires fresh authorization; absent it, the default is deferral — take no external action and record the release candidate instead. -## Initial build on `modularcloud/sdg-claude` (this repository) +## This repository is the product's home -This repository is the SDG process's home, not the product's. The `xspec` product was built here on branch `sdg/initial-build` (PR #1), and Developer will personally relocate the work to a dedicated xspec repository after the initial build completes. A release artifact created here (tag, GitHub Release, package publish) would brand the wrong repository as the product's home and would outlive the branch it points at — so none are created. +`modularcloud/xspec` is the xspec product's dedicated repository, and `main` is its released line. (The product was originally built in `modularcloud/sdg-claude`, the SDG process's home, where release was deliberately deferred so no artifact would brand that repository as the product's home; Developer relocated the work here on 2026-07-27, superseding that deferral and its recorded release candidate `9316048`.) -Release procedure for the initial build — **deferred**, by explicit Developer decision: +The normal Release-phase flow for a completed patch is: -- Take no external release action from this repository. -- Do not merge PR #1. It intentionally carries a `specs/GOALS.md` merge conflict and stays open, untouched. Do not merge `main` into the branch. -- Do not create version tags, GitHub Releases, or package publishes. -- Leave branch `sdg/initial-build` and PR #1 exactly as they are. -- The deliverable is the green branch head, ready for Developer's switch-over to the dedicated xspec repository. Release candidate: commit `9316048` — full suite green locally (485/485), all three CI jobs green. Commits after it on the branch are process bookkeeping only (spec-document edits, no product code). - -## Future runs in the product's own repository +1. Merge the patch's PR once CI is green on the PR head (never with red CI). +2. Nothing further. The standing npm release procedure below publishes the merged commit automatically; there is no per-release tagging, publishing, or Developer step. -Once xspec lives in its own repository, the normal release flow for a completed patch is: +## npm releases (standing procedure) -1. Merge the patch's PR once CI is green on the PR head (never with red CI). -2. With explicit Developer authorization, tag the release commit; a GitHub Release and/or package publish additionally requires Developer-provided credentials. -3. Absent authorization for any external artifact, defer that artifact and record the release candidate, per the standing rules. +- **Artifact.** The public npm package `@modularcloud/xspec`. `package.json` must always identify the package by that name, with this repository as `repository`/`homepage`/`bugs`, and carry `publishConfig.access: public`. +- **Trigger.** Every push to `main` (a PR merge is a push). The `Release` workflow (`.github/workflows/release.yml`) runs when the `CI` workflow completes for a `main` push. +- **Gate.** The publish job runs only when that CI run concluded successfully, and it checks out exactly the commit CI validated — the never-release-with-red-CI rule is enforced mechanically. Nothing beyond green CI gates a release. +- **Versioning.** Strictly increasing, computed by `.github/scripts/next-version.mjs` with no Developer involvement: if `package.json`'s version is greater than the latest published version (or nothing is published yet), that version is released — a deliberate minor/major bump is made by landing the `package.json` change on `main`; otherwise the latest published version's patch component is incremented. The registry and the `vX.Y.Z` tags are the record of released versions; the computed bump is not committed back to `main`, so the in-repo version is the floor, not the record. +- **Tags.** Each successful publish pushes the lightweight tag `vX.Y.Z` on the released commit, using the workflow's own repository token. +- **Credentials.** Publishing authenticates with the `NPM_TOKEN` GitHub repository secret — a granular npm automation token with read/write access to the package (or the `@modularcloud` scope), created under Developer's npm account. Credentials live only in that secret, never in the repository. If the token is missing or expired, recreate it on npmjs.com and set it again with `gh secret set NPM_TOKEN`. +- **Failure handling.** A missing/invalid secret or any publish error fails the Release run loudly — a release is never silently skipped. Re-running a failed Release run publishes the commit it was gated on and is always safe: the registry refuses to republish an existing version, so duplicate attempts fail rather than corrupt the sequence. A failed run never blocks later landings, which release independently. ## Post-update actions