@cortexkit/opencode-magic-context 0.43.1 → 0.43.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.
Files changed (51) hide show
  1. package/dist/{conflict-warning-hook-956fkedc.js → conflict-warning-hook-hyk9y29x.js} +3 -3
  2. package/dist/features/magic-context/dreamer/classify.d.ts +12 -0
  3. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  4. package/dist/features/magic-context/store-generation-rebase.d.ts +62 -1
  5. package/dist/features/magic-context/store-generation-rebase.d.ts.map +1 -1
  6. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  7. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +6 -0
  8. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  9. package/dist/hooks/magic-context/compartment-runner-validation.d.ts +7 -0
  10. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  11. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +60 -8
  12. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  13. package/dist/hooks/magic-context/hook.d.ts +3 -1
  14. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  15. package/dist/hooks/magic-context/system-prompt-hash.d.ts +9 -0
  16. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  17. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  18. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  19. package/dist/{index-kpmmr8s0.js → index-6j8th2hd.js} +1 -1
  20. package/dist/{index-v8qr6tt2.js → index-bmzt6xgy.js} +2 -2
  21. package/dist/{index-7wpwr2e2.js → index-g6hpfkqa.js} +250 -36
  22. package/dist/{index-yc81txp4.js → index-jgnag7sa.js} +1 -1
  23. package/dist/{index-1gtwrdc4.js → index-pa67brzn.js} +2 -2
  24. package/dist/{index-j7cnyvq1.js → index-tdrv6nd0.js} +1 -1
  25. package/dist/index.js +238 -28
  26. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  27. package/dist/{read-session-chunk-z7fv0qjv.js → read-session-chunk-53a7qbrh.js} +2 -2
  28. package/dist/{recomp-orchestrator-r00aa5t3.js → recomp-orchestrator-adsgqgse.js} +4 -4
  29. package/dist/{send-session-notification-3warjyjp.js → send-session-notification-e28r4xx2.js} +2 -2
  30. package/dist/shared/opencode-db-path.d.ts.map +1 -1
  31. package/dist/shared/test-fake-executable.d.ts +38 -0
  32. package/dist/shared/test-fake-executable.d.ts.map +1 -0
  33. package/dist/shared/user-facing-codes.d.ts +10 -0
  34. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  35. package/dist/v2/hooks/context.d.ts.map +1 -1
  36. package/dist/v2/hooks/refusal.d.ts +9 -1
  37. package/dist/v2/hooks/refusal.d.ts.map +1 -1
  38. package/dist/v2/hooks/restore-rows.d.ts +29 -0
  39. package/dist/v2/hooks/restore-rows.d.ts.map +1 -0
  40. package/dist/v2/hooks/update-check.d.ts +8 -0
  41. package/dist/v2/hooks/update-check.d.ts.map +1 -1
  42. package/dist/v2/server.js +470 -61
  43. package/dist/v2/store-reader.d.ts +8 -0
  44. package/dist/v2/store-reader.d.ts.map +1 -1
  45. package/dist/{wrapup-orchestrator-y0bs7t5a.js → wrapup-orchestrator-8xzbpvm8.js} +5 -5
  46. package/package.json +1 -1
  47. package/src/shared/opencode-db-path.test.ts +18 -0
  48. package/src/shared/opencode-db-path.ts +5 -2
  49. package/src/shared/test-fake-executable.test.ts +54 -0
  50. package/src/shared/test-fake-executable.ts +110 -0
  51. package/src/shared/user-facing-codes.ts +11 -0
