bigpowers 2.88.13 → 2.88.14

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.
Files changed (31) hide show
  1. package/.agents/skills/gate-trace/SKILL.md +2 -2
  2. package/.cline/skills/gate-trace/SKILL.md +2 -2
  3. package/.codebuddy/skills/gate-trace/SKILL.md +2 -2
  4. package/.codex/skills/gate-trace/SKILL.md +2 -2
  5. package/.copilot/skills/gate-trace/SKILL.md +2 -2
  6. package/.cursor/rules/gate-trace.mdc +2 -2
  7. package/.gemini/extensions/bigpowers/commands/prompts/gate-trace.md +2 -2
  8. package/.gemini/extensions/bigpowers/gemini-extension.json +1 -1
  9. package/.gemini/extensions/bigpowers/skills/gate-trace/SKILL.md +2 -2
  10. package/.hermes/skills/gate-trace/SKILL.md +2 -2
  11. package/.kilocode/rules/gate-trace.md +2 -2
  12. package/.mimocode/skills/gate-trace/SKILL.md +2 -2
  13. package/.opencode/skills/gate-trace/SKILL.md +2 -2
  14. package/.pi/package.json +1 -1
  15. package/.pi/prompts/gate-trace.md +2 -2
  16. package/.pi/skills/gate-trace/SKILL.md +2 -2
  17. package/.qwen/skills/gate-trace/SKILL.md +2 -2
  18. package/.trae/skills/gate-trace/SKILL.md +2 -2
  19. package/.windsurf/rules/gate-trace.md +2 -2
  20. package/.zcode/skills/gate-trace/SKILL.md +2 -2
  21. package/CHANGELOG.md +7 -0
  22. package/CLAUDE.md +1 -1
  23. package/package.json +1 -1
  24. package/scripts/lib/__pycache__/link_utils.cpython-310.pyc +0 -0
  25. package/scripts/lib/__pycache__/srp_engine_links.cpython-310.pyc +0 -0
  26. package/scripts/lib/golden-suite-gates.sh +5 -2
  27. package/scripts/test-ci-pipeline-contract.sh +162 -0
  28. package/skills/gate-trace/SKILL.md +2 -2
  29. package/skills-lock.json +1 -1
  30. package/scripts/lib/__pycache__/link_utils.cpython-314.pyc +0 -0
  31. package/scripts/lib/__pycache__/srp_engine_links.cpython-314.pyc +0 -0
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -69,8 +69,8 @@ gate_trace:
69
69
  ## Integration Points
70
70
 
71
71
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
72
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
73
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
72
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
73
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
74
74
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
75
75
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
76
76
 
@@ -69,8 +69,8 @@ gate_trace:
69
69
  ## Integration Points
70
70
 
71
71
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
72
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
73
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
72
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
73
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
74
74
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
75
75
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
76
76
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.88.13",
3
+ "version": "2.88.14",
4
4
  "description": "81 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "keywords": [
6
6
  "gemini-extension"
@@ -71,8 +71,8 @@ gate_trace:
71
71
  ## Integration Points
72
72
 
73
73
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
74
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
75
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
74
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
75
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
76
76
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
77
77
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
78
78
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
package/.pi/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.88.13",
3
+ "version": "2.88.14",
4
4
  "description": "81 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -69,8 +69,8 @@ gate_trace:
69
69
  ## Integration Points
70
70
 
71
71
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
72
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
73
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
72
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
73
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
74
74
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
75
75
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
76
76
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
@@ -70,8 +70,8 @@ gate_trace:
70
70
  ## Integration Points
71
71
 
