loopforge 3.7.0 → 3.7.1
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/LICENSE +21 -21
- package/README.md +17 -5
- package/dist/canonical-state.d.ts +23 -2
- package/dist/canonical-state.d.ts.map +1 -1
- package/dist/canonical-state.js +148 -27
- package/dist/canonical-state.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -8
- package/dist/cli.js.map +1 -1
- package/dist/cognitive-facts.d.ts.map +1 -1
- package/dist/cognitive-facts.js +2 -3
- package/dist/cognitive-facts.js.map +1 -1
- package/dist/cognitive-governance.d.ts +30 -6
- package/dist/cognitive-governance.d.ts.map +1 -1
- package/dist/cognitive-governance.js +74 -18
- package/dist/cognitive-governance.js.map +1 -1
- package/dist/committed-round.d.ts +7 -4
- package/dist/committed-round.d.ts.map +1 -1
- package/dist/committed-round.js +48 -8
- package/dist/committed-round.js.map +1 -1
- package/dist/enforcement-gate.d.ts +24 -19
- package/dist/enforcement-gate.d.ts.map +1 -1
- package/dist/enforcement-gate.js +100 -20
- package/dist/enforcement-gate.js.map +1 -1
- package/dist/engine.d.ts +10 -5
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +50 -30
- package/dist/engine.js.map +1 -1
- package/dist/evidence-provider.d.ts +7 -2
- package/dist/evidence-provider.d.ts.map +1 -1
- package/dist/evidence-provider.js +54 -9
- package/dist/evidence-provider.js.map +1 -1
- package/dist/generate-schema.js +104 -43
- package/dist/generate-schema.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/loop-compiler.d.ts +18 -4
- package/dist/loop-compiler.d.ts.map +1 -1
- package/dist/loop-compiler.js +167 -83
- package/dist/loop-compiler.js.map +1 -1
- package/dist/mcp/round-lifecycle.d.ts +10 -0
- package/dist/mcp/round-lifecycle.d.ts.map +1 -1
- package/dist/mcp/round-lifecycle.js +126 -17
- package/dist/mcp/round-lifecycle.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +12 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session.d.ts +32 -2
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +166 -50
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +169 -38
- package/dist/mcp/tools.js.map +1 -1
- package/dist/policy.d.ts +10 -2
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +3 -2
- package/dist/policy.js.map +1 -1
- package/dist/prompt-assembler.d.ts +6 -1
- package/dist/prompt-assembler.d.ts.map +1 -1
- package/dist/prompt-assembler.js +41 -48
- package/dist/prompt-assembler.js.map +1 -1
- package/dist/protocol.d.ts +47 -27
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +5 -6
- package/dist/protocol.js.map +1 -1
- package/dist/round-coordinator.d.ts +19 -0
- package/dist/round-coordinator.d.ts.map +1 -1
- package/dist/round-coordinator.js +62 -4
- package/dist/round-coordinator.js.map +1 -1
- package/dist/round-driver.d.ts +4 -0
- package/dist/round-driver.d.ts.map +1 -1
- package/dist/round-driver.js +2 -0
- package/dist/round-driver.js.map +1 -1
- package/dist/round-transaction.d.ts +4 -0
- package/dist/round-transaction.d.ts.map +1 -1
- package/dist/round-transaction.js +9 -0
- package/dist/round-transaction.js.map +1 -1
- package/dist/self-eval.d.ts +41 -3
- package/dist/self-eval.d.ts.map +1 -1
- package/dist/self-eval.js +125 -13
- package/dist/self-eval.js.map +1 -1
- package/dist/verification-gate.d.ts +14 -16
- package/dist/verification-gate.d.ts.map +1 -1
- package/dist/verification-gate.js +162 -93
- package/dist/verification-gate.js.map +1 -1
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/loop_policy.json +19 -3
- package/package.json +7 -7
- package/skills/perception/SKILL.md +53 -15
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** LoopForge — Cognitive State Runtime for AI coding agents.
|
|
2
2
|
*
|
|
3
|
-
* TypeScript reference implementation
|
|
3
|
+
* TypeScript reference implementation. Version is single-sourced from
|
|
4
|
+
* package.json (see src/version.ts).
|
|
4
5
|
*
|
|
5
6
|
* Usage:
|
|
6
7
|
* import { LoopForgeEngine, ReplayBackend, compileLoop } from "loopforge";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** LoopForge — Cognitive State Runtime for AI coding agents.
|
|
2
2
|
*
|
|
3
|
-
* TypeScript reference implementation
|
|
3
|
+
* TypeScript reference implementation. Version is single-sourced from
|
|
4
|
+
* package.json (see src/version.ts).
|
|
4
5
|
*
|
|
5
6
|
* Usage:
|
|
6
7
|
* import { LoopForgeEngine, ReplayBackend, compileLoop } from "loopforge";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,iBAAiB;AACjB,OAAO,EACL,IAAI,EACJ,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,kBAAkB,GACnB,MAAM,eAAe,CAAC;AA4BvB,SAAS;AACT,OAAO,EACL,SAAS,EACT,UAAU,EACV,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC;AAerB,gBAAgB;AAChB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAQzB,gBAAgB;AAChB,OAAO,EACL,WAAW,EACX,WAAW,EACX,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,SAAS;AACT,OAAO,EACL,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAMrB,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,2BAA2B;AAC3B,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,aAAa,EACb,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAWhC,8DAA8D;AAC9D,OAAO,EACL,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAG7B,oCAAoC;AACpC,OAAO,EACL,gCAAgC,EAChC,2BAA2B,EAC3B,WAAW,EACX,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC"}
|
package/dist/loop-compiler.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* The compiler evolves structured state and renders one prompt artifact.
|
|
4
4
|
* L0/L1/L2 control state density only; the external Agent owns reasoning.
|
|
5
5
|
*/
|
|
6
|
-
import { type CriterionStatus, type Lesson, type LoopCompileRequest, type LoopCompileResponse, type LoopHealth, type LoopObjective, type LoopRoundResult, type RollingSummary, type SubGoal, type TaskAlignment, type VerificationFlag } from "./protocol.js";
|
|
6
|
+
import { type CriterionStatus, type Lesson, type LoopCompileRequest, type LoopCompileResponse, type LoopHealth, type LoopObjective, type LoopRoundResult, type RollingSummary, type SubGoal, type SubGoalUpdate, type TaskAlignment, type VerificationFlag } from "./protocol.js";
|
|
7
7
|
import type { PresentedStateSnapshot } from "./canonical-state.js";
|
|
8
8
|
export interface PreviousRound {
|
|
9
9
|
round: number;
|
|
@@ -50,20 +50,34 @@ export declare function deriveConstraintId(text: string): string;
|
|
|
50
50
|
/** v2.11: Derive a stable criterion ID from its text hash (cr-XXXXXXXX).
|
|
51
51
|
* Same hash strategy as SubGoal — deterministic across rounds. */
|
|
52
52
|
export declare function deriveCriterionId(text: string): string;
|
|
53
|
+
/** Closed migration matrix. done/canceled are terminal (no out-edges); the
|
|
54
|
+
* matrix rejects re-opening. blocked → in_progress is the recovery path. */
|
|
55
|
+
export declare const SUBGOAL_TRANSITIONS: Record<SubGoalUpdate["status"], readonly SubGoal["status"][]>;
|
|
56
|
+
/** Whether a transition is legal. Same-status is a legal no-op (used by
|
|
57
|
+
* replay idempotency). References to terminal sub-goals are rejected by
|
|
58
|
+
* validateSubGoalUpdates before this is consulted. */
|
|
59
|
+
export declare function canTransitionSubGoal(from: SubGoal["status"], to: SubGoalUpdate["status"]): boolean;
|
|
60
|
+
/** Referential validation of a payload's subgoal_updates against the
|
|
61
|
+
* derived sub-goal set. Returns one error per invalid entry:
|
|
62
|
+
* unknown_id | terminal_reference | illegal_transition. */
|
|
63
|
+
export declare function validateSubGoalUpdates(subGoals: SubGoal[], updates: SubGoalUpdate[]): Array<{
|
|
64
|
+
id: string;
|
|
65
|
+
reason: string;
|
|
66
|
+
}>;
|
|
53
67
|
export declare function alignTask(proposedTask: string, request: LoopCompileRequest, context: Record<string, unknown> | null): TaskAlignment;
|
|
54
68
|
export declare function checkLoopHealth(loopId: string, request: LoopCompileRequest, context: Record<string, unknown> | null): LoopHealth;
|
|
55
69
|
export declare function decideLevel(request: LoopCompileRequest, context: Record<string, unknown> | null): "l0" | "l1" | "l2";
|
|
56
|
-
export declare function buildSelfEvalBlock(round: number, prevDriftFlags?: VerificationFlag[],
|
|
70
|
+
export declare function buildSelfEvalBlock(round: number, prevDriftFlags?: VerificationFlag[],
|
|
57
71
|
/** v2.12: L0 is the minimal retry template — the v2.12 declarative fields
|
|
58
72
|
* (outcome/blocker/retroactiveClaims) are L1/L2 additions so the retry
|
|
59
73
|
* prompt stays within its tight budget. */
|
|
60
|
-
level?: "l0" | "l1" | "l2",
|
|
74
|
+
level?: "l0" | "l1" | "l2",
|
|
61
75
|
/** v3.3/v3.4: Whether this round's Current Task IS the ACTIVE Round
|
|
62
76
|
* Contract (derived from committed rounds — compileLoop passes
|
|
63
77
|
* `activeContract != null`). Only then does the template ask the agent
|
|
64
78
|
* to restate/propose it — a generic empty contract template would invite
|
|
65
79
|
* placeholder submissions that trigger round_underspecified noise. */
|
|
66
|
-
hasContract?: boolean,
|
|
80
|
+
hasContract?: boolean,
|
|
67
81
|
/** v3.5: L2-only prose suggesting a Round Contract declaration when the
|
|
68
82
|
* Current Task is NOT one (contract_nudge_on_l2 policy, computed at the
|
|
69
83
|
* compileLoop call site). Mutually exclusive with hasContract. The prose
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop-compiler.d.ts","sourceRoot":"","sources":["../src/loop-compiler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAWL,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,eAAe,EAEpB,KAAK,cAAc,EAEnB,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAKvB,OAAO,KAAK,EAAiB,sBAAsB,EAAa,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"loop-compiler.d.ts","sourceRoot":"","sources":["../src/loop-compiler.ts"],"names":[],"mappings":"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"}
|
package/dist/loop-compiler.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createHash } from "node:crypto";
|
|
|
7
7
|
import { getPolicy } from "./policy.js";
|
|
8
8
|
import { AgentStatus, makeLoopCompileResponse, makeLoopHealth, makeLoopObjective, makeConstraintMeta, makeMilestoneSummary, makeRollingSummary, makeSubGoal, makeTaskAlignment, } from "./protocol.js";
|
|
9
9
|
import { createCanonicalLoopState, renderCanonicalStateMarkdown, } from "./canonical-state.js";
|
|
10
|
-
import { decodeRound, entryLineage, entryCriteriaMet, entryCriteriaRemaining, entryActiveConstraints, entryRetractedConstraints, entryProgressEstimate, entryEmergedSubtasks, machineGitMotionSeries, mergedRoundsFromEntries, } from "./committed-round.js";
|
|
10
|
+
import { decodeRound, entryLineage, entryCriteriaMet, entryCriteriaRemaining, entryActiveConstraints, entryRetractedConstraints, entryProgressEstimate, entryEmergedSubtasks, entrySubGoalUpdates, machineGitMotionSeries, mergedRoundsFromEntries, } from "./committed-round.js";
|
|
11
11
|
import { contractRoundEvaluations, deriveActiveRoundContract, } from "./round-contract.js";
|
|
12
12
|
import { assemblePromptArtifact } from "./prompt-assembler.js";
|
|
13
13
|
import { decidePromptLevel, } from "./prompt-policy.js";
|
|
@@ -144,9 +144,16 @@ function evolveObjective(request, context) {
|
|
|
144
144
|
let version = current.version ?? 1;
|
|
145
145
|
if (last?.objective_refinement?.trim()) {
|
|
146
146
|
const refinement = last.objective_refinement.trim();
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
// M5: fold each refinement exactly once per persisted objective state.
|
|
148
|
+
// A retry recompiles the same round against the same committed
|
|
149
|
+
// last_round_result; without this guard every retry attempt re-appends
|
|
150
|
+
// the refinement and inflates the version — the objective text and the
|
|
151
|
+
// state file grew "Refinement: X" once per attempt.
|
|
152
|
+
if (!history.includes(refinement)) {
|
|
153
|
+
history.push(refinement);
|
|
154
|
+
objective = `${objective}\nRefinement: ${refinement}`;
|
|
155
|
+
version++;
|
|
156
|
+
}
|
|
150
157
|
}
|
|
151
158
|
const revisions = new Map((last?.revised_success_criteria ?? []).map((item) => [item.old, item.new]));
|
|
152
159
|
return makeLoopObjective({
|
|
@@ -609,11 +616,10 @@ function isCriterionId(ref) {
|
|
|
609
616
|
return /^cr-[a-f0-9]{8}$/.test(ref);
|
|
610
617
|
}
|
|
611
618
|
/**
|
|
612
|
-
* Match a user-provided
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
* of the best-matching SubGoal, or -1 when no match reaches threshold.
|
|
619
|
+
* Match a user-provided description against existing SubGoals for DEDUP
|
|
620
|
+
* (emerged_subtasks creation). Exact ID first, then Jaccard similarity on
|
|
621
|
+
* descriptions. v3.7.1: status transitions no longer use this — they are
|
|
622
|
+
* strict ID references validated before the round advances.
|
|
617
623
|
*/
|
|
618
624
|
function matchSubGoal(target, subGoals, threshold) {
|
|
619
625
|
const trimmed = target.trim();
|
|
@@ -634,34 +640,90 @@ function matchSubGoal(target, subGoals, threshold) {
|
|
|
634
640
|
}
|
|
635
641
|
return bestScore >= threshold ? bestIdx : -1;
|
|
636
642
|
}
|
|
643
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
644
|
+
// Sub-goal transition matrix (v3.7.1 — single source)
|
|
645
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
646
|
+
/** Closed migration matrix. done/canceled are terminal (no out-edges); the
|
|
647
|
+
* matrix rejects re-opening. blocked → in_progress is the recovery path. */
|
|
648
|
+
export const SUBGOAL_TRANSITIONS = {
|
|
649
|
+
in_progress: ["pending", "blocked"],
|
|
650
|
+
done: ["pending", "in_progress", "blocked"],
|
|
651
|
+
blocked: ["pending", "in_progress"],
|
|
652
|
+
canceled: ["pending", "in_progress", "blocked"],
|
|
653
|
+
};
|
|
654
|
+
/** Whether a transition is legal. Same-status is a legal no-op (used by
|
|
655
|
+
* replay idempotency). References to terminal sub-goals are rejected by
|
|
656
|
+
* validateSubGoalUpdates before this is consulted. */
|
|
657
|
+
export function canTransitionSubGoal(from, to) {
|
|
658
|
+
if (from === to)
|
|
659
|
+
return true;
|
|
660
|
+
return SUBGOAL_TRANSITIONS[to].includes(from);
|
|
661
|
+
}
|
|
662
|
+
/** Referential validation of a payload's subgoal_updates against the
|
|
663
|
+
* derived sub-goal set. Returns one error per invalid entry:
|
|
664
|
+
* unknown_id | terminal_reference | illegal_transition. */
|
|
665
|
+
export function validateSubGoalUpdates(subGoals, updates) {
|
|
666
|
+
const byId = new Map(subGoals.map((sg) => [sg.id, sg]));
|
|
667
|
+
const errors = [];
|
|
668
|
+
for (const update of updates) {
|
|
669
|
+
const target = byId.get(update.id);
|
|
670
|
+
if (!target) {
|
|
671
|
+
errors.push({ id: update.id, reason: "unknown_id" });
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (target.status === "done" || target.status === "canceled") {
|
|
675
|
+
errors.push({ id: update.id, reason: "terminal_reference" });
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (!canTransitionSubGoal(target.status, update.status)) {
|
|
679
|
+
errors.push({ id: update.id, reason: "illegal_transition" });
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return errors;
|
|
683
|
+
}
|
|
684
|
+
/** Apply one transition to the accumulated list. Guards make replay of
|
|
685
|
+
* committed history idempotent: terminal sub-goals never change and
|
|
686
|
+
* same-status updates are no-ops. */
|
|
687
|
+
function applySubGoalUpdate(subGoals, update, rnd) {
|
|
688
|
+
const target = subGoals.find((sg) => sg.id === update.id);
|
|
689
|
+
if (!target)
|
|
690
|
+
return;
|
|
691
|
+
if (target.status === "done" || target.status === "canceled")
|
|
692
|
+
return;
|
|
693
|
+
if (!canTransitionSubGoal(target.status, update.status))
|
|
694
|
+
return;
|
|
695
|
+
if (target.status === update.status)
|
|
696
|
+
return;
|
|
697
|
+
target.status = update.status;
|
|
698
|
+
target.status_changed_at_round = rnd;
|
|
699
|
+
if (update.status === "done")
|
|
700
|
+
target.completed_at_round = rnd;
|
|
701
|
+
}
|
|
637
702
|
/**
|
|
638
703
|
* Manage the full sub-goal lifecycle across rounds.
|
|
639
704
|
*
|
|
640
|
-
*
|
|
641
|
-
* round
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
* 3. success_criteria_met match → auto done
|
|
705
|
+
* v3.7.1 derivation rule: EVERY committed round (round < currentRound) is
|
|
706
|
+
* replayed in round order — emerged_subtasks create pending items, then
|
|
707
|
+
* subgoal_updates apply explicit transitions. The round's own report
|
|
708
|
+
* (last_round_result, which the engine rebuilds from the same committed
|
|
709
|
+
* evaluation) contributes the same data on the fixture path, so applying
|
|
710
|
+
* it again is an idempotent no-op. Older transitions therefore never
|
|
711
|
+
* regress on later compiles, and no status is ever inferred.
|
|
648
712
|
*/
|
|
649
713
|
function manageSubGoals(loopId, currentRound, lastRoundResult, vaultContext) {
|
|
650
714
|
const policy = getPolicy().evolution;
|
|
651
715
|
const allEntries = loopEntries(loopId, vaultContext);
|
|
652
|
-
const completedEntries = allEntries
|
|
716
|
+
const completedEntries = allEntries
|
|
717
|
+
.filter((e) => entryRound(e) >= 1 && entryRound(e) < currentRound)
|
|
718
|
+
.sort((a, b) => entryRound(a) - entryRound(b));
|
|
653
719
|
const subGoals = [];
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const rnd = entryRound(entry);
|
|
657
|
-
const emerged = entryEmergedSubtasks(entry);
|
|
658
|
-
for (const desc of emerged) {
|
|
659
|
-
const id = deriveSubGoalId(desc);
|
|
720
|
+
const createEmerged = (descs, rnd) => {
|
|
721
|
+
for (const desc of descs) {
|
|
660
722
|
// Dedup: skip if an existing sub-goal is too similar
|
|
661
723
|
if (matchSubGoal(desc, subGoals, policy.subgoal_dedup_threshold) >= 0)
|
|
662
724
|
continue;
|
|
663
725
|
subGoals.push(makeSubGoal({
|
|
664
|
-
id,
|
|
726
|
+
id: deriveSubGoalId(desc),
|
|
665
727
|
description: desc.trim(),
|
|
666
728
|
status: "pending",
|
|
667
729
|
declared_at_round: rnd,
|
|
@@ -669,56 +731,24 @@ function manageSubGoals(loopId, currentRound, lastRoundResult, vaultContext) {
|
|
|
669
731
|
priority: subGoals.length,
|
|
670
732
|
}));
|
|
671
733
|
}
|
|
734
|
+
};
|
|
735
|
+
// Phase 1 — Replay every committed round in order: create, then apply
|
|
736
|
+
// that round's declared transitions.
|
|
737
|
+
for (const entry of completedEntries) {
|
|
738
|
+
const rnd = entryRound(entry);
|
|
739
|
+
createEmerged(entryEmergedSubtasks(entry), rnd);
|
|
740
|
+
for (const update of entrySubGoalUpdates(entry)) {
|
|
741
|
+
applySubGoalUpdate(subGoals, update, rnd);
|
|
742
|
+
}
|
|
672
743
|
}
|
|
673
|
-
// Phase 2 —
|
|
744
|
+
// Phase 2 — The current round's own report (fixture/rebuild path; on the
|
|
745
|
+
// vault path this duplicates the last committed round and is idempotent).
|
|
674
746
|
if (lastRoundResult) {
|
|
675
747
|
const rnd = lastRoundResult.round || (currentRound - 1);
|
|
676
|
-
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
if (matchSubGoal(desc, subGoals, policy.subgoal_dedup_threshold) >= 0)
|
|
680
|
-
continue;
|
|
681
|
-
subGoals.push(makeSubGoal({
|
|
682
|
-
id: deriveSubGoalId(desc),
|
|
683
|
-
description: desc.trim(),
|
|
684
|
-
status: "pending",
|
|
685
|
-
declared_at_round: rnd,
|
|
686
|
-
status_changed_at_round: rnd,
|
|
687
|
-
priority: subGoals.length,
|
|
688
|
-
}));
|
|
689
|
-
}
|
|
690
|
-
// Completed sub-goals
|
|
691
|
-
const completed = lastRoundResult.completed_subtasks ?? [];
|
|
692
|
-
for (const desc of completed) {
|
|
693
|
-
const idx = matchSubGoal(desc, subGoals, policy.subgoal_match_threshold);
|
|
694
|
-
if (idx >= 0 && subGoals[idx].status !== "done" && subGoals[idx].status !== "canceled") {
|
|
695
|
-
subGoals[idx].status = "done";
|
|
696
|
-
subGoals[idx].status_changed_at_round = rnd;
|
|
697
|
-
subGoals[idx].completed_at_round = rnd;
|
|
698
|
-
}
|
|
748
|
+
createEmerged(lastRoundResult.emerged_subtasks ?? [], rnd);
|
|
749
|
+
for (const update of lastRoundResult.subgoal_updates ?? []) {
|
|
750
|
+
applySubGoalUpdate(subGoals, update, rnd);
|
|
699
751
|
}
|
|
700
|
-
// Blocked sub-goals
|
|
701
|
-
const blocked = lastRoundResult.blocked_subtasks ?? [];
|
|
702
|
-
for (const desc of blocked) {
|
|
703
|
-
const idx = matchSubGoal(desc, subGoals, policy.subgoal_match_threshold);
|
|
704
|
-
if (idx >= 0 && subGoals[idx].status !== "done" && subGoals[idx].status !== "canceled") {
|
|
705
|
-
subGoals[idx].status = "blocked";
|
|
706
|
-
subGoals[idx].status_changed_at_round = rnd;
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
// Canceled sub-goals
|
|
710
|
-
const canceled = lastRoundResult.canceled_subtasks ?? [];
|
|
711
|
-
for (const desc of canceled) {
|
|
712
|
-
const idx = matchSubGoal(desc, subGoals, policy.subgoal_match_threshold);
|
|
713
|
-
if (idx >= 0 && subGoals[idx].status !== "done" && subGoals[idx].status !== "canceled") {
|
|
714
|
-
subGoals[idx].status = "canceled";
|
|
715
|
-
subGoals[idx].status_changed_at_round = rnd;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
// v3.7: no auto status inference. The v2.3 fuzzy heuristics
|
|
719
|
-
// (next_action Jaccard → in_progress, criteria Jaccard → done) were
|
|
720
|
-
// removed — they fabricated dashboard motion the machine never
|
|
721
|
-
// verified. Statuses change only via the agent declarations above.
|
|
722
752
|
}
|
|
723
753
|
// Sort for display: in_progress first, then pending by age desc, then blocked, then done, then canceled
|
|
724
754
|
subGoals.sort((a, b) => {
|
|
@@ -910,17 +940,17 @@ function levelDecision(request, context) {
|
|
|
910
940
|
export function decideLevel(request, context) {
|
|
911
941
|
return levelDecision(request, context).level;
|
|
912
942
|
}
|
|
913
|
-
export function buildSelfEvalBlock(round, prevDriftFlags,
|
|
943
|
+
export function buildSelfEvalBlock(round, prevDriftFlags,
|
|
914
944
|
/** v2.12: L0 is the minimal retry template — the v2.12 declarative fields
|
|
915
945
|
* (outcome/blocker/retroactiveClaims) are L1/L2 additions so the retry
|
|
916
946
|
* prompt stays within its tight budget. */
|
|
917
|
-
level,
|
|
947
|
+
level,
|
|
918
948
|
/** v3.3/v3.4: Whether this round's Current Task IS the ACTIVE Round
|
|
919
949
|
* Contract (derived from committed rounds — compileLoop passes
|
|
920
950
|
* `activeContract != null`). Only then does the template ask the agent
|
|
921
951
|
* to restate/propose it — a generic empty contract template would invite
|
|
922
952
|
* placeholder submissions that trigger round_underspecified noise. */
|
|
923
|
-
hasContract = false,
|
|
953
|
+
hasContract = false,
|
|
924
954
|
/** v3.5: L2-only prose suggesting a Round Contract declaration when the
|
|
925
955
|
* Current Task is NOT one (contract_nudge_on_l2 policy, computed at the
|
|
926
956
|
* compileLoop call site). Mutually exclusive with hasContract. The prose
|
|
@@ -948,9 +978,9 @@ proposalNudge = false) {
|
|
|
948
978
|
},
|
|
949
979
|
wrong_assumptions: [],
|
|
950
980
|
next_action: "<next concrete action, or empty when complete>",
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
981
|
+
subgoal_updates: [
|
|
982
|
+
{ id: "<sg-XXXXXXXX from the Sub-Goal Dashboard>", status: "done" },
|
|
983
|
+
],
|
|
954
984
|
};
|
|
955
985
|
// v2.12: Declarative tri-state outcome (L1/L2 only — keeps L0 retry lean)
|
|
956
986
|
if (declareOutcome) {
|
|
@@ -999,7 +1029,8 @@ proposalNudge = false) {
|
|
|
999
1029
|
lines.push("IMPORTANT: Replace every <placeholder> with your actual data.");
|
|
1000
1030
|
lines.push("Set success=true only when the full goal and ALL hard constraints are verified.");
|
|
1001
1031
|
lines.push("Use IDs for exact matching: c-XXXXXXXX, cr-XXXXXXXX, sg-XXXXXXXX.");
|
|
1002
|
-
lines.push("
|
|
1032
|
+
lines.push("Sub-goal changes go through `subgoal_updates` (active sub-goal IDs only;");
|
|
1033
|
+
lines.push("done/canceled are terminal — reopen via `emerged_subtasks`; bad IDs reject).");
|
|
1003
1034
|
// v3.5: L2 contract-less nudge (prose only — never the JSON key name, so
|
|
1004
1035
|
// contract-less rounds keep their template-lean assertions).
|
|
1005
1036
|
if (proposalNudge) {
|
|
@@ -1013,6 +1044,43 @@ proposalNudge = false) {
|
|
|
1013
1044
|
// v2.5: checkpoint() removed — agent_declared milestones from
|
|
1014
1045
|
// compression_checkpoint supersede the separate CheckpointSummary.
|
|
1015
1046
|
// See buildRollingSummary() signal 1.
|
|
1047
|
+
/** v3.7.1: Derived Recovery Brief for the state-file Recent tier. Present
|
|
1048
|
+
* ONLY while a committed backtrack decision is the current round's record
|
|
1049
|
+
* (the recovery window); the redo commit replaces that record, so the
|
|
1050
|
+
* brief exits the projection by construction. Sources are the committed
|
|
1051
|
+
* rollback decision's own fields — no new persistence, no rejected
|
|
1052
|
+
* payloads. */
|
|
1053
|
+
function committedBacktrackBrief(loopId, round, context) {
|
|
1054
|
+
const entry = loopEntries(loopId, context).find((e) => entryLineage(e).committed_action === "backtrack" && entryRound(e) === round);
|
|
1055
|
+
if (!entry)
|
|
1056
|
+
return undefined;
|
|
1057
|
+
// Read the facts the engine stamped onto the merged lineage entry from
|
|
1058
|
+
// the committed rollback decision (engine.ts mergeCommittedRound).
|
|
1059
|
+
const lineage = entryLineage(entry);
|
|
1060
|
+
const asStrings = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
1061
|
+
const asNumbers = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "number") : [];
|
|
1062
|
+
const failedRounds = asNumbers(lineage.backtrackFailedRounds);
|
|
1063
|
+
const approaches = asStrings(lineage.backtrackApproaches).slice(0, 6);
|
|
1064
|
+
const assumptions = asStrings(lineage.backtrackWrongAssumptions).slice(0, 5);
|
|
1065
|
+
const target = typeof lineage.backtrackTarget === "number" ? lineage.backtrackTarget : 0;
|
|
1066
|
+
const trigger = typeof lineage.backtrackTriggerRule === "string"
|
|
1067
|
+
? lineage.backtrackTriggerRule
|
|
1068
|
+
: "unknown";
|
|
1069
|
+
const lines = [
|
|
1070
|
+
`- **Trigger**: ${trigger}`,
|
|
1071
|
+
`- **Restored to round**: ${target} (redo round ${target + 1})`,
|
|
1072
|
+
];
|
|
1073
|
+
if (failedRounds.length > 0)
|
|
1074
|
+
lines.push(`- **Failed rounds**: ${failedRounds.join(", ")}`);
|
|
1075
|
+
for (const approach of approaches)
|
|
1076
|
+
lines.push(` - Failed approach: ${approach}`);
|
|
1077
|
+
if (assumptions.length > 0) {
|
|
1078
|
+
lines.push("- **Falsified assumptions** (do not rebuild on these):");
|
|
1079
|
+
for (const assumption of assumptions)
|
|
1080
|
+
lines.push(` - ${assumption}`);
|
|
1081
|
+
}
|
|
1082
|
+
return lines;
|
|
1083
|
+
}
|
|
1016
1084
|
export function compileLoop(request, context) {
|
|
1017
1085
|
const decision = levelDecision(request, context);
|
|
1018
1086
|
const previous = getPreviousRound(request.loop_id, request.round - 1, context);
|
|
@@ -1085,14 +1153,27 @@ export function compileLoop(request, context) {
|
|
|
1085
1153
|
warnings,
|
|
1086
1154
|
});
|
|
1087
1155
|
const policy = getPolicy();
|
|
1088
|
-
|
|
1156
|
+
// L7 (v3.7.x): the state-file path is empty when the file is disabled —
|
|
1157
|
+
// prompts must never point at (or collapse content behind) a file that
|
|
1158
|
+
// writeStateFile will not create. An empty path propagates into the
|
|
1159
|
+
// assembler's pointer lines and the L1 collapse gate below.
|
|
1160
|
+
const statePath = policy.state_file.enabled
|
|
1161
|
+
? `${policy.state_file.directory}/${request.loop_id}-state.md`
|
|
1162
|
+
: "";
|
|
1089
1163
|
const state = createCanonicalLoopState(request, response, statePath, {
|
|
1090
1164
|
roundStats,
|
|
1091
1165
|
machineStatus,
|
|
1092
1166
|
// v3.4: derived active contract — the Current Task's source of truth.
|
|
1093
1167
|
roundContract: activeContract,
|
|
1094
1168
|
});
|
|
1095
|
-
const markdown = renderCanonicalStateMarkdown(state
|
|
1169
|
+
const markdown = renderCanonicalStateMarkdown(state, {
|
|
1170
|
+
// v3.7.1: retry attempts are marked in the derived view (attempt is
|
|
1171
|
+
// request context, not a committed fact). The Recovery Brief renders in
|
|
1172
|
+
// the Recent tier only while a committed backtrack decision is this
|
|
1173
|
+
// round's record; the redo commit removes it by construction.
|
|
1174
|
+
attempt: request.attempt,
|
|
1175
|
+
recoveryBrief: committedBacktrackBrief(request.loop_id, request.round, context),
|
|
1176
|
+
});
|
|
1096
1177
|
// v2.4–v2.5: Adaptive L2 budget — scales with loop complexity
|
|
1097
1178
|
const adaptiveL2 = policy.prompt.l2_adaptive_enabled
|
|
1098
1179
|
? Math.min(policy.prompt.l2_max_chars
|
|
@@ -1103,7 +1184,10 @@ export function compileLoop(request, context) {
|
|
|
1103
1184
|
// v2.8: L2 pointer mode — when enabled, skip the monolithic markdown blob.
|
|
1104
1185
|
// Structured L2 sections (milestones, sub-goals, trust, progress) still
|
|
1105
1186
|
// render. The state file on disk is the durable source of truth.
|
|
1106
|
-
|
|
1187
|
+
// L7: pointer mode REQUIRES the file — with state_file disabled it would
|
|
1188
|
+
// silently drop the full state from L2 prompts and point at nothing.
|
|
1189
|
+
const l2Pointer = policy.state_file.enabled &&
|
|
1190
|
+
policy.prompt.l2_pointer_enabled && decision.level === "l2";
|
|
1107
1191
|
const artifact = assemblePromptArtifact({
|
|
1108
1192
|
state,
|
|
1109
1193
|
level: decision.level,
|
|
@@ -1114,11 +1198,11 @@ export function compileLoop(request, context) {
|
|
|
1114
1198
|
l2: adaptiveL2,
|
|
1115
1199
|
},
|
|
1116
1200
|
attempt: request.attempt,
|
|
1117
|
-
selfEvaluationBlock: buildSelfEvalBlock(request.round, request.verification_flags, decision.level,
|
|
1201
|
+
selfEvaluationBlock: buildSelfEvalBlock(request.round, request.verification_flags, decision.level,
|
|
1118
1202
|
// v3.4: restate the contract only when this prompt's Current Task IS
|
|
1119
1203
|
// the ACTIVE contract (derived — not the previous submission's field,
|
|
1120
1204
|
// which is a proposal and may differ from what this round executes).
|
|
1121
|
-
activeContract != null,
|
|
1205
|
+
activeContract != null,
|
|
1122
1206
|
// v3.5: L2-only declaration nudge when nothing is active (policy-gated;
|
|
1123
1207
|
// mutually exclusive with the restate template above).
|
|
1124
1208
|
decision.level === "l2" && activeContract === null &&
|