bmad-module-skill-forge 1.0.0-rc.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,7 +30,7 @@
30
30
  "name": "skill-forge",
31
31
  "source": "./",
32
32
  "description": "Evidence-based agent skills compiler with progressive capability tiers (Quick/Forge/Forge+/Deep).",
33
- "version": "1.0.0-rc.3",
33
+ "version": "1.1.0",
34
34
  "author": {
35
35
  "name": "Armel"
36
36
  },
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- <img src="website/public/img/skf-logo.svg" alt="Skill Forge Logo" width="120" />
3
+ <img src="website/public/img/skf-logo-animated.svg" alt="Skill Forge Logo" width="120" />
4
4
 
5
5
  # Skill Forge (SKF)
6
6
 
@@ -181,11 +181,11 @@ Past releases are documented in [CHANGELOG.md](CHANGELOG.md).
181
181
 
182
182
  ## Versioning & Stability
183
183
 
184
- The v1.0.0 public API contract is documented in [docs/STABILITY.md](docs/STABILITY.md).
184
+ The v1.0.0 public API contract is documented in [docs/_internal/STABILITY.md](docs/_internal/STABILITY.md).
185
185
 
186
186
  ## Release Process
187
187
 
188
- Maintainers: see [docs/RELEASING.md](docs/RELEASING.md) for branch-protection rules, required status checks, the [`release` environment with required-reviewer gate](docs/RELEASING.md#release-environment), the [npm Trusted Publisher registration](docs/RELEASING.md#npm-trusted-publisher) (OIDC-backed publish, auto-provenance), and the [rollback playbook](docs/RELEASING.md#rollback-playbook) covering seven failure scenarios.
188
+ Maintainers: see [docs/_internal/RELEASING.md](docs/_internal/RELEASING.md) for branch-protection rules, required status checks, the [`release` environment with required-reviewer gate](docs/_internal/RELEASING.md#release-environment), the [npm Trusted Publisher registration](docs/_internal/RELEASING.md#npm-trusted-publisher) (OIDC-backed publish, auto-provenance), and the [rollback playbook](docs/_internal/RELEASING.md#rollback-playbook) covering seven failure scenarios.
189
189
 
190
190
  ## License
191
191
 
@@ -22,8 +22,11 @@
22
22
  # File ignored by Astro/Starlight content collections because the parent
23
23
  # directory starts with `_`. It is purely a build-time / CI-time anchor.
24
24
 
25
- # SKF package version — matches the `version` field in package.json
26
- skf_version: "0.10.0"
25
+ # SKF package version — matches the `version` field in package.json.
26
+ # Enforced two ways: (1) release.yaml bumps this line in the same commit
27
+ # as package.json + marketplace.json on every release; (2) validate-docs-drift.js
28
+ # cross-checks this value against package.json.version and fails on mismatch.
29
+ skf_version: "1.1.0"
27
30
 
28
31
  # Path to the oh-my-skills repo, resolved relative to this repo's root.
29
32
  # Override at runtime with the OMS environment variable if oh-my-skills
@@ -77,12 +77,22 @@ The publish job is gated by a **GitHub [deployment environment](https://docs.git
77
77
  | `prevent_self_review` | `false` — see rationale below |
78
78
  | `reviewers` | `armelhbobdad` (user id `132626034`), 1 approver |
79
79
  | `deployment_branch_policy` | `custom_branch_policies: true`, list: `main` only |
80
- | Environment-scoped secrets | `0` (invariant — see `NPM_TOKEN` note below) |
80
+ | Environment-scoped secrets | `0` (invariant — see "No secret is scoped to this environment" note below) |
81
81
  | Cost | `$0` on public-repo tier (environments, required reviewers, and branch policies are [free for public repositories](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#about-environments)) |
82
82
 
83
83
  **`prevent_self_review: false` — correctness constraint, not a loosened control.** Solo-maintainer setups cannot self-approve when this is `true`, so the gate would deadlock on any maintainer-triggered publish. The value flips to `true` the moment a second reviewer joins — do not leave it loose by inertia.
84
84
 
85
- **`NPM_TOKEN` is NOT scoped to this environment.** It remains at repo-level secrets during the OIDC transition and is removed entirely post-v1.0.0 (see Story 6.3). The invariant: the `release` env must have zero secrets. If a future change scopes any secret here, re-audit whether the OIDC trusted-publisher path is still in force.
85
+ **No secret is scoped to this environment.** The repo no longer carries an `NPM_TOKEN` secret at any scope (removed in Story 6.3 post-v1.0.0 once OIDC trusted publishing was operationally proven by the v1.0.0 launch). The invariant: the `release` env must have zero environment-scoped secrets, and the repo must have zero `NPM_TOKEN`-shaped secrets at any scope. If a future change scopes any secret to this environment, or if an `NPM_TOKEN` secret is ever re-added at repo scope, re-audit whether the OIDC trusted-publisher path is still in force — the OIDC path SHOULD be self-sufficient and a re-added token is a signal that something has regressed off the canonical path.
86
+
87
+ **Audit command.** Both halves of the invariant are machine-checkable:
88
+
89
+ ```bash
90
+ # Repo-scope: expect 0
91
+ gh secret list --repo armelhbobdad/bmad-module-skill-forge | grep -ci npm_token
92
+
93
+ # Env-scope: expect {"total_count":0,"secrets":[]}
94
+ gh api repos/armelhbobdad/bmad-module-skill-forge/environments/release/secrets
95
+ ```
86
96
 
87
97
  **Coupling with npm trusted publishing (Story 1.3).** The npm trusted publisher binds on four fields — `organization=armelhbobdad`, `repository=bmad-module-skill-forge`, `workflow filename=release.yaml`, `environment=release`. The environment name above is load-bearing: any rename here must be accompanied by a matching npm-side update in the same change, or the next publish returns 404.
88
98
 
@@ -174,7 +184,7 @@ The future `release.yaml` workflow (Story 3.1) publishes to npm via **OIDC trust
174
184
 
175
185
  **Pre-registration inversion.** This entry was registered **before** `release.yaml` was authored (Story 3.1). The first live validator of the full OIDC chain is Story 3.2's alpha cut. If that cut's publish step 404s, open a **three-way comparison**: (1) the npm Settings tab, (2) the workflow YAML's `name` / `on` / `jobs.<id>.environment` lines, and (3) the Registered table above. The table is the ground truth because it captured the values at npm-save time — compare both the npm record and the workflow header against the table, never the workflow against itself (verifying the workflow against its own header will silently confirm a typo).
176
186
 
177
- **`NPM_TOKEN` is a legacy residual, not a safety net.** The token remains at repo-level secrets for two reasons: (a) the legacy `publish.yaml` still uses it until Story 3.3 retires that path, and (b) Story 6.3 deletes the secret entirely post-v1.0.0. Treat its continued presence as attack surface to minimize, not defence-in-depth a repo-scope token is reachable from any workflow with `secrets.*` access. The token does NOT sit "behind" OIDC: `release.yaml` does not yet exist, so there is no OIDC path for it to be a fallback to. If a future OIDC incident forces a last-resort token-based re-publish, document the flip in the commit body and revert as soon as OIDC is restored.
187
+ **`NPM_TOKEN` is gone OIDC is the only publish credential surface.** The token was removed from repo-level secrets in Story 6.3 (post-v1.0.0, once OIDC trusted publishing was operationally proven by the v1.0.0 launch). SKF's npm publish credential surface is now OIDC-only. Future incidents requiring credential revocation involve npmjs.com's trusted-publisher config, not a repo secret. `release.yaml` authenticates via Trusted Publisher OIDC and continues to set `NPM_TOKEN: ""` explicitly in both the pre-publish dry-run step and the final publish step as defense-in-depth against a stale token being auto-picked-up by npm from the runner env — those literal empty-string assignments are not `secrets.*` reads and stay load-bearing regardless of the secret's presence or absence. Both sites carry a `# DO NOT REMOVE FR4 defense-in-depth` inline comment so a future cleanup pass does not silently delete them; audit with `grep -c 'NPM_TOKEN: ""' .github/workflows/release.yaml` (expect `2`). If a future OIDC incident forces a last-resort token-based re-publish path, re-adding `NPM_TOKEN` at repo scope is the exception-path, not the default — document the flip in the commit body, file an issue for the OIDC incident class that required it, and remove the token again the moment OIDC is restored.
178
188
 
179
189
  **Fixing a bad registration.** The npm UI exposes both **Edit** and **Delete** on an existing Trusted Publisher entry (observed 2026-04-20). Prefer edit for a single-field typo; prefer delete-and-re-add if multiple fields are wrong or the edit form ever feels ambiguous. **Pre-Story 3.2**: there is no destructive side effect because no publish is attempted yet, and delete-and-re-add keeps the audit trail cleaner. **Post-Story 3.2**: a publish that fires during the delete-and-re-add window will 404 — gate any delete-and-re-add behind a manual publish freeze (pause any active `release.yaml` runs, confirm no tags are in-flight) before touching the entry.
180
190
 
@@ -423,8 +433,7 @@ Placeholder substitutions used throughout:
423
433
  - **Post-incident reactivation.** After audit completes and root cause is identified and patched, re-register the Trusted Publisher via the npm UI with the four fields matching the table in `## npm Trusted Publisher` above (`organization=armelhbobdad`, `repository=bmad-module-skill-forge`, `workflow filename=release.yaml`, `environment=release`). Re-verify via an alpha cut (dispatch `release.yaml` from a temporarily-allowed feature branch per the `## Release Environment § Temporarily allowing a feature branch` procedure) before any stable release.
424
434
  - **Pre-v1.0.0 context.** Trusted Publisher was pre-registered on 2026-04-20 (Story 1.3). A compromise discovered pre-v1.0.0 is recoverable via delete-and-re-register with no downstream-consumer blast radius (no stable release users yet). Post-v1.0.0, the incident has downstream blast radius and the `support@npmjs.com` coordination path is load-bearing.
425
435
  - **Do-NOT clause — `NPM_TOKEN` rotation is not OIDC incident response.** Do NOT rotate `NPM_TOKEN` as a first response. The token is not on the OIDC path; rotating it does nothing to stop an OIDC compromise.
426
- - If `NPM_TOKEN` itself is _also_ suspected compromised, revoke via `https://www.npmjs.com` → **Access Tokens** and remove from the repo: `gh secret delete NPM_TOKEN --repo armelhbobdad/bmad-module-skill-forge`. This is separate from the OIDC incident response above.
427
- - `NPM_TOKEN` still exists at repo scope until Story 6.3 (post-v1.0.0). A compromised `NPM_TOKEN` is a **separate incident class** from OIDC compromise. During the window where OIDC is revoked _and_ `NPM_TOKEN` is also compromised, there is no valid publish path — the repo enters lockdown until Trusted Publisher is re-registered. Document the flip in the incident post-mortem; do not publish via any stale path.
436
+ - If an `NPM_TOKEN` exists at repo scope at the time of an incident (exception-path per § npm Trusted Publisher), revoke it at `https://www.npmjs.com` → **Access Tokens** AND remove it from the repo: `gh secret delete NPM_TOKEN --repo armelhbobdad/bmad-module-skill-forge`. A compromised `NPM_TOKEN` would be a **separate incident class** from OIDC compromise. **Expected outcomes of the delete command under incident pressure** — read the response before escalating: (a) `Secret deleted` = success, token revoked at repo-scope; (b) `could not find secret NPM_TOKEN` (exit 1, 404) = no-op SAFE, the token is already absent per the post-Story-6.3 default and this is the expected normal-operation state, not a broken scope or auth issue; (c) any `401` / `403` / scope-permission error = investigate before retrying, likely a `gh auth` or org-permissions issue unrelated to the token's presence. Story 6.3 removed the token in 2026-04 post-v1.0.0 so outcome (b) is the default; outcome (a) only applies during the exception-path window where a temporary token re-add has already happened. During a window where OIDC is revoked AND an exception-path token is also compromised, there is no valid publish path — the repo enters lockdown until Trusted Publisher is re-registered. Document the flip in the incident post-mortem; do not publish via any stale path.
428
437
 
429
438
  ### Scenario G — "release.yaml disabled, reverted, or missing from main"
430
439
 
@@ -465,29 +474,16 @@ Placeholder substitutions used throughout:
465
474
  grep -l 'id-token: write' .github/workflows/*.{yaml,yml} 2>/dev/null
466
475
  # expected set:
467
476
  # - docs.yaml (GitHub Pages — orthogonal to release)
468
- # - publish.yaml (DEPRECATED — kept until Story 6.1 deletes it; workflow_dispatch-only,
469
- # surviving as the Scenario G emergency hatch)
470
477
  # - release.yaml (canonical)
471
478
 
472
- # No `v*` push trigger should exist in any workflow — release.yaml is workflow_dispatch-only,
473
- # and publish.yaml had its push:tags:v* trigger neutralized in Story 3.3 Patch A.
479
+ # No `v*` push trigger should exist in any workflow — release.yaml is workflow_dispatch-only.
474
480
  # Scan the 3 lines following each `push:` block for a v* tag pattern.
475
481
  grep -A3 -E '^\s*push:' .github/workflows/*.{yaml,yml} 2>/dev/null \
476
482
  | grep -E "['\"]v\*['\"]"
477
483
  # expected: zero matches.
478
484
  ```
479
485
 
480
- - **Escalation path — emergency hatch.** If Scenario G is detected mid-incident when a release is urgently needed, the legacy `.github/workflows/publish.yaml` retains `workflow_dispatch:` as an emergency hatch (NPM_TOKEN still at repo scope until Story 6.3). Invoke via:
481
-
482
- ```bash
483
- gh workflow run publish.yaml
484
- ```
485
-
486
- Read the next two paragraphs **before** dispatching:
487
- - **Auth vs. provenance — they are independent.** `publish.yaml` authenticates to npm with `NODE_AUTH_TOKEN=${{ secrets.NPM_TOKEN }}` (token-based; NOT OIDC trusted publishing — that path is `release.yaml`-only). However, the workflow also has `id-token: write` permission and calls `npm publish --provenance`, so npm WILL attach a SLSA-L2 provenance attestation derived from the GitHub Actions OIDC token. Provenance is independent of the auth-to-npm path. The trade-off is auth lineage (token vs. trusted-publisher OIDC), not attestation presence.
488
- - **State divergence — `publish.yaml` does NOT bump version, push the `v*` tag, update `CHANGELOG.md`, or create a GitHub Release.** It only runs `npm publish` against whatever `package.json` is at HEAD of the dispatched ref. Every emergency-hatch use therefore leaves npm + git state diverged and requires a Scenario E-style reconciliation afterward: bump `package.json` manually on `main` (so the next release does not collide), then recreate the tag and GitHub Release per Scenario E.
489
-
490
- Document every emergency-hatch use in an incident post-mortem, and re-enable `release.yaml` before the next release. This fallback disappears when Story 6.1 deletes `publish.yaml`.
486
+ - **Escalation path — PR-revert only.** There is no out-of-band emergency hatch. Recovery flows exclusively through the Case 2 PR-revert path above: revert the offending workflow change via `gh pr revert`, merge through branch protection, then retry the release via `release.yaml`. Every release threads through branch protection + code review + OIDC Trusted Publisher, matching NFR2 and NFR3.
491
487
 
492
488
  - **Constraints.** Branch protection on `main` blocks direct pushes — recovery goes through a PR in every case. Do not attempt to sidestep branch protection to "fix" `release.yaml` faster; the cost of a bad release (NFR5 audit-trail breakage, NFR10 commit-trail breakage) far exceeds the cost of a normal-review PR.
493
489
 
@@ -556,61 +552,91 @@ The `POST` body needs the same `name`, `target`, `enforcement`, `conditions`, `r
556
552
 
557
553
  For the `release` environment, a deletion+restore similarly uses the two-call pattern already documented at `## Release Environment § Restore / re-apply` — feed the environment-level baseline JSON to the `PUT .../environments/release` call, then re-POST each entry from the branch-policies baseline to `.../environments/release/deployment-branch-policies`.
558
554
 
559
- ### Cutting v1.0.0-rc.1
555
+ ### Cutting v1.0.0 under --tag latest
560
556
 
561
- - **Trigger.** Story 5.1 audit ([`release-audits/v1.0.0-launch-audit.md`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/release-audits/v1.0.0-launch-audit.md)) signed off and all blockers cleared; Story 5.2 ready to cut the first release-candidate. `package.json` still on a `0.x` line (at audit time: `0.10.0`). Running `release.yaml` with `version_bump: rc` on `0.10.0` would produce `0.10.1-rc.0` — NOT `1.0.0-rc.0` — because `npm version prerelease --preid=rc` advances the patch segment of the current version. The one-time hand-bump below lifts `package.json` onto the `1.0.0` line so the next workflow dispatch advances that line cleanly.
557
+ - **Trigger.** The passing RC has survived a clean-environment smoke test (`release-audits/v1.0.0-launch-audit.md § Story 5.2 RC Cut + Smoke Test § Decision: PASS cleared for Story 5.3 promotion to v1.0.0 under --tag latest with manual approval`); `npm view bmad-module-skill-forge@rc version` returns the passing RC (at Story 5.3 dispatch time: `1.0.0-rc.3`); Story 5.3 is ready to promote to `latest` under manual approval.
562
558
  - **CLI.**
563
559
 
564
560
  ```bash
565
- # Hand-bump main onto the 1.0.0 line. Do not tag; release.yaml owns tags.
566
561
  git checkout main && git pull
567
- npm version 1.0.0-rc.0 --no-git-tag-version
568
- # Leave .claude-plugin/marketplace.json alone release.yaml's jq-based
569
- # sync step rewrites .plugins[0].version atomically at RC cut time. A
570
- # double-bump here would race against that step.
571
- # Include package-lock.json npm version bumps both files; committing
572
- # only package.json leaves the lockfile out-of-sync and breaks `npm ci`.
573
- git add package.json package-lock.json
574
- git commit -m "chore(release): pre-RC bump to 1.0.0-rc.0 (Story 5.1 hand-off)"
575
- # Push via the normal PR path (branch protection blocks direct push to main).
576
- # Merge the PR to main after review.
577
-
578
- # Dispatch the canonical release workflow. `version_bump: rc` runs
579
- # `npm version prerelease --preid=rc` on 1.0.0-rc.0 → 1.0.0-rc.1.
580
- gh workflow run release.yaml -f version_bump=rc
562
+
563
+ # Pre-dispatch sanity check (read version from remote, not local clone).
564
+ gh api repos/armelhbobdad/bmad-module-skill-forge/contents/package.json \
565
+ --jq '.content' | base64 -d | jq -r .version
566
+ # expected: the passing RC (e.g., 1.0.0-rc.3)
567
+
568
+ # Dispatch the canonical release workflow. `version_bump: major` on
569
+ # 1.0.0-rc.N strips the prerelease suffix and produces 1.0.0 (node-semver
570
+ # inc(ver, 'major') behavior on a prerelease). `--ref main` is explicit
571
+ # (gh defaults to the repo's default branch, but any non-main ref takes
572
+ # the legacy tag-only path inside release.yaml, so pass it defensively).
573
+ gh workflow run release.yaml -f version_bump=major --ref main
574
+
575
+ # Capture the run id for monitoring + audit transcript.
576
+ RUN_ID=$(gh run list --workflow=release.yaml --limit 1 \
577
+ --json databaseId --jq '.[0].databaseId')
578
+ gh run watch $RUN_ID
581
579
  ```
582
580
 
583
- - **Expected outcome.** `main` tip at `1.0.0-rc.1`; `npm view bmad-module-skill-forge@rc version` returns `1.0.0-rc.1`; a GitHub Release `v1.0.0-rc.1` exists with `prerelease: true` and the auto-generated body; `CHANGELOG.md` now carries an auto-generated `## [1.0.0-rc.1]` entry prepended ABOVE the hand-curated `## [1.0.0] - TBD` placeholder (Story 5.1 staged that placeholder; Story 5.3 reconciles the date at the v1.0.0 final cut); `.claude-plugin/marketplace.json`'s `.plugins[0].version` reflects `1.0.0-rc.1`.
581
+ The workflow pauses at **two** gates that the maintainer must clear in the browser. Gate 1 requires explicit approval; gate 2 accepts either approval or admin-bypass-merge:
582
+
583
+ 1. The `release` environment deployment gate (at job start). Approve via "Review deployments" → "Approve and deploy" on the run page.
584
+ 2. The bot PR review-decision gate (after the 7 required status checks pass). EITHER approve the bot PR via the review UI, OR admin-bypass-merge via the PR merge button — both paths are accepted by `release.yaml`'s `Wait for PR approval or admin-bypass merge` step. Admin-bypass-merge is the observed pattern for prior cuts (PRs #209 and #213).
585
+
586
+ Expected wall-clock: ~5–8 minutes end-to-end when both gates are approved promptly.
587
+
588
+ - **Expected outcome.** `main` tip advances by 2 commits (the `release: bump to v1.0.0` commit on the bot temp branch `release/bot/v1.0.0-<run_id>`, plus the merge commit from the auto-merged or admin-bypass-merged bot PR); `jq -r .version package.json` → `1.0.0`; `jq -r '.plugins[0].version' .claude-plugin/marketplace.json` → `1.0.0`; `npm view bmad-module-skill-forge dist-tags.latest` → `1.0.0` (flipped from the prior stable, e.g. `0.10.0`); `rc` dist-tag UNCHANGED at the prior RC; SLSA L2 provenance attached (NFR4); GitHub Release `v1.0.0` with `prerelease: false` (NFR6 threshold — `1.0.0` contains no `alpha|beta|rc` substring); tag `v1.0.0` anchors on the bot PR's merge commit per Story 3.4 P9 (the tag is annotated, so `git rev-parse 'v1.0.0^{}'` gives the commit SHA to compare against `main` tip).
589
+
584
590
  - **Constraints.**
585
- - Execute ONLY after `v1.0.0-launch-audit.md § Sign-off` is populated with a date.
586
- - The pre-RC bump commit subject MUST be `chore(release): pre-RC bump to 1.0.0-rc.0 (Story 5.1 hand-off)` use the `chore(release):` prefix (not bare `release:`) or the commit-msg hook rejects it for non-conventional form.
587
- - Do NOT bump `.claude-plugin/marketplace.json` in the hand-bump commit. `release.yaml`'s jq-based marketplace sync handles it atomically at RC cut time; a double-bump here would race the workflow.
588
- - The RC cut is the FIRST time the jq-based marketplace.json update path runs in anger. A failure there (jq syntax error, missing `jq` on runner unlikely on `ubuntu-latest` but treat as a real risk) would halt the cut mid-step, possibly leaving a half-updated `CHANGELOG.md` on `main` with no `marketplace.json` follow-through. Recovery: `git revert` the pre-RC bump PR + retry after fixing the workflow.
589
- - If the workflow dispatch emits `1.0.1-rc.0` instead of `1.0.0-rc.1`, the hand-bump commit never landed on `main` OR `npm version prerelease --preid=rc` behavior diverged from the documented semantics. Abort the RC cut and investigate before retry.
591
+ - Execute ONLY after the RC audit Sign-off` is populated AND the smoke-test `Decision` is `PASS`.
592
+ - The cut is IRREVERSIBLE once `npm publish --tag latest` succeeds for `1.0.0`, NFR6 forbids unpublish regardless of eligibility window. Rollback is `npm deprecate` + ship-forward (Scenarios A / B).
593
+ - The CHANGELOG reconciliation is a POST-workflow step (authored as a separate sign-off commit on `feat/v1-final-signoff`). Do NOT hand-edit the `## [1.0.0] - TBD` placeholder BEFORE dispatch — let the workflow auto-generate its `## [1.0.0]` block (which may be EMPTY when there are zero conventional-commit `feat:` / `fix:` entries between the RC and the final cut, which is the normal case), then merge the hand-curated prose into the auto-gen header's position and delete the stale placeholder in one commit.
594
+ - Do NOT pre-bump `package.json` or `.claude-plugin/marketplace.json` — the workflow's `Bump version` and `Update marketplace.json version` steps handle both atomically and own those files.
595
+ - If `npm version major` unexpectedly emits `2.0.0` instead of `1.0.0` on `1.0.0-rc.N`, the node-semver engine behavior has regressed. Abort the dispatch and investigate before retry a workflow override (`npm version 1.0.0 --no-git-tag-version`) would be required in `release.yaml`.
596
+
590
597
  - **Verification.**
591
598
 
592
599
  ```bash
593
- # Confirm the rc dist-tag advanced.
594
- npm view bmad-module-skill-forge@rc version
595
- # expected: 1.0.0-rc.1
600
+ # Confirm the latest dist-tag flipped to 1.0.0.
601
+ npm view bmad-module-skill-forge dist-tags --json
602
+ # expected: {"latest":"1.0.0","alpha":"...","rc":"1.0.0-rc.N"}
603
+
604
+ npm view bmad-module-skill-forge@latest version
605
+ # expected: 1.0.0
606
+
607
+ # Confirm SLSA L2 provenance (NFR4 CRITICAL). A null attestation is a
608
+ # blocker — emergency-deprecate + cut 1.0.1 with provenance per Scenario B.
609
+ npm view bmad-module-skill-forge@1.0.0 --json | jq '.dist.attestations'
610
+ # expected: non-null object; .provenance.predicateType starts with
611
+ # "https://slsa.dev/provenance/"
612
+
613
+ # Confirm the GitHub Release exists and is NOT a prerelease (NFR6 threshold).
614
+ gh release view v1.0.0 --json tagName,isPrerelease
615
+ # expected: {"tagName":"v1.0.0","isPrerelease":false}
616
+
617
+ # Confirm the v1.0.0 tag is reachable from main (annotated tag — dereference with ^{}).
618
+ # Uses --is-ancestor so the check stays valid after subsequent commits land on main;
619
+ # pin to the recorded merge SHA if you need strict tag-anchor equivalence.
620
+ git fetch origin --tags
621
+ git merge-base --is-ancestor "$(git rev-parse 'v1.0.0^{}')" origin/main && echo OK
622
+ # expected: OK
623
+
624
+ # Confirm CHANGELOG reconciliation after the sign-off commit lands on main.
625
+ grep -c '^## \[1\.0\.0\] - TBD' CHANGELOG.md # expected: 0 (stale placeholder gone)
626
+ grep -cE '^## \[1\.0\.0\]' CHANGELOG.md # expected: 1 (one reconciled block)
627
+ grep -cE '^## \[1\.0\.0\]\(https' CHANGELOG.md # expected: 1 (compare-URL header survived)
628
+ ```
596
629
 
597
- npm view bmad-module-skill-forge dist-tags --json | jq -r .rc
598
- # expected: 1.0.0-rc.1
630
+ **NFR6 immutability activation** is the `npm publish --tag latest` success timestamp for `1.0.0`, recorded verbatim in `release-audits/v1.0.0-launch-audit.md § Story 5.3 v1.0.0 Final Cut § NFR6 v1.0.0 immutability activation`. For Story 5.3's dispatch, that instant was **2026-04-23T18:56:39Z**. From that moment, `v1.0.0` is forever-burned — `npm deprecate` + ship-forward is the only rollback path.
599
631
 
600
- # Confirm SLSA L2 provenance is attached (NFR4 reconfirm).
601
- npm view bmad-module-skill-forge@1.0.0-rc.1 --json | jq '.dist.attestations'
602
- # expected: non-null object containing a provenance url
632
+ The `release` environment + bot PR approval-or-admin-bypass-merge pattern is the canonical flow for all main-dispatched cuts since Story 3.4 ([GitHub issue #198](https://github.com/armelhbobdad/bmad-module-skill-forge/issues/198), [PR #199](https://github.com/armelhbobdad/bmad-module-skill-forge/pull/199)): the release commit is pushed to a temp branch `release/bot/vX.Y.Z-<run_id>`, a bot PR is opened against `main`, the 7 required status checks are force-triggered against the temp branch via `workflow_dispatch`, and the merge is gated behind maintainer approval at both the `release` environment gate and the PR review-decision gate. Non-main dispatches (feature-branch alpha cuts) skip the PR dance entirely and keep the legacy tag-only behavior.
603
633
 
604
- # Confirm the GitHub Release exists and is marked prerelease.
605
- gh release view v1.0.0-rc.1 --json tagName,isPrerelease
606
- # expected: {"tagName":"v1.0.0-rc.1","isPrerelease":true}
634
+ #### Post-publish verification (NFR9)
607
635
 
608
- # Confirm the CHANGELOG carries both the auto-generated rc entry and the
609
- # hand-curated v1.0.0 placeholder (Story 5.3 reconciles the placeholder).
610
- grep -c '^## \[1.0.0-rc.1\]' CHANGELOG.md # expected: 1
611
- grep -c '^## \[1.0.0\] - TBD' CHANGELOG.md # expected: 1
612
- ```
636
+ Cross-platform install verification for any cut is performed by the [`install-smoke.yaml`](../.github/workflows/install-smoke.yaml) workflow, not by `release.yaml` itself. Dispatch it within 1 hour of publish per NFR9:
613
637
 
614
- #### Story 3.4 refactor note — PR-auto-merge flow
638
+ ```bash
639
+ gh workflow run install-smoke.yaml -f version=latest --ref main
640
+ ```
615
641
 
616
- After Story 3.4 (GitHub issue [#198](https://github.com/armelhbobdad/bmad-module-skill-forge/issues/198), [PR #199](https://github.com/armelhbobdad/bmad-module-skill-forge/pull/199)), `release.yaml` no longer pushes the `release: bump to vX.Y.Z` commit directly to `main`. Instead, a main-dispatched cut pushes the release commit to a temp branch `release/bot/vX.Y.Z-<run_id>`, opens a bot PR against `main`, force-triggers `quality.yaml` against the temp branch via `workflow_dispatch` (so the 7 required status checks run and gate the merge), then auto-merges once checks pass and a maintainer approves. Approval is required at **two** gates — the `release` environment gate at job start, and the PR review-decision gate before auto-merge. Non-main dispatches (feature-branch alpha cuts) skip the PR dance and keep the legacy tag-only behavior. Story 5.2's dev agent on resume will refresh the § Cutting v1.0.0-rc.1 prose above to describe the refactored flow directly.
642
+ The workflow fans a `workflow_dispatch` input over `ubuntu-latest`, `windows-latest`, and `macos-latest`, running `npx --yes bmad-module-skill-forge@<version> --version` on each runner. A clean three-leg run is the canonical post-publish evidence its run URL + matrix table belong in the release audit artifact's `## Story <N> Post-Publish Verification` section. Any failing leg routes through the `Rollback Playbook § Scenario B` (deprecate + ship `vX.Y.Z+1`).
@@ -111,13 +111,13 @@ If a surface you depend on is NOT explicitly enumerated in [§ Covered Surfaces]
111
111
 
112
112
  ## Changes to This Contract
113
113
 
114
- Shrinking the covered surface (removing a commitment) is a breaking change and requires a major-version bump. Expanding the covered surface (promoting an `@internal` surface to covered, or adding a new commitment) is additive and ships in a minor release. This document is versioned alongside the package; historical versions are visible via `git log docs/STABILITY.md`.
114
+ Shrinking the covered surface (removing a commitment) is a breaking change and requires a major-version bump. Expanding the covered surface (promoting an `@internal` surface to covered, or adding a new commitment) is additive and ships in a minor release. This document is versioned alongside the package; historical versions are visible via `git log -- docs/STABILITY.md docs/_internal/STABILITY.md`.
115
115
 
116
116
  ## References
117
117
 
118
118
  - [agentskills.io spec](https://github.com/agentskills/agentskills) — external canonical source for the `SKILL.md` frontmatter grammar.
119
119
  - [Semantic Versioning 2.0.0](https://semver.org/) — the SemVer semantics this contract commits to.
120
120
  - [`CHANGELOG.md`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/CHANGELOG.md) — release-by-release history; breaking changes are called out there.
121
- - [`docs/RELEASING.md`](RELEASING.md) — maintainer reference for the release pipeline (companion document: this file is about what ships, `RELEASING.md` is about how).
121
+ - [`docs/_internal/RELEASING.md`](RELEASING.md) — maintainer reference for the release pipeline (companion document: this file is about what ships, `RELEASING.md` is about how).
122
122
  - [`tools/cli/lib/platform-codes.yaml`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/tools/cli/lib/platform-codes.yaml) — source of truth for the IDE → skills-directory mapping covered under [§ Installation Layout](#installation-layout).
123
123
  - [`test/schema/agent.js`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/test/schema/agent.js) — zod schema definitions for `bmad-skill-manifest.yaml` covered under [§ Skill Manifest & Frontmatter Contract](#skill-manifest--frontmatter-contract).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-module-skill-forge",
4
- "version": "1.0.0-rc.3",
4
+ "version": "1.1.0",
5
5
  "description": "BMAD module — Turn code and docs into instructions AI agents can actually follow. Progressive capability tiers (Quick/Forge/Forge+/Deep).",
6
6
  "keywords": [
7
7
  "bmad",
@@ -45,11 +45,6 @@
45
45
  "lint:md": "markdownlint-cli2 \"**/*.md\"",
46
46
  "prepare": "husky || exit 0",
47
47
  "quality": "npm run format:check && npm run lint && npm run lint:md && npm run test:schemas && npm run test:install && npm run test:cli && npm run test:workflow && npm run test:python && npm run test:knowledge && npm run validate:schemas && npm run validate:skills && npm run validate:refs && npm run docs:validate-drift",
48
- "release": "echo '[DEPRECATED] Use .github/workflows/release.yaml via GitHub Actions. See docs/RELEASING.md.' >&2 && exit 1 ; npm run release:patch",
49
- "release:major": "echo '[DEPRECATED] Use .github/workflows/release.yaml via GitHub Actions. See docs/RELEASING.md.' >&2 && exit 1 ; npm version major && git push --follow-tags",
50
- "release:minor": "echo '[DEPRECATED] Use .github/workflows/release.yaml via GitHub Actions. See docs/RELEASING.md.' >&2 && exit 1 ; npm version minor && git push --follow-tags",
51
- "release:patch": "echo '[DEPRECATED] Use .github/workflows/release.yaml via GitHub Actions. See docs/RELEASING.md.' >&2 && exit 1 ; npm version patch && git push --follow-tags",
52
- "release:prerelease": "echo '[DEPRECATED] Use .github/workflows/release.yaml via GitHub Actions. See docs/RELEASING.md.' >&2 && exit 1 ; npm version prerelease && git push --follow-tags",
53
48
  "skf:install": "node tools/cli/skf-cli.js install",
54
49
  "skf:status": "node tools/cli/skf-cli.js status",
55
50
  "skf:uninstall": "node tools/cli/skf-cli.js uninstall",