@davesheffer/hunch 0.38.0 → 0.38.2

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/README.md CHANGED
@@ -27,6 +27,10 @@ hunch conform --strict # ✅/⛔ deterministic gate — wire into CI; runs o
27
27
  > dbQuery — VIOLATED · why: the Mar-2025 N+1 meltdown · prevents recurrence of bug_0317."* See
28
28
  > [`demo/architectural-conformance.sh`](demo/architectural-conformance.sh).
29
29
 
30
+ **It works both ways — prevent *and* catch — and you need both:**
31
+ - **Prevent** — in a reproducible benchmark ([`bench/`](bench/architectural-conformance.md): n=90, Haiku/Sonnet/Opus, 3 invariant classes), the recorded invariant in context cut architectural violations **58% → 16%** overall (Sonnet **67% → 0%**). But prevention is *necessary, not sufficient*: **even Opus ignored a layering rule 60% of the time when told.** Each violation passes a linter clean.
32
+ - **Catch** — which is exactly why the deterministic gate exists. `hunch check --strict` (the pre-commit hook + the [`hunch ci`](https://hunch-pi.vercel.app/docs#ci) PR gate) **blocks** what the model ignores — with the receipt, **no model in the gate**. Injection helps; the gate is the guarantee.
33
+
30
34
  <sub>Works with **Claude Code, Cursor, Copilot, Windsurf & Google Antigravity** from one shared, git-native graph.</sub>
31
35
 
32
36
  ### 📚 **[Read the full documentation → hunch-pi.vercel.app/docs](https://hunch-pi.vercel.app/docs)**
package/dist/cli/index.js CHANGED
@@ -170,6 +170,7 @@ program
170
170
  store.close();
171
171
  console.log("\nNext: make a commit (the hook captures a decision), then ask your coding assistant \"why is X built this way?\"");
172
172
  console.log("Cold start? Seed from history: hunch backfill --since 90d");
173
+ console.log("\n⭐ If Hunch earns its keep, a star helps others find it → https://github.com/davesheffer/hunch");
173
174
  });
174
175
  // ---- index ----------------------------------------------------------------
175
176
  program
@@ -1182,7 +1183,43 @@ program
1182
1183
  console.log("");
1183
1184
  }
1184
1185
  console.log(markdown ? renderMarkdown(report) : renderText(report));
1185
- if (reportFailsStrict(report))
1186
+ // ARCHITECTURAL CONFORMANCE: does the RESULTING code still satisfy every recorded
1187
+ // architectural invariant? This is graph-reachability, not a diff — so it catches semantic
1188
+ // violations a pattern-matcher / SAST can't express (a controller that now reaches the DB
1189
+ // directly). It must run over the CHANGED code, so re-parse the working tree first — but
1190
+ // ONLY when conformance predicates exist (zero cost on repos that don't use them). The
1191
+ // gate cases (--staged / --base / --commit HEAD) all have the working tree AT the change.
1192
+ // Surfaced always; gates the commit/PR under --strict, with the receipt of the why.
1193
+ const hasConformance = store.recs("decisions").some((d) => (d.conformance?.length ?? 0) > 0);
1194
+ if (hasConformance) {
1195
+ indexRepo(store, root, { churn: false }); // refresh the symbol/dep graph from the working tree
1196
+ store.reindex();
1197
+ }
1198
+ const confViolations = hasConformance ? checkConformance(store).filter((c) => !c.satisfied) : [];
1199
+ if (confViolations.length) {
1200
+ if (markdown) {
1201
+ console.log(`\n### ⛔ Architectural conformance — ${confViolations.length} invariant(s) violated\n`);
1202
+ for (const c of confViolations) {
1203
+ const dec = store.json.get("decisions", c.decision);
1204
+ const why = dec?.context ? ` · _why: ${dec.context}_` : "";
1205
+ const bug = dec?.caused_by_bug ? ` · prevents recurrence of \`${dec.caused_by_bug}\`` : "";
1206
+ console.log(`- ⛔ **${c.detail}** — \`${c.decision}\` "${c.title}"${why}${bug}`);
1207
+ }
1208
+ }
1209
+ else {
1210
+ console.log(`\n⛔ Architectural conformance — ${confViolations.length} invariant(s) the code no longer satisfies (an AI change drifted from the architecture):`);
1211
+ for (const c of confViolations) {
1212
+ const dec = store.json.get("decisions", c.decision);
1213
+ console.log(` ${c.detail} (${c.decision} "${c.title}")`);
1214
+ if (dec?.context)
1215
+ console.log(` ↳ why: ${dec.context}`);
1216
+ if (dec?.caused_by_bug)
1217
+ console.log(` ↳ prevents recurrence of: ${dec.caused_by_bug}`);
1218
+ }
1219
+ console.log(` The semantic invariant a linter can't see — run \`hunch conform\` for the full picture.`);
1220
+ }
1221
+ }
1222
+ if (reportFailsStrict(report) || (!!opts.strict && confViolations.length > 0))
1186
1223
  process.exitCode = 1;
1187
1224
  store.close();
1188
1225
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "0.38.0",
3
+ "version": "0.38.2",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Dave Sheffer <dave.sheffer1@gmail.com>",
6
6
  "description": "Architectural Conformance for AI-generated code: a git-native graph that deterministically blocks AI changes which break your architecture — the semantic invariants (layering, must-reach, dependency direction) pattern-SAST can't express — grounded in the decisions and bugs behind each rule, across any MCP assistant (Claude Code, Cursor, Copilot, Windsurf, Codex).",