@gamaze/hicortex 0.20.6 → 0.20.9

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 (61) hide show
  1. package/README.md +10 -41
  2. package/dist/calibration.d.ts +174 -0
  3. package/dist/calibration.js +231 -0
  4. package/dist/capture.d.ts +15 -3
  5. package/dist/capture.js +10 -1
  6. package/dist/classify-domains.d.ts +6 -0
  7. package/dist/classify-domains.js +7 -1
  8. package/dist/cli.js +2 -3
  9. package/dist/config-read.d.ts +1 -1
  10. package/dist/config-read.js +96 -9
  11. package/dist/consolidate.d.ts +79 -68
  12. package/dist/consolidate.js +218 -174
  13. package/dist/dashboard.d.ts +4 -3
  14. package/dist/dedup.d.ts +34 -26
  15. package/dist/dedup.js +91 -57
  16. package/dist/distiller.js +1 -1
  17. package/dist/domain-classify.d.ts +7 -6
  18. package/dist/domain-classify.js +12 -10
  19. package/dist/eval/decay-eval.d.ts +3 -3
  20. package/dist/eval/decay-eval.js +4 -4
  21. package/dist/eval/planted-eval.d.ts +26 -0
  22. package/dist/eval/planted-eval.js +97 -0
  23. package/dist/eval/planted-fixtures.d.ts +107 -0
  24. package/dist/eval/planted-fixtures.js +283 -0
  25. package/dist/eval/planted-harness.d.ts +176 -0
  26. package/dist/eval/planted-harness.js +649 -0
  27. package/dist/index.js +4 -3
  28. package/dist/init.d.ts +9 -3
  29. package/dist/init.js +52 -9
  30. package/dist/llm.d.ts +43 -58
  31. package/dist/llm.js +87 -101
  32. package/dist/mcp-server.js +29 -29
  33. package/dist/nightly.js +105 -103
  34. package/dist/nofit.d.ts +4 -11
  35. package/dist/nofit.js +6 -23
  36. package/dist/recall-index.d.ts +30 -28
  37. package/dist/recall-index.js +21 -18
  38. package/dist/recall-registry.d.ts +2 -1
  39. package/dist/recall-registry.js +35 -1
  40. package/dist/reconsolidation.d.ts +124 -72
  41. package/dist/reconsolidation.js +390 -169
  42. package/dist/relink.js +3 -4
  43. package/dist/retrieval.d.ts +68 -35
  44. package/dist/retrieval.js +292 -104
  45. package/dist/run-deadline.d.ts +62 -0
  46. package/dist/run-deadline.js +73 -0
  47. package/dist/schema-prototypes.d.ts +3 -3
  48. package/dist/schema-prototypes.js +3 -3
  49. package/dist/state.d.ts +2 -3
  50. package/dist/storage.d.ts +16 -16
  51. package/dist/storage.js +62 -24
  52. package/dist/telemetry.d.ts +8 -7
  53. package/dist/token-budget.js +3 -4
  54. package/dist/type-classify.js +4 -4
  55. package/dist/types.d.ts +95 -155
  56. package/domains.example.json +4 -5
  57. package/hermes-plugin/hicortex/README.md +2 -2
  58. package/openclaw.plugin.json +1 -1
  59. package/package.json +2 -1
  60. package/pi-extension/hicortex/README.md +1 -1
  61. package/server.json +3 -3
package/dist/cli.js CHANGED
@@ -445,9 +445,8 @@ Options:
445
445
  dedup --apply Execute the merge (default: dry run, report only)
446
446
  Losers are absorbed — hidden from recall, kept as
447
447
  evidence (fetchable by id; dedup_log audit) — not deleted
448
- dedup --threshold <t> Override the threshold for one run (default: config
449
- dedupAutoMergeThreshold, legacy dedupMergeThreshold
450
- still honored; else 0.92)
448
+ dedup --threshold <t> Override the threshold for one run (default: the
449
+ release-managed calibration ceiling, 0.92)
451
450
  dedup --db <path> DB path override (defaults to the configured DB)
452
451
  history --rollback <row> Roll back history row <row>: restores prior content/status, un-absorbs triggers
453
452
  history --db <path> DB path override (defaults to the configured DB)
