guardian-framework 0.1.104 → 0.1.109

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 (71) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.js +232 -16
  3. package/dist/exports.js +232 -16
  4. package/package.json +1 -1
  5. package/templates/languages/rust-patterns.md +5 -2
  6. package/templates/pi/context/checklists.md +15 -1
  7. package/templates/pi/domain/exploration.md +9 -0
  8. package/templates/pi/domain/ubiquitous-language.md +12 -0
  9. package/templates/pi/extensions/architect-lib/generators.ts +163 -12
  10. package/templates/pi/extensions/architect-lib/helpers.ts +49 -0
  11. package/templates/pi/extensions/architect-lib/tdd-generator.ts +1 -1
  12. package/templates/pi/extensions/architect-lib/types.ts +44 -2
  13. package/templates/pi/extensions/architect.ts +105 -41
  14. package/templates/pi/extensions/ask-user-question.ts +2 -2
  15. package/templates/pi/extensions/bash-guard.ts +2 -2
  16. package/templates/pi/extensions/config-reload.ts +12 -5
  17. package/templates/pi/extensions/coordinator.ts +2 -2
  18. package/templates/pi/extensions/curator.ts +1 -1
  19. package/templates/pi/extensions/domain-explorer.ts +50 -3
  20. package/templates/pi/extensions/filechanges.ts +2 -2
  21. package/templates/pi/extensions/goal-loop.ts +3 -3
  22. package/templates/pi/extensions/hooks.ts +1 -1
  23. package/templates/pi/extensions/pi-env.d.ts +96 -0
  24. package/templates/pi/extensions/pipeline.ts +1 -1
  25. package/templates/pi/extensions/project-scaffolder.ts +1 -1
  26. package/templates/pi/extensions/read-only-mode.ts +5 -1
  27. package/templates/pi/extensions/tsconfig.json +9 -2
  28. package/templates/pi/preflight_report.json +1 -1
  29. package/templates/pi/prompts/ci-blueprint.md +2 -2
  30. package/templates/pi/scripts/check_model_judgment.sh +28 -0
  31. package/templates/pi/scripts/ci/check_judgment_contracts.sh +93 -0
  32. package/templates/pi/scripts/ci/run_preflight.sh +3 -3
  33. package/templates/pi/scripts/ci/run_stage.sh +1 -1
  34. package/templates/pi/scripts/ci/stage_lint.sh +1 -1
  35. package/templates/pi/scripts/coverage.sh +58 -0
  36. package/templates/pi/scripts/install_coverage_tools.sh +43 -0
  37. package/templates/pi/scripts/languages/go/check_model_judgment.sh +70 -0
  38. package/templates/pi/scripts/languages/go/check_runtime_reachability.sh +34 -0
  39. package/templates/pi/scripts/languages/go/coverage.sh +78 -0
  40. package/templates/pi/scripts/languages/go/install_coverage_tools.sh +17 -0
  41. package/templates/pi/scripts/languages/java/check_model_judgment.sh +142 -0
  42. package/templates/pi/scripts/languages/java/check_runtime_reachability.sh +31 -0
  43. package/templates/pi/scripts/languages/java/coverage.sh +103 -0
  44. package/templates/pi/scripts/languages/java/install_coverage_tools.sh +40 -0
  45. package/templates/pi/scripts/languages/java/validate-architecture.sh +20 -0
  46. package/templates/pi/scripts/languages/python/check_model_judgment.sh +67 -0
  47. package/templates/pi/scripts/languages/python/check_runtime_reachability.sh +34 -0
  48. package/templates/pi/scripts/languages/python/coverage.sh +88 -0
  49. package/templates/pi/scripts/languages/python/install_coverage_tools.sh +22 -0
  50. package/templates/pi/scripts/languages/rust/check_model_judgment.sh +61 -0
  51. package/templates/pi/scripts/languages/rust/check_runtime_reachability.sh +40 -0
  52. package/templates/pi/scripts/languages/rust/coverage.sh +79 -0
  53. package/templates/pi/scripts/languages/rust/install_coverage_tools.sh +20 -0
  54. package/templates/pi/scripts/languages/rust/validate-tests.sh +9 -6
  55. package/templates/pi/scripts/languages/typescript/check_model_judgment.sh +81 -0
  56. package/templates/pi/scripts/languages/typescript/check_runtime_reachability.sh +41 -0
  57. package/templates/pi/scripts/languages/typescript/coverage.sh +154 -0
  58. package/templates/pi/scripts/languages/typescript/install_coverage_tools.sh +41 -0
  59. package/templates/pi/scripts/languages/typescript/validate-canonical.sh +6 -2
  60. package/templates/pi/scripts/languages/typescript/validate-ci.sh +2 -2
  61. package/templates/pi/scripts/validate-architecture-readiness.sh +29 -0
  62. package/templates/pi/scripts/validate-exploration-depth.sh +112 -0
  63. package/templates/pi/scripts/validate-runtime-wiring.sh +35 -0
  64. package/templates/pi/skills/agents/architecture-validator.md +28 -0
  65. package/templates/pi/skills/agents/test-validator.md +1 -1
  66. package/templates/pi/skills/go-enterprise-codegen.md +46 -0
  67. package/templates/pi/skills/java-spring-enterprise-codegen.md +50 -0
  68. package/templates/pi/skills/python-enterprise-codegen.md +46 -0
  69. package/templates/pi/skills/rust-enterprise-codegen.md +46 -0
  70. package/templates/pi/skills/tdd-practice.md +17 -9
  71. package/templates/pi/skills/typescript-enterprise-codegen.md +46 -0
