@davesheffer/hunch 1.20.0-rc.1 → 1.20.0-rc.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.
@@ -121,10 +121,15 @@ export async function syncCommit(store, root, sha, opts = {}) {
121
121
  // grounding. No-ops when no assistant CLI is available; never raises trust (dec_9a2f2fe72a).
122
122
  if (wantVerify)
123
123
  draft = await verifyDecisionSafe(await selectVerifier({ root }), input, draft);
124
+ // The draft's own drafter, not merely the one selected — draftDecisionSafe sets
125
+ // fellBackTo when the selected provider threw and it silently substituted the
126
+ // deterministic heuristic. Every telemetry/return below must report THIS, since
127
+ // backfill's LLM-vs-heuristic tally reads it directly off the return value.
128
+ const actualProvider = draft.fellBackTo ?? provider.name;
124
129
  // Advisory synthesis telemetry for `hunch review` — which provider ran, how many drafts
125
130
  // were reconciled, their agreement, and the verifier's grounding. Rides in `evidence`
126
131
  // (no schema change → respects forward-migration invariant con_947c578b2c).
127
- const synthBits = [`provider=${provider.name}`];
132
+ const synthBits = [`provider=${actualProvider}`];
128
133
  if (draft.samples)
129
134
  synthBits.push(`samples=${draft.samples}`);
130
135
  if (draft.agreement != null)
@@ -215,7 +220,7 @@ export async function syncCommit(store, root, sha, opts = {}) {
215
220
  store.putPrivate("decisions", decision);
216
221
  else
217
222
  store.json.put("decisions", decision);
218
- return { status: "written", decision, provider: provider.name };
223
+ return { status: "written", decision, provider: actualProvider };
219
224
  }
220
225
  function putBugInHome(store, bug, home) {
221
226
  return home === "private" ? store.putPrivate("bugs", bug) : store.json.put("bugs", bug);
@@ -244,6 +249,9 @@ export async function recordFailure(store, root, failure, opts = {}) {
244
249
  suspects: suspects.map((s) => `${s.name} @ ${s.file}`),
245
250
  };
246
251
  const draft = await draftBugSafe(provider, input);
252
+ // The draft's own drafter, not merely the one selected — see the identical
253
+ // comment in syncCommit above.
254
+ const actualProvider = draft.fellBackTo ?? provider.name;
247
255
  // Seed the id from the test id (stable), not the LLM title — one bug per test.
248
256
  const id = bugId(failure.test);
249
257
  // recurrence = a DIFFERENT prior bug with a similar symptom (not this same one).
@@ -284,7 +292,7 @@ export async function recordFailure(store, root, failure, opts = {}) {
284
292
  putBugInHome(store, bug, home);
285
293
  }
286
294
  raiseFragility(store, affectedFiles, home);
287
- return { status: "written", bug, constraint, provider: provider.name, touchedHomes: [home] };
295
+ return { status: "written", bug, constraint, provider: actualProvider, touchedHomes: [home] };
288
296
  }
289
297
  /** Orchestrate one `hunch test` run into graph writes: capture each failing test
290
298
  * as a Bug (recordFailure → suspects / recurrence / Constraint promotion), and
@@ -506,19 +514,26 @@ export async function draftDecisionSafe(provider, input) {
506
514
  try {
507
515
  return await provider.draftDecision(input);
508
516
  }
509
- catch {
517
+ catch (error) {
510
518
  // A provider failure (network, bad creds, CLI crash, unparseable output) must
511
519
  // never abort the learning loop — fall back to the deterministic heuristic
512
520
  // draft, which is honestly labeled ("inferred") rather than a hollow llm_draft.
513
- return new DeterministicProvider().draftDecision(input);
521
+ // fellBackTo/fallbackReason tell the caller what ACTUALLY drafted this, not
522
+ // merely what was selected — see syncCommit, which must report this instead
523
+ // of the originally-selected provider's name.
524
+ const draft = await new DeterministicProvider().draftDecision(input);
525
+ return { ...draft, fellBackTo: "deterministic", fallbackReason: error instanceof Error ? error.message : String(error) };
514
526
  }
515
527
  }
516
528
  export async function draftBugSafe(provider, input) {
517
529
  try {
518
530
  return await provider.draftBug(input);
519
531
  }
520
- catch {
521
- return new DeterministicProvider().draftBug(input);
532
+ catch (error) {
533
+ // See draftDecisionSafe above — the same fallback contract applies to bugs,
534
+ // and recordFailure must report the actual (fallback) provider likewise.
535
+ const draft = await new DeterministicProvider().draftBug(input);
536
+ return { ...draft, fellBackTo: "deterministic", fallbackReason: error instanceof Error ? error.message : String(error) };
522
537
  }
523
538
  }
524
539
  //# sourceMappingURL=synthesize.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "1.20.0-rc.1",
3
+ "version": "1.20.0-rc.2",
4
4
  "mcpName": "io.github.davesheffer/hunch",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Dave Sheffer <dave.sheffer1@gmail.com>",
package/server.json CHANGED
@@ -7,13 +7,13 @@
7
7
  "source": "github"
8
8
  },
9
9
  "websiteUrl": "https://hunch-pi.vercel.app",
10
- "version": "1.20.0-rc.1",
10
+ "version": "1.20.0-rc.2",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "@davesheffer/hunch",
16
- "version": "1.20.0-rc.1",
16
+ "version": "1.20.0-rc.2",
17
17
  "runtimeHint": "npx",
18
18
  "packageArguments": [
19
19
  {