@@ -51,11 +51,12 @@ import {
51
51
  getCachedAbsoluteMessageCount2,
52
52
  readRawSessionMessageIdOrdinalsForRange2,
53
53
  hasRawSessionMessageById2,
54
+ readRawSessionMessageOrdinalById2,
54
55
  getRawSessionMessageCount2,
55
56
  getRawSessionTagKeysThrough2,
56
57
  getLegacyProtectedTailStartOrdinal2,
57
58
  readSessionChunk2
58
- } from "./index-j7cnyvq1.js";
59
+ } from "./index-tdrv6nd0.js";
59
60
  import {
60
61
  resolveOpenCodeDbPath,
61
62
  hasV1MessageTables,
@@ -70,7 +71,7 @@ import {
70
71
  closeQuietly,
71
72
  withReadOnlySessionDb,
72
73
  getMessageTimesFromOpenCodeDb
73
- } from "./index-v8qr6tt2.js";
74
+ } from "./index-bmzt6xgy.js";
74
75
  import {
75
76
  piModelRefToCanonical,
76
77
  modelRefLookupOrder,
@@ -98,7 +99,7 @@ import {
98
99
  getErrorMessage,
99
100
  describeError,
100
101
  sendStatusNotification2
101
- } from "./index-yc81txp4.js";
102
+ } from "./index-jgnag7sa.js";
102
103
  import {
103
104
  logSlowWriteTransaction
104
105
  } from "./index-9r1cbh9e.js";
@@ -8333,6 +8334,11 @@ var USER_FACING_FAILURES = {
8333
8334
  sentence: "Some finished background sessions could not be removed from this host.",
8334
8335
  action: "They are removed automatically the next time Magic Context runs inside a registered OpenCode service."
8335
8336
  },
