@nexus-cortex/core 4.124.14 → 4.124.17

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.
@@ -23,7 +23,8 @@ import { resolveEndTurnResolverConfig, parseResolverVerdict, effectiveMaxRejects
23
23
  import { jevAvailable, jevNoul, buildGapHoldState, GAP_HOLD_QUESTIONS } from '../training/jevGate.js'; // R173b
24
24
  import { resolveFrameConfig, FRAME_CONTRACT, FRAME_TOOL_NAME } from '../frames/frameConfig.js'; // R179
25
25
  import { FrameRunner } from '../frames/frameRunner.js'; // R179
26
- import { parseRequirementLedger, initLedger, updateLedger, ledgerCounts, ledgerHoldable, formatLedgerForWriter, formatLedgerForJudge, formatLedgerHoldMessage, buildLedgerJevState, buildLedgerJevQuestions, applyLedgerJevAnswers } from '../training/requirementLedger.js'; // R187
26
+ import { emptySessionUsage, addMainUsage } from '../training/usageAccounting.js'; // R190
27
+ import { parseRequirementLedger, initLedger, updateLedger, ledgerCounts, ledgerHoldable, formatLedgerForWriter, formatLedgerForJudge, formatLedgerHoldMessage, buildLedgerJevState, buildLedgerJevQuestions, applyLedgerJevAnswers, looksLikeBrokenCheck } from '../training/requirementLedger.js'; // R187 / R191
27
28
  import { isValueShapedTask, parseDerivationReply, methodsDiffer, parseValueLines, extractNumbers, reconcile, buildDerivationHoldMessage, isDerivationCommandAllowed, checkRunPassed, checkRunBody } from '../training/independentDerivation.js'; // R176
28
29
  import { resolveDeadlineExitConfig, deadlineExitCallBudget, parseDeadlineExitVerdict } from '../training/deadlineExitMentor.js';
29
30
  import { isTaskShaped } from './requirementsVerification.js';
@@ -252,8 +253,11 @@ export class CortexOrchestrator {
252
253
  specChecksPromise = null; // R174b: authored at lift in the background (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
253
254
  reqLedger = null; // R187: the stated-requirement ledger for this turn (null = not yet authored)
254
255
  reqLedgerPromise = null; // R187: authored at lift in the background
256
+ sessionUsage = emptySessionUsage(); // R190: every main-model request this session (exact) + helper calls (estimated)
255
257
  reqLedgerHolds = 0; // R187: ledger holds used this turn
258
+ reqLedgerRetried = false; // R187c: one re-author at the first finish after an empty lift-time result
256
259
  reqLedgerMeta = { genLatencyMs: 0, raw: 0, refused: 0 }; // R187
260
+ reqLedgerBroken = new Set(); // R191: ids whose check was dropped as malformed
257
261
  specFailHistory = new Map(); // R174b: consecutive identical spec failures
258
262
  lastHoldMs = 0; // R173c: wall clock of the last hold/veto this turn
259
263
  derivationHolds = 0; // R176: independent-derivation holds this turn (max 1)
@@ -603,6 +607,15 @@ export class CortexOrchestrator {
603
607
  }
604
608
  catch { /* fail-open */ }
605
609
  }
610
+ /** R190: the session usage with the helper middleware's estimated calls merged in, plus a decision-store row so trajectories carry it. */
611
+ snapshotSessionUsage() {
612
+ const h = this.helperMiddleware?.getHelperUsageEstimate?.();
613
+ const snap = { ...this.sessionUsage, helper: h ? { ...h } : { ...this.sessionUsage.helper } };
614
+ const store = this.getDecisionStore();
615
+ if (store)
616
+ void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'session_usage', detail: { ...snap } }).catch(() => { });
617
+ return snap;
618
+ }
606
619
  /** Bounded read-only environment recon (ENV_RECON_COMMAND), gathered ONCE and cached — shared by the
607
620
  * lift planner and the EndTurn resolver. Fail-open: partial stdout on timeout/non-zero, else empty. */