@@ -25,6 +25,8 @@ import {
25
25
  const COMMAND_NAME = "read-only";
26
26
  const STATUS_KEY = "read-only-mode";
27
27
  const WIDGET_KEY = "read-only-mode";
28
+ let readOnlyActive = false;
29
+
28
30
  const READ_ONLY_TOOL_NAMES = ["read", "grep", "find", "ls"] as const;
29
31
 
30
32
  function getReadOnlyToolNames(pi: ExtensionAPI): string[] {
@@ -95,6 +97,7 @@ export default function (pi: ExtensionAPI) {
95
97
  });
96
98
 
97
99
  function enable(ctx: ExtensionContext): void {
100
+ readOnlyActive = true;
98
101
  if (enabled) {
99
102
  updateUi(pi, ctx, enabled);
100
103
  ctx.ui.notify("Read-only mode is already enabled.", "info");
@@ -111,6 +114,7 @@ export default function (pi: ExtensionAPI) {
111
114
  }
112
115
 
113
116
  function disable(ctx: ExtensionContext): void {
117
+ readOnlyActive = false;
114
118
  if (!enabled) {
115
119
  updateUi(pi, ctx, enabled);
116
120
  ctx.ui.notify("Read-only mode is already disabled.", "info");
@@ -130,7 +134,7 @@ export default function (pi: ExtensionAPI) {
130
134
  switch (action) {
131
135
  case "":
132
136
  case "toggle":
133
- toggle(ctx);
137
+ if (readOnlyActive) disable(ctx); else enable(ctx);
134
138
  return;
135
139
  case "on":
136
140
  case "enable":
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "types": ["bun-types"],
3
+ "types": [
4
+ "bun-types"
5
+ ],
4
6
  "strict": true,
7
+ "noImplicitAny": false,
8
+ "strictNullChecks": false,
5
9
  "target": "ES2022",
6
10
  "module": "ESNext",
7
11
  "moduleResolution": "bundler",
@@ -11,5 +15,8 @@
11
15
  "isolatedModules": true,
12
16
  "allowImportingTsExtensions": true
13
17
  },
14
- "include": ["**/*.ts"]
18
+ "include": [
19
+ "**/*.ts",
20
+ "**/*.d.ts"
21
+ ]
15
22
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-07-20T15:54:07Z",
2
+ "timestamp": "2026-09-04T13:00:27Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {
@@ -72,7 +72,7 @@ Language-specific linting.
72
72
  | `unit_application` | `pytest tests/unit/application` | No |
73
73
  | `unit_contract` | `pytest tests/contract` | No |
74
74
  | `unit_verification` | `pytest tests/verification` | No |
75
- | `coverage_threshold_check` | `.pi/scripts/ci/check_coverage_thresholds.py` | No |
75
+ | `coverage_gate` | `bash .pi/scripts/install_coverage_tools.sh && bash .pi/scripts/coverage.sh --gate --lcov` | No |
76
76
 
77
77
  ## Stage 6: Integration
78
78
 
@@ -119,7 +119,7 @@ Language-specific linting.
119
119
  | Rule | Jobs Using It |
120
120
  |------|---------------|
121
121
  | `rules_default` (MRs or main branch) | Most jobs |
122
- | `rules_sonar` (requires `$SONAR_TOKEN` + `$SONAR_HOST_URL`) | coverage_report, sonar_quality_gate |
122
+ | `rules_sonar` (requires `$SONAR_TOKEN` + `$SONAR_HOST_URL`) | coverage_gate (uploads lcov artifact), sonar_quality_gate |
123
123
  | `rules_main_only` | `package_build` |
124
124
  | `rules_migration_changes` (migration file changes only) | `migration_verify` stage |
125
125
 
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_model_judgment.sh — ADR-008/009 dispatcher
4
+ # Runs the language-scoped model-judgment hard gates (dip-domain,
5
+ # interface-ownership, adapter-purity, transaction placement per language).
6
+ # Usage: bash .pi/scripts/check_model_judgment.sh [--root <dir>]
7
+ # ============================================================================
8
+ set -uo pipefail
9
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ ROOT="$(pwd)"
11
+ if [ "${1:-}" = "--root" ] && [ -n "${2:-}" ]; then ROOT="$2"; fi
12
+ cd "$ROOT" || exit 1
13
+
14
+ detect_language() {
15
+ if [ -f "Cargo.lock" ] || [ -f "Cargo.toml" ]; then echo "rust"
16
+ elif [ -f "package.json" ]; then echo "typescript"
17
+ elif [ -f "go.mod" ]; then echo "go"
18
+ elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then echo "python"
19
+ elif [ -f "pom.xml" ] || [ -f "build.gradle" ]; then echo "java"
20
+ else echo "unknown"; fi
21
+ }
22
+ LANG="$(detect_language)"
23
+ SCRIPT="${SCRIPT_DIR}/languages/${LANG}/check_model_judgment.sh"
24
+ if [ -f "$SCRIPT" ]; then
25
+ exec bash "$SCRIPT" --root "$ROOT"
26
+ fi
27
+ echo "model-judgment: no gate script for language '${LANG}'"
28
+ exit 0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_judgment_contracts.sh — proofing for ADR-008 P1 (judgment-aware
4
+ # modeling). Deterministic proof that each frozen contract (§1–§7 of
5
+ # .pi/architecture/contracts/judgment-aware-modeling-p1.md) is implemented
6
+ # in the framework sources.
7
+ #
8
+ # Checks:
9
+ # 1. exploration prompt emits ADR-008 schema markers (src)
10
+ # 2. validate-exploration-depth.sh exists + executable
11
+ # 3. java model-judgment gate exists + executable
12
+ # 4. module-doc scaffold emits 'Modeling Depth' header (src)
13
+ # 5. java-spring codegen skill carries 'Judgment Tables (ADR-008)'
14
+ # 6. architecture-validator skill carries Model Judgment Review R1-R4
15
+ # 7. modeling contracts: ModuleComponent type carries the ADR-008 fields
16
+ # 8. exploration.md template carries the Modeling Judgment section
17
+ #
18
+ # Exit 0 = all contracts proven; 1 = at least one missing.
19
+ # ============================================================================
20
+ set -uo pipefail
21
+
22
+ ROOT="$(pwd)"
23
+ if [ "${1:-}" = "--root" ] && [ -n "${2:-}" ]; then ROOT="$2"; fi
24
+ cd "$ROOT" || exit 1
25
+
26
+ FAILED=0
27
+ PASSED=0
28
+
29
+ check() { # label, file-or-dir, grep pattern
30
+ local label="$1" path="$2" pattern="$3"
31
+ if [ -n "$path" ] && [ -e "$path" ] && grep -qE "$pattern" "$path" 2>/dev/null; then
32
+ echo " PASS: $label"
33
+ PASSED=$((PASSED + 1))
34
+ else
35
+ echo " FAIL: $label (missing: $path / $pattern)" >&2
36
+ FAILED=$((FAILED + 1))
37
+ fi
38
+ }
39
+
40
+ check_file() { # label file
41
+ if [ -f "$2" ] && [ -x "$2" ]; then
42
+ echo " PASS: $1"
43
+ PASSED=$((PASSED + 1))
44
+ else
45
+ echo " FAIL: $1 (not found/executable: $2)" >&2
46
+ FAILED=$((FAILED + 1))
47
+ fi
48
+ }
49
+
50
+ echo "Judgment contracts proofing (ADR-008 P1)"
51
+ echo "----------------------------------------"
52
+
53
+ # 1. exploration prompt schema markers
54
+ check "exploration prompt: subdomainType/invariants/triage/contextMap/conflicts" \
55
+ "src/lib/domain-explorer.ts" 'subdomainType|"invariants"|"triage"|"contextMap"|"conflicts"'
56
+
57
+ # 2. depth validator present + executable
58
+ check_file "validate-exploration-depth.sh executable" ".pi/scripts/validate-exploration-depth.sh"
59
+ check_file "validate-exploration-depth.sh (templates copy)" "templates/pi/scripts/validate-exploration-depth.sh"
60
+
61
+ # 3. java model-judgment gate present + executable
62
+ check_file "java model-judgment gate" ".pi/scripts/languages/java/check_model_judgment.sh"
63
+ check_file "java model-judgment gate (templates copy)" "templates/pi/scripts/languages/java/check_model_judgment.sh"
64
+
65
+ # 4. scaffold emits Modeling Depth header + invariants + depth note
66
+ check "scaffold: Modeling Depth header" "src/lib/domain-explorer.ts" 'Modeling Depth'
67
+ check "scaffold: depth note for service/adapter" "src/lib/domain-explorer.ts" 'Modeling Depth Note \(ADR-008\)'
68
+
69
+ # 5. java-spring codegen skill: judgment tables
70
+ check "java-spring skill: Judgment Tables (ADR-008)" \
71
+ ".pi/skills/java-spring-enterprise-codegen.md" 'Judgment Tables \(ADR-008\)'
72
+
73
+ # 6. architecture-validator skill: R1-R4 review questions
74
+ check "architecture-validator skill: Model Judgment Review" \
75
+ ".pi/skills/agents/architecture-validator.md" 'Model Judgment Review'
76
+
77
+ # 7. ModuleComponent modeling-contract fields
78
+ check "architect-lib types: modelingDepth/aggregateRoot/invariants/events" \
79
+ ".pi/extensions/architect-lib/types.ts" 'modelingDepth|aggregateRoot|invariants|publishes'
80
+ check "generators: Modeling Contract emission" \
81
+ ".pi/extensions/architect-lib/generators.ts" 'Modeling Contract \(ADR-008\)'
82
+
83
+ # 8. exploration.md template: Modeling Judgment section
84
+ check "exploration.md template: Modeling Judgment section" \
85
+ "templates/pi/domain/exploration.md" 'Modeling Judgment \(ADR-008\)'
86
+
87
+ echo ""
88
+ echo " Passed: $PASSED Failed: $FAILED"
89
+ if [ "$FAILED" -gt 0 ]; then
90
+ exit 1
91
+ fi
92
+ echo "All judgment contracts proven."
93
+ exit 0
@@ -255,10 +255,10 @@ run_stage_lint() {
255
255
  log_fail "biome check" "lint errors found" "$(( $(date +%s) - t ))"
256
256
  fi
257
257
  t=$(date +%s)
258
- if biome format --check . >/dev/null 2>&1; then
259
- log_pass "biome format --check" "$(( $(date +%s) - t ))"
258
+ if biome ci . >/dev/null 2>&1; then
259
+ log_pass "biome ci" "$(( $(date +%s) - t ))"
260
260
  else
261
- log_fail "biome format --check" "format errors found" "$(( $(date +%s) - t ))"
261
+ log_fail "biome ci" "format errors found" "$(( $(date +%s) - t ))"
262
262
  fi
263
263
  else
264
264
  log_skip "biome" "not installed"
@@ -76,7 +76,7 @@ case "$STAGE" in
76
76
  ruff check . && ruff format --check .
77
77
  elif [[ -f "package.json" ]]; then
78
78
  echo "TypeScript project detected"
79
- biome check . && biome format --check .
79
+ biome check . && biome ci .
80
80
  elif [[ -f "Cargo.toml" ]]; then
81
81
  echo "Rust project detected"
82
82
  cargo clippy -- -D warnings && cargo fmt --check
@@ -72,7 +72,7 @@ case "$LANG" in
72
72
  else
73
73
  log_fail "biome lint" "Lint errors found"
74
74
  fi
75
- if biome format . --check 2>/dev/null; then
75
+ if biome ci . 2>/dev/null; then
76
76
  log_pass "biome format check"
77
77
  else
78
78
  log_fail "biome format check" "Format errors found"
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # coverage.sh — Real project coverage measurement + gate (dispatcher)
4
+ #
5
+ # Runs the project's REAL coverage tool for the detected language and reports
6
+ # line coverage. This is the honest replacement for the old per-module
7
+ # heuristic `*_coverage.sh` checks (coverage-theater — they counted test
8
+ # functions via grep, never a real percentage).
9
+ #
10
+ # Delegates to languages/<lang>/coverage.sh. Real coverage tool per language:
11
+ # rust — cargo llvm-cov (workspace line coverage, lcov artifact)
12
+ # python — coverage.py (pytest/unittest)
13
+ # typescript — vitest / jest / bun test --coverage (istanbul text)
14
+ # go — go test -coverprofile + go tool cover
15
+ # java — JaCoCo (maven/gradle)
16
+ #
17
+ # Usage:
18
+ # bash .pi/scripts/coverage.sh # measure + print summary
19
+ # bash .pi/scripts/coverage.sh --gate # exit 1 if lines < COVERAGE_THRESHOLD
20
+ # bash .pi/scripts/coverage.sh --lcov # also emit the tool's report artifact
21
+ #
22
+ # Env:
23
+ # COVERAGE_THRESHOLD minimum line-coverage % (default: 60 — a conservative
24
+ # floor; set it to the threshold your CI actually enforces)
25
+ #
26
+ # Exit codes:
27
+ # 0 — measured and (with --gate) meets threshold, or language not applicable
28
+ # 1 — coverage tool missing / below threshold / could not measure (honest
29
+ # fail — never fake-pass)
30
+ # 2 — unknown argument
31
+ # ============================================================================
32
+ set -uo pipefail
33
+
34
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
35
+
36
+ detect_language() {
37
+ if [ -f "Cargo.lock" ] || [ -f "Cargo.toml" ]; then echo "rust"
38
+ elif [ -f "poetry.lock" ] || [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then echo "python"
39
+ elif [ -f "go.mod" ]; then echo "go"
40
+ elif [ -f "package.json" ]; then echo "typescript"
41
+ elif [ -f "pom.xml" ] || [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then echo "java"
42
+ else echo "unknown"; fi
43
+ }
44
+
45
+ LANG="$(detect_language)"
46
+
47
+ if [ "$LANG" = "unknown" ]; then
48
+ echo "⚠️ No project language detected — no real coverage gate applies." >&2
49
+ exit 0
50
+ fi
51
+
52
+ LANG_SCRIPT="${SCRIPT_DIR}/languages/${LANG}/coverage.sh"
53
+ if [ ! -f "$LANG_SCRIPT" ]; then
54
+ echo "⚠️ No coverage gate script for '${LANG}' yet (${LANG_SCRIPT})." >&2
55
+ exit 0
56
+ fi
57
+
58
+ exec bash "$LANG_SCRIPT" "$@"
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # install_coverage_tools.sh — Install the project's real coverage tooling
4
+ # (dispatcher)
5
+ #
6
+ # Delegates to languages/<lang>/install_coverage_tools.sh based on the
7
+ # detected language. Run this before `.pi/scripts/coverage.sh --gate` in CI
8
+ # or on a fresh checkout.
9
+ #
10
+ # Usage:
11
+ # bash .pi/scripts/install_coverage_tools.sh
12
+ #
13
+ # Exit codes:
14
+ # 0 — tooling available / installed / not required
15
+ # 1 — install failed
16
+ # ============================================================================
17
+ set -uo pipefail
18
+
19
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
+
21
+ detect_language() {
22
+ if [ -f "Cargo.lock" ] || [ -f "Cargo.toml" ]; then echo "rust"
23
+ elif [ -f "poetry.lock" ] || [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then echo "python"
24
+ elif [ -f "go.mod" ]; then echo "go"
25
+ elif [ -f "package.json" ]; then echo "typescript"
26
+ elif [ -f "pom.xml" ] || [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then echo "java"
27
+ else echo "unknown"; fi
28
+ }
29
+
30
+ LANG="$(detect_language)"
31
+
32
+ if [ "$LANG" = "unknown" ]; then
33
+ echo "⚠️ No project language detected — nothing to install." >&2
34
+ exit 0
35
+ fi
36
+
37
+ LANG_SCRIPT="${SCRIPT_DIR}/languages/${LANG}/install_coverage_tools.sh"
38
+ if [ ! -f "$LANG_SCRIPT" ]; then
39
+ echo "⚠️ No coverage installer for '${LANG}' yet (${LANG_SCRIPT})." >&2
40
+ exit 0
41
+ fi
42
+
43
+ exec bash "$LANG_SCRIPT" "$@"
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_model_judgment.sh — Go (ADR-008/009)
4
+ # Deterministic hard gates:
5
+ # dip-domain domain/ imports gorm/sqlx/gin/echo
6
+ # txn-placement sql.Tx / BeginTx outside application/
7
+ # interface-ownership (tactical) infra adapters without a domain interface
8
+ # adapter-purity (adapter modules) model code in generic subdomains
9
+ # Usage: bash check_model_judgment.sh [--root <dir>]
10
+ # ============================================================================
11
+ set -uo pipefail
12
+ ROOT="$(pwd)"
13
+ if [ "${1:-}" = "--root" ] && [ -n "${2:-}" ]; then ROOT="$2"; fi
14
+ cd "$ROOT" || exit 1
15
+ VIOLATIONS=0
16
+ report() { echo "$1:$2: [$3] $4"; VIOLATIONS=$((VIOLATIONS + 1)); }
17
+ [ -d src ] || { echo "model-judgment (go): no src/"; exit 0; }
18
+
19
+ while IFS= read -r f; do
20
+ [ -n "$f" ] || continue
21
+ case "$f" in */domain/*)
22
+ while IFS=: read -r ln rest; do
23
+ case "$rest" in
24
+ *gorm.io*|*database/sql*|*sqlx*|*gin-gonic*|*labstack*|*uptrace/bun*)
25
+ report "$f" "$ln" "dip-domain" "domain imports persistence/web framework: $rest" ;;
26
+ esac
27
+ done < <(grep -nE '^\s*("|_ "|import )' "$f" | grep -E 'gorm|sqlx|database/sql|gin-gonic|labstack|bun' || true) ;;
28
+ esac
29
+ case "$f" in */application/*) ;; *)
30
+ if grep -qE "sql\.Tx|BeginTx|\.Commit\(\)" "$f" 2>/dev/null; then
31
+ report "$f" "1" "txn-placement" "transaction handling outside application layer"
32
+ fi ;;
33
+ esac
34
+ done < <(find src -type f -name "*.go" 2>/dev/null | grep -vE "_test\.go$|/tests?/" || true)
35
+
36
+ if [ -d ".pi/architecture/modules" ]; then
37
+ for doc in .pi/architecture/modules/*.md; do
38
+ [ -f "$doc" ] || continue
39
+ doc_name="$(basename "$doc" .md)"
40
+ depth="$(grep -m1 '^\*\*Modeling Depth:\*\*' "$doc" | sed 's/.*\*\*Modeling Depth:\*\* *//' | cut -d' ' -f1 || true)"
41
+ docnorm="$(echo "$doc_name" | sed 's/^module[-_]//' | tr '[:upper:]' '[:lower:]' | tr '-' '_')"
42
+ match_dir=""
43
+ while IFS= read -r d; do
44
+ norm="$(basename "$d" | tr '[:upper:]' '[:lower:]' | tr '-' '_')"
45
+ if [ "$norm" = "$docnorm" ]; then match_dir="$d"; break; fi
46
+ done < <(find src -mindepth 1 -maxdepth 1 -type d 2>/dev/null || true)
47
+ [ -n "$match_dir" ] || continue
48
+ if [ "$depth" = "adapter" ]; then
49
+ for layer in domain application; do
50
+ while IFS= read -r f; do [ -n "$f" ] || continue; report "$f" "1" "adapter-purity" "generic subdomain '${doc_name}' must not contain ${layer}/ model code (ADR-008)"; done < <(find "$match_dir/$layer" -type f -name "*.go" 2>/dev/null || true)
51
+ done
52
+ elif [ "$depth" = "tactical" ]; then
53
+ while IFS= read -r impl; do
54
+ [ -n "$impl" ] || continue
55
+ simple="$(basename "$impl" .go)"
56
+ stem="$(echo "$simple" | sed -E 's/Impl$//;s/impl$//')"
57
+ if ! grep -rqiE "type ${stem} interface|type ${simple} interface|${stem}" "$match_dir/domain" 2>/dev/null; then
58
+ compact="$(printf '%s' "$simple" | tr -d '_-')"
59
+ if [ -z "$compact" ] || ! grep -rqil "$compact" "$match_dir/domain" 2>/dev/null; then
60
+ report "$impl" "1" "interface-ownership" "adapter without a domain/-owned interface (${simple})"
61
+ fi
62
+ fi
63
+ done < <(find "$match_dir/infrastructure" -type f -name "*.go" 2>/dev/null || true)
64
+ fi
65
+ done
66
+ fi
67
+
68
+ if [ "$VIOLATIONS" -gt 0 ]; then echo "model-judgment (go): ${VIOLATIONS} violation(s)" >&2; exit 1; fi
69
+ echo "model-judgment (go): all gates passed (dip-domain, txn-placement, interface-ownership, adapter-purity)"
70
+ exit 0
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_runtime_reachability.sh — Go (ADR-009)
4
+ #
5
+ # Every service file under src/<module>/application/ must be referenced from
6
+ # production code OUTSIDE its own module and OUTSIDE tests. Candidates: the
7
+ # file stem (snake), its PascalCase type name, and the separator-stripped
8
+ # form (case-insensitive).
9
+ # Usage: bash check_runtime_reachability.sh [--root <dir>]
10
+ # Exit: 0 all reachable ; 1 dead service(s)
11
+ # ============================================================================
12
+ set -uo pipefail
13
+ ROOT="$(pwd)"
14
+ if [ "${1:-}" = "--root" ] && [ -n "${2:-}" ]; then ROOT="$2"; fi
15
+ cd "$ROOT" || exit 1
16
+ VIOLATIONS=0
17
+ [ -d src ] || { echo "runtime-reachability (go): no src/"; exit 0; }
18
+
19
+ while IFS= read -r svc; do
20
+ [ -n "$svc" ] || continue
21
+ mod="$(echo "$svc" | sed 's|^src/||; s|/application/.*||')"
22
+ stem="$(basename "$svc" .go)"
23
+ pascal="$(echo "$stem" | python3 -c 'import sys; s=sys.stdin.read().strip(); print("".join(w.capitalize() for w in s.split("_")) if s else "")' 2>/dev/null || echo "$stem")"
24
+ compact="$(echo "$stem" | tr -d '_-')"
25
+ refs="$(grep -rliE "\b(${pascal}|${stem}|${compact})\b" src 2>/dev/null | grep -vE "_test\.go$|/tests?/|/test/" | grep -v "^src/${mod}/" | grep -v "^${svc}$" | grep -cv '^$' || true)"
26
+ if [ "${refs:-0}" -eq 0 ]; then
27
+ echo "$svc: [runtime-reachability] application service has no production caller outside its module (tests-only callers don't count — ADR-009)"
28
+ VIOLATIONS=$((VIOLATIONS + 1))
29
+ fi
30
+ done < <(find src -path "*/application/*.go" -type f 2>/dev/null | grep -vE "_test\.go$" || true)
31
+
32
+ if [ "$VIOLATIONS" -gt 0 ]; then echo "runtime-wiring (go): ${VIOLATIONS} unwired service(s)" >&2; exit 1; fi
33
+ echo "runtime-reachability (go): all application services reachable from production code"
34
+ exit 0
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # coverage.sh — Go: real line coverage via `go test -coverprofile`
4
+ #
5
+ # Runs the full test suite with a coverage profile and reports total line
6
+ # coverage from `go tool cover -func`.
7
+ #
8
+ # Usage (normally via the .pi/scripts/coverage.sh dispatcher):
9
+ # bash coverage.sh # measure coverage
10
+ # bash coverage.sh --gate # fail if lines < COVERAGE_THRESHOLD
11
+ # bash coverage.sh --lcov # keep coverage.out profile artifact
12
+ #
13
+ # Env:
14
+ # COVERAGE_THRESHOLD minimum line-coverage % (default: 60)
15
+ # ============================================================================
16
+ set -uo pipefail
17
+
18
+ COVERAGE_THRESHOLD="${COVERAGE_THRESHOLD:-60}"
19
+ GATE=0
20
+ LCOV=0
21
+
22
+ for arg in "$@"; do
23
+ case "$arg" in
24
+ --gate) GATE=1 ;;
25
+ --lcov) LCOV=1 ;;
26
+ *) echo "unknown arg: $arg" >&2; exit 2 ;;
27
+ esac
28
+ done
29
+
30
+ # Walk up from CWD to the module root (go.mod).
31
+ ROOT="$(pwd)"
32
+ while [ "$ROOT" != "/" ] && [ ! -f "$ROOT/go.mod" ]; do
33
+ ROOT="$(dirname "$ROOT")"
34
+ done
35
+ if [ ! -f "$ROOT/go.mod" ]; then
36
+ echo "✗ No go.mod found in this directory tree" >&2
37
+ exit 1
38
+ fi
39
+ cd "$ROOT" || exit 1
40
+
41
+ if ! command -v go >/dev/null 2>&1; then
42
+ echo "✗ go toolchain not found on PATH" >&2
43
+ exit 1
44
+ fi
45
+
46
+ echo "═══ Coverage (go test -coverprofile) ═══"
47
+ go test -coverprofile=coverage.out ./... 2>&1 | tail -10
48
+
49
+ if [ ! -f "coverage.out" ]; then
50
+ echo "✗ No coverage profile generated (go test -coverprofile failed)" >&2
51
+ exit 1
52
+ fi
53
+
54
+ FUNC_OUT="$(go tool cover -func=coverage.out 2>/dev/null || true)"
55
+ COVERAGE="$(echo "$FUNC_OUT" | awk '/^total:/{print $NF}' | tr -d '%')"
56
+ echo ""
57
+ echo "Line coverage: ${COVERAGE:-unavailable}% (threshold: ${COVERAGE_THRESHOLD}%)"
58
+
59
+ if [ -z "$COVERAGE" ]; then
60
+ echo "✗ Could not extract total coverage from coverage profile" >&2
61
+ exit 1
62
+ fi
63
+
64
+ if [ "$LCOV" -eq 1 ]; then
65
+ echo "coverage profile artifact kept: coverage.out"
66
+ else
67
+ rm -f coverage.out
68
+ fi
69
+
70
+ if [ "$GATE" -eq 1 ]; then
71
+ if awk "BEGIN { exit !($COVERAGE >= $COVERAGE_THRESHOLD) }"; then
72
+ echo "✓ Coverage gate passed"
73
+ else
74
+ echo "✗ Coverage below threshold (${COVERAGE}% < ${COVERAGE_THRESHOLD}%)" >&2
75
+ exit 1
76
+ fi
77
+ fi
78
+ exit 0
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # install_coverage_tools.sh — Go: no extra install required
4
+ #
5
+ # `go test -coverprofile` is built into the Go toolchain. This script exists
6
+ # so the language dispatcher is uniform; it only verifies the toolchain is
7
+ # present.
8
+ # ============================================================================
9
+ set -euo pipefail
10
+
11
+ if command -v go >/dev/null 2>&1; then
12
+ echo "Go coverage tooling is built-in (go version $(go version | awk '{print $3}'))."
13
+ exit 0
14
+ fi
15
+
16
+ echo "✗ go toolchain not found — install Go (https://go.dev/dl/) to use the coverage gate." >&2
17
+ exit 1