@cortexkit/opencode-magic-context 0.36.1 → 0.38.0

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 (176) hide show
  1. package/README.md +2 -0
  2. package/dist/config/index.d.ts.map +1 -1
  3. package/dist/config/project-security.d.ts +2 -1
  4. package/dist/config/project-security.d.ts.map +1 -1
  5. package/dist/config/schema/magic-context.d.ts +10 -0
  6. package/dist/config/schema/magic-context.d.ts.map +1 -1
  7. package/dist/{conflict-warning-hook-mt0ttc4x.js → conflict-warning-hook-an4fxhwf.js} +3 -3
  8. package/dist/{derive-budgets-88mxk2w1.js → derive-budgets-da4yg3tz.js} +3 -2
  9. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/classify-prompt.d.ts +5 -1
  11. package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  13. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/manifest-parser.d.ts +8 -0
  15. package/dist/features/magic-context/dreamer/manifest-parser.d.ts.map +1 -1
  16. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +7 -1
  17. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/map-memories.d.ts +18 -0
  19. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +5 -0
  21. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  23. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +5 -1
  24. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  26. package/dist/features/magic-context/fail-closed-block.d.ts +6 -1
  27. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  28. package/dist/features/magic-context/memory/embedding-openai.d.ts +3 -1
  29. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  30. package/dist/features/magic-context/memory/project-identity.d.ts +6 -0
  31. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  32. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  33. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  34. package/dist/features/magic-context/reclaim-protection.d.ts +13 -0
  35. package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -0
  36. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  37. package/dist/features/magic-context/smart-notes/wake-plane.d.ts +21 -0
  38. package/dist/features/magic-context/smart-notes/wake-plane.d.ts.map +1 -0
  39. package/dist/features/magic-context/storage-db.d.ts +19 -3
  40. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  41. package/dist/features/magic-context/storage-meta-persisted.d.ts +23 -0
  42. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  43. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  44. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  45. package/dist/features/magic-context/storage-primers.d.ts +11 -0
  46. package/dist/features/magic-context/storage-primers.d.ts.map +1 -1
  47. package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
  48. package/dist/features/magic-context/storage-tags.d.ts +13 -5
  49. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  50. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +7 -0
  51. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  52. package/dist/features/magic-context/window-report-ledger.d.ts +70 -0
  53. package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -0
  54. package/dist/hooks/auto-update-checker/checker.d.ts +8 -1
  55. package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
  56. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/channel2-cycle.d.ts +16 -0
  58. package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -0
  59. package/dist/hooks/magic-context/channel2-delivery.d.ts +3 -9
  60. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/command-handler.d.ts +2 -0
  62. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +33 -103
  64. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  67. package/dist/hooks/magic-context/event-resolvers.d.ts +4 -0
  68. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/execute-status.d.ts +3 -1
  70. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/fold-execution-gate.d.ts +2 -0
  72. package/dist/hooks/magic-context/fold-execution-gate.d.ts.map +1 -0
  73. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  76. package/dist/hooks/magic-context/live-session-state.d.ts +3 -0
  77. package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  79. package/dist/hooks/magic-context/lkg-slot.d.ts +20 -0
  80. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  81. package/dist/hooks/magic-context/module-state-sync.d.ts +8 -0
  82. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  83. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/module-wire.d.ts +6 -1
  85. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/rust-mode-transform.d.ts +21 -2
  87. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  88. package/dist/hooks/magic-context/strip-content.d.ts +27 -0
  89. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  92. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +78 -0
  93. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -0
  94. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +14 -3
  96. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  97. package/dist/hooks/magic-context/transform.d.ts +10 -0
  98. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  100. package/dist/{index-nsx2n9eg.js → index-4cz5nfxf.js} +3 -3
  101. package/dist/{index-f1tnb3vm.js → index-8pqfcghm.js} +21 -9
  102. package/dist/index-9zhhvr4w.js +733 -0
  103. package/dist/{index-zp6x6s6a.js → index-cae89eas.js} +25 -6
  104. package/dist/index-cgyfn1s2.js +53 -0
  105. package/dist/{index-3zqcdwqr.js → index-crke4z5j.js} +7 -4
  106. package/dist/{index-1skzp4dc.js → index-mmvhrqqb.js} +1991 -274
  107. package/dist/{index-tsgs7td8.js → index-pck9vadr.js} +1 -1
  108. package/dist/{index-3tnkymva.js → index-sw8gnq34.js} +1 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +1714 -988
  111. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -0
  112. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  113. package/dist/plugin/messages-transform.d.ts.map +1 -1
  114. package/dist/plugin/rpc-handlers.d.ts +2 -0
  115. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  116. package/dist/{recomp-orchestrator-a0g9b52q.js → recomp-orchestrator-jsde4ygw.js} +7 -6
  117. package/dist/{safe-notification-target-c11fdda2.js → safe-notification-target-b693f9x3.js} +2 -2
  118. package/dist/{send-session-notification-bgtf4853.js → send-session-notification-dxske5zm.js} +3 -3
  119. package/dist/shared/conflict-detector.d.ts +63 -0
  120. package/dist/shared/conflict-detector.d.ts.map +1 -1
  121. package/dist/shared/harness-provider-map.d.ts +8 -0
  122. package/dist/shared/harness-provider-map.d.ts.map +1 -1
  123. package/dist/shared/logger.d.ts +8 -0
  124. package/dist/shared/logger.d.ts.map +1 -1
  125. package/dist/shared/models-dev-cache.d.ts +7 -0
  126. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  127. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  128. package/dist/shared/prompt-surface.d.ts +2 -0
  129. package/dist/shared/prompt-surface.d.ts.map +1 -1
  130. package/dist/shared/rpc-client.d.ts.map +1 -1
  131. package/dist/shared/rpc-server.d.ts.map +1 -1
  132. package/dist/shared/rpc-types.d.ts +29 -0
  133. package/dist/shared/rpc-types.d.ts.map +1 -1
  134. package/dist/shared/rpc-utils.d.ts +28 -9
  135. package/dist/shared/rpc-utils.d.ts.map +1 -1
  136. package/dist/shared/tail-hygiene-status.d.ts +15 -0
  137. package/dist/shared/tail-hygiene-status.d.ts.map +1 -0
  138. package/dist/shared/window-geometry.d.ts +90 -0
  139. package/dist/shared/window-geometry.d.ts.map +1 -0
  140. package/dist/{storage-meta-session-df9tstzr.js → storage-meta-session-mk4gsnke.js} +4 -3
  141. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  142. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  143. package/dist/tui/data/context-db.d.ts.map +1 -1
  144. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  145. package/package.json +3 -1
  146. package/src/config/index.ts +2 -0
  147. package/src/config/latch-permanence-guard.test.ts +218 -0
  148. package/src/config/project-security.ts +10 -1
  149. package/src/config/schema/magic-context.ts +12 -2
  150. package/src/shared/__fixtures__/window-overlay.v1.json +337 -0
  151. package/src/shared/conflict-detector.test.ts +176 -1
  152. package/src/shared/conflict-detector.ts +126 -3
  153. package/src/shared/harness-provider-map.test.ts +20 -0
  154. package/src/shared/harness-provider-map.ts +19 -0
  155. package/src/shared/logger.test.ts +119 -0
  156. package/src/shared/logger.ts +33 -15
  157. package/src/shared/models-dev-cache.test.ts +42 -0
  158. package/src/shared/models-dev-cache.ts +62 -9
  159. package/src/shared/prompt-surface-runtime.ts +5 -3
  160. package/src/shared/prompt-surface.test.ts +38 -0
  161. package/src/shared/prompt-surface.ts +15 -2
  162. package/src/shared/rpc-client.ts +4 -2
  163. package/src/shared/rpc-server.ts +1 -0
  164. package/src/shared/rpc-types.ts +30 -0
  165. package/src/shared/rpc-utils.test.ts +162 -13
  166. package/src/shared/rpc-utils.ts +224 -31
  167. package/src/shared/tail-hygiene-status.ts +57 -0
  168. package/src/shared/window-geometry.test.ts +342 -0
  169. package/src/shared/window-geometry.ts +626 -0
  170. package/src/tui/data/context-db.ts +5 -0
  171. package/src/tui/index.tsx +33 -1
  172. package/src/tui/slots/sidebar-content.tsx +17 -5
  173. package/src/tui-compiled/data/context-db.ts +5 -0
  174. package/src/tui-compiled/index.tsx +359 -273
  175. package/src/tui-compiled/slots/sidebar-content.tsx +316 -287
  176. package/dist/index-wgvxkqpx.js +0 -342