608
621
  gatherEnvReport(opts = {}) {
@@ -801,7 +814,9 @@ export class CortexOrchestrator {
801
814
  this.reqLedger = [];
802
815
  return [];
803
816
  }
804
- const tmo = mentorSurfaceTimeoutMs('endturn-resolver', parseInt(process.env.CORTEX_ENDTURN_RESOLVER_TIMEOUT_MS ?? '90000', 10));
817
+ // R187c: the extractor runs in the background at lift beside the planner (which itself takes 80–190 s on pro), so it gets the planner's
818
+ // timeout, not the judge's 90 s — the 09-23 L7 smoke lost the whole ledger to a 98-s pro call (deliveredBy none).
819
+ const tmo = mentorSurfaceTimeoutMs('lift-plan', parseInt(process.env.CORTEX_JUDGE_REQ_LEDGER_TIMEOUT_MS ?? process.env.CORTEX_LIFT_PLAN_TIMEOUT_MS ?? '180000', 10));
805
820
  try {
806
821
  const raw = await withTimeout(this.helperMiddleware.deriveRequirementLedger({ task, envReport: this.gatherEnvReport({ fresh: false }), max: cfg.reqLedgerMax, helperModelId: this.config.reactiveMentorship?.helperModelId }), tmo);
807
822
  const lines = parseRequirementLedger(raw ?? '', cfg.reqLedgerMax);
@@ -949,7 +964,17 @@ export class CortexOrchestrator {
949
964
  if (cfg.reqLedger) {
950
965
  if (this.reqLedger === null)
951
966
  this.reqLedger = await (this.reqLedgerPromise ?? this.authorRequirementLedger(task));
952
- const runs = this.reqLedger.filter((e) => e.check).map((e) => { const r = runCheck(judgeCwd, e.check, jcfg); return { id: e.id, result: r, cls: classifyCheckRun(r) }; });
967
+ // R187c: an empty ledger from a timed-out lift-time call is retried ONCE here (the judge would otherwise run with no lines all session)
968
+ if (this.reqLedger.length === 0 && !this.reqLedgerRetried) {
969
+ this.reqLedgerRetried = true;
970
+ this.reqLedger = await this.authorRequirementLedger(task);
971
+ }
972
+ // R191: a check whose failure is its own defect (usage error, missing script, syntax error) is BROKEN, not FAILED — L7 09-23: photonic's
973
+ // extractor guessed a checker's CLI, two lines failed at every finish on a passing solution, and the writer spent turns on the "harness quirk".
974
+ const runs = this.reqLedger.filter((e) => e.check).map((e) => { const r = runCheck(judgeCwd, e.check, jcfg); const k = classifyCheckRun(r); const cls = k !== 'passed' && looksLikeBrokenCheck(r) ? 'broken' : k; return { id: e.id, result: r, cls }; });
975
+ for (const x of runs)
976
+ if (x.cls === 'broken')
977
+ this.reqLedgerBroken.add(x.id);
953
978
  this.reqLedger = updateLedger(this.reqLedger, runs);
954
979
  // R187b: Jev decides the lines the shell could not — typed per-line questions on the writer's attestation + harness evidence.
955
980
  if (cfg.reqLedgerJev && jevAvailable() && this.reqLedger.some((e) => e.status === 'open' || e.status === 'unverifiable')) {
@@ -1202,6 +1227,7 @@ export class CortexOrchestrator {
1202
1227
  vetoMinRemaining: cfg.vetoMinRemaining, belowFloor, holdProgressed: holdProg, holdGapMs: msSinceLastHold, planSim: Number(planSimilarity(this.judgePriorPlan, verdict.plan).toFixed(3)), msSinceLastHold, // R173c
1203
1228
  derivation: cfg.derivation, derivationAgreement: derivationInfo?.agreement ?? null, derivationHeld: !!derivationHold, // R176
1204
1229
  reqLedger: cfg.reqLedger, reqLines: reqCounts.lines, reqOpen: reqCounts.open, reqExercised: reqCounts.exercised, reqFailed: reqCounts.failed, reqUnverifiable: reqCounts.unverifiable, reqHeld: !!reqHold, reqHolds: this.reqLedgerHolds, reqGenLatencyMs: this.reqLedgerMeta.genLatencyMs, reqJev: cfg.reqLedgerJev, reqJevAsked: reqJev?.asked ?? 0, reqJevClosed: reqJev?.closed ?? [], reqJevLatencyMs: reqJev?.latencyMs ?? 0, // R187/R187b
1230
+ reqBroken: [...this.reqLedgerBroken], reqLinesDetail: (this.reqLedger ?? []).map((e) => ({ id: e.id, kind: e.kind, status: e.status, check: !!e.check, runs: e.runs, last: (e.lastResult ?? '').split('\n').slice(0, 2).join(' / ').slice(0, 200) })), // R191: per-line outcomes so a false-failure read is possible from the decisions file
1205
1231
  latencyMs, rawLen: (text ?? '').length,
1206
1232
  deltaChars: workspaceDelta.length, checkRan: !!checkResult, checkPassed: checkResult ? /→ PASSED/.test(checkResult) : null,
1207
1233
  liftPlanChars: this.liftPlanText.length,
@@ -2255,6 +2281,7 @@ export class CortexOrchestrator {
2255
2281
  this.reqLedgerHolds = 0;
2256
2282
  this.reqLedgerMeta = { genLatencyMs: 0, raw: 0, refused: 0 };
2257
2283
  this.reqLedgerDelivered = false;
2284
+ this.reqLedgerRetried = false;
2258
2285
  this.lastHoldMs = 0;
2259
2286
  this.derivationHolds = 0; // R165 per-turn / R174 / R173c / R176
2260
2287
  this.recordDsmlRecovery(currentAssistantCanonicalMessage);
@@ -3949,10 +3976,10 @@ export class CortexOrchestrator {
3949
3976
  messageId: currentAssistantMessage.uuid,
3950
3977
  content: currentAssistantCanonicalMessage.content,
3951
3978
  toolUses: allExecutedToolUses,
3952
- usage: convertedResponse.usage || {
3953
- inputTokens: 0,
3954
- outputTokens: 0,
3955
- totalTokens: 0
3979
+ usage: {
3980
+ ...(convertedResponse.usage || { inputTokens: 0, outputTokens: 0, totalTokens: 0 }),
3981
+ // R190: the whole session's tokens — every main request (exact) + helper/mentor calls (estimated) — not the last request's
3982
+ session: this.snapshotSessionUsage(),
3956
3983
  },
3957
3984
  model: {
3958
3985
  id: model.id,
@@ -3960,6 +3987,7 @@ export class CortexOrchestrator {
3960
3987
  },
3961
3988
  metadata: {
3962
3989
  conversationId: this.currentConversationId,
3990
+ sessionUsage: this.snapshotSessionUsage(), // R190
3963
3991
  usedHelperModel,
3964
3992
  compactionTriggered: usedHelperModel,
3965
3993
  serverSideTools: serverSideMetadata || undefined,
@@ -4475,6 +4503,7 @@ export class CortexOrchestrator {
4475
4503
  this.reqLedgerHolds = 0;
4476
4504
  this.reqLedgerMeta = { genLatencyMs: 0, raw: 0, refused: 0 };
4477
4505
  this.reqLedgerDelivered = false;
4506
+ this.reqLedgerRetried = false;
4478
4507
  this.lastHoldMs = 0;
4479
4508
  this.derivationHolds = 0; // R165 per-turn / R174 / R173c / R176
4480
4509
  this.recordDsmlRecovery(currentAssistantCanonicalMessage);
@@ -5795,6 +5824,7 @@ export class CortexOrchestrator {
5795
5824
  usage: {
5796
5825
  inputTokens: finalUsage.inputTokens || 0,
5797
5826
  outputTokens: finalUsage.outputTokens || 0,
5827
+ session: this.snapshotSessionUsage(), // R190
5798
5828
  },
5799
5829
  durationMs: Date.now() - turnStartMs,
5800
5830
  toolCallIterations: toolCallIteration,
@@ -6637,6 +6667,7 @@ export class CortexOrchestrator {
6637
6667
  * absorbed by the delta logic in anchoredRequestEstimate.
6638
6668
  */
6639
6669
  noteRequestUsage(usage) {
6670
+ this.sessionUsage = addMainUsage(this.sessionUsage, usage); // R190: cumulative first — the anchor logic below skips zero usage
6640
6671
  const promptTokens = Number(usage?.inputTokens ?? 0);
6641
6672
  if (!(promptTokens > 0))
6642
6673
  return;