@nexus-cortex/core 4.120.0 → 4.122.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.
- package/.env.defaults +32 -0
- package/dist/config/RuntimeConfigRegistry.d.ts.map +1 -1
- package/dist/config/RuntimeConfigRegistry.js +7 -0
- package/dist/config/RuntimeConfigRegistry.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +7 -0
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/SettingsSchema.d.ts +7 -0
- package/dist/config/SettingsSchema.d.ts.map +1 -1
- package/dist/config/SettingsSchema.js +31 -0
- package/dist/config/SettingsSchema.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +7 -0
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +13 -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 +11 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +159 -37
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/training/DecisionStore.d.ts +1 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/DecisionStore.js.map +1 -1
- package/dist/training/endTurnResolver.d.ts +39 -0
- package/dist/training/endTurnResolver.d.ts.map +1 -1
- package/dist/training/endTurnResolver.js +54 -1
- package/dist/training/endTurnResolver.js.map +1 -1
- package/dist/training/independentDerivation.d.ts +62 -0
- package/dist/training/independentDerivation.d.ts.map +1 -0
- package/dist/training/independentDerivation.js +168 -0
- package/dist/training/independentDerivation.js.map +1 -0
- package/package.json +3 -3
|
@@ -19,8 +19,9 @@ import { join as pathJoin } from 'path';
|
|
|
19
19
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
20
20
|
import { execSync } from 'node:child_process';
|
|
21
21
|
import { ENV_RECON_COMMAND, resolveLiftPlanConfig, parsePlannerResponse } from '../training/liftPlanner.js';
|
|
22
|
-
import { resolveEndTurnResolverConfig, parseResolverVerdict, effectiveMaxRejects, budgetedVetoEscalation, decideVetoAction, shouldFinishConfirm, buildFinishConfirmMessage, buildMeetsConfirmMessage, gapHoldable, parseSpecChecks } from '../training/endTurnResolver.js';
|
|
22
|
+
import { resolveEndTurnResolverConfig, parseResolverVerdict, effectiveMaxRejects, budgetedVetoEscalation, decideVetoAction, shouldFinishConfirm, buildFinishConfirmMessage, buildMeetsConfirmMessage, gapHoldable, parseSpecChecks, applyVetoFloor, holdProgressed, specCheckEvidence } from '../training/endTurnResolver.js';
|
|
23
23
|
import { jevAvailable, jevNoul, buildGapHoldState, GAP_HOLD_QUESTIONS } from '../training/jevGate.js'; // R173b
|
|
24
|
+
import { isValueShapedTask, parseDerivationReply, methodsDiffer, parseValueLines, extractNumbers, reconcile, buildDerivationHoldMessage, isDerivationCommandAllowed } from '../training/independentDerivation.js'; // R176
|
|
24
25
|
import { resolveDeadlineExitConfig, deadlineExitCallBudget, parseDeadlineExitVerdict } from '../training/deadlineExitMentor.js';
|
|
25
26
|
import { isTaskShaped } from './requirementsVerification.js';
|
|
26
27
|
import { extractServerSideMetadata, XAIServerSideTools, OpenAIServerSideTools, toCanonicalTool } from '../tools/ServerSideTools.js';
|
|
@@ -244,6 +245,10 @@ export class CortexOrchestrator {
|
|
|
244
245
|
judgeAdjudicatedThisFinish = false;
|
|
245
246
|
specChecks = null; // R174: blind spec-derived checks authored for this turn (null = not yet)
|
|
246
247
|
specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 }; // R174
|
|
248
|
+
specChecksPromise = null; // R174b: authored at lift in the background (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
|
|
249
|
+
specFailHistory = new Map(); // R174b: consecutive identical spec failures
|
|
250
|
+
lastHoldMs = 0; // R173c: wall clock of the last hold/veto this turn
|
|
251
|
+
derivationHolds = 0; // R176: independent-derivation holds this turn (max 1)
|
|
247
252
|
liftPlanText = ''; // 4.107.0: the PLAN OF ATTACK delivered at lift — handed to the resolver / deadline-exit / loop-exit judges as an advisory anchor
|
|
248
253
|
effectiveDeferredLoading = true; // per-turn resolved deferred-loading (card > env > settings); set at assembly
|
|
249
254
|
/**
|
|
@@ -713,6 +718,59 @@ export class CortexOrchestrator {
|
|
|
713
718
|
}
|
|
714
719
|
}
|
|
715
720
|
}
|
|
721
|
+
/** R176: read the artifact the task names (the agent's deliverable) for reconciliation — direct, bounded, text only;
|
|
722
|
+
* an absolute path outside the workspace is still the task's own file, so it is read rather than refused. */
|
|
723
|
+
readDeliverable(cwd, artifact, maxChars = 1500) {
|
|
724
|
+
try {
|
|
725
|
+
const abs = artifact.startsWith('/') ? artifact : `${cwd}/${artifact}`;
|
|
726
|
+
if (!existsSync(abs))
|
|
727
|
+
return `${artifact}: NOT FOUND`;
|
|
728
|
+
const text = readFileSync(abs, 'utf8');
|
|
729
|
+
return `${artifact}:\n${text.length > maxChars ? text.slice(0, maxChars) + '\n…' : text}`;
|
|
730
|
+
}
|
|
731
|
+
catch (e) {
|
|
732
|
+
return `${artifact}: unreadable (${String(e?.message ?? e).slice(0, 80)})`;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
/** R174/R174b: author the blind spec checks (task text + env report ONLY). Sets specChecks/specChecksMeta; never throws. */
|
|
736
|
+
async authorSpecChecks(task) {
|
|
737
|
+
const cfg = resolveEndTurnResolverConfig();
|
|
738
|
+
const store = this.getDecisionStore();
|
|
739
|
+
const sessionId = this.currentSessionId ?? 'unknown';
|
|
740
|
+
const g0 = Date.now();
|
|
741
|
+
if (!this.helperMiddleware?.deriveSpecChecks) {
|
|
742
|
+
this.specChecks = [];
|
|
743
|
+
return [];
|
|
744
|
+
}
|
|
745
|
+
const specTimeoutMs = mentorSurfaceTimeoutMs('endturn-resolver', parseInt(process.env.CORTEX_ENDTURN_RESOLVER_TIMEOUT_MS ?? '90000', 10));
|
|
746
|
+
try {
|
|
747
|
+
const raw = await withTimeout(this.helperMiddleware.deriveSpecChecks({ task, envReport: this.gatherEnvReport({ fresh: false }), max: cfg.specTestsMax, helperModelId: this.config.reactiveMentorship?.helperModelId }), specTimeoutMs);
|
|
748
|
+
const parsed = parseSpecChecks(raw ?? '', cfg.specTestsMax);
|
|
749
|
+
const allowed = parsed.filter((c) => isInvestigateCommandAllowed(c));
|
|
750
|
+
this.specChecks = allowed;
|
|
751
|
+
this.specChecksMeta = { genLatencyMs: Date.now() - g0, refused: parsed.length - allowed.length, raw: (raw ?? '').length };
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
this.specChecks = [];
|
|
755
|
+
this.specChecksMeta = { genLatencyMs: Date.now() - g0, refused: 0, raw: 0 };
|
|
756
|
+
}
|
|
757
|
+
if (store)
|
|
758
|
+
void store.recordEvent({ sessionId, kind: 'spec_tests', toolName: 'EndTurn', detail: { checks: this.specChecks, ...this.specChecksMeta, at: cfg.specTestsAt, mentor: this.mentorWire('endturn-resolver', cfg.effort, 1200) } }).catch(() => { });
|
|
759
|
+
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)`);
|
|
760
|
+
return this.specChecks;
|
|
761
|
+
}
|
|
762
|
+
/** R174b: at lift, start authoring the spec checks in the background so a late first finish still has them. */
|
|
763
|
+
maybeAuthorSpecChecksAtLift() {
|
|
764
|
+
const cfg = resolveEndTurnResolverConfig();
|
|
765
|
+
if (!cfg.specTests || cfg.specTestsAt !== 'lift' || this.specChecks !== null || this.specChecksPromise)
|
|
766
|
+
return;
|
|
767
|
+
if (!resolveEndTurnResolver(process.env))
|
|
768
|
+
return;
|
|
769
|
+
const task = this.lastRealUserText();
|
|
770
|
+
if (!task.trim())
|
|
771
|
+
return;
|
|
772
|
+
this.specChecksPromise = this.authorSpecChecks(task).catch(() => []);
|
|
773
|
+
}
|
|
716
774
|
async adjudicateEndTurn(ev, toolResults, toolUses, model) {
|
|
717
775
|
if (!resolveEndTurnResolver(process.env, model.endTurnResolver))
|
|
718
776
|
return;
|
|
@@ -788,39 +846,27 @@ export class CortexOrchestrator {
|
|
|
788
846
|
let specPassed = 0;
|
|
789
847
|
let specFailed = 0;
|
|
790
848
|
let specInconclusive = 0;
|
|
849
|
+
let specSuspect = 0;
|
|
791
850
|
let specResults = '';
|
|
792
|
-
if (cfg.specTests
|
|
793
|
-
if (this.specChecks === null)
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
this.specChecksMeta = { genLatencyMs: Date.now() - g0, refused: parsed.length - allowed.length, raw: (raw ?? '').length };
|
|
802
|
-
}
|
|
803
|
-
catch {
|
|
804
|
-
this.specChecks = [];
|
|
805
|
-
this.specChecksMeta = { genLatencyMs: Date.now() - g0, refused: 0, raw: 0 };
|
|
806
|
-
}
|
|
807
|
-
if (store)
|
|
808
|
-
void store.recordEvent({ sessionId, kind: 'spec_tests', toolName: 'EndTurn', detail: { checks: this.specChecks, ...this.specChecksMeta, mentor: this.mentorWire('endturn-resolver', cfg.effort, 1200) } }).catch(() => { });
|
|
809
|
-
console.warn(`[EndTurnResolver] R174 SPEC-TESTS — ${this.specChecks.length} blind check(s) authored in ${this.specChecksMeta.genLatencyMs} ms (${this.specChecksMeta.refused} refused)`);
|
|
810
|
-
}
|
|
811
|
-
for (const c of this.specChecks) {
|
|
812
|
-
const r = runCheck(judgeCwd, c, jcfg);
|
|
851
|
+
if (cfg.specTests) {
|
|
852
|
+
if (this.specChecks === null)
|
|
853
|
+
this.specChecks = await (this.specChecksPromise ?? this.authorSpecChecks(task)); // R174b: lift-authored or now
|
|
854
|
+
// R174b: two passes — classify every check, then apply repeat suppression (a check failing identically at
|
|
855
|
+
// specRepeatMax consecutive adjudications, while no OTHER check failed, is `suspect`: shown, not evidence).
|
|
856
|
+
const runs = this.specChecks.map((c) => { const r = runCheck(judgeCwd, c, jcfg); return { c, r, k: classifyCheckRun(r) }; });
|
|
857
|
+
const failedCmds = runs.filter((x) => x.k === 'failed').map((x) => x.c);
|
|
858
|
+
for (const x of runs) {
|
|
859
|
+
const ev = specCheckEvidence(this.specFailHistory, x.c, x.r, x.k, cfg.specRepeatMax, failedCmds.some((f) => f !== x.c));
|
|
813
860
|
specRan += 1;
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
specResults += (specResults ? '\n\n' : '') + r;
|
|
861
|
+
if (ev === 'passed')
|
|
862
|
+
specPassed += 1;
|
|
863
|
+
else if (ev === 'failed')
|
|
864
|
+
specFailed += 1;
|
|
865
|
+
else if (ev === 'suspect')
|
|
866
|
+
specSuspect += 1;
|
|
867
|
+
else
|
|
868
|
+
specInconclusive += 1;
|
|
869
|
+
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)' : '');
|
|
824
870
|
}
|
|
825
871
|
}
|
|
826
872
|
const combinedCheck = [checkResult, namedResults ? `JUDGE-NAMED CHECKS (from your previous fix plan; executed by the harness just now):\n${namedResults}` : '',
|
|
@@ -951,8 +997,12 @@ export class CortexOrchestrator {
|
|
|
951
997
|
}
|
|
952
998
|
const holdable = gapHoldable({ gapHold: cfg.gapHold, remainingFrac: resolverRemainingFrac, minRemaining: resolveBudgetContinueMinRemaining(), planChars: verdict.plan.length, jevMode: cfg.gapHoldJev, jevFixable, jevMin: cfg.gapHoldJevMin });
|
|
953
999
|
const checksFailed = namedFailed > 0 || specFailed > 0; // R166 + R174
|
|
1000
|
+
// R173c: a re-hold needs real work since the last hold (elapsed time or a changed open-items list), not just tool calls.
|
|
1001
|
+
const msSinceLastHold = this.lastHoldMs > 0 ? Date.now() - this.lastHoldMs : null;
|
|
1002
|
+
const holdProg = holdProgressed({ rejects: this.endTurnResolverRejects, msSinceLastHold, priorPlan: this.judgePriorPlan, plan: verdict.plan, minIntervalMs: cfg.gapHoldMinIntervalMs, maxSimilarity: cfg.gapHoldPlanMaxSimilarity });
|
|
1003
|
+
const progressedForHold = holdable ? (progressed && holdProg) : progressed;
|
|
954
1004
|
let action = cfg.semantic
|
|
955
|
-
? decideVetoAction({ meets: verdict.meets, blank: verdict.blank, retire: verdict.retire && cfg.abstain, confidence: verdict.confidence, rejects: this.endTurnResolverRejects, cap: resolverCap, progressed, escalated: this.judgeEscalated, checksFailed, vetoMode: cfg.vetoMode, evidenceCap: cfg.evidenceCap, gapHoldable: holdable })
|
|
1005
|
+
? decideVetoAction({ meets: verdict.meets, blank: verdict.blank, retire: verdict.retire && cfg.abstain, confidence: verdict.confidence, rejects: this.endTurnResolverRejects, cap: resolverCap, progressed: progressedForHold, escalated: this.judgeEscalated, checksFailed, vetoMode: cfg.vetoMode, evidenceCap: cfg.evidenceCap, gapHoldable: holdable })
|
|
956
1006
|
: (verdict.blank || (verdict.retire && cfg.abstain) || verdict.meets || !verdict.plan ? 'accept' : 'veto');
|
|
957
1007
|
if (action === 'escalate') {
|
|
958
1008
|
// R165: the junior re-attested without working the plan — one thinking-on adjudication before we accept with the gap recorded.
|
|
@@ -966,10 +1016,60 @@ export class CortexOrchestrator {
|
|
|
966
1016
|
verdict = v2;
|
|
967
1017
|
}
|
|
968
1018
|
}
|
|
969
|
-
action = decideVetoAction({ meets: verdict.meets, blank: verdict.blank, retire: verdict.retire && cfg.abstain, confidence: verdict.confidence, rejects: this.endTurnResolverRejects, cap: resolverCap, progressed, escalated: true, checksFailed, vetoMode: cfg.vetoMode, evidenceCap: cfg.evidenceCap, gapHoldable: holdable });
|
|
1019
|
+
action = decideVetoAction({ meets: verdict.meets, blank: verdict.blank, retire: verdict.retire && cfg.abstain, confidence: verdict.confidence, rejects: this.endTurnResolverRejects, cap: resolverCap, progressed: progressedForHold, escalated: true, checksFailed, vetoMode: cfg.vetoMode, evidenceCap: cfg.evidenceCap, gapHoldable: holdable });
|
|
970
1020
|
if (action === 'escalate')
|
|
971
1021
|
action = 'accept-with-gap';
|
|
972
1022
|
}
|
|
1023
|
+
// R173c: the budget floor — below CORTEX_JUDGE_VETO_MIN_REMAINING nothing holds the finish (the gap is recorded).
|
|
1024
|
+
const belowFloor = cfg.vetoMinRemaining > 0 && resolverRemainingFrac !== null && resolverRemainingFrac < cfg.vetoMinRemaining && action === 'veto';
|
|
1025
|
+
action = applyVetoFloor(action, resolverRemainingFrac, cfg.vetoMinRemaining);
|
|
1026
|
+
// R176 HB-INDEPENDENT-DERIVATION: on a value-shaped task, before a finish that would otherwise STAND, recompute the result by a
|
|
1027
|
+
// different method and hold ONCE on disagreement. Never below the budget floor; never more than once per turn.
|
|
1028
|
+
let derivationHold = null;
|
|
1029
|
+
let derivationInfo = null;
|
|
1030
|
+
if (cfg.derivation === 'on' && action !== 'veto' && action !== 'escalate' && this.derivationHolds < 1 && !belowFloor &&
|
|
1031
|
+
!(cfg.vetoMinRemaining > 0 && resolverRemainingFrac !== null && resolverRemainingFrac < cfg.vetoMinRemaining) && this.helperMiddleware.deriveIndependentCheck) {
|
|
1032
|
+
const shape = isValueShapedTask(task);
|
|
1033
|
+
derivationInfo = { valueShaped: shape.valueShaped, reason: shape.reason, artifacts: shape.artifacts };
|
|
1034
|
+
if (shape.valueShaped) {
|
|
1035
|
+
const d0 = Date.now();
|
|
1036
|
+
try {
|
|
1037
|
+
const deliverable = shape.artifacts.map((a) => this.readDeliverable(judgeCwd, a)).join('\n\n');
|
|
1038
|
+
const raw = await withTimeout(this.helperMiddleware.deriveIndependentCheck({ task, deliverable: `${deliverable}\n\nAGENT FINAL MESSAGE:\n${this.lastAssistantText().slice(0, 2000)}`, agentSummary: attestation, envReport: this.gatherEnvReport({ fresh: false }), values: [], helperModelId: this.config.reactiveMentorship?.helperModelId }), timeoutMs);
|
|
1039
|
+
const plan = parseDerivationReply(raw ?? '', 3);
|
|
1040
|
+
const allowed = plan.checks.filter((c) => isDerivationCommandAllowed(c, isInvestigateCommandAllowed));
|
|
1041
|
+
const refusedCmds = plan.checks.filter((c) => !allowed.includes(c)).map((c) => c.slice(0, 200));
|
|
1042
|
+
const derived = {};
|
|
1043
|
+
const outputs = [];
|
|
1044
|
+
for (const c of allowed) {
|
|
1045
|
+
const r = runCheck(judgeCwd, c, jcfg);
|
|
1046
|
+
outputs.push(r);
|
|
1047
|
+
Object.assign(derived, parseValueLines(r));
|
|
1048
|
+
}
|
|
1049
|
+
// Fallback when the author printed values without the `VALUE name=` contract: take the LAST few numbers each check printed
|
|
1050
|
+
// and require that at least one matches the deliverable — conservative (a disagreement needs every printed number to miss).
|
|
1051
|
+
let fallback = false;
|
|
1052
|
+
if (!Object.keys(derived).length && outputs.length) {
|
|
1053
|
+
const tail = outputs.flatMap((o) => extractNumbers(o.split('\n').slice(1).join('\n')).slice(-3));
|
|
1054
|
+
tail.slice(-6).forEach((v, i) => { derived[`printed${i + 1}`] = String(v); });
|
|
1055
|
+
fallback = tail.length > 0;
|
|
1056
|
+
}
|
|
1057
|
+
let rec = reconcile(`${deliverable}\n${this.lastAssistantText()}`, derived, cfg.derivationTol);
|
|
1058
|
+
if (fallback && rec.compared.some((c) => c.matched !== null))
|
|
1059
|
+
rec = { ...rec, agreement: 'agree' };
|
|
1060
|
+
const differ = methodsDiffer(plan.methodAgent, plan.methodIndependent);
|
|
1061
|
+
derivationInfo = { ...derivationInfo, methodAgent: plan.methodAgent, methodIndependent: plan.methodIndependent, methodsDiffer: differ, checks: allowed.length, refused: refusedCmds.length, refusedCmds, fallback, checkOutputs: outputs.map((o) => o.slice(0, 600)), derived, agreement: rec.agreement, compared: rec.compared, latencyMs: Date.now() - d0 };
|
|
1062
|
+
if (rec.agreement === 'disagree' && differ)
|
|
1063
|
+
derivationHold = { message: buildDerivationHoldMessage({ methodIndependent: plan.methodIndependent, compared: rec.compared, remainingFrac: resolverRemainingFrac }) };
|
|
1064
|
+
console.warn(`[EndTurnResolver] R176 DERIVATION — ${rec.agreement} (${allowed.length} check(s), methodsDiffer=${differ}) in ${Date.now() - d0} ms`);
|
|
1065
|
+
}
|
|
1066
|
+
catch (e) {
|
|
1067
|
+
derivationInfo = { ...derivationInfo, error: String(e?.message ?? e).slice(0, 120) };
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (store)
|
|
1071
|
+
void store.recordEvent({ sessionId, kind: 'independent_derivation', toolName: 'EndTurn', detail: { ...derivationInfo, held: !!derivationHold, remainingFrac: resolverRemainingFrac } }).catch(() => { });
|
|
1072
|
+
}
|
|
973
1073
|
this.judgeAdjudicatedThisFinish = verdict.parsed;
|
|
974
1074
|
const latencyMs = Date.now() - t0;
|
|
975
1075
|
// OBSERVABILITY (resolver-AB follow-up, 2026-09-05): bank the TEXT the resolver produced +
|
|
@@ -990,7 +1090,9 @@ export class CortexOrchestrator {
|
|
|
990
1090
|
vetoMode: cfg.vetoMode, evidenceCap: cfg.evidenceCap, namedRanNow, namedInconclusive, // R166 / R166b
|
|
991
1091
|
toolRounds: cfg.toolRounds, roundsUsed, investigateChecks, investigateReads, investigateRefused, autoLooped, toolAutoLoop: cfg.toolAutoLoop, roundLatencyMs, evidenceChars: evidenceRounds.join('').length, // R170 / R170b
|
|
992
1092
|
gapHold: cfg.gapHold, gapHoldable: holdable, jevMode: cfg.gapHoldJev, jevFixable, jevLatencyMs, // R173 / R173b
|
|
993
|
-
specTests: cfg.specTests, specChecks: this.specChecks?.length ?? 0, specRan, specPassed, specFailed, specInconclusive, specGenLatencyMs: this.specChecksMeta.genLatencyMs, // R174
|
|
1093
|
+
specTests: cfg.specTests, specChecks: this.specChecks?.length ?? 0, specRan, specPassed, specFailed, specInconclusive, specSuspect, specGenLatencyMs: this.specChecksMeta.genLatencyMs, specTestsAt: cfg.specTestsAt, // R174 / R174b
|
|
1094
|
+
vetoMinRemaining: cfg.vetoMinRemaining, belowFloor, holdProgressed: holdProg, msSinceLastHold, // R173c
|
|
1095
|
+
derivation: cfg.derivation, derivationAgreement: derivationInfo?.agreement ?? null, derivationHeld: !!derivationHold, // R176
|
|
994
1096
|
latencyMs, rawLen: (text ?? '').length,
|
|
995
1097
|
deltaChars: workspaceDelta.length, checkRan: !!checkResult, checkPassed: checkResult ? /→ PASSED/.test(checkResult) : null,
|
|
996
1098
|
liftPlanChars: this.liftPlanText.length,
|
|
@@ -1016,6 +1118,7 @@ export class CortexOrchestrator {
|
|
|
1016
1118
|
}
|
|
1017
1119
|
else if (action === 'veto') {
|
|
1018
1120
|
this.endTurnResolverRejects += 1;
|
|
1121
|
+
this.lastHoldMs = Date.now(); // R173c
|
|
1019
1122
|
ev.endTurnCalled = false; // VETO the finish
|
|
1020
1123
|
if (cfg.semantic) {
|
|
1021
1124
|
this.judgeNamedChecks = verdict.checks;
|
|
@@ -1033,6 +1136,15 @@ export class CortexOrchestrator {
|
|
|
1033
1136
|
budgetedVetoEscalation(this.endTurnResolverRejects, resolverCap, resolverRemainingMs ?? 0, this.turnDeadlineMsActive); // R160
|
|
1034
1137
|
console.warn(`[EndTurnResolver] GAP — vetoed finish (${verdict.plan.length}-char plan, reject ${this.endTurnResolverRejects}/${resolverCap}${resolverRemainingFrac === null ? '' : `, budget remaining ${Math.round(resolverRemainingFrac * 100)}%`})`);
|
|
1035
1138
|
}
|
|
1139
|
+
else if (derivationHold) {
|
|
1140
|
+
// R176: the finish would stand, but an independent recomputation disagrees — hold once with both values shown.
|
|
1141
|
+
this.derivationHolds += 1;
|
|
1142
|
+
this.lastHoldMs = Date.now();
|
|
1143
|
+
ev.endTurnCalled = false;
|
|
1144
|
+
et.is_error = true;
|
|
1145
|
+
et.content = derivationHold.message;
|
|
1146
|
+
console.warn(`[EndTurnResolver] R176 DERIVATION-HOLD — finish held once on a disagreeing independent recomputation`);
|
|
1147
|
+
}
|
|
1036
1148
|
else if ((action === 'accept-with-gap' || action === 'accept-low-confidence') &&
|
|
1037
1149
|
shouldFinishConfirm({ action, remainingFrac: resolverRemainingFrac, confirmsUsed: this.finishConfirms, cfg })) {
|
|
1038
1150
|
// R167 HB-FINISH-CONFIRM: the judge would accept with a gap and budget remains — hold ONCE with an informed
|
|
@@ -2010,7 +2122,11 @@ export class CortexOrchestrator {
|
|
|
2010
2122
|
this.judgeEscalated = false;
|
|
2011
2123
|
this.judgeAdjudicatedThisFinish = false;
|
|
2012
2124
|
this.specChecks = null;
|
|
2013
|
-
this.specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 };
|
|
2125
|
+
this.specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 };
|
|
2126
|
+
this.specChecksPromise = null;
|
|
2127
|
+
this.specFailHistory.clear();
|
|
2128
|
+
this.lastHoldMs = 0;
|
|
2129
|
+
this.derivationHolds = 0; // R165 per-turn / R174 / R173c / R176
|
|
2014
2130
|
this.recordDsmlRecovery(currentAssistantCanonicalMessage);
|
|
2015
2131
|
let toolCallIteration = 0;
|
|
2016
2132
|
// R137 HB-POLL-REPEAT-BREAKER: the exact-repeat breaker used to force-exit by overwriting
|
|
@@ -3226,6 +3342,7 @@ export class CortexOrchestrator {
|
|
|
3226
3342
|
await this.deliverDeferredCorpusAtLift(effectiveModel);
|
|
3227
3343
|
this.deliverLiftNudge(allTools, effectiveModel); // A′ proposal-1: SearchTools/AskForAdvice signpost at lift
|
|
3228
3344
|
await this.deliverLiftPlanAtLift(effectiveModel); // LIFT_MENTOR_PLANNER: bounded mentor-planner at lift (dark unless CORTEX_LIFT_PLAN)
|
|
3345
|
+
this.maybeAuthorSpecChecksAtLift(); // R174b: blind spec checks authored in the background at lift (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
|
|
3229
3346
|
if (this.config.debug)
|
|
3230
3347
|
console.log('[Anchor] lifted at first tool_result boundary — session profile applies');
|
|
3231
3348
|
}
|
|
@@ -4215,7 +4332,11 @@ export class CortexOrchestrator {
|
|
|
4215
4332
|
this.judgeEscalated = false;
|
|
4216
4333
|
this.judgeAdjudicatedThisFinish = false;
|
|
4217
4334
|
this.specChecks = null;
|
|
4218
|
-
this.specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 };
|
|
4335
|
+
this.specChecksMeta = { genLatencyMs: 0, refused: 0, raw: 0 };
|
|
4336
|
+
this.specChecksPromise = null;
|
|
4337
|
+
this.specFailHistory.clear();
|
|
4338
|
+
this.lastHoldMs = 0;
|
|
4339
|
+
this.derivationHolds = 0; // R165 per-turn / R174 / R173c / R176
|
|
4219
4340
|
this.recordDsmlRecovery(currentAssistantCanonicalMessage);
|
|
4220
4341
|
const assistantMessageId = currentAssistantCanonicalMessage.uuid;
|
|
4221
4342
|
const assistantMessage = {
|
|
@@ -5014,6 +5135,7 @@ export class CortexOrchestrator {
|
|
|
5014
5135
|
await this.deliverDeferredCorpusAtLift(effectiveModel);
|
|
5015
5136
|
this.deliverLiftNudge(allTools, effectiveModel); // A′ proposal-1: SearchTools/AskForAdvice signpost at lift
|
|
5016
5137
|
await this.deliverLiftPlanAtLift(effectiveModel); // LIFT_MENTOR_PLANNER: bounded mentor-planner at lift (dark unless CORTEX_LIFT_PLAN)
|
|
5138
|
+
this.maybeAuthorSpecChecksAtLift(); // R174b: blind spec checks authored in the background at lift (CORTEX_JUDGE_SPEC_TESTS_AT=lift)
|
|
5017
5139
|
if (this.config.debug)
|
|
5018
5140
|
console.log('[Anchor] lifted at first tool_result boundary — session profile applies');
|
|
5019
5141
|
}
|