@@ -0,0 +1,626 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getDataDir } from "./data-path";
4
+ import { modelRefLookupOrder } from "./harness-provider-map";
5
+ import { sessionLog } from "./logger";
6
+ import type { ModelLimit } from "./models-dev-cache";
7
+
8
+ export const WINDOW_OVERLAY_SCHEMA = "fusiform-window-overlay/v1";
9
+ export const PROMPT_WALL_MARGIN = 4_096;
10
+ export const PI_OUTPUT_FLOOR = 4_096;
11
+ export const OPENCODE_OUTPUT_CAP = 32_000;
12
+
13
+ const MIN_PLAUSIBLE_CONTEXT_LIMIT = 1_024;
14
+ const OUTPUT_RESERVE_CAP_RATIO = 0.25;
15
+
16
+ export type WindowGeometry = "shared_upfront" | "shared_truncating" | "separate";
17
+ export type WindowReserveSource = "output_catalog" | "output_config" | "wall_margin" | "none";
18
+ export type WindowOverlayGrade =
19
+ | "provider_asserted_runtime"
20
+ | "measured"
21
+ | "provider_asserted_doc"
22
+ | "catalog"
23
+ | "unknown";
24
+ export type WindowOverlayUnits = "provider" | "estimate";
25
+ export type WindowOverlayBoundary = "Observed" | "Asserted" | "Corrected";
26
+ export type WindowOverlayUnknownWhy =
27
+ | "placeholder_output_equals_context"
28
+ | "placeholder_zero"
29
+ | "never_measured"
30
+ // Asserts the KEY cannot hold one fact (e.g. a router samples heterogeneous
31
+ // backends per request), so measurement cannot settle it and measured
32
+ // reports must not be promoted into stated/bracket cells at this key.
33
+ // Ratified terminal at fusiform 080e70208aad713d (2026-08-13), added without a schema bump: an
34
+ // additive vocabulary value degrades per-cell for ignorant consumers,
35
+ // whereas a version bump would trigger the file-level refusal rule.
36
+ | "not_single_valued_at_key"
37
+ | "retracted";
38
+
39
+ export type WindowOverlayFactValue =
40
+ | { kind: "stated"; value: number | string }
41
+ | { kind: "bracket"; at_least?: number; below?: number }
42
+ | { kind: "unknown"; why: WindowOverlayUnknownWhy };
43
+
44
+ export interface WindowOverlayFact {
45
+ value: WindowOverlayFactValue;
46
+ grade: WindowOverlayGrade;
47
+ units: WindowOverlayUnits;
48
+ boundary: WindowOverlayBoundary;
49
+ source_ref: string;
50
+ observed_at: string;
51
+ [unknownField: string]: unknown;
52
+ }
53
+
54
+ export interface WindowOverlayCell {
55
+ provider_id: string;
56
+ model_id: string;
57
+ /** Unknown fact keys are retained so a newer producer can coexist with this v1 consumer. */
58
+ facts: Record<string, WindowOverlayFact>;
59
+ }
60
+
61
+ export interface WindowOverlay {
62
+ schema: typeof WINDOW_OVERLAY_SCHEMA;
63
+ generated_at: string;
64
+ minted_provider_ids: string[];
65
+ cells: WindowOverlayCell[];
66
+ }
67
+
68
+ export interface ResolvedWindowOverlayFacts {
69
+ /** Includes facts whose tagged value is explicitly unknown. */
70
+ facts: Record<string, WindowOverlayFact>;
71
+ }
72
+
73
+ export interface WindowDerivation {
74
+ window: number;
75
+ reserve: number;
76
+ reserveSource: WindowReserveSource;
77
+ geometry: WindowGeometry;
78
+ }
79
+
80
+ export interface WindowGeometryResult {
81
+ usableSoft: number;
82
+ usableHard: number;
83
+ geometry: WindowGeometry;
84
+ derivation: WindowDerivation;
85
+ }
86
+
87
+ export interface DeriveWindowGeometryOptions {
88
+ overlay?: ResolvedWindowOverlayFacts;
89
+ /** A provider/auth hook has higher precedence than the overlay, field by field. */
90
+ providerLimit?: ModelLimit;
91
+ /** Resolved user override; higher precedence than catalog, overlay, and geometry defaults. */
92
+ outputReserveOverride?: number;
93
+ harness?: "opencode" | "pi";
94
+ /** Detected overflow remains the final downward cap regardless of other sources. */
95
+ contextCap?: number;
96
+ log?: (message: string) => void;
97
+ }
98
+
99
+ const PROVIDER_GEOMETRY: Readonly<Record<string, WindowGeometry>> = {
100
+ anthropic: "shared_truncating",
101
+ xai: "shared_truncating",
102
+ google: "separate",
103
+ "google-antigravity": "separate",
104
+ };
105
+
106
+ const GRADES = new Set<WindowOverlayGrade>([
107
+ "provider_asserted_runtime",
108
+ "measured",
109
+ "provider_asserted_doc",
110
+ "catalog",
111
+ "unknown",
112
+ ]);
113
+ const UNITS = new Set<WindowOverlayUnits>(["provider", "estimate"]);
114
+ const BOUNDARIES = new Set<WindowOverlayBoundary>(["Observed", "Asserted", "Corrected"]);
115
+ const UNKNOWN_REASONS = new Set<WindowOverlayUnknownWhy>([
116
+ "placeholder_output_equals_context",
117
+ "placeholder_zero",
118
+ "never_measured",
119
+ "not_single_valued_at_key",
120
+ "retracted",
121
+ ]);
122
+ const NUMERIC_FACT_KEYS = new Set([
123
+ "window.advertised",
124
+ "window.enforced",
125
+ "output.advertised",
126
+ "output.enforced",
127
+ "output.default",
128
+ ]);
129
+
130
+ let configuredOverlayPath: string | undefined;
131
+ let loadedOverlayPath: string | undefined;
132
+ let loadedOverlay: WindowOverlay | null | undefined;
133
+ const geometryClampLogSeen = new Set<string>();
134
+
135
+ function isRecord(value: unknown): value is Record<string, unknown> {
136
+ return typeof value === "object" && value !== null && !Array.isArray(value);
137
+ }
138
+
139
+ function isFinitePositive(value: unknown): value is number {
140
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
141
+ }
142
+
143
+ /** Convert the ratified tagged numeric union into the conservative scalar used by derivation. */
144
+ export function scalarizeFact(value: WindowOverlayFactValue): number | undefined {
145
+ if (value.kind === "stated") return isFinitePositive(value.value) ? value.value : undefined;
146
+ if (value.kind === "bracket") {
147
+ return isFinitePositive(value.at_least) ? value.at_least : undefined;
148
+ }
149
+ return undefined;
150
+ }
151
+
152
+ function parseFactValue(value: unknown): WindowOverlayFactValue | undefined {
153
+ if (!isRecord(value) || typeof value.kind !== "string") return undefined;
154
+ if (value.kind === "stated") {
155
+ if (
156
+ (typeof value.value !== "number" || !Number.isFinite(value.value)) &&
157
+ typeof value.value !== "string"
158
+ ) {
159
+ return undefined;
160
+ }
161
+ return { kind: "stated", value: value.value };
162
+ }
163
+ if (value.kind === "bracket") {
164
+ const atLeast = value.at_least;
165
+ const below = value.below;
166
+ if (atLeast === undefined && below === undefined) return { kind: "bracket" };
167
+ if (atLeast !== undefined && !isFinitePositive(atLeast)) return undefined;
168
+ if (below !== undefined && !isFinitePositive(below)) return undefined;
169
+ if (isFinitePositive(atLeast) && isFinitePositive(below) && below <= atLeast) {
170
+ return undefined;
171
+ }
172
+ return {
173
+ kind: "bracket",
174
+ ...(isFinitePositive(atLeast) ? { at_least: atLeast } : {}),
175
+ ...(isFinitePositive(below) ? { below } : {}),
176
+ };
177
+ }
178
+ if (value.kind === "unknown" && UNKNOWN_REASONS.has(value.why as WindowOverlayUnknownWhy)) {
179
+ return { kind: "unknown", why: value.why as WindowOverlayUnknownWhy };
180
+ }
181
+ return undefined;
182
+ }
183
+
184
+ function parseFact(key: string, value: unknown): WindowOverlayFact | undefined {
185
+ if (!isRecord(value)) return undefined;
186
+ const parsedValue = parseFactValue(value.value);
187
+ if (
188
+ !parsedValue ||
189
+ !GRADES.has(value.grade as WindowOverlayGrade) ||
190
+ !UNITS.has(value.units as WindowOverlayUnits) ||
191
+ !BOUNDARIES.has(value.boundary as WindowOverlayBoundary) ||
192
+ typeof value.source_ref !== "string" ||
193
+ value.source_ref.length === 0 ||
194
+ typeof value.observed_at !== "string" ||
195
+ value.observed_at.length === 0
196
+ ) {
197
+ return undefined;
198
+ }
199
+ if (
200
+ NUMERIC_FACT_KEYS.has(key) &&
201
+ parsedValue.kind === "stated" &&
202
+ !isFinitePositive(parsedValue.value)
203
+ ) {
204
+ return undefined;
205
+ }
206
+ if (
207
+ key === "geometry" &&
208
+ parsedValue.kind === "stated" &&
209
+ !["shared_upfront", "shared_truncating", "separate"].includes(String(parsedValue.value))
210
+ ) {
211
+ return undefined;
212
+ }
213
+ return {
214
+ ...value,
215
+ value: parsedValue,
216
+ grade: value.grade as WindowOverlayGrade,
217
+ units: value.units as WindowOverlayUnits,
218
+ boundary: value.boundary as WindowOverlayBoundary,
219
+ source_ref: value.source_ref,
220
+ observed_at: value.observed_at,
221
+ } as WindowOverlayFact;
222
+ }
223
+
224
+ export function parseWindowOverlay(value: unknown): {
225
+ overlay?: WindowOverlay;
226
+ badCells: number;
227
+ refusal?: string;
228
+ } {
229
+ if (!isRecord(value)) {
230
+ return { badCells: 0, refusal: "overlay root is not an object" };
231
+ }
232
+ if (value.schema !== WINDOW_OVERLAY_SCHEMA) {
233
+ return {
234
+ badCells: 0,
235
+ refusal: `unrecognized schema ${JSON.stringify(value.schema)}`,
236
+ };
237
+ }
238
+ if (
239
+ typeof value.generated_at !== "string" ||
240
+ !Array.isArray(value.minted_provider_ids) ||
241
+ !value.minted_provider_ids.every((id) => typeof id === "string" && id.length > 0) ||
242
+ !Array.isArray(value.cells)
243
+ ) {
244
+ return { badCells: 0, refusal: "invalid v1 envelope" };
245
+ }
246
+
247
+ const cells: WindowOverlayCell[] = [];
248
+ let badCells = 0;
249
+ for (const rawCell of value.cells) {
250
+ if (
251
+ !isRecord(rawCell) ||
252
+ typeof rawCell.provider_id !== "string" ||
253
+ rawCell.provider_id.length === 0 ||
254
+ typeof rawCell.model_id !== "string" ||
255
+ rawCell.model_id.length === 0 ||
256
+ !isRecord(rawCell.facts)
257
+ ) {
258
+ badCells++;
259
+ continue;
260
+ }
261
+ const facts: Record<string, WindowOverlayFact> = {};
262
+ let valid = true;
263
+ for (const [key, rawFact] of Object.entries(rawCell.facts)) {
264
+ const fact = parseFact(key, rawFact);
265
+ if (!fact) {
266
+ valid = false;
267
+ break;
268
+ }
269
+ facts[key] = fact;
270
+ }
271
+ if (!valid) {
272
+ badCells++;
273
+ continue;
274
+ }
275
+ cells.push({
276
+ provider_id: rawCell.provider_id,
277
+ model_id: rawCell.model_id,
278
+ facts,
279
+ });
280
+ }
281
+
282
+ return {
283
+ overlay: {
284
+ schema: WINDOW_OVERLAY_SCHEMA,
285
+ generated_at: value.generated_at,
286
+ minted_provider_ids: [...value.minted_provider_ids],
287
+ cells,
288
+ },
289
+ badCells,
290
+ };
291
+ }
292
+
293
+ export function defaultWindowOverlayPath(): string {
294
+ return join(getDataDir(), "fusiform", "window-overlay.json");
295
+ }
296
+
297
+ export function readWindowOverlayFile(
298
+ path: string,
299
+ log: (message: string) => void = (message) => sessionLog("global", message),
300
+ ): WindowOverlay | undefined {
301
+ let raw: string;
302
+ try {
303
+ raw = readFileSync(path, "utf8");
304
+ } catch (error) {
305
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
306
+ log(`window-overlay: unable to read ${path}; overlay ignored`);
307
+ return undefined;
308
+ }
309
+ let decoded: unknown;
310
+ try {
311
+ decoded = JSON.parse(raw);
312
+ } catch {
313
+ log(`window-overlay: invalid JSON in ${path}; overlay ignored`);
314
+ return undefined;
315
+ }
316
+ const parsed = parseWindowOverlay(decoded);
317
+ if (parsed.refusal) {
318
+ log(`window-overlay: ${parsed.refusal} in ${path}; entire overlay ignored`);
319
+ return undefined;
320
+ }
321
+ if (parsed.badCells > 0) {
322
+ log(`window-overlay: skipped ${parsed.badCells} invalid cell(s) from ${path}`);
323
+ }
324
+ return parsed.overlay;
325
+ }
326
+
327
+ /** Set the user-tier overlay path. Undefined restores the Fusiform data-dir default. */
328
+ export function setWindowOverlayPath(path: string | undefined): void {
329
+ configuredOverlayPath = path;
330
+ loadedOverlayPath = undefined;
331
+ loadedOverlay = undefined;
332
+ }
333
+
334
+ export function clearWindowOverlayCacheForTest(): void {
335
+ loadedOverlayPath = undefined;
336
+ loadedOverlay = undefined;
337
+ geometryClampLogSeen.clear();
338
+ }
339
+
340
+ export function getWindowOverlay(): WindowOverlay | undefined {
341
+ const path = configuredOverlayPath ?? defaultWindowOverlayPath();
342
+ if (loadedOverlayPath === path && loadedOverlay !== undefined) {
343
+ return loadedOverlay ?? undefined;
344
+ }
345
+ loadedOverlayPath = path;
346
+ loadedOverlay = readWindowOverlayFile(path) ?? null;
347
+ return loadedOverlay ?? undefined;
348
+ }
349
+
350
+ export function resolveWindowOverlayFacts(
351
+ providerID: string,
352
+ modelID: string,
353
+ overlay: WindowOverlay | undefined = getWindowOverlay(),
354
+ ): ResolvedWindowOverlayFacts | undefined {
355
+ if (!overlay) return undefined;
356
+ const modelRefs = modelRefLookupOrder(`${providerID}/${modelID}`);
357
+ const providerCandidates = new Set(modelRefs.map((ref) => ref.slice(0, ref.indexOf("/"))));
358
+ const modelCandidates = new Set([
359
+ modelID,
360
+ ...modelRefs.map((ref) => ref.slice(ref.indexOf("/") + 1)),
361
+ ]);
362
+ const colon = modelID.lastIndexOf(":");
363
+ if (colon > 0) modelCandidates.add(modelID.slice(0, colon));
364
+
365
+ const wildcardFacts: Record<string, WindowOverlayFact> = {};
366
+ const specificFacts: Record<string, WindowOverlayFact> = {};
367
+ for (const cell of overlay.cells) {
368
+ if (!providerCandidates.has(cell.provider_id)) continue;
369
+ if (cell.model_id === "*") Object.assign(wildcardFacts, cell.facts);
370
+ else if (modelCandidates.has(cell.model_id)) Object.assign(specificFacts, cell.facts);
371
+ }
372
+ const facts = { ...wildcardFacts, ...specificFacts };
373
+ return Object.keys(facts).length > 0 ? { facts } : undefined;
374
+ }
375
+
376
+ function numericOverlayFact(
377
+ overlay: ResolvedWindowOverlayFacts | undefined,
378
+ key: string,
379
+ ): number | undefined {
380
+ const fact = overlay?.facts[key];
381
+ return fact ? scalarizeFact(fact.value) : undefined;
382
+ }
383
+
384
+ /**
385
+ * Three-state geometry resolution from the overlay. The absent-vs-unknown
386
+ * distinction is ratified contract semantics: a fact ABSENT from the cell was
387
+ * never considered (our static provider table still applies), while a fact
388
+ * present with kind "unknown" was considered and has no answer — the dataset
389
+ * owner checked the primary source and found the usual inference unsupported
390
+ * (e.g. Google's own docs contradict the separate-quota reading), so the
391
+ * static assumption built on that same inference must NOT apply either.
392
+ */
393
+ function overlayGeometry(
394
+ overlay: ResolvedWindowOverlayFacts | undefined,
395
+ ): { kind: "stated"; value: WindowGeometry } | { kind: "unknown" } | undefined {
396
+ const fact = overlay?.facts.geometry;
397
+ if (fact === undefined) return undefined;
398
+ if (fact.value.kind === "unknown") return { kind: "unknown" };
399
+ if (fact.value.kind !== "stated") return undefined;
400
+ const value = fact.value.value;
401
+ return value === "shared_upfront" || value === "shared_truncating" || value === "separate"
402
+ ? { kind: "stated", value }
403
+ : undefined;
404
+ }
405
+
406
+ /** Placeholder filtering is deliberately per output field, never a row-level rejection. */
407
+ export function placeholderFilteredOutput(
408
+ output: number | undefined,
409
+ context: number | undefined,
410
+ ): number | undefined {
411
+ if (!isFinitePositive(output)) return undefined;
412
+ if (isFinitePositive(context) && output >= context) return undefined;
413
+ return output;
414
+ }
415
+
416
+ function mergePositive(
417
+ overlayValue: number | undefined,
418
+ providerValue: number | undefined,
419
+ ): number | undefined {
420
+ return isFinitePositive(providerValue) ? providerValue : overlayValue;
421
+ }
422
+
423
+ function logGeometryClampOnce(key: string, message: string, log?: (message: string) => void): void {
424
+ if (geometryClampLogSeen.has(key)) return;
425
+ geometryClampLogSeen.add(key);
426
+ (log ?? ((entry) => sessionLog("global", `window-geometry: ${entry}`)))(message);
427
+ }
428
+
429
+ export function deriveWindowGeometry(
430
+ providerID: string,
431
+ modelID: string,
432
+ catalogLimit: ModelLimit | undefined,
433
+ options: DeriveWindowGeometryOptions = {},
434
+ ): WindowGeometryResult | undefined {
435
+ if (!catalogLimit && !options.providerLimit) return undefined;
436
+ const providerLimit = options.providerLimit;
437
+ const catalogContext = isFinitePositive(catalogLimit?.context)
438
+ ? catalogLimit.context
439
+ : undefined;
440
+ const advertised = numericOverlayFact(options.overlay, "window.advertised");
441
+ const enforced = numericOverlayFact(options.overlay, "window.enforced");
442
+ let softContext = mergePositive(
443
+ enforced ?? advertised ?? catalogContext,
444
+ providerLimit?.context,
445
+ );
446
+ let hardContext = mergePositive(enforced ?? softContext, providerLimit?.context);
447
+ if (isFinitePositive(options.contextCap)) {
448
+ softContext = isFinitePositive(softContext)
449
+ ? Math.min(softContext, options.contextCap)
450
+ : options.contextCap;
451
+ hardContext = isFinitePositive(hardContext)
452
+ ? Math.min(hardContext, options.contextCap)
453
+ : options.contextCap;
454
+ }
455
+ const input = mergePositive(
456
+ isFinitePositive(catalogLimit?.input) ? catalogLimit.input : undefined,
457
+ providerLimit?.input,
458
+ );
459
+ if (!isFinitePositive(softContext) && !isFinitePositive(input)) return undefined;
460
+
461
+ const catalogOutput =
462
+ options.overlay === undefined && options.providerLimit === undefined
463
+ ? isFinitePositive(catalogLimit?.output)
464
+ ? catalogLimit.output
465
+ : undefined
466
+ : placeholderFilteredOutput(catalogLimit?.output, softContext);
467
+ const overlayOutput = placeholderFilteredOutput(
468
+ numericOverlayFact(options.overlay, "output.enforced") ??
469
+ numericOverlayFact(options.overlay, "output.default") ??
470
+ numericOverlayFact(options.overlay, "output.advertised"),
471
+ softContext,
472
+ );
473
+ const providerOutput = placeholderFilteredOutput(providerLimit?.output, softContext);
474
+ const output = providerOutput ?? overlayOutput ?? catalogOutput;
475
+ const geometryFact = overlayGeometry(options.overlay);
476
+ // Considered-unknown demotes to shared_upfront — the conservative geometry
477
+ // in both directions (largest soft reserve, lowest hard wall) — until a
478
+ // measurement settles the cell. Absence falls through to the static table.
479
+ const geometry =
480
+ geometryFact?.kind === "stated"
481
+ ? geometryFact.value
482
+ : geometryFact?.kind === "unknown"
483
+ ? "shared_upfront"
484
+ : (PROVIDER_GEOMETRY[providerID] ?? "shared_upfront");
485
+ const geometryOverride = geometryFact?.kind === "stated" ? geometryFact.value : undefined;
486
+
487
+ const preCarvedInput =
488
+ isFinitePositive(input) && (!isFinitePositive(softContext) || input < softContext);
489
+ const outputReserveOverride =
490
+ typeof options.outputReserveOverride === "number" &&
491
+ Number.isFinite(options.outputReserveOverride) &&
492
+ options.outputReserveOverride >= 0
493
+ ? options.outputReserveOverride
494
+ : undefined;
495
+ let derivationWindow = softContext ?? input;
496
+ let usableSoft: number;
497
+ let softReserve = 0;
498
+ let reserveSource: WindowReserveSource = "none";
499
+ if (outputReserveOverride !== undefined) {
500
+ // An explicit user reserve owns the usable-window carve. When the
501
+ // provider also publishes a smaller input cap, use that cap as the
502
+ // window; treating the cap as final would silently ignore the config.
503
+ const reserveWindow = preCarvedInput ? input : (softContext ?? input);
504
+ if (!isFinitePositive(reserveWindow)) return undefined;
505
+ derivationWindow = reserveWindow;
506
+ softReserve = outputReserveOverride;
507
+ reserveSource = "output_config";
508
+ const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, reserveWindow * 0.5);
509
+ const flooredReserve = Math.min(softReserve, Math.max(0, reserveWindow - floor));
510
+ if (flooredReserve < softReserve) {
511
+ logGeometryClampOnce(
512
+ `soft-floor|${providerID}/${modelID}|${softReserve}|${flooredReserve}`,
513
+ `output reserve clamped by the half-window floor for ${providerID}/${modelID}: reserve ${softReserve} → ${flooredReserve}`,
514
+ options.log,
515
+ );
516
+ }
517
+ softReserve = flooredReserve;
518
+ usableSoft = Math.floor(reserveWindow - softReserve);
519
+ } else if (preCarvedInput) {
520
+ usableSoft = input;
521
+ if (isFinitePositive(softContext)) {
522
+ softReserve = Math.max(0, softContext - input);
523
+ reserveSource = "output_catalog";
524
+ }
525
+ } else if (isFinitePositive(softContext)) {
526
+ if (
527
+ geometry === "separate" &&
528
+ (options.overlay === undefined ||
529
+ options.harness === "pi" ||
530
+ geometryOverride !== undefined)
531
+ ) {
532
+ softReserve = 0;
533
+ reserveSource = "none";
534
+ } else {
535
+ softReserve = output ?? 0;
536
+ reserveSource = output === undefined ? "none" : "output_catalog";
537
+ const cap = softContext * OUTPUT_RESERVE_CAP_RATIO;
538
+ softReserve = Math.min(
539
+ softReserve,
540
+ options.harness === "pi" || options.overlay === undefined
541
+ ? cap
542
+ : Math.min(cap, OPENCODE_OUTPUT_CAP),
543
+ );
544
+ }
545
+ const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, softContext * 0.5);
546
+ const flooredReserve = Math.min(softReserve, Math.max(0, softContext - floor));
547
+ if (flooredReserve < softReserve) {
548
+ // A reserve large enough to hit the half-window floor means the
549
+ // catalog's context/output pair contradicts itself (93 live rows
550
+ // publish output > context — fusiform's negative-window detector).
551
+ // The floor keeps the window functional; the log keeps the
552
+ // degradation visible instead of silently halving the window.
553
+ logGeometryClampOnce(
554
+ `soft-floor|${providerID}/${modelID}|${softReserve}|${flooredReserve}`,
555
+ `output reserve clamped by the half-window floor for ${providerID}/${modelID}: reserve ${softReserve} → ${flooredReserve} (catalog context/output pair is contradictory)`,
556
+ options.log,
557
+ );
558
+ }
559
+ softReserve = flooredReserve;
560
+ usableSoft = Math.floor(softContext - softReserve);
561
+ } else {
562
+ usableSoft = input as number;
563
+ }
564
+
565
+ const hardWindow = hardContext ?? softContext ?? input;
566
+ if (!isFinitePositive(hardWindow)) return undefined;
567
+ let usableHard: number;
568
+ if (geometry === "separate") {
569
+ usableHard = hardWindow;
570
+ } else if (geometry === "shared_truncating") {
571
+ usableHard = hardWindow - PROMPT_WALL_MARGIN;
572
+ } else if (options.harness === "pi" && providerID !== "openai-codex") {
573
+ usableHard = hardWindow - PI_OUTPUT_FLOOR;
574
+ } else if (options.harness === "pi") {
575
+ usableHard = hardWindow - (output ?? OPENCODE_OUTPUT_CAP);
576
+ } else {
577
+ const requestedOutput = Math.min(output ?? OPENCODE_OUTPUT_CAP, OPENCODE_OUTPUT_CAP);
578
+ usableHard = hardWindow - requestedOutput;
579
+ }
580
+ usableHard = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, Math.floor(usableHard));
581
+ if (usableHard < usableSoft) {
582
+ logGeometryClampOnce(
583
+ `${providerID}/${modelID}|${usableSoft}|${usableHard}`,
584
+ `usable hard limit clamped for ${providerID}/${modelID}: ${usableHard} → ${usableSoft} (overlay/provider inversion)`,
585
+ options.log,
586
+ );
587
+ usableHard = usableSoft;
588
+ }
589
+
590
+ const resolvedWindow = derivationWindow ?? usableSoft;
591
+ return {
592
+ usableSoft,
593
+ usableHard,
594
+ geometry,
595
+ derivation: {
596
+ window: Math.floor(resolvedWindow),
597
+ reserve: Math.floor(Math.max(0, resolvedWindow - usableSoft)),
598
+ reserveSource,
599
+ geometry,
600
+ },
601
+ };
602
+ }
603
+
604
+ export function formatWindowDerivationLine(
605
+ inputTokens: number,
606
+ result: WindowGeometryResult,
607
+ ): string {
608
+ const percentage = result.usableSoft > 0 ? (inputTokens / result.usableSoft) * 100 : 0;
609
+ const reserveLabel =
610
+ result.derivation.reserveSource === "wall_margin"
611
+ ? "wall margin"
612
+ : result.derivation.reserveSource === "none"
613
+ ? "reserve"
614
+ : "output reserve";
615
+ return `Context: ${formatCompactTokens(inputTokens)} / ${formatCompactTokens(result.usableSoft)} usable (${percentage.toFixed(1)}%) — window ${formatCompactTokens(result.derivation.window)} − ${formatCompactTokens(result.derivation.reserve)} ${reserveLabel} [${result.geometry}]`;
616
+ }
617
+
618
+ export function formatCompactTokens(value: number): string {
619
+ if (Math.abs(value) >= 1_000_000) {
620
+ return `${(value / 1_000_000).toFixed(1).replace(/\.0$/, "")}m`;
621
+ }
622
+ if (Math.abs(value) >= 1_000) {
623
+ return `${(value / 1_000).toFixed(1).replace(/\.0$/, "")}k`;
624
+ }
625
+ return Math.round(value).toLocaleString();
626
+ }
@@ -204,6 +204,11 @@ export async function loadStatusDetail(
204
204
  compressionBudget: null,
205
205
  compressionUsage: null,
206
206
  toastDurationMs: 5000,
207
+ loggerDiagnostics: {
208
+ swallowedWriteCount: 0,
209
+ lastErrorMessage: null,
210
+ lastErrorTime: null,
211
+ },
207
212
  storage_versions: {
208
213
  context_db_schema_version: null,
209
214
  plugin_supported_version: 0,