8337
+ historian_saved_history_misaligned: {
8338
+ code: "MC-H03",
8339
+ sentence: "History compression is paused because this session's saved summaries no longer line up with its messages.",
8340
+ action: "Run /ctx-recomp to rebuild them."
8341
+ },
8336
8342
  recomp_unavailable: {
8337
8343
  code: "MC-R01",
8338
8344
  sentence: "History compression could not be rebuilt.",
@@ -8503,6 +8509,11 @@ var USER_FACING_FAILURES = {
8503
8509
  sentence: "History compression is paused while the engine syncs.",
8504
8510
  action: "Retry in a moment."
8505
8511
  },
8512
+ history_compression_needs_message: {
8513
+ code: "MC-C12",
8514
+ sentence: "History compression has not seen this session since Magic Context reconnected.",
8515
+ action: "Send a message in this session first, then run /ctx-wrapup again."
8516
+ },
8506
8517
  context_service_unavailable: {
8507
8518
  code: "MC-C10",
8508
8519
  sentence: "Magic Context is temporarily unavailable.",
@@ -17606,6 +17617,7 @@ function emptyOutcome(status, generation, previousGeneration) {
17606
17617
  previousGeneration,
17607
17618
  compartmentsRebased: 0,
17608
17619
  compartmentsUnresolved: 0,
17620
+ compartmentsDerived: 0,
17609
17621
  compartmentsResolvedAgain: 0,
17610
17622
  recompCompartmentsRebased: 0,
17611
17623
  recompCompartmentsUnresolved: 0,
@@ -17659,6 +17671,12 @@ function readCoordinateRebaseNotice(db, sessionId) {
17659
17671
  if (record.generation !== "v1" && record.generation !== "v2")
17660
17672
  return null;
17661
17673
  const count = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
17674
+ const ranges = (value) => Array.isArray(value) ? value.flatMap((entry) => {
17675
+ if (!entry || typeof entry !== "object")
17676
+ return [];
17677
+ const { sequence, start, end } = entry;
17678
+ return typeof sequence === "number" && typeof start === "number" && typeof end === "number" ? [{ sequence, start, end }] : [];
17679
+ }) : [];
17662
17680
  return {
17663
17681
  generation: record.generation,
17664
17682
  previousGeneration: record.previousGeneration === "v1" || record.previousGeneration === "v2" ? record.previousGeneration : null,
@@ -17667,7 +17685,10 @@ function readCoordinateRebaseNotice(db, sessionId) {
17667
17685
  discardedReductions: count(record.discardedReductions),
17668
17686
  droppedDepthRows: count(record.droppedDepthRows),
17669
17687
  healedGaps: count(record.healedGaps),
17670
- narrativeGaps: count(record.narrativeGaps)
17688
+ narrativeGaps: count(record.narrativeGaps),
17689
+ derivedCompartments: ranges(record.derivedCompartments),
17690
+ unresolvedCompartmentRanges: ranges(record.unresolvedCompartmentRanges),
17691
+ neighbourRecoveryAt: typeof record.neighbourRecoveryAt === "number" && Number.isFinite(record.neighbourRecoveryAt) ? record.neighbourRecoveryAt : null
17671
17692
  };
17672
17693
  } catch {
17673
17694
  return null;
@@ -17678,8 +17699,13 @@ function formatCoordinateRebaseNotice(notice) {
17678
17699
  if (notice.discardedReductions > 0) {
17679
17700
  parts.push(`${notice.discardedReductions} queued reduction${notice.discardedReductions === 1 ? " was" : "s were"} discarded because their targets merged in the host's store conversion`);
17680
17701
  }
17702
+ if (notice.derivedCompartments.length > 0) {
17703
+ const count = notice.derivedCompartments.length;
17704
+ parts.push(`${count} compartment${count === 1 ? " was" : "s were"} re-anchored from the compartments around ${count === 1 ? "it" : "them"} (${formatRangeNotes(notice.derivedCompartments)})`);
17705
+ }
17681
17706
  if (notice.unresolvedCompartments > 0) {
17682
- parts.push(`${notice.unresolvedCompartments} compartment${notice.unresolvedCompartments === 1 ? "" : "s"} could not be re-anchored and are excluded from range recovery`);
17707
+ const listed = notice.unresolvedCompartmentRanges.length > 0 ? ` (${formatRangeNotes(notice.unresolvedCompartmentRanges)})` : "";
17708
+ parts.push(`${notice.unresolvedCompartments} compartment${notice.unresolvedCompartments === 1 ? "" : "s"} could not be re-anchored and are excluded from range recovery${listed}`);
17683
17709
  }
17684
17710
  if (notice.droppedDepthRows > 0) {
17685
17711
  parts.push(`${notice.droppedDepthRows} compression-depth records were rebuilt from zero`);
@@ -17692,6 +17718,9 @@ function formatCoordinateRebaseNotice(notice) {
17692
17718
  }
17693
17719
  return parts.length === 0 ? null : parts.join("; ");
17694
17720
  }
17721
+ function formatRangeNotes(notes) {
17722
+ return notes.map((note) => `messages ${note.start}-${note.end}`).join(", ");
17723
+ }
17695
17724
  function isCompartmentCoordinateRow(row) {
17696
17725
  if (row === null || typeof row !== "object")
17697
17726
  return false;
@@ -17723,36 +17752,62 @@ function readCompartmentRows(db, table, sessionId) {
17723
17752
  return db.prepare(`SELECT id, sequence, start_message, end_message, start_message_id, end_message_id, rebase_status
17724
17753
  FROM ${table} WHERE session_id = ? ORDER BY sequence ASC`).all(sessionId).filter(isCompartmentCoordinateRow);
17725
17754
  }
17755
+ function resolveAnchor(messageId, resolveOrdinal) {
17756
+ return messageId && messageId.length > 0 ? resolveOrdinal(messageId) : undefined;
17757
+ }
17726
17758
  function planCompartments(rows, table, projection) {
17727
- return rows.map((row) => {
17728
- const previousStatus = row.rebase_status === "unresolved" ? "unresolved" : "ok";
17729
- const startId = row.start_message_id ?? "";
17730
- const endId = row.end_message_id ?? "";
17731
- const start = startId.length > 0 ? projection.ordinalById.get(startId) : undefined;
17732
- const end = endId.length > 0 ? projection.ordinalById.get(endId) : undefined;
17733
- if (start === undefined || end === undefined) {
17734
- return {
17735
- table,
17736
- id: row.id,
17737
- previousStart: row.start_message,
17738
- previousEnd: row.end_message,
17739
- start: row.start_message,
17740
- end: row.end_message,
17741
- status: "unresolved",
17742
- previousStatus
17743
- };
17744
- }
17745
- return {
17759
+ const resolveOrdinal = (messageId) => projection.ordinalById.get(messageId);
17760
+ return recoverFromNeighbours(rows, table, rows.map((row) => ({
17761
+ start: resolveAnchor(row.start_message_id, resolveOrdinal),
17762
+ end: resolveAnchor(row.end_message_id, resolveOrdinal)
17763
+ })));
17764
+ }
17765
+ function recoverFromNeighbours(rows, table, known) {
17766
+ const plans = rows.map((row, index) => {
17767
+ const own = known[index] ?? { start: undefined, end: undefined };
17768
+ const previousEnd = index === 0 ? 0 : known[index - 1]?.end;
17769
+ const nextStart = index === rows.length - 1 ? undefined : known[index + 1]?.start;
17770
+ const start = own.start ?? (previousEnd === undefined ? undefined : previousEnd + 1);
17771
+ const end = own.end ?? (nextStart === undefined ? undefined : nextStart - 1);
17772
+ const base = {
17746
17773
  table,
17747
17774
  id: row.id,
17775
+ sequence: row.sequence,
17748
17776
  previousStart: row.start_message,
17749
17777
  previousEnd: row.end_message,
17750
- start,
17751
- end,
17752
- status: "ok",
17753
- previousStatus
17778
+ previousStatus: row.rebase_status === "unresolved" ? "unresolved" : "ok"
17779
+ };
17780
+ if (start !== undefined && end !== undefined && start <= end) {
17781
+ return {
17782
+ ...base,
17783
+ start,
17784
+ end,
17785
+ status: "ok",
17786
+ derived: own.start === undefined || own.end === undefined
17787
+ };
17788
+ }
17789
+ return {
17790
+ ...base,
17791
+ start: start ?? row.start_message,
17792
+ end: end ?? row.end_message,
17793
+ status: "unresolved",
17794
+ derived: false
17754
17795
  };
17755
17796
  });
17797
+ for (let index = 0;index < plans.length; index += 1) {
17798
+ const plan = plans[index];
17799
+ if (plan?.status !== "unresolved")
17800
+ continue;
17801
+ const previous = plans[index - 1];
17802
+ const next = plans[index + 1];
17803
+ if (previous?.status === "ok" && plan.start <= previous.end) {
17804
+ plan.start = previous.end + 1;
17805
+ }
17806
+ if (next?.status === "ok" && plan.end >= next.start) {
17807
+ plan.end = next.start - 1;
17808
+ }
17809
+ }
17810
+ return plans;
17756
17811
  }
17757
17812
  function healNonNarrativeCompartmentGaps(plans, projection) {
17758
17813
  let healed = 0;
@@ -17783,7 +17838,10 @@ function healNonNarrativeCompartmentGaps(plans, projection) {
17783
17838
  return { healed, narrative };
17784
17839
  }
17785
17840
  function compartmentPlanChanges(plan) {
17786
- return plan.status !== plan.previousStatus || plan.status === "ok" && (plan.start !== plan.previousStart || plan.end !== plan.previousEnd);
17841
+ return plan.status !== plan.previousStatus || plan.start !== plan.previousStart || plan.end !== plan.previousEnd;
17842
+ }
17843
+ function rangeNotes(plans, predicate) {
17844
+ return plans.filter((plan) => plan.table === "compartments" && predicate(plan)).map((plan) => ({ sequence: plan.sequence, start: plan.start, end: plan.end }));
17787
17845
  }
17788
17846
  function planNotes(db, sessionId, projection) {
17789
17847
  const rows = db.prepare("SELECT id, anchor_ordinal, anchor_block_id FROM notes WHERE session_id = ? AND anchor_ordinal IS NOT NULL").all(sessionId);
@@ -17869,7 +17927,14 @@ function rebaseSessionCoordinates(args) {
17869
17927
  }
17870
17928
  const previousGeneration = readCoordinateGeneration(db, sessionId);
17871
17929
  if (previousGeneration === generation) {
17872
- return emptyOutcome("unchanged", generation, previousGeneration);
17930
+ const outcome = emptyOutcome("unchanged", generation, previousGeneration);
17931
+ const repair = repairStampedSessionOnce(db, sessionId, args.readMessages);
17932
+ if (repair !== null && repair.rowsRewritten > 0) {
17933
+ outcome.status = "repaired";
17934
+ outcome.compartmentsDerived = repair.derived.length;
17935
+ outcome.compartmentsUnresolved = repair.unresolved.length;
17936
+ }
17937
+ return outcome;
17873
17938
  }
17874
17939
  const impliedGeneration = previousGeneration ?? generationImpliedByHarness(db, sessionId) ?? generation;
17875
17940
  if (impliedGeneration === generation) {
@@ -17933,6 +17998,8 @@ function rebaseSessionCoordinates(args) {
17933
17998
  if (plan.table === "compartments") {
17934
17999
  outcome.compartmentsRebased += rebased;
17935
18000
  outcome.compartmentsUnresolved += unresolved;
18001
+ if (rebased === 1 && plan.derived)
18002
+ outcome.compartmentsDerived += 1;
17936
18003
  if (rebased === 1 && plan.previousStatus === "unresolved")
17937
18004
  outcome.compartmentsResolvedAgain += 1;
17938
18005
  } else {
@@ -17989,7 +18056,10 @@ function rebaseSessionCoordinates(args) {
17989
18056
  discardedReductions: outcome.queuedReductionsDiscarded,
17990
18057
  droppedDepthRows: outcome.compressionDepthRowsDropped,
17991
18058
  healedGaps: outcome.healedGaps,
17992
- narrativeGaps: outcome.narrativeGaps
18059
+ narrativeGaps: outcome.narrativeGaps,
18060
+ derivedCompartments: rangeNotes(compartmentPlans, (plan) => plan.status === "ok" && plan.derived),
18061
+ unresolvedCompartmentRanges: rangeNotes(compartmentPlans, (plan) => plan.status === "unresolved"),
18062
+ neighbourRecoveryAt: Date.now()
17993
18063
  });
17994
18064
  db.exec("COMMIT");
17995
18065
  committed = true;
@@ -18007,10 +18077,115 @@ function rebaseSessionCoordinates(args) {
18007
18077
  sessionLog(sessionId, formatRebaseLogLine(outcome, performance.now() - startedAt));
18008
18078
  return outcome;
18009
18079
  }
18080
+ function recoverUnresolvedCompartments(args) {
18081
+ const { db, sessionId } = args;
18082
+ const rows = readCompartmentRows(db, "compartments", sessionId);
18083
+ const result = { rowsRewritten: 0, derived: [], unresolved: [] };
18084
+ if (!rows.some((row) => row.rebase_status === "unresolved"))
18085
+ return result;
18086
+ const known = rows.map((row) => {
18087
+ if (row.rebase_status !== "unresolved") {
18088
+ return { start: row.start_message, end: row.end_message };
18089
+ }
18090
+ return {
18091
+ start: resolveAnchor(row.start_message_id, args.resolveOrdinal),
18092
+ end: resolveAnchor(row.end_message_id, args.resolveOrdinal)
18093
+ };
18094
+ });
18095
+ const plans = recoverFromNeighbours(rows, "compartments", known);
18096
+ const wasUnresolved = (plan) => plan.previousStatus === "unresolved";
18097
+ result.derived = rangeNotes(plans, (plan) => wasUnresolved(plan) && plan.status === "ok" && plan.derived);
18098
+ result.unresolved = rangeNotes(plans, (plan) => plan.status === "unresolved");
18099
+ const changed = plans.filter(compartmentPlanChanges);
18100
+ const now = Date.now();
18101
+ db.exec("BEGIN IMMEDIATE");
18102
+ let committed = false;
18103
+ try {
18104
+ for (const plan of changed) {
18105
+ db.prepare("UPDATE compartments SET start_message = ?, end_message = ?, rebase_status = ? WHERE id = ?").run(plan.start, plan.end, plan.status, plan.id);
18106
+ }
18107
+ const previous = readCoordinateRebaseNotice(db, sessionId);
18108
+ const generation = previous?.generation ?? readCoordinateGeneration(db, sessionId);
18109
+ if (generation !== null) {
18110
+ const derivedSequences = new Set(result.derived.map((note) => note.sequence));
18111
+ const notice = {
18112
+ generation,
18113
+ previousGeneration: previous?.previousGeneration ?? null,
18114
+ at: previous?.at ?? now,
18115
+ unresolvedCompartments: result.unresolved.length,
18116
+ discardedReductions: previous?.discardedReductions ?? 0,
18117
+ droppedDepthRows: previous?.droppedDepthRows ?? 0,
18118
+ healedGaps: previous?.healedGaps ?? 0,
18119
+ narrativeGaps: previous?.narrativeGaps ?? 0,
18120
+ derivedCompartments: [
18121
+ ...(previous?.derivedCompartments ?? []).filter((note) => !derivedSequences.has(note.sequence)),
18122
+ ...result.derived
18123
+ ],
18124
+ unresolvedCompartmentRanges: result.unresolved,
18125
+ neighbourRecoveryAt: now
18126
+ };
18127
+ ensureSessionMetaRow(db, sessionId);
18128
+ db.prepare("UPDATE session_meta SET coordinate_rebase_notice = ? WHERE session_id = ?").run(JSON.stringify(notice), sessionId);
18129
+ }
18130
+ db.exec("COMMIT");
18131
+ committed = true;
18132
+ } finally {
18133
+ if (!committed) {
18134
+ try {
18135
+ db.exec("ROLLBACK");
18136
+ } catch {}
18137
+ }
18138
+ }
18139
+ result.rowsRewritten = changed.length;
18140
+ sessionLog(sessionId, `INFO compartment neighbour recovery (${args.reason}) rows_rewritten=${changed.length} ` + `derived=${result.derived.map((note) => `${note.start}-${note.end}`).join(",") || "none"} ` + `unresolved=${result.unresolved.map((note) => `${note.start}-${note.end}`).join(",") || "none"}`);
18141
+ return result;
18142
+ }
18143
+ var repairCheckedSessions = new WeakMap;
18144
+ function unresolvedRowBreaksTiling(rows) {
18145
+ let expectedStart = 1;
18146
+ for (let index = 0;index < rows.length; index += 1) {
18147
+ const row = rows[index];
18148
+ if (!row)
18149
+ continue;
18150
+ const broken = row.start_message !== expectedStart || row.end_message < row.start_message;
18151
+ const touchesUnresolved = row.rebase_status === "unresolved" || rows[index - 1]?.rebase_status === "unresolved";
18152
+ if (broken && touchesUnresolved)
18153
+ return true;
18154
+ expectedStart = row.end_message + 1;
18155
+ }
18156
+ return false;
18157
+ }
18158
+ function repairStampedSessionOnce(db, sessionId, readMessages) {
18159
+ let checked = repairCheckedSessions.get(db);
18160
+ if (!checked) {
18161
+ checked = new Set;
18162
+ repairCheckedSessions.set(db, checked);
18163
+ }
18164
+ if (checked.has(sessionId))
18165
+ return null;
18166
+ checked.add(sessionId);
18167
+ const rows = readCompartmentRows(db, "compartments", sessionId);
18168
+ if (!rows.some((row) => row.rebase_status === "unresolved"))
18169
+ return null;
18170
+ if (readCoordinateRebaseNotice(db, sessionId)?.neighbourRecoveryAt != null)
18171
+ return null;
18172
+ if (!unresolvedRowBreaksTiling(rows))
18173
+ return null;
18174
+ let ordinalById = null;
18175
+ return recoverUnresolvedCompartments({
18176
+ db,
18177
+ sessionId,
18178
+ resolveOrdinal: (messageId) => {
18179
+ ordinalById ??= buildProjection(readMessages(sessionId)).ordinalById;
18180
+ return ordinalById.get(messageId);
18181
+ },
18182
+ reason: "stamped-session repair"
18183
+ });
18184
+ }
18010
18185
  function formatRebaseLogLine(outcome, elapsedMs) {
18011
18186
  const rowsRewritten = outcome.compartmentsRebased + outcome.recompCompartmentsRebased + outcome.notesRebased + outcome.notesCleared + (outcome.priorBoundaryRebased ? 1 : 0) + (outcome.recompPartialRangeRebased ? 1 : 0);
18012
18187
  const unresolved = outcome.compartmentsUnresolved + outcome.recompCompartmentsUnresolved;
18013
- return `INFO store-generation-rebase ${outcome.previousGeneration ?? "unrecorded"}->${outcome.generation} ` + `rows_rewritten=${rowsRewritten} unresolved=${unresolved} ` + `index_rows_rebuilt=${outcome.indexRowsRebuilt} drops_discarded=${outcome.queuedReductionsDiscarded} ` + `healed_gaps=${outcome.healedGaps} narrative_gaps=${outcome.narrativeGaps} ` + `ms=${Math.round(elapsedMs)} ` + `(chunk_windows_deleted=${outcome.chunkEmbeddingsDeleted} depth_rows_dropped=${outcome.compressionDepthRowsDropped} ` + `part_tags_folded=${outcome.partTagsFolded} lkg_slots_dropped=${outcome.lkgSlotsDropped} ` + `frozen_part_entries_dropped=${outcome.frozenPartEntriesDropped})`;
18188
+ return `INFO store-generation-rebase ${outcome.previousGeneration ?? "unrecorded"}->${outcome.generation} ` + `rows_rewritten=${rowsRewritten} unresolved=${unresolved} derived=${outcome.compartmentsDerived} ` + `index_rows_rebuilt=${outcome.indexRowsRebuilt} drops_discarded=${outcome.queuedReductionsDiscarded} ` + `healed_gaps=${outcome.healedGaps} narrative_gaps=${outcome.narrativeGaps} ` + `ms=${Math.round(elapsedMs)} ` + `(chunk_windows_deleted=${outcome.chunkEmbeddingsDeleted} depth_rows_dropped=${outcome.compressionDepthRowsDropped} ` + `part_tags_folded=${outcome.partTagsFolded} lkg_slots_dropped=${outcome.lkgSlotsDropped} ` + `frozen_part_entries_dropped=${outcome.frozenPartEntriesDropped})`;
18014
18189
  }
18015
18190
  function planPriorBoundary(db, sessionId, plans) {
18016
18191
  const row = db.prepare("SELECT prior_boundary_ordinal FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -25663,7 +25838,7 @@ function finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion)
25663
25838
  { readRawSessionMessagePage, readRawSessionMessages },
25664
25839
  { startMessageTimeBackfill }
25665
25840
  ] = await Promise.all([
25666
- import("./read-session-chunk-z7fv0qjv.js"),
25841
+ import("./read-session-chunk-53a7qbrh.js"),
25667
25842
  import("./message-time-backfill-0ccvyk9n.js")
25668
25843
  ]);
25669
25844
  await startMessageTimeBackfill(db, Object.assign(readRawSessionMessages, {
@@ -31498,6 +31673,14 @@ function buildHistorianFailureNotice(failureCount, _lastError) {
31498
31673
  return [heading, "", renderUserFacingFailure("historian_unavailable")].join(`
31499
31674
  `);
31500
31675
  }
31676
+ function buildStoredCompartmentsInvalidNotice() {
31677
+ return [
31678
+ "## Magic Context — History compression",
31679
+ "",
31680
+ renderUserFacingFailure("historian_saved_history_misaligned")
31681
+ ].join(`
31682
+ `);
31683
+ }
31501
31684
  function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError, language) {
31502
31685
  const prompt = [
31503
31686
  originalPrompt,
@@ -38212,6 +38395,13 @@ function v2NonNarrativeStoredGapRanges(db, sessionId, compartments) {
38212
38395
  return safeRanges;
38213
38396
  }
38214
38397
  var lastHistorianAlertBySession = new Map;
38398
+ var STORED_COMPARTMENT_FAILURE_BACKOFF_MS = 30 * 60 * 1000;
38399
+ function storedCompartmentFailureBackingOff(db, sessionId, validationError, now = Date.now()) {
38400
+ if (getHistorianFailureState(db, sessionId).lastError !== validationError)
38401
+ return false;
38402
+ const failedAt = loadProtectedTailMeta(db, sessionId).historianDrainFailureAt;
38403
+ return failedAt > 0 && failedAt <= now && now - failedAt < STORED_COMPARTMENT_FAILURE_BACKOFF_MS;
38404
+ }
38215
38405
  function shouldSuppressHistorianAlert(sessionId) {
38216
38406
  const lastAlert = lastHistorianAlertBySession.get(sessionId);
38217
38407
  if (lastAlert && Date.now() - lastAlert < HISTORIAN_ALERT_COOLDOWN_MS) {
@@ -38334,13 +38524,37 @@ async function runCompartmentAgent(deps) {
38334
38524
  }
38335
38525
  return;
38336
38526
  }
38337
- const priorCompartments = getCompartments(db, sessionId);
38338
- const existingValidationError = validateStoredCompartments(priorCompartments, v2NonNarrativeStoredGapRanges(db, sessionId, priorCompartments));
38527
+ let priorCompartments = getCompartments(db, sessionId);
38528
+ let existingValidationError = validateStoredCompartments(priorCompartments, v2NonNarrativeStoredGapRanges(db, sessionId, priorCompartments));
38529
+ const unresolvedInvolved = existingValidationError !== null && priorCompartments.some((compartment) => compartment.rebaseStatus === "unresolved");
38530
+ if (unresolvedInvolved && existingValidationError && storedCompartmentFailureBackingOff(db, sessionId, existingValidationError)) {
38531
+ sessionLog(sessionId, `historian no-op: stored compartments still invalid ("${existingValidationError}"); backing off`);
38532
+ telemetry.status = "noop";
38533
+ telemetry.failureReason = `existing-validation backoff: ${existingValidationError}`;
38534
+ return;
38535
+ }
38536
+ if (unresolvedInvolved && existingValidationError) {
38537
+ const recovery = recoverUnresolvedCompartments({
38538
+ db,
38539
+ sessionId,
38540
+ resolveOrdinal: (messageId) => readRawSessionMessageOrdinalById2(sessionId, messageId) ?? undefined,
38541
+ reason: `historian pre-run check failed: ${existingValidationError}`
38542
+ });
38543
+ if (recovery.rowsRewritten > 0) {
38544
+ priorCompartments = getCompartments(db, sessionId);
38545
+ existingValidationError = validateStoredCompartments(priorCompartments, v2NonNarrativeStoredGapRanges(db, sessionId, priorCompartments));
38546
+ }
38547
+ }
38339
38548
  if (existingValidationError) {
38340
38549
  sessionLog(sessionId, `historian failure: source=existing-validation reason="${existingValidationError}"`);
38341
38550
  const failCount = incrementHistorianFailure(db, sessionId, existingValidationError);
38342
38551
  telemetry.failureReason = `existing-validation: ${existingValidationError}`;
38343
- await notifyHistorianIssue(buildHistorianFailureNotice(failCount, existingValidationError));
38552
+ if (unresolvedInvolved) {
38553
+ retainDrainReservationForRetryThrottle = true;
38554
+ await notifyHistorianIssue(buildStoredCompartmentsInvalidNotice());
38555
+ } else {
38556
+ await notifyHistorianIssue(buildHistorianFailureNotice(failCount, existingValidationError));
38557
+ }
38344
38558
  return;
38345
38559
  }
38346
38560
  const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
@@ -6,7 +6,7 @@ import {
6
6
  } from "./index-febg06dy.js";
7
7
  import {
8
8
  shouldHoldIgnoredNotification
9
- } from "./index-v8qr6tt2.js";
9
+ } from "./index-bmzt6xgy.js";
10
10
 
11
11
  // src/shared/error-message.ts
12
12
  function getErrorMessage(error) {
@@ -23,13 +23,13 @@ import {
23
23
  registerActiveCompartmentRun,
24
24
  setRecompStarting2,
25
25
  setRecompTerminal2
26
- } from "./index-7wpwr2e2.js";
26
+ } from "./index-g6hpfkqa.js";
27
27
  import {
28
28
  pushNotification2
29
29
  } from "./index-jdxxq8cz.js";
30
30
  import {
31
31
  sendStatusNotification2
32
- } from "./index-yc81txp4.js";
32
+ } from "./index-jgnag7sa.js";
33
33
 
34
34
  // src/hooks/magic-context/wrapup-orchestrator.ts
35
35
  import * as crypto from "node:crypto";
@@ -6,7 +6,7 @@ import {
6
6
  withReadOnlySessionDb,
7
7
  getRawSessionMessageCountFromDb,
8
8
  getMessageTimesFromOpenCodeDb
9
- } from "./index-v8qr6tt2.js";
9
+ } from "./index-bmzt6xgy.js";
10
10
  import {
11
11
  UNKNOWN_FIT_RATIO,
12
12
  resolveDecisionCalibration,