72
72
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
73
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
74
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
73
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
74
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
75
75
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
76
76
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
77
77
 
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [2.88.14](https://github.com/danielvm-git/bigpowers/compare/v2.88.13...v2.88.14) (2026-10-25)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **ci:** gate release on every check in one test-build-release pipeline ([#162](https://github.com/danielvm-git/bigpowers/issues/162)) ([14250d8](https://github.com/danielvm-git/bigpowers/commit/14250d843011da03f766de59f18371276fe16478))
7
+
1
8
  ## [2.88.13](https://github.com/danielvm-git/bigpowers/compare/v2.88.12...v2.88.13) (2026-10-25)
2
9
 
3
10
 
package/CLAUDE.md CHANGED
@@ -68,7 +68,7 @@ Stack: Markdown / Bash (documentation-based; skills integrate with Claude Code,
68
68
  | Lint | `bash scripts/sync-skills.sh` (validates SKILL.md syntax) |
69
69
  | Validate specs YAML | `bash scripts/validate-specs-yaml.sh` |
70
70
  | Typecheck | N/A (Markdown / Bash project) |
71
- | CI platform | GitHub Actions (`.github/workflows/publish.yml`, `sync-skills.yml`, `golden-suite.yml`) |
71
+ | CI platform | GitHub Actions — one pipeline `.github/workflows/test-build-release.yml` (sync, verification-gates, skill-verify, story-verify → release); plus `docs-site.yml`, `publish-wiki.yml` |
72
72
  | Compliance | `npm run compliance` |
73
73
  | Verification Gates | `bash scripts/run-verification-gates.sh` |
74
74
  | Traceability | `bash scripts/trace-stories.sh --strict` | grep for story tags (traceability check) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.88.13",
3
+ "version": "2.88.14",
4
4
  "description": "73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -74,8 +74,11 @@ GOLDEN_GATES=(
74
74
  "specs-parse:bash scripts/validate-specs-yaml.sh:false"
75
75
  # The runner itself: failing output is shown, skips are named and reasoned.
76
76
  "golden-gate-runner:bash scripts/test-golden-gate-runner.sh:false"
77
+ # One pipeline, release needs: every gate, pinned runner and actions.
78
+ "ci-pipeline-contract-selftest:bash scripts/test-ci-pipeline-contract.sh --self-test:false"
79
+ "ci-pipeline-contract:bash scripts/test-ci-pipeline-contract.sh:false"
77
80
  # Tier 2 of the verify arc (#106): executes the verify: of every story marked
78
- # done. Tier 1 (SKILL.md) is run-skill-verify.sh in golden-suite.yml.
81
+ # done. Tier 1 (SKILL.md) is run-skill-verify.sh in test-build-release.yml.
79
82
  "story-verify-selftest:bash scripts/run-story-verify.sh --self-test:false"
80
83
  "story-verify:bash scripts/run-story-verify.sh:false"
81
84
  )
@@ -123,7 +126,7 @@ golden_agent_dry_run() {
123
126
  }
124
127
 
125
128
  # GOLDEN_SKIP_GATES (comma list) skips gates another CI job already runs —
126
- # golden-suite.yml skips story-verify because its story-verify job runs the
129
+ # test-build-release.yml skips story-verify because its story-verify job runs the
127
130
  # same command. Local Preflight leaves it unset, so every gate runs there. A
128
131
  # name that matches no gate is a FAIL: a typo must not look like a skip.
129
132
  golden_is_skipped() { # $1 = gate name
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env bash
2
+ # story: BUG-2026-10-25-release-not-gated
3
+ # test-ci-pipeline-contract.sh — the CI shape the portfolio template requires
4
+ # (danielvm-git/.github, docs/concept/github-actions-best-practices.md):
5
+ #
6
+ # 1. one pipeline, .github/workflows/test-build-release.yml, holds every gate
7
+ # job and the release job; the workflows it replaced are gone
8
+ # 2. release needs: every gate job and runs only on push to main — a release
9
+ # that does not wait for the gates publishes unverified builds
10
+ # 3. no ubuntu-latest; every non-local action is pinned to a 40-char SHA
11
+ # 4. every job has timeout-minutes
12
+ # 5. release and Pages never cancel a run in progress
13
+ #
14
+ # Agent workflows (agent-locks.yml, generated agentics-maintenance.yml) are
15
+ # exempt from 3–4 per migration plan v2.
16
+ #
17
+ # Usage: bash scripts/test-ci-pipeline-contract.sh [--self-test] [workflows-dir]
18
+ set -euo pipefail
19
+ source "$(dirname "${BASH_SOURCE[0]}")/lib/skill-common.sh"
20
+ resolve_repo_root
21
+ cd "$REPO_ROOT"
22
+ source scripts/lib/python-env.sh
23
+ resolve_python >/dev/null || exit 1
24
+
25
+ check_dir() { # $1 = workflows dir; prints violations, exits non-zero on any
26
+ "$PYTHON" - "$1" <<'PY'
27
+ import glob, os, re, sys, yaml
28
+
29
+ d = sys.argv[1]
30
+ GATES = {"sync", "verification-gates", "skill-verify", "story-verify"}
31
+ RETIRED = ["publish.yml", "sync-skills.yml", "golden-suite.yml"]
32
+ EXEMPT = {"agent-locks.yml", "agentics-maintenance.yml"}
33
+ bad = []
34
+
35
+ def load(path):
36
+ with open(path) as f:
37
+ return yaml.safe_load(f) or {}
38
+
39
+ def cancels(block):
40
+ # Literal true cancels; an expression or false does not cancel a push run.
41
+ return isinstance(block, dict) and block.get("cancel-in-progress") is True
42
+
43
+ pipe_path = os.path.join(d, "test-build-release.yml")
44
+ if not os.path.isfile(pipe_path):
45
+ bad.append("test-build-release.yml missing")
46
+ else:
47
+ pipe = load(pipe_path)
48
+ jobs = pipe.get("jobs", {})
49
+ missing = GATES - set(jobs)
50
+ if missing:
51
+ bad.append(f"pipeline lacks gate jobs: {sorted(missing)}")
52
+ rel = jobs.get("release")
53
+ if not rel:
54
+ bad.append("pipeline has no release job")
55
+ else:
56
+ needs = rel.get("needs", [])
57
+ needs = {needs} if isinstance(needs, str) else set(needs)
58
+ gate_jobs = set(jobs) - {"release"}
59
+ if not gate_jobs <= needs:
60
+ bad.append(f"release does not need: {sorted(gate_jobs - needs)}")
61
+ cond = str(rel.get("if", ""))
62
+ if "github.event_name == 'push'" not in cond or "refs/heads/main" not in cond:
63
+ bad.append("release is not limited to push on main")
64
+ if cancels(pipe.get("concurrency")) or cancels(rel.get("concurrency")):
65
+ bad.append("release can be cancelled in progress")
66
+
67
+ for name in RETIRED:
68
+ if os.path.exists(os.path.join(d, name)):
69
+ bad.append(f"retired workflow still present: {name}")
70
+
71
+ docs = os.path.join(d, "docs-site.yml")
72
+ if os.path.isfile(docs) and cancels(load(docs).get("concurrency")):
73
+ bad.append("docs-site.yml: Pages deploy can be cancelled in progress")
74
+
75
+ for path in sorted(glob.glob(os.path.join(d, "*.yml"))):
76
+ name = os.path.basename(path)
77
+ if name in EXEMPT:
78
+ continue
79
+ for job_name, job in (load(path).get("jobs") or {}).items():
80
+ where = f"{name}:{job_name}"
81
+ if "uses" in job: # reusable-workflow call: no runner of its own
82
+ continue
83
+ if "ubuntu-latest" in str(job.get("runs-on", "")):
84
+ bad.append(f"{where}: runs-on ubuntu-latest")
85
+ if "timeout-minutes" not in job:
86
+ bad.append(f"{where}: no timeout-minutes")
87
+ for step in job.get("steps", []):
88
+ uses = step.get("uses")
89
+ if uses and not uses.startswith("./") and not re.search(r"@[0-9a-f]{40}$", uses):
90
+ bad.append(f"{where}: action not SHA-pinned: {uses}")
91
+
92
+ for b in bad:
93
+ print(f"FAIL: {b}")
94
+ sys.exit(1 if bad else 0)
95
+ PY
96
+ }
97
+
98
+ # Anti-vacuity: a conforming fixture passes, and each rule fails on its own breach.
99
+ self_test() {
100
+ local tmp ok=1
101
+ tmp=$(mktemp -d)
102
+ trap "rm -rf '$tmp'" EXIT
103
+ local pin="actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"
104
+ write_fixture() { # $1 = dir
105
+ mkdir -p "$1"
106
+ cat > "$1/test-build-release.yml" <<YAML
107
+ on: push
108
+ jobs:
109
+ sync: {runs-on: ubuntu-22.04, timeout-minutes: 10, steps: [{uses: $pin}]}
110
+ verification-gates: {runs-on: ubuntu-22.04, timeout-minutes: 15, steps: [{run: "true"}]}
111
+ skill-verify: {runs-on: ubuntu-22.04, timeout-minutes: 10, steps: [{run: "true"}]}
112
+ story-verify: {runs-on: ubuntu-22.04, timeout-minutes: 10, steps: [{run: "true"}]}
113
+ release:
114
+ needs: [sync, verification-gates, skill-verify, story-verify]
115
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
116
+ runs-on: ubuntu-22.04
117
+ timeout-minutes: 15
118
+ concurrency: {group: release, cancel-in-progress: false}
119
+ steps: [{run: "true"}]
120
+ YAML
121
+ }
122
+ expect() { # $1 = label, $2 = want pass|fail, $3 = dir
123
+ if check_dir "$3" >/dev/null; then got=pass; else got=fail; fi
124
+ if [ "$got" = "$2" ]; then echo "PASS ($1)"; else echo "FAIL ($1): got $got, want $2"; ok=0; fi
125
+ }
126
+
127
+ write_fixture "$tmp/good"; expect "conforming pipeline passes" pass "$tmp/good"
128
+
129
+ write_fixture "$tmp/no-needs"
130
+ sed -i.bak 's/needs: \[sync, verification-gates, skill-verify, story-verify\]/needs: [sync]/' "$tmp/no-needs/test-build-release.yml"
131
+ expect "release missing gate needs fails" fail "$tmp/no-needs"
132
+
133
+ write_fixture "$tmp/latest"
134
+ sed -i.bak 's/runs-on: ubuntu-22.04, timeout-minutes: 15/runs-on: ubuntu-latest, timeout-minutes: 15/' "$tmp/latest/test-build-release.yml"
135
+ expect "ubuntu-latest fails" fail "$tmp/latest"
136
+
137
+ write_fixture "$tmp/tag"
138
+ sed -i.bak "s|$pin|actions/checkout@v7|" "$tmp/tag/test-build-release.yml"
139
+ expect "tag-pinned action fails" fail "$tmp/tag"
140
+
141
+ write_fixture "$tmp/cancel"
142
+ sed -i.bak 's/cancel-in-progress: false/cancel-in-progress: true/' "$tmp/cancel/test-build-release.yml"
143
+ expect "cancellable release fails" fail "$tmp/cancel"
144
+
145
+ write_fixture "$tmp/retired"; : > "$tmp/retired/publish.yml"
146
+ expect "retired workflow present fails" fail "$tmp/retired"
147
+
148
+ [ "$ok" -eq 1 ] && echo "OK: pipeline contract self-test" || { echo "pipeline contract self-test FAILED"; exit 1; }
149
+ }
150
+
151
+ if [ "${1:-}" = "--self-test" ]; then
152
+ self_test
153
+ exit 0
154
+ fi
155
+
156
+ dir="${1:-.github/workflows}"
157
+ if check_dir "$dir"; then
158
+ echo "OK: CI pipeline contract ($dir)"
159
+ else
160
+ echo "CI pipeline contract violated — see danielvm-git/.github docs/concept/github-actions-best-practices.md"
161
+ exit 1
162
+ fi
@@ -75,8 +75,8 @@ gate_trace:
75
75
  ## Integration Points
76
76
 
77
77
  - **release-branch SKILL.md** — pre-PR gate (FAIL blocks merge).
78
- - **sync-skills.yml** — runs `trace-stories.sh --strict` as its "Traceability gate" step (FAIL
79
- blocks pipeline), which shares this skill's coverage data (`traceability-matrix.json`) but
78
+ - **test-build-release.yml** — its `sync` job runs `trace-stories.sh --strict` as the "Traceability gate" step (FAIL
79
+ blocks the release job), which shares this skill's coverage data (`traceability-matrix.json`) but
80
80
  does not invoke a gate-trace PASS/CONCERNS/FAIL/WAIVED verdict directly.
81
81
  - **verify-work SKILL.md** — runs blind-spot checks; gate-trace consumes the result.
82
82
 
package/skills-lock.json CHANGED
@@ -143,7 +143,7 @@
143
143
  },
144
144
  "gate-trace": {
145
145
  "description": "\"Deterministic traceability quality gate — reads coverage matrix + blind-spot data, applies decision rules with oracle confidence downgrade, emits PASS/CONCERNS/FAIL/WAIVED verdict. Use before release-branch to gate merges on traceability.\"",
146
- "sha256": "978894220e82c96a",
146
+ "sha256": "282c950cf9db124a",
147
147
  "path": "skills/gate-trace/SKILL.md"
148
148
  },
149
149
  "generate-allure-report": {