@davesheffer/hunch 0.21.0 → 0.21.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.
@@ -79,7 +79,7 @@ export const RetiredSignalSchema = z.object({
79
79
  * existed in code, so its prose is turned into a testable set/regex. Carries its
80
80
  * OWN provenance, separate from the decision's: an LLM may DRAFT a tripwire
81
81
  * (advisory only); only a `human_confirmed` tripwire may BLOCK a commit — for every
82
- * tier. One predictable rule (dec_a466655539). See docs/veto.md. */
82
+ * tier. One predictable rule (dec_a466655539). */
83
83
  export const RejectedTripwireSchema = z.object({
84
84
  alternative: z.string().describe("the rejected approach's human text — printed verbatim in the receipt"),
85
85
  scope: z.array(z.string()).default([]).describe("glob(s) it applies to, e.g. vscode-extension/**"),
@@ -288,9 +288,13 @@ export function buildServer(root) {
288
288
  else
289
289
  store.json.put("decisions", rec);
290
290
  // Invalidate, don't delete: closing the superseded decision's valid-time window
291
- // (+ a supersedes edge) preserves the why-it-changed trail. Supersede operates on
292
- // the public store, so skip it for a private record (a v1 limitation, not a leak).
293
- const superseded = decision.supersedes && !decision.private ? store.supersede(decision.supersedes, rec) : null;
291
+ // (+ a supersedes edge) preserves the why-it-changed trail. Route the close to the
292
+ // same store the new record landed in a private decision supersedes within the
293
+ // private overlay; a public one in the committed store. A private write never
294
+ // mutates the public store.
295
+ const superseded = decision.supersedes
296
+ ? (decision.private ? store.supersedePrivate(decision.supersedes, rec) : store.supersede(decision.supersedes, rec))
297
+ : null;
294
298
  store.reindex();
295
299
  // Auto-flush the private repo when configured (hunch private --auto-commit), so a
296
300
  // record made via MCP between public commits is committed+pushed immediately.
@@ -615,7 +615,22 @@ export class HunchStore {
615
615
  * and write a `supersedes` edge. Returns the updated old decision, or null if it
616
616
  * doesn't exist. All writes are atomic via json.put (con_902759b3dc). */
617
617
  supersede(oldId, by) {
618
- const old = this.json.get("decisions", oldId);
618
+ return this.supersedeIn(this.json, oldId, by);
619
+ }
620
+ /** Private-overlay counterpart of `supersede`: close + link the old decision inside
621
+ * the HUNCH_PRIVATE_DIR store, so a PRIVATE decision can supersede another private
622
+ * one (the MCP record path is private→private). A private write never mutates the
623
+ * committed public store. Returns null if no private store is configured or the old
624
+ * record isn't in it. */
625
+ supersedePrivate(oldId, by) {
626
+ if (!this.privateJson)
627
+ return null;
628
+ this.privateJson.ensureDirs();
629
+ return this.supersedeIn(this.privateJson, oldId, by);
630
+ }
631
+ /** Shared body for supersede / supersedePrivate against a specific store. */
632
+ supersedeIn(json, oldId, by) {
633
+ const old = json.get("decisions", oldId);
619
634
  if (!old || old.id === by.id)
620
635
  return null;
621
636
  const closed = {
@@ -624,7 +639,7 @@ export class HunchStore {
624
639
  superseded_by: by.id,
625
640
  valid_to: old.valid_to ?? by.valid_from ?? null,
626
641
  };
627
- this.json.put("decisions", closed);
642
+ json.put("decisions", closed);
628
643
  const edge = {
629
644
  id: edgeId(by.id, oldId, "supersedes"),
630
645
  from: by.id,
@@ -634,7 +649,7 @@ export class HunchStore {
634
649
  strength: 1,
635
650
  provenance: { source: "derived", confidence: 1, evidence: [by.id, oldId] },
636
651
  };
637
- this.json.put("edges", edge);
652
+ json.put("edges", edge);
638
653
  return closed;
639
654
  }
640
655
  /** Regression Guard: detect a change RE-INTRODUCING something an in-force
@@ -690,7 +705,7 @@ export class HunchStore {
690
705
  * never did. Precision-first ladder (dep > symbol > pattern); the semantic tier is
691
706
  * advisory and lives elsewhere. A hit `blocks` only when isVetoBlocker passes (a
692
707
  * human-confirmed tripwire on an in-force, non-stale decision — dec_a466655539).
693
- * Read-only; shared by buildCheckReport. See docs/veto.md. */
708
+ * Read-only; shared by buildCheckReport. */
694
709
  vetoHits(an, files, staleDecisions = new Set()) {
695
710
  const addedDeps = new Set(an.addedDeps);
696
711
  const out = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "0.21.0",
3
+ "version": "0.21.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 reasoning graph over a codebase, exposed to Claude Code via MCP.",