@@ -27,7 +27,7 @@ export declare function readStrictBoolean(config: Record<string, unknown>, key:
27
27
  /**
28
28
  * Read a non-negative finite number (allows 0, unlike readPositiveConfig).
29
29
  * Returns `def` when absent OR invalid. Used for keys where 0 is a valid "off"
30
- * value (e.g. ollamaFlushEvery).
30
+ * value (e.g. memorySoftCap's eviction opt-out, timerJitterSeconds).
31
31
  */
32
32
  export declare function readNonNegativeConfig(config: Record<string, unknown>, key: string, def: number): number;
33
33
  /**
@@ -52,7 +52,7 @@ function readStrictBoolean(config, key) {
52
52
  /**
53
53
  * Read a non-negative finite number (allows 0, unlike readPositiveConfig).
54
54
  * Returns `def` when absent OR invalid. Used for keys where 0 is a valid "off"
55
- * value (e.g. ollamaFlushEvery).
55
+ * value (e.g. memorySoftCap's eviction opt-out, timerJitterSeconds).
56
56
  */
57
57
  function readNonNegativeConfig(config, key, def) {
58
58
  const v = config[key];
@@ -152,6 +152,63 @@ const IGNORED_CONFIG_KEYS = [
152
152
  "classifyModel", "classifyBaseUrl", "classifyApiKey", "classifyProvider",
153
153
  "distillFallback",
154
154
  ];
155
+ /**
156
+ * Config keys REMOVED by the #405 budget simplification, each mapped to its
157
+ * replacement (or "removed" when there is none). The old single 0.16.8-style
158
+ * message does not fit — every key here needs to name where its job went.
159
+ * Warned at the config boundary alongside the 0.16.8 keys above.
160
+ */
161
+ const REMOVED_CONFIG_KEYS = {
162
+ reconsolidationMaxMinutes: "removed — the ONE run deadline (nightlyTimeBudgetMinutes) bounds the stage",
163
+ reconsolidationMaxCalls: "removed — the ONE call budget (nightlyLlmCallBudget) caps all stages",
164
+ supersessionMaxCalls: "removed — the ONE call budget (nightlyLlmCallBudget) caps all stages",
165
+ dedupNightlyMaxMerges: "removed — the run deadline (nightlyTimeBudgetMinutes) bounds nightly merges",
166
+ classifyMaxTokens: "removed — maxTokens is the single output ceiling for every call",
167
+ llmBreakerThreshold: "removed — the breaker threshold is a constant (3)",
168
+ llmBreakerCooldownMs: "removed — the breaker cooldown is a constant (10 min)",
169
+ llmSingleFlightWaitMs: "removed — the wait derives from llmTimeoutMs",
170
+ preflightTimeoutMs: "removed — a constant (20 s per attempt)",
171
+ preflightAttempts: "removed — a constant (3 attempts)",
172
+ preflightRetryGapMs: "removed — a constant (60 s gap)",
173
+ moduleIndexTokenBudget: "removed — was documentation-only",
174
+ };
175
+ /**
176
+ * Config keys that became RELEASE-MANAGED CALIBRATION constants (#408): the
177
+ * ~35 tuning keys of the 0.15–0.20 era. Their values are ignored — the
178
+ * constants ship with each release (src/calibration.ts) and change only in
179
+ * releases with eval evidence linked in the changelog. Like the #405 list,
180
+ * this is deliberately WIDER than the `HicortexConfig` type ever was: several
181
+ * keys (supersessionPenalty, the rrf/bm25 knob set, recallTitleChars, ...)
182
+ * were README-documented but never typed. Don't trim the list to match the
183
+ * interface — the warn exists precisely for the untyped surface.
184
+ */
185
+ const RELEASE_MANAGED_CONFIG_KEYS = [
186
+ "decayHalfLifeDays", "searchLimit", "recentLimit", "recentWindowDays",
187
+ "coldExposureSlots", "recallMaxItems", "recallMinSimilarity",
188
+ "recallReshowTurns", "recallMinPromptChars", "recallTitleChars",
189
+ "sessionIntentWeight", "noveltyFloorSlots", "scoreSimilarityWeight",
190
+ "scoreStrengthWeight", "scoreConnectionsWeight", "scoreRecencyWeight",
191
+ "freshnessBoostDays", "freshnessBoostWeight", "supersededDemotion",
192
+ "projectAffinityWeight", "domainAffinityWeight", "rrfK",
193
+ "rrfCompositeWeight", "rrfFtsWeight", "rrfVectorWeight",
194
+ "bm25WeightBody", "bm25WeightProject", "bm25WeightDomain",
195
+ "dedupAutoMergeThreshold", "dedupMergeThreshold",
196
+ "supersessionMinSimilarity", "supersessionPenalty",
197
+ "correctionMinSimilarity", "correctionRewriteMinConfidence",
198
+ "weakPrimaryFloor",
199
+ ];
200
+ /**
201
+ * Config keys MOVED to the diagnostic env tier (#408): the ollama-operational
202
+ * family left config.json and now resolves from environment variables
203
+ * (calibration.ts resolvers; env > constant, invalid env warns + falls back).
204
+ * Each entry maps the old config key to its env replacement so the warning
205
+ * can name the exact variable.
206
+ */
207
+ const ENV_MOVED_CONFIG_KEYS = {
208
+ numCtx: "HICORTEX_NUM_CTX",
209
+ ollamaFlushEvery: "HICORTEX_OLLAMA_FLUSH_EVERY",
210
+ ollamaFlushWaitMs: "HICORTEX_OLLAMA_FLUSH_WAIT_MS",
211
+ };
155
212
  /**
156
213
  * Warn if the saved config carries keys that 0.16.8+ ignores. Call at every
157
214
  * config read (daemon boot + nightly). The warning clears once the keys are
@@ -163,12 +220,42 @@ function warnIgnoredConfigKeys(savedConfig) {
163
220
  return;
164
221
  const present = IGNORED_CONFIG_KEYS.filter((k) => savedConfig[k] !== undefined);
165
222
  const hasModelsBlock = savedConfig.models !== undefined;
166
- if (present.length === 0 && !hasModelsBlock)
167
- return;
168
- const detail = [...present, ...(hasModelsBlock ? ["models"] : [])].join(", ");
169
- console.warn(`[hicortex] config has keys IGNORED since 0.16.8 (${detail}). They have no effect now. ` +
170
- `Per-stage model keys / the \`models\` block: one model serves all phases — set ` +
171
- `llmModel/llmBaseUrl/llmProvider (+ llmApiKey) to your intended model. ` +
172
- `distillFallback: removed (strict mode is default — a failed distill retries next run). ` +
173
- `Remove these keys to clear this warning. See the 0.16.8 changelog.`);
223
+ if (present.length > 0 || hasModelsBlock) {
224
+ const detail = [...present, ...(hasModelsBlock ? ["models"] : [])].join(", ");
225
+ console.warn(`[hicortex] config has keys IGNORED since 0.16.8 (${detail}). They have no effect now. ` +
226
+ `Per-stage model keys / the \`models\` block: one model serves all phases — set ` +
227
+ `llmModel/llmBaseUrl/llmProvider (+ llmApiKey) to your intended model. ` +
228
+ `distillFallback: removed (strict mode is default — a failed distill retries next run). ` +
229
+ `Remove these keys to clear this warning. See the 0.16.8 changelog.`);
230
+ }
231
+ // #405: keys removed by the budget simplification — one line naming each
232
+ // present key and its replacement (or "removed").
233
+ const removed = Object.entries(REMOVED_CONFIG_KEYS)
234
+ .filter(([k]) => savedConfig[k] !== undefined);
235
+ if (removed.length > 0) {
236
+ const detail = removed.map(([k, v]) => `${k} (${v})`).join(", ");
237
+ console.warn(`[hicortex] config has keys REMOVED by the budget simplification (#405): ${detail}. ` +
238
+ `They have no effect. Remove them to clear this warning.`);
239
+ }
240
+ // #408: tuning keys that became release-managed calibration constants —
241
+ // one line naming every present key (their VALUES are ignored; the
242
+ // constants ship with each release and change only with published eval
243
+ // evidence linked in the changelog).
244
+ const releaseManaged = RELEASE_MANAGED_CONFIG_KEYS
245
+ .filter((k) => savedConfig[k] !== undefined);
246
+ if (releaseManaged.length > 0) {
247
+ console.warn(`[hicortex] config has keys that are now RELEASE-MANAGED CALIBRATION ` +
248
+ `(${releaseManaged.join(", ")}): their values are ignored — calibration ` +
249
+ `ships with each release and changes only with published eval evidence. ` +
250
+ `Remove them to clear this warning.`);
251
+ }
252
+ // #408: the diagnostic-tier keys that moved to environment variables —
253
+ // one line naming each old key AND its env replacement.
254
+ const envMoved = Object.entries(ENV_MOVED_CONFIG_KEYS)
255
+ .filter(([k]) => savedConfig[k] !== undefined);
256
+ if (envMoved.length > 0) {
257
+ const detail = envMoved.map(([k, env]) => `${k} → set ${env} instead`).join(", ");
258
+ console.warn(`[hicortex] config has keys that MOVED to environment variables (#408): ${detail}. ` +
259
+ `The config keys are ignored. Remove them to clear this warning.`);
260
+ }
174
261
  }
@@ -9,18 +9,27 @@ import type { LlmClient } from "./llm.js";
9
9
  import type { EmbedFn } from "./retrieval.js";
10
10
  import { type DomainDef } from "./domain-classify.js";
11
11
  import { type ReconsolidationOptions } from "./reconsolidation.js";
12
+ import type { RunDeadline } from "./run-deadline.js";
12
13
  /**
13
- * Default ceiling on total LLM calls across all classify-tier consolidation
14
- * stages (content-domain, link discovery, supersession) per run. This is a
15
- * runaway BACKSTOP, not a throughput throttle — on a free local model there is
16
- * no per-call cost to defend against; the binding constraint is the nightly
17
- * unit's wall-clock timeout (TimeoutStartSec), not call count. 5000 clears a
18
- * one-time classification backlog (a ~2000-memory batch drains in ~1-2 runs
19
- * instead of ~11 nights at the old 200) with margin for link/supersession, and
20
- * ~5000 calls x ~1-3s/call ≈ 1.4-4.2h fits the 6h consolidation backstop.
21
- * Config-overridable as `consolidateMaxLlmCalls` (#241).
14
+ * Default ceiling on LLM calls across the WHOLE nightly pipeline (#405; the
15
+ * #241 consolidateMaxLlmCalls mechanism, renamed and widened). A runaway
16
+ * BACKSTOP that bounds money/load INDEPENDENT OF LATENCY — a fast metered or
17
+ * capacity-limited endpoint permits thousands of calls inside the wall-clock
18
+ * budget, so time alone cannot protect it (owner ruling 2026-09-12). Consumed
19
+ * in run order: a stage that exhausts it defers its remainder via its cursor.
20
+ * 5000 clears a one-time classification backlog (a ~2000-memory batch drains
21
+ * in ~1-2 runs) with margin. Config: `nightlyLlmCallBudget` (#405); the old
22
+ * `consolidateMaxLlmCalls` key is a deprecated alias honored one release.
22
23
  */
23
- export declare const CONSOLIDATE_MAX_LLM_CALLS = 5000;
24
+ export declare const DEFAULT_NIGHTLY_LLM_CALL_BUDGET = 5000;
25
+ /**
26
+ * Resolve the per-run LLM call budget from config (#405):
27
+ * - `nightlyLlmCallBudget` present (positive finite) → it wins;
28
+ * - else `consolidateMaxLlmCalls` present → used as a DEPRECATED ALIAS with
29
+ * a warn naming the replacement (honored one release);
30
+ * - absent/invalid → the 5000 default.
31
+ */
32
+ export declare function resolveNightlyLlmCallBudget(config: Record<string, unknown> | null | undefined): number;
24
33
  /**
25
34
  * Minimum COSINE similarity for a link candidate.
26
35
  *
@@ -66,14 +75,12 @@ export declare class BudgetTracker {
66
75
  callsByStage: Record<string, number>;
67
76
  /**
68
77
  * Per-stage count of LLM-call REQUESTS refused because the budget was
69
- * exhausted (#255). Keys are the same stage labels passed to `use()`. The
70
- * value is the SUM of the `count` args passed to each refused `use()` call
71
- * in that stage (in production every `use()` call passes count=1, so each
72
- * refused call adds 1 — but the API accepts a batch count, so a single
73
- * refused batch request accrues its full count). Stages break on the first
74
- * refusal, so a stage's value is the count of the one request that crossed
75
- * the boundary. For item-level skip counts (how many memories or pairs were
76
- * left unprocessed), see the per-stage reports — e.g.
78
+ * exhausted (#255). Keys are the same stage labels passed to `use()`; each
79
+ * refused call adds 1 (the dead batch `count` param is gone — #405 —
80
+ * production always passed 1 anyway). Stages break on the first refusal,
81
+ * so a stage's value is the count of requests that crossed the boundary.
82
+ * For item-level skip counts (how many memories or pairs were left
83
+ * unprocessed), see the per-stage reports — e.g.
77
84
  * `stages.importance.skipped_budget` — which count MEMORIES, not call
78
85
  * requests. Surfaced in summary() and ConsolidationReport as
79
86
  * `deferred_by_stage`.
@@ -99,7 +106,7 @@ export declare class BudgetTracker {
99
106
  constructor(maxCalls: number);
100
107
  get exhausted(): boolean;
101
108
  get remaining(): number;
102
- use(stage: string, count?: number): boolean;
109
+ use(stage: string): boolean;
103
110
  /**
104
111
  * Record token usage from one LLM call (#246). Called by the consolidation
105
112
  * stages after each metered completion. `undefined` usage (claude-cli path,
@@ -113,6 +120,14 @@ export declare class BudgetTracker {
113
120
  } | undefined): void;
114
121
  summary(): NonNullable<ConsolidationReport["budget"]>;
115
122
  }
123
+ /**
124
+ * True when a token-period start stamp is ABSENT or sits in a previous UTC
125
+ * calendar month than `now` — the monthly-reset staleness check. #405: ONE
126
+ * shared helper — the check was triplicated (the nightly's throttle branch,
127
+ * the nightly's accrual write, token-budget.ts recordDistillUsage) and each
128
+ * copy re-derived the year+month comparison by hand.
129
+ */
130
+ export declare function isStaleTokenPeriod(periodStart: string | undefined, now?: Date): boolean;
116
131
  /**
117
132
  * Decide whether consolidation should be throttled this run based on the
118
133
  * `llmTokensPerMonth` fair-use cap. Pure (no I/O) so it can be unit-tested
@@ -125,8 +140,8 @@ export declare class BudgetTracker {
125
140
  *
126
141
  * `cap = 0` (the self-hosted default) → never throttle (unlimited).
127
142
  * `periodStart` in a previous calendar month → period resets to 0 first
128
- * (mirrors the reset logic in nightly.ts; both sides agree because both read
129
- * the same state + clock).
143
+ * (isStaleTokenPeriod — the same helper every monthly-reset site uses, so
144
+ * the sides agree because they read the same state + clock).
130
145
  */
131
146
  export declare function shouldThrottleTokens(cap: number, period: {
132
147
  total: number;
@@ -176,19 +191,16 @@ export declare function discoverLinkCandidates(db: Database.Database, mem: Memor
176
191
  * 672-link audit (see the Stage 3 header) found the LLM-classified UPPERCASE
177
192
  * types near-useless (CONTRADICTS 4% acceptable). Every candidate now takes its
178
193
  * pre-computed `heuristicType` (only `extends` or `relates_to` — see
179
- * classifyRelationship). No LLM call is made.
180
- *
181
- * Signature stability: `llm` and `budget` are RETAINED but intentionally
182
- * ignored so the callers (nightly `stageLinks`, `hicortex relink`) and the
183
- * tests that import this need no change to their call sites. The return shape
184
- * is unchanged; `llmClassified` is always 0 now and `heuristicFallback` counts
185
- * every candidate. Do NOT re-add an LLM path here without a classifier that
186
- * passes the audit harness at >= 70% acceptable.
194
+ * classifyRelationship). No LLM call is made. #405: the ignored `llm`/`budget`
195
+ * params are deleted — the signature now tells the truth.
196
+ * The return shape is unchanged; `llmClassified` is always 0 and
197
+ * `heuristicFallback` counts every candidate. Do NOT re-add an LLM path here
198
+ * without a classifier that passes the audit harness at >= 70% acceptable.
187
199
  *
188
200
  * Shared between the nightly `stageLinks` and `hicortex relink`.
189
201
  * Returns one relationship type per candidate (same order as input).
190
202
  */
191
- export declare function classifyLinkCandidates(candidates: LinkCandidate[], _llm: LlmClient | null, _budget: BudgetTracker): Promise<{
203
+ export declare function classifyLinkCandidates(candidates: LinkCandidate[]): Promise<{
192
204
  types: string[];
193
205
  llmClassified: number;
194
206
  heuristicFallback: number;
@@ -210,22 +222,17 @@ export declare function classifyLinkCandidates(candidates: LinkCandidate[], _llm
210
222
  * boundary from the l2ToCosine calibration is preserved.
211
223
  */
212
224
  export declare function classifyRelationship(source: Memory, target: Memory, similarity: number): string;
213
- /** Default minimum COSINE similarity for a supersession candidate pair. */
225
+ /** Default minimum COSINE similarity for a supersession candidate pair —
226
+ * RELEASE-MANAGED since #408 (calibration.ts SUPERSESSION_MIN_SIMILARITY). */
214
227
  export declare const DEFAULT_SUPERSESSION_MIN_SIMILARITY = 0.8;
215
- /**
216
- * Default max classify-tier LLM calls (pairs evaluated) spent per nightly run.
217
- * 0 = no separate cap — supersession shares the consolidation budget
218
- * (CONSOLIDATE_MAX_LLM_CALLS, default 5000) like every other stage. The old
219
- * default of 30 was set when the corpus had 14 decisions; with the distiller
220
- * now classifying types correctly (#216), decisions are common and the cap
221
- * was throttling supersession to a crawl. On a local free model there is no
222
- * per-call cost to defend against — the binding constraint is the wall-clock
223
- * timeout (TimeoutStartSec), not call count.
224
- */
225
- export declare const DEFAULT_SUPERSESSION_MAX_CALLS = 0;
226
228
  export interface SupersessionOptions {
229
+ /** Candidate-pair cosine floor. Release-managed default (calibration.ts);
230
+ * this field is the eval/test seam. Invalid → default. */
227
231
  minSimilarity?: number;
228
- maxCalls?: number;
232
+ /** The run-wide pipeline deadline (#405) — checked at each candidate
233
+ * boundary; on expiry the scan stops and the cursor holds at the last
234
+ * fully-considered candidate (resumed next run). */
235
+ deadline?: RunDeadline;
229
236
  }
230
237
  export interface SupersessionStageResult {
231
238
  scanned: number;
@@ -265,6 +272,13 @@ export declare function parseSupersessionReply(reply: string): boolean | null;
265
272
  * candidacy. It only stops SHORT of a candidate when the budget is already
266
273
  * exhausted before that candidate starts, so the cursor never skips a
267
274
  * candidate that was never looked at.
275
+ *
276
+ * #405: the cursor persists after EVERY fully-considered candidate (the
277
+ * post-#404 reconsolidation pattern), not at stage end — a run killed or
278
+ * deadline-deferred mid-stage loses at most the candidate in flight. No
279
+ * orphan clamp is needed (unlike reconsolidation): supersession applies each
280
+ * verdict's link immediately, so `cursor = candidate.__rowid` always sits
281
+ * after all of that candidate's writes.
268
282
  */
269
283
  export declare function stageSupersession(db: Database.Database, llm: LlmClient, budget: BudgetTracker, embedFn: EmbedFn, dryRun: boolean, stateDir: string | undefined, options?: SupersessionOptions): Promise<SupersessionStageResult>;
270
284
  /**
@@ -320,7 +334,7 @@ export declare function stageMemoryCapEviction(db: Database.Database, dryRun: bo
320
334
  * When `domains` is a non-empty list, the pipeline uses content-based
321
335
  * classification (config-owned) INSTEAD of project grouping. The single
322
336
  * model serves all phases; if it's unavailable, `complete()` retries
323
- * internally (30s/60s/120s) and the phase fails soft on persistence —
337
+ * internally (one 60 s retry, #405) and the phase fails soft on persistence —
324
338
  * the nightly retries on the next run. No pre-flight health checks; the
325
339
  * phase either answers or is skipped until the next scheduled run. When
326
340
  * `domains` is absent/empty, the legacy project-grouping curation runs
@@ -330,38 +344,35 @@ export interface DomainStageOptions {
330
344
  domains?: DomainDef[] | null;
331
345
  contentDomainsReady?: boolean;
332
346
  /**
333
- * Weak-primary floor for the no-fit path (see nofit.ts). Resolved by the
334
- * caller from config (`weakPrimaryFloor`); defaults to
335
- * DEFAULT_WEAK_PRIMARY_FLOOR when absent.
347
+ * Weak-primary floor for the no-fit path (see nofit.ts). Release-managed
348
+ * default (#408 — calibration.ts WEAK_PRIMARY_FLOOR via nofit's
349
+ * DEFAULT_WEAK_PRIMARY_FLOOR); this field stays as the eval/test seam.
336
350
  */
337
351
  weakPrimaryFloor?: number;
338
352
  }
339
353
  export declare function runConsolidation(db: Database.Database, llm: LlmClient, embedFn: EmbedFn, dryRun?: boolean, skipReflection?: boolean, stateDir?: string, domainOptions?: DomainStageOptions, supersessionOptions?: SupersessionOptions,
340
- /** Total LLM-call ceiling across classify-tier stages (#241). The caller
341
- * reads `consolidateMaxLlmCalls` from config and passes it; unset → the
342
- * exported `CONSOLIDATE_MAX_LLM_CALLS` default (5000). */
354
+ /** The ONE per-run LLM-call ceiling (#405/#241). The caller resolves
355
+ * `nightlyLlmCallBudget` from config (consolidateMaxLlmCalls is a
356
+ * deprecated alias — resolveNightlyLlmCallBudget) and passes it; unset →
357
+ * the exported DEFAULT_NIGHTLY_LLM_CALL_BUDGET (5000). */
343
358
  budgetMaxCalls?: number,
344
359
  /** Soft cap on the corpus (#245). Nightly.ts reads `memorySoftCap` from
345
360
  * config and passes it; unset → `DEFAULT_MEMORY_SOFT_CAP` (10000). `0`
346
361
  * disables eviction (indefinite growth). */
347
362
  memorySoftCap?: number,
348
- /** Reconsolidation-stage knobs (#384), threaded from config by nightly.ts
349
- * (correctionMinSimilarity / correctionRewriteMinConfidence) exactly like
350
- * supersessionOptions above; unset fields → the stage's defaults.
351
- * Appended AFTER the pre-#384 params so every existing positional caller
352
- * (tests, hosted nightly) keeps its argument meaning. */
353
- reconsolidationOptions?: ReconsolidationOptions): Promise<ConsolidationReport>;
363
+ /** Reconsolidation-stage knobs (#384) — eval/test seams since #408 (the
364
+ * values are release-managed calibration constants; nightly.ts threads
365
+ * NOTHING), exactly like supersessionOptions above; unset fields → the
366
+ * stage's calibration defaults. Appended AFTER the pre-#384 params so
367
+ * every existing positional caller (tests, hosted nightly) keeps its
368
+ * argument meaning. */
369
+ reconsolidationOptions?: ReconsolidationOptions,
354
370
  /**
355
- * Calculate milliseconds until the next occurrence of a given hour (local time).
356
- */
357
- export declare function msUntilHour(hour: number): number;
358
- /**
359
- * Schedule the consolidation pipeline to run nightly.
360
- * Returns a cleanup function to cancel the timer.
361
- *
362
- * NOTE: currently unused (nightly.ts drives consolidation directly). Any future
363
- * caller MUST read config.domains and thread `domainOptions` into runConsolidation
364
- * when content domains are configured — otherwise it silently falls back to the
365
- * legacy project-grouping path even when a domain list is set.
371
+ * The run-wide pipeline deadline (#405), created at nightly start and
372
+ * shared by capture + every consolidation stage. Absent = no deadline
373
+ * (tests, evict-only paths, pre-#405 callers). When it fires, every
374
+ * not-yet-run stage defers (logs event=deadline_deferred stage=<name>) and
375
+ * the report status becomes "deferred" — which keeps lastConsolidated
376
+ * un-advanced so the next run re-finds the pending work.
366
377
  */
367
- export declare function scheduleConsolidation(db: Database.Database, llm: LlmClient, embedFn: EmbedFn, hour?: number): () => void;
378
+ deadline?: RunDeadline): Promise<ConsolidationReport>;