@davesheffer/hunch 0.35.0 → 0.35.1

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
@@ -172,6 +172,12 @@ Plus the **Regression Guard** (re-adding deliberately-retired code) and the
172
172
  **[CI Constraint Guard](https://hunch-pi.vercel.app/docs#ci)** (`hunch ci` — a PR gate that
173
173
  comments the affected `con_`/`dec_` ids and fails on a blocking one).
174
174
 
175
+ Give a blocking rule a content matcher — `record-constraint "…" --scope "src/**" --severity
176
+ blocking --match "lodash"` — and it blocks the *actual* violation across the file's whole life
177
+ (matched against added code; comments ignored) instead of relaxing to advisory after the file
178
+ is edited again. It's a deterministic guard for the obvious/accidental violation, not a
179
+ bypass-proof boundary.
180
+
175
181
  ## Working as a team
176
182
 
177
183
  The `.hunch/` JSON is the **source of truth** — diffable, reviewable in PRs, synced for free
package/dist/cli/index.js CHANGED
@@ -955,6 +955,12 @@ program
955
955
  store.reindex();
956
956
  updateClaudeMd(root, store);
957
957
  console.log(`✓ recorded ${c.severity} constraint ${c.id}: "${c.statement}" (scope: ${scope.join(", ") || "repo"})`);
958
+ if (c.severity === "blocking" && !c.match) {
959
+ // The default path's sharp edge: a scope-only blocking rule fails OPEN once any
960
+ // file in scope is committed after today (staleness). Point the user at the fix.
961
+ console.log(` ⚠ scope-only — this will downgrade to advisory once a file in scope is changed after today.`);
962
+ console.log(` To block the actual violation across the file's life, add a content matcher, e.g. --match "lodash"`);
963
+ }
958
964
  store.close();
959
965
  });
960
966
  // ---- test (failure-learning loop) -----------------------------------------
@@ -19,10 +19,20 @@ export function constraintMatcher(pattern) {
19
19
  return null; // malformed pattern → inert, never throws
20
20
  }
21
21
  }
22
- /** True iff any ADDED line trips the constraint's content matcher. */
22
+ /** The enforceable CODE of an added line: a comment carries no invariant, so a rule
23
+ * must not fire on it (a `// we avoid lodash` note is not a violation). We strip
24
+ * comments but NOT string literals — the thing a matcher most often targets, an
25
+ * import specifier (`from "lodash"`), IS a string, so stripping strings would blind
26
+ * the matcher to the real violation. A comment-only line → "". */
27
+ export function matchableCode(line) {
28
+ if (/^\s*(\/\/|\/\*|\*)/.test(line))
29
+ return ""; // // line, /* block, or * JSDoc-continuation
30
+ return line.replace(/\s+\/\/.*$/, ""); // drop a trailing inline // comment (keeps "://" in URLs/strings)
31
+ }
32
+ /** True iff any ADDED line's CODE trips the constraint's content matcher. */
23
33
  export function contentViolates(re, addedLines) {
24
34
  if (!re)
25
35
  return false;
26
- return addedLines.some((l) => re.test(l));
36
+ return addedLines.some((l) => re.test(matchableCode(l)));
27
37
  }
28
38
  //# sourceMappingURL=constraintmatch.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "0.35.0",
3
+ "version": "0.35.1",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Dave Sheffer <dave.sheffer1@gmail.com>",
6
6
  "description": "Hunch — an Engineering Memory OS: a persistent, git-native graph of the decisions, bugs, and rules behind your code, served to any MCP coding assistant (Claude Code, Cursor, Copilot, Windsurf, Codex).",