bigpowers 2.80.0 → 2.81.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.
package/.pi/package.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [2.81.0](https://github.com/danielvm-git/bigpowers/compare/v2.80.0...v2.81.0) (2026-07-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **e54s02:** advisory catalog drift-detection gate ([7761f75](https://github.com/danielvm-git/bigpowers/commit/7761f75ed2312d419f3e28f192385304e36e83f2))
|
|
7
|
+
|
|
1
8
|
# [2.80.0](https://github.com/danielvm-git/bigpowers/compare/v2.79.1...v2.80.0) (2026-07-23)
|
|
2
9
|
|
|
3
10
|
|
package/CLAUDE.md
CHANGED
|
@@ -65,7 +65,7 @@ Stack: Markdown / Bash (documentation-based; skills integrate with Claude Code,
|
|
|
65
65
|
| Compliance | `npm run compliance` |
|
|
66
66
|
| Verification Gates | `bash scripts/run-verification-gates.sh` |
|
|
67
67
|
| Traceability | `bash scripts/trace-stories.sh --strict` | grep for story tags (traceability check) |
|
|
68
|
-
| Preflight | `npm run compliance && bash scripts/run-verification-gates.sh && bash scripts/sync-skills.sh && bash scripts/trace-stories.sh --strict` | Full local green stack before forward work |
|
|
68
|
+
| Preflight | `npm run compliance && bash scripts/run-verification-gates.sh && bash scripts/sync-skills.sh && bash scripts/trace-stories.sh --strict && bash scripts/check-catalog-drift.sh` | Full local green stack before forward work. Trailing step is advisory only (e54s02 catalog-freeze drift check) — it always exits 0 and can never break this chain. |
|
|
69
69
|
| CI | `gh pr checks` | Remote CI green when a PR is open |
|
|
70
70
|
|
|
71
71
|
### Pre-Merge Checklist
|
package/package.json
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# story: e54s02
|
|
3
|
+
# check-catalog-drift.sh — advisory (Confirm-gate) diff of the live skill
|
|
4
|
+
# catalog against e54s01's frozen baseline. ALWAYS exits 0: this warns during
|
|
5
|
+
# the freeze window, it never blocks Preflight (never add to GOLDEN_GATES).
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
source "$SCRIPT_DIR/lib/skill-common.sh"
|
|
10
|
+
source "$SCRIPT_DIR/lib/python-env.sh"
|
|
11
|
+
|
|
12
|
+
resolve_repo_root
|
|
13
|
+
cd "$REPO_ROOT"
|
|
14
|
+
|
|
15
|
+
BASELINE="$(ls -1 "$REPO_ROOT"/specs/tech-architecture/CATALOG-BASELINE-*.yaml 2>/dev/null | sort | tail -1 || true)"
|
|
16
|
+
|
|
17
|
+
if [[ -z "$BASELINE" ]]; then
|
|
18
|
+
echo "no baseline found, skipping drift check"
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
"$PYTHON" - "$BASELINE" "$SKILLS_ROOT" <<'PY'
|
|
23
|
+
import sys, glob, os, re
|
|
24
|
+
import yaml
|
|
25
|
+
|
|
26
|
+
baseline_path, skills_root = sys.argv[1], sys.argv[2]
|
|
27
|
+
baseline = yaml.safe_load(open(baseline_path)) or {}
|
|
28
|
+
base_by_name = {s["name"]: s for s in baseline.get("skills") or []}
|
|
29
|
+
|
|
30
|
+
EXCEPTION_MARKER = "freeze-exception"
|
|
31
|
+
|
|
32
|
+
def has_exception(skill_md):
|
|
33
|
+
if not os.path.isfile(skill_md):
|
|
34
|
+
return False
|
|
35
|
+
with open(skill_md, encoding="utf-8") as f:
|
|
36
|
+
return EXCEPTION_MARKER in f.read()
|
|
37
|
+
|
|
38
|
+
def parse_live(skill_md):
|
|
39
|
+
text = open(skill_md, encoding="utf-8").read()
|
|
40
|
+
fm = re.search(r"^---\n(.*?)\n---", text, re.S | re.M)
|
|
41
|
+
fields = {}
|
|
42
|
+
if fm:
|
|
43
|
+
for line in fm.group(1).splitlines():
|
|
44
|
+
m = re.match(r"^(phase|effort|model):\s*(.+)$", line)
|
|
45
|
+
if m:
|
|
46
|
+
fields[m.group(1)] = m.group(2).strip()
|
|
47
|
+
return fields
|
|
48
|
+
|
|
49
|
+
live_by_name = {}
|
|
50
|
+
for skill_md in sorted(glob.glob(os.path.join(skills_root, "*", "SKILL.md"))):
|
|
51
|
+
name = os.path.basename(os.path.dirname(skill_md))
|
|
52
|
+
live_by_name[name] = {"path": skill_md, **parse_live(skill_md)}
|
|
53
|
+
|
|
54
|
+
warnings = []
|
|
55
|
+
|
|
56
|
+
for name, live in live_by_name.items():
|
|
57
|
+
if name not in base_by_name:
|
|
58
|
+
if not has_exception(live["path"]):
|
|
59
|
+
warnings.append(f"WARNING: addition — new skill '{name}' not in frozen baseline")
|
|
60
|
+
continue
|
|
61
|
+
base = base_by_name[name]
|
|
62
|
+
for field in ("phase", "effort", "model"):
|
|
63
|
+
base_val = base.get(field)
|
|
64
|
+
base_val = None if base_val in ("null", None) else str(base_val)
|
|
65
|
+
live_val = live.get(field)
|
|
66
|
+
if base_val != live_val:
|
|
67
|
+
if not has_exception(live["path"]):
|
|
68
|
+
warnings.append(
|
|
69
|
+
f"WARNING: structural change — '{name}' field '{field}' "
|
|
70
|
+
f"changed from {base_val!r} to {live_val!r}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
for name, base in base_by_name.items():
|
|
74
|
+
if name not in live_by_name:
|
|
75
|
+
warnings.append(f"WARNING: removal — skill '{name}' present in baseline but missing from live catalog")
|
|
76
|
+
|
|
77
|
+
for w in warnings:
|
|
78
|
+
print(w)
|
|
79
|
+
PY
|
|
80
|
+
|
|
81
|
+
exit 0
|
|
Binary file
|