@nexus-cortex/core 4.124.10 → 4.124.12
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.
- package/.env.defaults +39 -0
- package/dist/config/RuntimeConfigRegistry.d.ts.map +1 -1
- package/dist/config/RuntimeConfigRegistry.js +6 -0
- package/dist/config/RuntimeConfigRegistry.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +6 -0
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/SettingsSchema.d.ts +6 -0
- package/dist/config/SettingsSchema.d.ts.map +1 -1
- package/dist/config/SettingsSchema.js +14 -0
- package/dist/config/SettingsSchema.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +6 -0
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/frames/chooser.d.ts +8 -9
- package/dist/frames/chooser.d.ts.map +1 -1
- package/dist/frames/chooser.js +17 -68
- package/dist/frames/chooser.js.map +1 -1
- package/dist/frames/frameConfig.d.ts +2 -1
- package/dist/frames/frameConfig.d.ts.map +1 -1
- package/dist/frames/frameConfig.js +4 -3
- package/dist/frames/frameConfig.js.map +1 -1
- package/dist/frames/frameRunner.d.ts.map +1 -1
- package/dist/frames/frameRunner.js +6 -7
- package/dist/frames/frameRunner.js.map +1 -1
- package/dist/frames/terminusFrame.d.ts +2 -0
- package/dist/frames/terminusFrame.d.ts.map +1 -1
- package/dist/frames/terminusFrame.js +5 -4
- package/dist/frames/terminusFrame.js.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +11 -0
- package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.js +18 -0
- package/dist/middleware/HelperModelMiddleware.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +12 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +134 -4
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/tools/registries/BaseToolRegistry.d.ts.map +1 -1
- package/dist/tools/registries/BaseToolRegistry.js +2 -1
- package/dist/tools/registries/BaseToolRegistry.js.map +1 -1
- package/dist/training/DecisionStore.d.ts +1 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/endTurnResolver.d.ts +9 -0
- package/dist/training/endTurnResolver.d.ts.map +1 -1
- package/dist/training/endTurnResolver.js +6 -1
- package/dist/training/endTurnResolver.js.map +1 -1
- package/dist/training/requirementLedger.d.ts +84 -0
- package/dist/training/requirementLedger.d.ts.map +1 -0
- package/dist/training/requirementLedger.js +155 -0
- package/dist/training/requirementLedger.js.map +1 -0
- package/package.json +3 -3
|
@@ -23,6 +23,7 @@ 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
27
|
import { isValueShapedTask, parseDerivationReply, methodsDiffer, parseValueLines, extractNumbers, reconcile, buildDerivationHoldMessage, isDerivationCommandAllowed, checkRunPassed, checkRunBody } from '../training/independentDerivation.js'; // R176
|
|
27
28
|
import { resolveDeadlineExitConfig, deadlineExitCallBudget, parseDeadlineExitVerdict } from '../training/deadlineExitMentor.js';
|
|
28
29
|
import { isTaskShaped } from './requirementsVerification.js';
|
|
@@ -249,6 +250,10 @@ export class CortexOrchestrator {
|
|
|
249
250
|
specChecks = null; // R174: blind spec-derived checks authored for this turn (null = not yet)
|
|
250
251
|
specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 }; // R174
|
|
251
252
|
specChecksPromise = null; // R174b: authored at lift in the background (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
|
|
253
|
+
reqLedger = null; // R187: the stated-requirement ledger for this turn (null = not yet authored)
|
|
254
|
+
reqLedgerPromise = null; // R187: authored at lift in the background
|
|
255
|
+
reqLedgerHolds = 0; // R187: ledger holds used this turn
|
|
256
|
+
reqLedgerMeta = { genLatencyMs: 0, raw: 0, refused: 0 }; // R187
|
|
252
257
|
specFailHistory = new Map(); // R174b: consecutive identical spec failures
|
|
253
258
|
lastHoldMs = 0; // R173c: wall clock of the last hold/veto this turn
|
|
254
259
|
derivationHolds = 0; // R176: independent-derivation holds this turn (max 1)
|
|
@@ -542,6 +547,7 @@ export class CortexOrchestrator {
|
|
|
542
547
|
void store.recordEvent({
|
|
543
548
|
sessionId, kind: 'lift_plan', detail: { fired: true, planChars: 0, empty: true, ...r171, mentor: this.mentorWire('lift-plan', resolveLiftPlanConfig().effort, resolveLiftPlanConfig().outputBudgetTokens) },
|
|
544
549
|
}).catch(() => { });
|
|
550
|
+
await this.deliverRequirementLedgerToWriter(lastMsg); // R187: the ledger rides even when the plan is empty
|
|
545
551
|
return; // fail-open: proceed without a plan
|
|
546
552
|
}
|
|
547
553
|
const retire = /\bRETIRE\b/i.test(plan);
|
|
@@ -564,6 +570,7 @@ export class CortexOrchestrator {
|
|
|
564
570
|
if (this.config.debug) {
|
|
565
571
|
console.log(`[LiftPlan] plan delivered at lift (${plan.length} chars, retire=${retire}, criteria=${criteriaStated})`);
|
|
566
572
|
}
|
|
573
|
+
await this.deliverRequirementLedgerToWriter(lastMsg); // R187
|
|
567
574
|
}
|
|
568
575
|
catch (e) {
|
|
569
576
|
if (store)
|
|
@@ -574,6 +581,26 @@ export class CortexOrchestrator {
|
|
|
574
581
|
console.warn(`[LiftPlan] delivery failed (continuing without): ${e?.message ?? e}`);
|
|
575
582
|
}
|
|
576
583
|
}
|
|
584
|
+
/** R187: append the requirement ledger to the lift observation the writer is about to see (waits for the lift-time authoring,
|
|
585
|
+
* bounded by the resolver timeout; fail-open to nothing). One-shot per turn. */
|
|
586
|
+
reqLedgerDelivered = false;
|
|
587
|
+
async deliverRequirementLedgerToWriter(lastMsg) {
|
|
588
|
+
const cfg = resolveEndTurnResolverConfig();
|
|
589
|
+
if (!cfg.reqLedger || this.reqLedgerDelivered)
|
|
590
|
+
return;
|
|
591
|
+
this.reqLedgerDelivered = true;
|
|
592
|
+
try {
|
|
593
|
+
const entries = this.reqLedger ?? (this.reqLedgerPromise ? await withTimeout(this.reqLedgerPromise, mentorSurfaceTimeoutMs('endturn-resolver', parseInt(process.env.CORTEX_ENDTURN_RESOLVER_TIMEOUT_MS ?? '90000', 10))) : null);
|
|
594
|
+
const text = formatLedgerForWriter(entries ?? []);
|
|
595
|
+
if (!text)
|
|
596
|
+
return;
|
|
597
|
+
lastMsg?.message?.content?.push?.({ type: 'text', text: `<system-reminder>\n${text}\n</system-reminder>` });
|
|
598
|
+
const store = this.getDecisionStore();
|
|
599
|
+
if (store)
|
|
600
|
+
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'requirement_ledger_delivered', toolName: 'EndTurn', detail: { lines: (entries ?? []).length, chars: text.length } }).catch(() => { });
|
|
601
|
+
}
|
|
602
|
+
catch { /* fail-open */ }
|
|
603
|
+
}
|
|
577
604
|
/** Bounded read-only environment recon (ENV_RECON_COMMAND), gathered ONCE and cached — shared by the
|
|
578
605
|
* lift planner and the EndTurn resolver. Fail-open: partial stdout on timeout/non-zero, else empty. */
|
|
579
606
|
gatherEnvReport(opts = {}) {
|
|
@@ -762,6 +789,47 @@ export class CortexOrchestrator {
|
|
|
762
789
|
console.warn(`[EndTurnResolver] R174 SPEC-TESTS — ${this.specChecks.length} blind check(s) authored at ${cfg.specTestsAt} in ${this.specChecksMeta.genLatencyMs} ms (${this.specChecksMeta.refused} refused)`);
|
|
763
790
|
return this.specChecks;
|
|
764
791
|
}
|
|
792
|
+
/** R187: author the requirement ledger (task text + env report ONLY). Sets reqLedger/reqLedgerMeta; never throws. */
|
|
793
|
+
async authorRequirementLedger(task) {
|
|
794
|
+
const cfg = resolveEndTurnResolverConfig();
|
|
795
|
+
const store = this.getDecisionStore();
|
|
796
|
+
const sessionId = this.currentSessionId ?? 'unknown';
|
|
797
|
+
const g0 = Date.now();
|
|
798
|
+
if (!this.helperMiddleware?.deriveRequirementLedger) {
|
|
799
|
+
this.reqLedger = [];
|
|
800
|
+
return [];
|
|
801
|
+
}
|
|
802
|
+
const tmo = mentorSurfaceTimeoutMs('endturn-resolver', parseInt(process.env.CORTEX_ENDTURN_RESOLVER_TIMEOUT_MS ?? '90000', 10));
|
|
803
|
+
try {
|
|
804
|
+
const raw = await withTimeout(this.helperMiddleware.deriveRequirementLedger({ task, envReport: this.gatherEnvReport({ fresh: false }), max: cfg.reqLedgerMax, helperModelId: this.config.reactiveMentorship?.helperModelId }), tmo);
|
|
805
|
+
const lines = parseRequirementLedger(raw ?? '', cfg.reqLedgerMax);
|
|
806
|
+
// a check that is not read-only is dropped (the line stays, unverifiable) — same denylist as every other harness-run check
|
|
807
|
+
let refused = 0;
|
|
808
|
+
const safe = lines.map((l) => (l.check && !isInvestigateCommandAllowed(l.check) ? (refused += 1, { ...l, check: null }) : l));
|
|
809
|
+
this.reqLedger = initLedger(safe);
|
|
810
|
+
this.reqLedgerMeta = { genLatencyMs: Date.now() - g0, raw: (raw ?? '').length, refused };
|
|
811
|
+
}
|
|
812
|
+
catch {
|
|
813
|
+
this.reqLedger = [];
|
|
814
|
+
this.reqLedgerMeta = { genLatencyMs: Date.now() - g0, raw: 0, refused: 0 };
|
|
815
|
+
}
|
|
816
|
+
if (store)
|
|
817
|
+
void store.recordEvent({ sessionId, kind: 'requirement_ledger', toolName: 'EndTurn', detail: { lines: this.reqLedger.map((e) => ({ id: e.id, kind: e.kind, text: e.text, check: e.check })), ...this.reqLedgerMeta, mentor: this.mentorWire('endturn-resolver', cfg.effort, 2000) } }).catch(() => { });
|
|
818
|
+
console.warn(`[EndTurnResolver] R187 REQUIREMENT LEDGER — ${this.reqLedger.length} line(s) (${this.reqLedger.filter((e) => e.check).length} with checks, ${this.reqLedgerMeta.refused} refused) in ${this.reqLedgerMeta.genLatencyMs} ms`);
|
|
819
|
+
return this.reqLedger;
|
|
820
|
+
}
|
|
821
|
+
/** R187: at lift, start authoring the ledger in the background (delivered to the writer by deliverLiftPlanAtLift when ready). */
|
|
822
|
+
maybeAuthorRequirementLedgerAtLift() {
|
|
823
|
+
const cfg = resolveEndTurnResolverConfig();
|
|
824
|
+
if (!cfg.reqLedger || this.reqLedger !== null || this.reqLedgerPromise)
|
|
825
|
+
return;
|
|
826
|
+
if (!resolveEndTurnResolver(process.env))
|
|
827
|
+
return;
|
|
828
|
+
const task = this.lastRealUserText();
|
|
829
|
+
if (!task.trim())
|
|
830
|
+
return;
|
|
831
|
+
this.reqLedgerPromise = this.authorRequirementLedger(task).catch(() => []);
|
|
832
|
+
}
|
|
765
833
|
/** R174b: at lift, start authoring the spec checks in the background so a late first finish still has them. */
|
|
766
834
|
maybeAuthorSpecChecksAtLift() {
|
|
767
835
|
const cfg = resolveEndTurnResolverConfig();
|
|
@@ -872,8 +940,34 @@ export class CortexOrchestrator {
|
|
|
872
940
|
specResults += (specResults ? '\n\n' : '') + x.r + (ev === 'suspect' ? '\n(this check has failed identically at consecutive finishes while everything else passed — treat it as SUSPECT, not as proof of a gap)' : '');
|
|
873
941
|
}
|
|
874
942
|
}
|
|
943
|
+
// R187 HB-REQUIREMENT-LEDGER: run each stated requirement's check; a FAILED line is R166 evidence; an OPEN line (never exercised) can hold once.
|
|
944
|
+
let reqResults = '';
|
|
945
|
+
let reqCounts = { lines: 0, open: 0, exercised: 0, failed: 0, unverifiable: 0 };
|
|
946
|
+
let reqJev = null;
|
|
947
|
+
if (cfg.reqLedger) {
|
|
948
|
+
if (this.reqLedger === null)
|
|
949
|
+
this.reqLedger = await (this.reqLedgerPromise ?? this.authorRequirementLedger(task));
|
|
950
|
+
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) }; });
|
|
951
|
+
this.reqLedger = updateLedger(this.reqLedger, runs);
|
|
952
|
+
// R187b: Jev decides the lines the shell could not — typed per-line questions on the writer's attestation + harness evidence.
|
|
953
|
+
if (cfg.reqLedgerJev && jevAvailable() && this.reqLedger.some((e) => e.status === 'open' || e.status === 'unverifiable')) {
|
|
954
|
+
const j0 = Date.now();
|
|
955
|
+
try {
|
|
956
|
+
const jr = await jevNoul(buildLedgerJevState({ task, entries: this.reqLedger, attestation, workProduct }), buildLedgerJevQuestions(this.reqLedger));
|
|
957
|
+
const applied = applyLedgerJevAnswers(this.reqLedger, jr ? jr.probabilities : null, cfg.reqLedgerJevMin);
|
|
958
|
+
this.reqLedger = applied.entries;
|
|
959
|
+
reqJev = { asked: applied.asked, closed: applied.closed, latencyMs: Date.now() - j0 };
|
|
960
|
+
}
|
|
961
|
+
catch {
|
|
962
|
+
reqJev = { asked: 0, closed: [], latencyMs: Date.now() - j0, error: true };
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
reqCounts = ledgerCounts(this.reqLedger);
|
|
966
|
+
reqResults = formatLedgerForJudge(this.reqLedger);
|
|
967
|
+
}
|
|
875
968
|
const combinedCheck = [checkResult, namedResults ? `JUDGE-NAMED CHECKS (from your previous fix plan; executed by the harness just now):\n${namedResults}` : '',
|
|
876
|
-
specResults ? `SPEC CHECKS (derived from the TASK text before any work was seen; executed by the harness just now — a FAILED one is a requirement not yet met):\n${specResults}` : ''
|
|
969
|
+
specResults ? `SPEC CHECKS (derived from the TASK text before any work was seen; executed by the harness just now — a FAILED one is a requirement not yet met):\n${specResults}` : '', // R174
|
|
970
|
+
reqResults] // R187
|
|
877
971
|
.filter(Boolean).join('\n\n');
|
|
878
972
|
const callsSince = this.turnToolCallTotal - this.toolCallsAtLastVeto;
|
|
879
973
|
const progressed = this.endTurnResolverRejects === 0 || callsSince >= cfg.progressMinCalls || namedPassed > this.judgePriorNamedPassed; // R166a: newly-passing checks, not any passing check
|
|
@@ -999,7 +1093,7 @@ export class CortexOrchestrator {
|
|
|
999
1093
|
}
|
|
1000
1094
|
}
|
|
1001
1095
|
const holdable = gapHoldable({ gapHold: cfg.gapHold, remainingFrac: resolverRemainingFrac, minRemaining: resolveBudgetContinueMinRemaining(), planChars: verdict.plan.length, jevMode: cfg.gapHoldJev, jevFixable, jevMin: cfg.gapHoldJevMin });
|
|
1002
|
-
const checksFailed = namedFailed > 0 || specFailed > 0; // R166 + R174
|
|
1096
|
+
const checksFailed = namedFailed > 0 || specFailed > 0 || reqCounts.failed > 0; // R166 + R174 + R187
|
|
1003
1097
|
// R173c: a re-hold needs real work since the last hold (elapsed time or a changed open-items list), not just tool calls.
|
|
1004
1098
|
const msSinceLastHold = this.lastHoldMs > 0 ? Date.now() - this.lastHoldMs : null;
|
|
1005
1099
|
const holdProg = holdProgressed({ rejects: this.endTurnResolverRejects, msSinceLastHold, priorPlan: this.judgePriorPlan, plan: verdict.plan, minIntervalMs: cfg.gapHoldMinIntervalMs, maxSimilarity: cfg.gapHoldPlanMaxSimilarity });
|
|
@@ -1026,11 +1120,18 @@ export class CortexOrchestrator {
|
|
|
1026
1120
|
// R173c: the budget floor — below CORTEX_JUDGE_VETO_MIN_REMAINING nothing holds the finish (the gap is recorded).
|
|
1027
1121
|
const belowFloor = cfg.vetoMinRemaining > 0 && resolverRemainingFrac !== null && resolverRemainingFrac < cfg.vetoMinRemaining && action === 'veto';
|
|
1028
1122
|
action = applyVetoFloor(action, resolverRemainingFrac, cfg.vetoMinRemaining);
|
|
1123
|
+
// R187: a finish that would otherwise stand while a STATED requirement is still OPEN (its check never passed nor failed — never
|
|
1124
|
+
// exercised) is held once with the open lines named. Never below the budget floor; a FAILED line already went the R166 evidence way.
|
|
1125
|
+
let reqHold = null;
|
|
1126
|
+
if (cfg.reqLedger && this.reqLedger && action !== 'veto' && action !== 'escalate' && !belowFloor &&
|
|
1127
|
+
ledgerHoldable({ open: reqCounts.open, holdsUsed: this.reqLedgerHolds, maxHolds: cfg.reqLedgerHoldMax, remainingFrac: resolverRemainingFrac, minRemaining: cfg.vetoMinRemaining })) {
|
|
1128
|
+
reqHold = { message: formatLedgerHoldMessage({ entries: this.reqLedger, holdIndex: this.reqLedgerHolds + 1, maxHolds: cfg.reqLedgerHoldMax, remainingFrac: resolverRemainingFrac }) };
|
|
1129
|
+
}
|
|
1029
1130
|
// R176 HB-INDEPENDENT-DERIVATION: on a value-shaped task, before a finish that would otherwise STAND, recompute the result by a
|
|
1030
1131
|
// different method and hold ONCE on disagreement. Never below the budget floor; never more than once per turn.
|
|
1031
1132
|
let derivationHold = null;
|
|
1032
1133
|
let derivationInfo = null;
|
|
1033
|
-
if (cfg.derivation === 'on' && action !== 'veto' && action !== 'escalate' && this.derivationHolds < 1 && !belowFloor &&
|
|
1134
|
+
if (cfg.derivation === 'on' && !reqHold && action !== 'veto' && action !== 'escalate' && this.derivationHolds < 1 && !belowFloor &&
|
|
1034
1135
|
!(cfg.vetoMinRemaining > 0 && resolverRemainingFrac !== null && resolverRemainingFrac < cfg.vetoMinRemaining) && this.helperMiddleware.deriveIndependentCheck) {
|
|
1035
1136
|
const shape = isValueShapedTask(task);
|
|
1036
1137
|
derivationInfo = { valueShaped: shape.valueShaped, reason: shape.reason, artifacts: shape.artifacts };
|
|
@@ -1098,6 +1199,7 @@ export class CortexOrchestrator {
|
|
|
1098
1199
|
specTests: cfg.specTests, specChecks: this.specChecks?.length ?? 0, specRan, specPassed, specFailed, specInconclusive, specSuspect, specGenLatencyMs: this.specChecksMeta.genLatencyMs, specTestsAt: cfg.specTestsAt, // R174 / R174b
|
|
1099
1200
|
vetoMinRemaining: cfg.vetoMinRemaining, belowFloor, holdProgressed: holdProg, holdGapMs: msSinceLastHold, planSim: Number(planSimilarity(this.judgePriorPlan, verdict.plan).toFixed(3)), msSinceLastHold, // R173c
|
|
1100
1201
|
derivation: cfg.derivation, derivationAgreement: derivationInfo?.agreement ?? null, derivationHeld: !!derivationHold, // R176
|
|
1202
|
+
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
|
|
1101
1203
|
latencyMs, rawLen: (text ?? '').length,
|
|
1102
1204
|
deltaChars: workspaceDelta.length, checkRan: !!checkResult, checkPassed: checkResult ? /→ PASSED/.test(checkResult) : null,
|
|
1103
1205
|
liftPlanChars: this.liftPlanText.length,
|
|
@@ -1137,10 +1239,20 @@ export class CortexOrchestrator {
|
|
|
1137
1239
|
`${verdict.plan}\n\nDo this, verify against the task's own criteria (not your own tests), then call EndTurn again.` +
|
|
1138
1240
|
(namedResultsNow ? `\n\nHARNESS-RUN CHECKS (named by the reviewer, executed just now — the failing ones are the gap):\n${namedResultsNow.slice(0, 3000)}` : '') + // R166
|
|
1139
1241
|
(specFailed > 0 ? `\n\nSPEC CHECKS (derived from the TASK text before your work was seen, executed just now — a FAILED one is a stated requirement not yet met):\n${specResults.slice(0, 3000)}` : '') + // R174
|
|
1242
|
+
(reqCounts.failed > 0 ? `\n\nREQUIREMENT LEDGER (stated requirements, checked just now — a FAILED line is a stated requirement not yet met):\n${reqResults.slice(0, 3000)}` : '') + // R187
|
|
1140
1243
|
(holdable && !checksFailed ? `\n\nNo harness-run check failed, but the reviewer named open items and budget remains — this hold returns them to you (hold ${this.endTurnResolverRejects}/${resolverCap}).` : '') + // R173
|
|
1141
1244
|
budgetedVetoEscalation(this.endTurnResolverRejects, resolverCap, resolverRemainingMs ?? 0, this.turnDeadlineMsActive); // R160
|
|
1142
1245
|
console.warn(`[EndTurnResolver] GAP — vetoed finish (${verdict.plan.length}-char plan, reject ${this.endTurnResolverRejects}/${resolverCap}${resolverRemainingFrac === null ? '' : `, budget remaining ${Math.round(resolverRemainingFrac * 100)}%`})`);
|
|
1143
1246
|
}
|
|
1247
|
+
else if (reqHold) {
|
|
1248
|
+
// R187: the finish would stand, but a stated requirement was never exercised — hold once with the open lines named.
|
|
1249
|
+
this.reqLedgerHolds += 1;
|
|
1250
|
+
this.lastHoldMs = Date.now();
|
|
1251
|
+
ev.endTurnCalled = false;
|
|
1252
|
+
et.is_error = true;
|
|
1253
|
+
et.content = reqHold.message;
|
|
1254
|
+
console.warn(`[EndTurnResolver] R187 LEDGER-HOLD — finish held (${reqCounts.open} open of ${reqCounts.lines} stated requirements; hold ${this.reqLedgerHolds}/${cfg.reqLedgerHoldMax})`);
|
|
1255
|
+
}
|
|
1144
1256
|
else if (derivationHold) {
|
|
1145
1257
|
// R176: the finish would stand, but an independent recomputation disagrees — hold once with both values shown.
|
|
1146
1258
|
this.derivationHolds += 1;
|
|
@@ -1847,6 +1959,9 @@ export class CortexOrchestrator {
|
|
|
1847
1959
|
if (toolsToUse && toolsToUse.length > 0) {
|
|
1848
1960
|
toolsToUse = this.applyAnchorIfArmed(toolsToUse);
|
|
1849
1961
|
}
|
|
1962
|
+
// R179 engagement evidence: in the terminal frame the offered surface must be FrameAction (+EndTurn) — log it so a silent narrowing is visible.
|
|
1963
|
+
if (frameCfg.frame === 'terminus')
|
|
1964
|
+
console.log(`[Frame] tools offered (${toolsToUse?.length ?? 0}): ${(toolsToUse ?? []).map((t) => t.name).join(', ')}`);
|
|
1850
1965
|
// StructuredOutput (grok-build port): when the caller requested
|
|
1851
1966
|
// schema-constrained output, inject the request-scoped synthetic tool.
|
|
1852
1967
|
// Appended AFTER server-side detection and the deferred filter so it can
|
|
@@ -2133,6 +2248,11 @@ export class CortexOrchestrator {
|
|
|
2133
2248
|
this.specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 };
|
|
2134
2249
|
this.specChecksPromise = null;
|
|
2135
2250
|
this.specFailHistory.clear();
|
|
2251
|
+
this.reqLedger = null;
|
|
2252
|
+
this.reqLedgerPromise = null;
|
|
2253
|
+
this.reqLedgerHolds = 0;
|
|
2254
|
+
this.reqLedgerMeta = { genLatencyMs: 0, raw: 0, refused: 0 };
|
|
2255
|
+
this.reqLedgerDelivered = false;
|
|
2136
2256
|
this.lastHoldMs = 0;
|
|
2137
2257
|
this.derivationHolds = 0; // R165 per-turn / R174 / R173c / R176
|
|
2138
2258
|
this.recordDsmlRecovery(currentAssistantCanonicalMessage);
|
|
@@ -3350,6 +3470,7 @@ export class CortexOrchestrator {
|
|
|
3350
3470
|
await this.deliverDeferredCorpusAtLift(effectiveModel);
|
|
3351
3471
|
this.deliverLiftNudge(allTools, effectiveModel); // A′ proposal-1: SearchTools/AskForAdvice signpost at lift
|
|
3352
3472
|
await this.deliverLiftPlanAtLift(effectiveModel); // LIFT_MENTOR_PLANNER: bounded mentor-planner at lift (dark unless CORTEX_LIFT_PLAN)
|
|
3473
|
+
this.maybeAuthorRequirementLedgerAtLift(); // R187: the stated-requirement ledger, authored in the background at lift
|
|
3353
3474
|
this.maybeAuthorSpecChecksAtLift(); // R174b: blind spec checks authored in the background at lift (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
|
|
3354
3475
|
if (this.config.debug)
|
|
3355
3476
|
console.log('[Anchor] lifted at first tool_result boundary — session profile applies');
|
|
@@ -4160,6 +4281,9 @@ export class CortexOrchestrator {
|
|
|
4160
4281
|
if (toolsToUse && toolsToUse.length > 0) {
|
|
4161
4282
|
toolsToUse = this.applyAnchorIfArmed(toolsToUse);
|
|
4162
4283
|
}
|
|
4284
|
+
// R179 engagement evidence: in the terminal frame the offered surface must be FrameAction (+EndTurn) — log it so a silent narrowing is visible.
|
|
4285
|
+
if (resolveFrameConfig(process.env).frame === 'terminus')
|
|
4286
|
+
console.log(`[Frame] tools offered (${toolsToUse?.length ?? 0}): ${(toolsToUse ?? []).map((t) => t.name).join(', ')}`);
|
|
4163
4287
|
// StructuredOutput (grok-build port) — streaming mirror of the sendMessage
|
|
4164
4288
|
// injection: appended AFTER server-side detection and the deferred filter;
|
|
4165
4289
|
// covers every request of the turn via the shared `toolsToUse` variable
|
|
@@ -4344,6 +4468,11 @@ export class CortexOrchestrator {
|
|
|
4344
4468
|
this.specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 };
|
|
4345
4469
|
this.specChecksPromise = null;
|
|
4346
4470
|
this.specFailHistory.clear();
|
|
4471
|
+
this.reqLedger = null;
|
|
4472
|
+
this.reqLedgerPromise = null;
|
|
4473
|
+
this.reqLedgerHolds = 0;
|
|
4474
|
+
this.reqLedgerMeta = { genLatencyMs: 0, raw: 0, refused: 0 };
|
|
4475
|
+
this.reqLedgerDelivered = false;
|
|
4347
4476
|
this.lastHoldMs = 0;
|
|
4348
4477
|
this.derivationHolds = 0; // R165 per-turn / R174 / R173c / R176
|
|
4349
4478
|
this.recordDsmlRecovery(currentAssistantCanonicalMessage);
|
|
@@ -5144,6 +5273,7 @@ export class CortexOrchestrator {
|
|
|
5144
5273
|
await this.deliverDeferredCorpusAtLift(effectiveModel);
|
|
5145
5274
|
this.deliverLiftNudge(allTools, effectiveModel); // A′ proposal-1: SearchTools/AskForAdvice signpost at lift
|
|
5146
5275
|
await this.deliverLiftPlanAtLift(effectiveModel); // LIFT_MENTOR_PLANNER: bounded mentor-planner at lift (dark unless CORTEX_LIFT_PLAN)
|
|
5276
|
+
this.maybeAuthorRequirementLedgerAtLift(); // R187: the stated-requirement ledger, authored in the background at lift
|
|
5147
5277
|
this.maybeAuthorSpecChecksAtLift(); // R174b: blind spec checks authored in the background at lift (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
|
|
5148
5278
|
if (this.config.debug)
|
|
5149
5279
|
console.log('[Anchor] lifted at first tool_result boundary — session profile applies');
|
|
@@ -5823,7 +5953,7 @@ export class CortexOrchestrator {
|
|
|
5823
5953
|
recordEvent: (kind, detail) => { const st = this.getDecisionStore(); if (st)
|
|
5824
5954
|
void st.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: kind, toolName: FRAME_TOOL_NAME, detail }).catch(() => { }); },
|
|
5825
5955
|
jev: cfg.chooser === 'jev' && jevAvailable() ? async (state, questions) => { const r = await jevNoul(state, questions); return r ? r.probabilities : null; } : undefined,
|
|
5826
|
-
author: cfg.author === 'helper' && this.helperMiddleware ? async (ctx) => this.helperMiddleware.generateFrameCandidates(ctx) : undefined, // R185
|
|
5956
|
+
author: cfg.author === 'helper' && this.helperMiddleware ? async (ctx) => this.helperMiddleware.generateFrameCandidates({ ...ctx, ...(cfg.authorModel ? { helperModelId: cfg.authorModel } : {}) }) : undefined, // R185 (+R186 author model)
|
|
5827
5957
|
});
|
|
5828
5958
|
}
|
|
5829
5959
|
return this.frameRunner;
|