guardian-framework 0.1.163 → 0.1.164

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/dist/cli.js CHANGED
@@ -3206,7 +3206,7 @@ __export(exports_package, {
3206
3206
  bin: () => bin,
3207
3207
  author: () => author
3208
3208
  });
3209
- var name = "guardian-framework", version = "0.1.163", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
3209
+ var name = "guardian-framework", version = "0.1.164", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
3210
3210
  var init_package = __esm(() => {
3211
3211
  exports = {
3212
3212
  ".": {
package/dist/exports.js CHANGED
@@ -1991,7 +1991,7 @@ __export(exports_package, {
1991
1991
  bin: () => bin,
1992
1992
  author: () => author
1993
1993
  });
1994
- var name = "guardian-framework", version = "0.1.163", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1994
+ var name = "guardian-framework", version = "0.1.164", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1995
1995
  var init_package = __esm(() => {
1996
1996
  exports = {
1997
1997
  ".": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardian-framework",
3
- "version": "0.1.163",
3
+ "version": "0.1.164",
4
4
  "description": "Token-optimized agentic framework scaffolder with pi-first architecture",
5
5
  "type": "module",
6
6
  "main": "dist/exports.js",
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-11-13T20:44:26Z",
2
+ "timestamp": "2026-11-13T21:11:04Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {
@@ -16,13 +16,14 @@
16
16
  # freeze.sh status [--root DIR]
17
17
  # freeze.sh list [--root DIR]
18
18
  # freeze.sh next [--root DIR] # next module eligible to freeze, in order
19
+ # freeze.sh unfreeze --module <m> --reason "<why>" [--root DIR]
19
20
  #
20
21
  # Exit: 0 pass · 1 verification failed · 2 usage/state error
21
22
  # ============================================================================
22
23
  set -uo pipefail
23
24
 
24
25
  CMD="${1:-}"; shift || true
25
- MODULE=""; ROOT_OPT=""; BASE="main"; JSON_OUT=0; COMMIT=""
26
+ MODULE=""; ROOT_OPT=""; BASE="main"; JSON_OUT=0; COMMIT=""; REASON=""
26
27
 
27
28
  while [ $# -gt 0 ]; do
28
29
  case "$1" in
@@ -31,6 +32,7 @@ while [ $# -gt 0 ]; do
31
32
  --base) BASE="${2:-main}"; shift 2 ;;
32
33
  --commit) COMMIT="${2:-}"; shift 2 ;;
33
34
  --json) JSON_OUT=1; shift ;;
35
+ --reason) REASON="${2:-}"; shift 2 ;;
34
36
  *) echo "unknown argument: $1" >&2; exit 2 ;;
35
37
  esac
36
38
  done
@@ -54,15 +56,15 @@ usage() {
54
56
  }
55
57
 
56
58
  case "$CMD" in
57
- verify | record | status | list | next) ;;
59
+ verify | record | status | list | next | unfreeze) ;;
58
60
  *) usage; exit 2 ;;
59
61
  esac
60
62
 
61
- exec python3 - "$CMD" "$ROOT" "$GIT_TOP" "$STATE" "$MODULE" "$BASE" "$JSON_OUT" "$COMMIT" <<'PY'
63
+ exec python3 - "$CMD" "$ROOT" "$GIT_TOP" "$STATE" "$MODULE" "$BASE" "$JSON_OUT" "$COMMIT" "$REASON" <<'PY'
62
64
  import json, os, re, subprocess, sys
63
65
  from datetime import datetime, timezone
64
66
 
65
- cmd, root, git_top, state_path, module, base, json_out, commit = sys.argv[1:9]
67
+ cmd, root, git_top, state_path, module, base, json_out, commit, reason = sys.argv[1:10]
66
68
  json_out = json_out == "1"
67
69
 
68
70
  MODS = os.path.join(root, ".pi", "architecture", "modules")
@@ -391,6 +393,31 @@ def verify(slug):
391
393
  checks.append(("red state", ok_red, f"{status}: {reason}"))
392
394
  ok_all &= ok_red
393
395
 
396
+ # 3b. static types — a frozen contract that does not type-check is a defect.
397
+ # This is what caught `Invoice.record` shadowing `AggregateRoot.record`
398
+ # (a classmethod factory hiding the event recorder) inside a frozen module.
399
+ pyproject = read(os.path.join(root, "pyproject.toml"))
400
+ has_mypy_cfg = ("[tool.mypy]" in pyproject
401
+ or os.path.exists(os.path.join(root, "mypy.ini"))
402
+ or "[mypy]" in read(os.path.join(root, "setup.cfg")))
403
+ mypy = os.path.join(root, ".venv", "bin", "mypy")
404
+ # dedupe: for a slug without hyphens both candidates are the same path, and
405
+ # passing it twice makes mypy report "Duplicate module named …"
406
+ pkg_dirs = sorted({d for d in (os.path.join(root, "src", slug),
407
+ os.path.join(root, "src", slug.replace("-", "_")))
408
+ if os.path.isdir(d)})
409
+ if has_mypy_cfg and pkg_dirs and (os.path.exists(mypy) or os.path.exists("/usr/bin/env")):
410
+ try:
411
+ tc = subprocess.run([mypy if os.path.exists(mypy) else "mypy", *pkg_dirs],
412
+ cwd=root, capture_output=True, text=True, timeout=600)
413
+ ok_tc = tc.returncode == 0
414
+ tail = [l for l in (tc.stdout or "").splitlines() if ": error:" in l][:3]
415
+ checks.append(("type check", ok_tc,
416
+ "mypy clean" if ok_tc else "mypy errors: " + " | ".join(tail)))
417
+ ok_all &= ok_tc
418
+ except Exception as e:
419
+ checks.append(("type check", True, f"skipped ({e})"))
420
+
394
421
  # 4b. recorded evidence must still hold (spec: a contract change means
395
422
  # the module is no longer frozen and must be re-frozen).
396
423
  st_rec = load_state()
@@ -519,6 +546,31 @@ if cmd == "next":
519
546
  print("no eligible module: every module is frozen/implemented or blocked by an unfrozen dependency")
520
547
  raise SystemExit(1)
521
548
 
549
+ if cmd == "unfreeze":
550
+ if not module:
551
+ print("usage: freeze.sh unfreeze --module <m> --reason \"why\"", file=sys.stderr)
552
+ raise SystemExit(2)
553
+ if not reason:
554
+ print("refusing to unfreeze without a reason: a contract change must be recorded",
555
+ file=sys.stderr)
556
+ raise SystemExit(2)
557
+ slug = slugify(module)
558
+ st = load_state()
559
+ e = entry(st, slug)
560
+ if not e:
561
+ print(f"{slug} is not recorded — nothing to unfreeze", file=sys.stderr)
562
+ raise SystemExit(2)
563
+ history = e.get("history") or []
564
+ if e.get("evidence"):
565
+ history.append({"evidence": e["evidence"], "state": e.get("state"),
566
+ "unfrozenAt": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
567
+ "reason": reason})
568
+ set_entry(st, slug, state="unfrozen", contractFrozen=False, evidence=None, history=history)
569
+ save_state(st)
570
+ print(f"unfrozen: {slug} — {reason}")
571
+ print("Re-run Phase A for the changed contract, then record again.")
572
+ raise SystemExit(0)
573
+
522
574
  # ── commands ────────────────────────────────────────────────────────────────
523
575
  if cmd == "list":
524
576
  st = load_state()