@evomap/evolver-core 2.0.0-beta.2 → 2.0.0-beta.22
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/assets/gep/genes.jsonl +5 -5
- package/dist/algo/bans.d.ts +10 -1
- package/dist/algo/bans.js +56 -6
- package/dist/algo/candidateAssembly.d.ts +25 -2
- package/dist/algo/candidateAssembly.js +171 -26
- package/dist/algo/capabilityCandidates.js +10 -0
- package/dist/algo/conversationSniffer.js +25 -8
- package/dist/algo/cycleEngine.d.ts +63 -5
- package/dist/algo/cycleEngine.js +320 -42
- package/dist/algo/cycleFailureClassifier.d.ts +1 -1
- package/dist/algo/evolutionEvent.d.ts +26 -0
- package/dist/algo/evolutionEvent.js +32 -0
- package/dist/algo/exploration.d.ts +7 -0
- package/dist/algo/exploration.js +16 -3
- package/dist/algo/geneHealth.d.ts +36 -3
- package/dist/algo/geneHealth.js +47 -4
- package/dist/algo/geneIntake.d.ts +46 -1
- package/dist/algo/geneIntake.js +121 -10
- package/dist/algo/geneSelection.d.ts +126 -6
- package/dist/algo/geneSelection.js +479 -36
- package/dist/algo/index.d.ts +6 -1
- package/dist/algo/index.js +6 -1
- package/dist/algo/kautoProjection.d.ts +41 -0
- package/dist/algo/kautoProjection.js +95 -0
- package/dist/algo/kautoValidator.d.ts +68 -0
- package/dist/algo/kautoValidator.js +256 -0
- package/dist/algo/memoryGraph.d.ts +62 -0
- package/dist/algo/memoryGraph.js +86 -0
- package/dist/algo/orchestrator.d.ts +17 -1
- package/dist/algo/orchestrator.js +30 -4
- package/dist/algo/publishEligibility.d.ts +34 -0
- package/dist/algo/publishEligibility.js +52 -0
- package/dist/algo/solidify.d.ts +11 -2
- package/dist/algo/solidify.js +37 -7
- package/dist/algo/ucb1.d.ts +53 -0
- package/dist/algo/ucb1.js +156 -0
- package/dist/assetrepair/hubRejection.d.ts +12 -0
- package/dist/assetrepair/hubRejection.js +109 -0
- package/dist/assetrepair/index.d.ts +2 -0
- package/dist/assetrepair/index.js +2 -0
- package/dist/assetrepair/repair.d.ts +33 -0
- package/dist/assetrepair/repair.js +155 -0
- package/dist/assetstore/assetSidecarRecords.d.ts +28 -0
- package/dist/assetstore/assetSidecarRecords.js +384 -0
- package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
- package/dist/assetstore/assetSidecarRecovery.js +288 -0
- package/dist/assetstore/assetStoreHealth.d.ts +81 -0
- package/dist/assetstore/assetStoreHealth.js +319 -0
- package/dist/assetstore/assetStoreLayout.d.ts +2 -0
- package/dist/assetstore/assetStoreLayout.js +6 -0
- package/dist/assetstore/assetStoreStorage.d.ts +42 -0
- package/dist/assetstore/assetStoreStorage.js +336 -0
- package/dist/assetstore/assetSyncLedger.d.ts +91 -1
- package/dist/assetstore/assetSyncLedger.js +718 -59
- package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
- package/dist/assetstore/foreignJsonlSource.js +150 -0
- package/dist/assetstore/index.d.ts +5 -0
- package/dist/assetstore/index.js +5 -0
- package/dist/assetstore/learningHistory.js +3 -3
- package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
- package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
- package/dist/assetstore/localJsonl.d.ts +12 -1
- package/dist/assetstore/localJsonl.js +251 -42
- package/dist/assetstore/provenance.d.ts +93 -4
- package/dist/assetstore/provenance.js +368 -84
- package/dist/assetstore/provider.d.ts +63 -0
- package/dist/assetstore/provider.js +97 -6
- package/dist/assetstore/reviewFilter.d.ts +19 -1
- package/dist/assetstore/reviewFilter.js +39 -1
- package/dist/assetstore/reviewLedger.d.ts +8 -2
- package/dist/assetstore/reviewLedger.js +71 -45
- package/dist/assetstore/unionReadStore.d.ts +25 -0
- package/dist/assetstore/unionReadStore.js +119 -0
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +4 -3
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +4 -3
- package/dist/benchmark/index.d.ts +3 -1
- package/dist/benchmark/index.js +3 -1
- package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
- package/dist/benchmark/selectionFlatAbstention.js +481 -0
- package/dist/benchmark/triggerShift.d.ts +62 -0
- package/dist/benchmark/triggerShift.js +106 -0
- package/dist/bootstrap/envFingerprint.d.ts +9 -0
- package/dist/bootstrap/envFingerprint.js +5 -0
- package/dist/bootstrap/index.d.ts +3 -1
- package/dist/bootstrap/index.js +3 -1
- package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
- package/dist/bootstrap/lifecycleBootstrap.js +433 -0
- package/dist/bootstrap/v1EnvCompat.d.ts +113 -0
- package/dist/bootstrap/v1EnvCompat.js +303 -0
- package/dist/events/eventArchive.d.ts +2 -0
- package/dist/events/eventArchive.js +13 -3
- package/dist/events/eventSchema.d.ts +7 -7
- package/dist/events/eventStore.d.ts +2 -0
- package/dist/events/eventStore.js +5 -1
- package/dist/events/ingest.d.ts +2 -1
- package/dist/events/ingest.js +15 -0
- package/dist/events/paths.d.ts +12 -10
- package/dist/events/paths.js +24 -20
- package/dist/events/public.d.ts +2 -2
- package/dist/events/public.js +2 -2
- package/dist/events/reports.d.ts +2 -0
- package/dist/events/reports.js +4 -0
- package/dist/exec/autoExec.d.ts +68 -4
- package/dist/exec/autoExec.js +392 -33
- package/dist/exec/autonomousCycle.d.ts +31 -4
- package/dist/exec/autonomousCycle.js +71 -13
- package/dist/exec/claudeBridge.d.ts +80 -15
- package/dist/exec/claudeBridge.js +845 -76
- package/dist/exec/executionBinding.d.ts +414 -0
- package/dist/exec/executionBinding.js +588 -0
- package/dist/exec/index.d.ts +1 -0
- package/dist/exec/index.js +1 -0
- package/dist/exec/openPrRegistry.d.ts +8 -2
- package/dist/exec/openPrRegistry.js +32 -22
- package/dist/exec/prompt.js +14 -1
- package/dist/exec/proofOfWork.d.ts +1 -1
- package/dist/exec/proofOfWork.js +2 -2
- package/dist/exec/runnerRegistry.d.ts +153 -36
- package/dist/exec/runnerRegistry.js +848 -65
- package/dist/exec/selfPr.js +1 -7
- package/dist/feedback/envelope.d.ts +61 -0
- package/dist/feedback/envelope.js +168 -0
- package/dist/feedback/index.d.ts +1 -0
- package/dist/feedback/index.js +1 -0
- package/dist/hooks/hooks.js +1 -0
- package/dist/hub/assetCallLog.d.ts +35 -1
- package/dist/hub/assetCallLog.js +124 -1
- package/dist/hub/bindings.d.ts +8 -1
- package/dist/hub/bindings.js +29 -8
- package/dist/hub/capability.d.ts +130 -4
- package/dist/hub/conversationDistiller.d.ts +19 -0
- package/dist/hub/conversationDistiller.js +115 -37
- package/dist/hub/fake.d.ts +3 -2
- package/dist/hub/fake.js +2 -1
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/hub/questionGenerator.d.ts +5 -1
- package/dist/hub/questionGenerator.js +8 -6
- package/dist/hub/recipeCompose.d.ts +27 -0
- package/dist/hub/recipeCompose.js +90 -0
- package/dist/hub/sanitize.js +122 -7
- package/dist/index.d.ts +6 -1
- package/dist/index.js +7 -1
- package/dist/issueReporter/index.d.ts +156 -0
- package/dist/issueReporter/index.js +1688 -0
- package/dist/mailbox/dispatch.d.ts +1 -1
- package/dist/mailbox/dispatch.js +22 -6
- package/dist/mailbox/envelope.d.ts +7 -1
- package/dist/mailbox/envelope.js +9 -2
- package/dist/mailbox/ipcServer.d.ts +12 -2
- package/dist/mailbox/ipcServer.js +183 -13
- package/dist/mailbox/store.d.ts +89 -3
- package/dist/mailbox/store.js +895 -41
- package/dist/modelCompatibility.d.ts +164 -0
- package/dist/modelCompatibility.js +309 -0
- package/dist/observers/valueDigestObserver.d.ts +9 -0
- package/dist/observers/valueDigestObserver.js +35 -2
- package/dist/ops/cleanup.js +1 -1
- package/dist/ops/evolutionGraphProjection.d.ts +20 -0
- package/dist/ops/evolutionGraphProjection.js +315 -0
- package/dist/ops/index.d.ts +2 -1
- package/dist/ops/index.js +2 -1
- package/dist/ops/savingsCore.js +1 -2
- package/dist/ops/selfUpdate.d.ts +18 -1
- package/dist/ops/selfUpdate.js +88 -23
- package/dist/ops/valueOutreach.d.ts +3 -1
- package/dist/ops/valueOutreach.js +5 -1
- package/dist/personality/schema.d.ts +24 -24
- package/dist/schema/evolutionGraph.d.ts +784 -0
- package/dist/schema/evolutionGraph.js +187 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/proofOfWork.d.ts +125 -6
- package/dist/schema/proofOfWork.js +102 -4
- package/dist/schema/signal.d.ts +3 -3
- package/dist/schema/signal.js +1 -1
- package/dist/shadow/shadowHub.js +1 -0
- package/dist/signals/curriculum.d.ts +55 -0
- package/dist/signals/curriculum.js +202 -0
- package/dist/signals/cycleHistoryFromEvents.js +17 -8
- package/dist/signals/expand.d.ts +15 -1
- package/dist/signals/expand.js +169 -1
- package/dist/signals/extractor.d.ts +2 -2
- package/dist/signals/extractor.js +31 -6
- package/dist/signals/index.d.ts +4 -1
- package/dist/signals/index.js +4 -1
- package/dist/signals/metaSignals.d.ts +4 -0
- package/dist/signals/metaSignals.js +42 -0
- package/dist/signals/scopeVocabulary.d.ts +75 -0
- package/dist/signals/scopeVocabulary.js +91 -0
- package/dist/signals/signalGate.js +1 -1
- package/dist/signals/taskDomain.d.ts +22 -0
- package/dist/signals/taskDomain.js +43 -0
- package/dist/strategy/constraintAblation.d.ts +64 -0
- package/dist/strategy/constraintAblation.js +2820 -0
- package/dist/strategy/constraintAblationPredicates.d.ts +31 -0
- package/dist/strategy/constraintAblationPredicates.js +339 -0
- package/dist/strategy/index.d.ts +2 -1
- package/dist/strategy/index.js +2 -1
- package/dist/trace/index.d.ts +3 -1
- package/dist/trace/index.js +3 -1
- package/dist/trace/learningTrace.d.ts +216 -0
- package/dist/trace/learningTrace.js +298 -0
- package/dist/trace/proxyTurns.d.ts +31 -0
- package/dist/trace/proxyTurns.js +137 -0
- package/dist/trace/trajectory.d.ts +8 -0
- package/dist/trace/trajectory.js +14 -2
- package/dist/util/fetchPort.d.ts +1 -0
- package/dist/util/fetchPort.js +11 -0
- package/dist/util/fileLock.d.ts +113 -7
- package/dist/util/fileLock.js +1035 -80
- package/dist/util/index.d.ts +3 -1
- package/dist/util/index.js +2 -1
- package/dist/verify/index.d.ts +2 -1
- package/dist/verify/index.js +1 -1
- package/dist/verify/sandboxRunner.d.ts +30 -0
- package/dist/verify/sandboxRunner.js +370 -27
- package/dist/verify/sandboxedValidation.d.ts +16 -2
- package/dist/verify/sandboxedValidation.js +200 -22
- package/dist/verify/validation.d.ts +35 -4
- package/dist/verify/validation.js +164 -16
- package/dist/wire/geneHints.d.ts +88 -16
- package/dist/wire/geneHints.js +124 -15
- package/dist/wire/index.d.ts +8 -3
- package/dist/wire/index.js +2 -2
- package/dist/wire/schemaGate.d.ts +21 -0
- package/dist/wire/schemaGate.js +119 -10
- package/dist/workflow/dsl.d.ts +24 -3
- package/dist/workflow/dsl.js +4 -0
- package/dist/workflow/engine.d.ts +5 -1
- package/dist/workflow/engine.js +3 -0
- package/dist/workflow/index.d.ts +3 -1
- package/dist/workflow/index.js +3 -1
- package/dist/workflow/runtime.d.ts +110 -0
- package/dist/workflow/runtime.js +1298 -0
- package/dist/workflow/stateStore.d.ts +172 -0
- package/dist/workflow/stateStore.js +1044 -0
- package/package.json +12 -4
package/dist/exec/autoExec.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import type { AssetStoreProvider } from '../assetstore/provider.js';
|
|
2
2
|
import { type ProvenanceStore } from '../assetstore/provenance.js';
|
|
3
3
|
import type { ReviewLedger } from '../assetstore/reviewLedger.js';
|
|
4
|
-
import type { GeneCandidateInput } from '../algo/geneSelection.js';
|
|
5
|
-
import type { CycleEngine, SolidifyPermitGate } from '../algo/cycleEngine.js';
|
|
4
|
+
import type { GeneCandidateInput, SelectionGuardMode } from '../algo/geneSelection.js';
|
|
5
|
+
import type { CycleEngine, ExecutionFailureKind, ExecutionResult, SolidifyPermitGate } from '../algo/cycleEngine.js';
|
|
6
6
|
import { type AutonomousSafety } from './autonomousCycle.js';
|
|
7
|
-
import type
|
|
7
|
+
import { type GitRunner, type ValidateHook } from './claudeBridge.js';
|
|
8
8
|
import type { AgentRunner } from './runnerRegistry.js';
|
|
9
9
|
import { type OpenPrLister } from './openPrRegistry.js';
|
|
10
10
|
import type { ReuseOutcomeSummary, ReuseOutcomeEvent } from '../ops/reuseOutcomes.js';
|
|
11
11
|
import type { PersonalityStore } from '../personality/store.js';
|
|
12
|
+
import type { MemoryGraphProvider } from '../algo/memoryGraph.js';
|
|
13
|
+
import type { SelectionPolicy } from '../algo/ucb1.js';
|
|
14
|
+
import { type LearningPacketSink, type TraceSink } from '../trace/learningTrace.js';
|
|
15
|
+
import type { TraceReadOptions } from '../trace/trajectoryExport.js';
|
|
16
|
+
import { ExecutionBindingJournal, type BindingAuthorityChecks, type ExecutionBindingInput } from './executionBinding.js';
|
|
12
17
|
export interface AutoExecTask {
|
|
13
18
|
id: string;
|
|
14
19
|
repo: string;
|
|
@@ -28,10 +33,18 @@ export interface AutoExecTask {
|
|
|
28
33
|
/** Optional explicit strategy preset name for this task; wins over daemon default and meta-signal auto-detection. */
|
|
29
34
|
strategyName?: string;
|
|
30
35
|
validationCmds?: readonly string[];
|
|
36
|
+
/** Frozen external execution binding; bound tasks never fall back to unbound execution. */
|
|
37
|
+
execution_binding?: ExecutionBindingInput;
|
|
31
38
|
}
|
|
32
39
|
export interface AutoExecVerdict {
|
|
33
40
|
taskId: string;
|
|
34
|
-
status: 'refused' | 'skipped' | 'solidified' | 'failed' | 'innovated';
|
|
41
|
+
status: 'refused' | 'skipped' | 'solidified' | 'failed' | 'innovated' | 'unsafe_to_replay';
|
|
42
|
+
binding_digest?: `sha256:${string}`;
|
|
43
|
+
run_id?: string;
|
|
44
|
+
execution_terminal?: ExecutionResult['executionTerminal'];
|
|
45
|
+
hub_lifecycle?: {
|
|
46
|
+
state: 'not_submitted';
|
|
47
|
+
};
|
|
35
48
|
reason?: string;
|
|
36
49
|
finalStage?: string;
|
|
37
50
|
outcome?: {
|
|
@@ -39,6 +52,8 @@ export interface AutoExecVerdict {
|
|
|
39
52
|
score: number;
|
|
40
53
|
};
|
|
41
54
|
proofOfWork?: unknown;
|
|
55
|
+
failureKind?: ExecutionFailureKind;
|
|
56
|
+
exitCode?: number | null;
|
|
42
57
|
usedAssetIds?: readonly string[];
|
|
43
58
|
}
|
|
44
59
|
/**
|
|
@@ -80,6 +95,15 @@ export interface AutoExecDeps {
|
|
|
80
95
|
validate?: (task: AutoExecTask) => ValidateHook;
|
|
81
96
|
/** Optional adapter/runtime permit gate. Core owns only the seam; adapters own the verification policy. */
|
|
82
97
|
solidifyPermit?: SolidifyPermitGate;
|
|
98
|
+
/** Bound execution uses the existing root-event journal; composition supplies its authoritative external checks. */
|
|
99
|
+
executionBinding?: {
|
|
100
|
+
journal: ExecutionBindingJournal;
|
|
101
|
+
authority: BindingAuthorityChecks;
|
|
102
|
+
now?: () => number;
|
|
103
|
+
maxRuntimeMs?: number;
|
|
104
|
+
maxFiles?: number;
|
|
105
|
+
maxLines?: number;
|
|
106
|
+
};
|
|
83
107
|
/**
|
|
84
108
|
* Optional open-PR dedup: when set, before spawning an agent the task's signals are compared against open PR
|
|
85
109
|
* titles/branches; a strong overlap yields a 'skipped' verdict so the daemon never re-implements work that is
|
|
@@ -97,14 +121,54 @@ export interface AutoExecDeps {
|
|
|
97
121
|
/** Observed `value.recall` events (#274 slice 3): folded into the same soft re-order as reuseOutcomes (lower
|
|
98
122
|
* weight) so transcript-observed recall influences selection. Forwarded to runEvolutionCycle. Omit → none. */
|
|
99
123
|
recallEvents?: readonly ReuseOutcomeEvent[];
|
|
124
|
+
/** Scoped local MemoryGraph seam. Queries and records structured outcome data only. */
|
|
125
|
+
memoryGraph?: MemoryGraphProvider;
|
|
100
126
|
/** Optional daemon-level explicit strategy preset name, e.g. EVOLVE_STRATEGY. */
|
|
101
127
|
strategyName?: string;
|
|
128
|
+
/** Emergency rollback for semantic IDF selection. Omit to keep IDF enabled. */
|
|
129
|
+
disableSemanticIdf?: boolean;
|
|
130
|
+
/** Experimental plateau selection policy. Omit to preserve engine-health + legacy drift. */
|
|
131
|
+
selectionPolicy?: SelectionPolicy;
|
|
132
|
+
/** Production relevance-guard rollout. Omit only for legacy/custom composition. */
|
|
133
|
+
selectionGuard?: SelectionGuardMode;
|
|
134
|
+
/** Optional score floor canary. Omit to keep the selector default of zero. */
|
|
135
|
+
selectionFloor?: number;
|
|
102
136
|
/** Optional evolvable personality store shared with CycleEngine and the exec prompt. */
|
|
103
137
|
personality?: PersonalityStore;
|
|
104
138
|
/** Test/custom seam: inject a runner instead of spawning a real agent. */
|
|
105
139
|
agent?: AgentRunner;
|
|
106
140
|
/** Test/custom seam: inject git instead of spawning git. */
|
|
107
141
|
git?: GitRunner;
|
|
142
|
+
/**
|
|
143
|
+
* Learning trace (Learning Ops slice 2): when set, each task run gets its own AgentRunTraceRecorder
|
|
144
|
+
* (traceId = the cycleId) emitting run.started/model.called/tool.failed/run.completed, and a
|
|
145
|
+
* LearningPacket draft is submitted here after the cycle. Best-effort: trace/packet failures never
|
|
146
|
+
* change the verdict. Omit → zero trace work, byte-identical to today.
|
|
147
|
+
*/
|
|
148
|
+
learningTrace?: {
|
|
149
|
+
/** Where packet drafts go (file/memory/hub-adapter implementation). */
|
|
150
|
+
packetSink: LearningPacketSink;
|
|
151
|
+
/** Optional live per-event sink (e.g. FileTraceSink JSONL tail). */
|
|
152
|
+
traceSink?: TraceSink;
|
|
153
|
+
/** Hub packet sourceRepo column; default 'evolver-v2'. */
|
|
154
|
+
sourceRepo?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Proxy llm_turn fold (Learning Ops slice 5): when set, after the cycle (and BEFORE run.completed, so
|
|
157
|
+
* sequence order holds) the run's wall-clock window of proxy trace records is read from `dir`
|
|
158
|
+
* (llm-trace-*.jsonl day-files) and folded into the recorder via recordLlmTurn — real per-request
|
|
159
|
+
* model.called + tool.called/tool.failed detail instead of only the bridge's coarse spawn event.
|
|
160
|
+
* Correlation is the time window + session-first-turn heuristic (see trace/proxyTurns.ts). Best-effort:
|
|
161
|
+
* a missing dir / unreadable file / no proxy degrades to zero folded turns, never a verdict change.
|
|
162
|
+
*/
|
|
163
|
+
proxyTraces?: {
|
|
164
|
+
/** Proxy trace day-file dir (events/paths.ts tracesDir()). */
|
|
165
|
+
dir: string;
|
|
166
|
+
/** Decryption material for encrypted trace envelopes (allowPartial is always forced on). */
|
|
167
|
+
readOptions?: TraceReadOptions;
|
|
168
|
+
/** Injected clock for deterministic tests. Default Date.now. */
|
|
169
|
+
now?: () => number;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
108
172
|
}
|
|
109
173
|
export interface ForcedGeneFields {
|
|
110
174
|
forcedGeneId?: unknown;
|
package/dist/exec/autoExec.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
// Autonomous-exec task runner — the productized per-task kernel a resident daemon polls (the deployment form
|
|
2
|
-
// of the scratch autoexec daemon). One task → one fully-hardened evolution cycle, with a deny-by-default
|
|
3
|
-
// allowlist pre-check that yields a clean "refused" verdict WITHOUT running anything when the repo is not
|
|
4
|
-
// allowlisted. Secure by construction: the execute is built by makeSafeExecute (all six controls); callers
|
|
5
|
-
// cannot bypass the safety composition.
|
|
6
|
-
import { resolve as resolvePath, sep } from 'node:path';
|
|
7
1
|
import { normalizeForPut } from '../assetstore/provider.js';
|
|
8
2
|
import { ingestUntrusted } from '../assetstore/provenance.js';
|
|
9
3
|
import { mergePendingSignalsForStore } from '../assetstore/pendingSignals.js';
|
|
10
4
|
import { intakeGene } from '../algo/geneIntake.js';
|
|
11
5
|
import { runEvolutionCycle } from '../algo/orchestrator.js';
|
|
12
6
|
import { makeSafeExecute, makeTrustedGeneResolver } from './autonomousCycle.js';
|
|
7
|
+
import { defaultGitRunner, isWithinRoot } from './claudeBridge.js';
|
|
13
8
|
import { findSignalHints } from './openPrRegistry.js';
|
|
9
|
+
import { AgentRunTraceRecorder, buildLearningPacketDraft } from '../trace/learningTrace.js';
|
|
10
|
+
import { collectRunLlmTurns } from '../trace/proxyTurns.js';
|
|
11
|
+
import { uniqueSessionId } from '../trace/trajectory.js';
|
|
12
|
+
import { ExecutionBindingError, ExecutionBindingJournal, freezeExecutionBinding, preflightExecutionBinding, } from './executionBinding.js';
|
|
14
13
|
/** Same path-containment as the bridge guard — used here to refuse before running anything (clean verdict). */
|
|
15
14
|
function withinAllowlist(repo, roots) {
|
|
16
|
-
|
|
17
|
-
return roots.some((root) => { const r = resolvePath(root); return c === r || c.startsWith(r.endsWith(sep) ? r : r + sep); });
|
|
15
|
+
return roots.some((root) => isWithinRoot(repo, root));
|
|
18
16
|
}
|
|
19
17
|
function cleanForcedGeneId(value) {
|
|
20
18
|
if (typeof value !== 'string')
|
|
@@ -96,6 +94,78 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
96
94
|
if (!withinAllowlist(task.repo, safety.allowedRoots)) {
|
|
97
95
|
return { taskId: task.id, status: 'refused', reason: `repo not in allowlist: ${task.repo}` };
|
|
98
96
|
}
|
|
97
|
+
const cycleId = `autoexec-${task.id}`;
|
|
98
|
+
let binding;
|
|
99
|
+
let bindingClaimed = false;
|
|
100
|
+
let baseValidate;
|
|
101
|
+
if (task.execution_binding !== undefined) {
|
|
102
|
+
try {
|
|
103
|
+
binding = freezeExecutionBinding(task.execution_binding);
|
|
104
|
+
if (!deps.executionBinding)
|
|
105
|
+
throw new ExecutionBindingError('binding_missing', 'execution binding journal and authority checks are required');
|
|
106
|
+
const recovery = deps.executionBinding.journal.recover(task.id, binding.binding_digest);
|
|
107
|
+
if (recovery.kind === 'terminal') {
|
|
108
|
+
const recoveredStatus = recovery.terminal.disposition === 'unsafe_to_replay'
|
|
109
|
+
? 'unsafe_to_replay'
|
|
110
|
+
: recovery.terminal.disposition === 'completed' && recovery.terminal.final_stage === 'solidified'
|
|
111
|
+
? 'solidified'
|
|
112
|
+
: recovery.terminal.disposition === 'completed' && recovery.terminal.final_stage === 'innovated'
|
|
113
|
+
? 'innovated'
|
|
114
|
+
: recovery.terminal.disposition === 'denied'
|
|
115
|
+
? 'refused'
|
|
116
|
+
: 'failed';
|
|
117
|
+
return {
|
|
118
|
+
taskId: task.id,
|
|
119
|
+
status: recoveredStatus,
|
|
120
|
+
binding_digest: recovery.binding_digest,
|
|
121
|
+
run_id: binding.correlation.run_id,
|
|
122
|
+
execution_terminal: {
|
|
123
|
+
status: recovery.terminal.outcome?.status === 'success' ? 'success' : 'failed',
|
|
124
|
+
disposition: recovery.terminal.disposition,
|
|
125
|
+
},
|
|
126
|
+
hub_lifecycle: { state: 'not_submitted' },
|
|
127
|
+
...(recovery.terminal.outcome ? { outcome: recovery.terminal.outcome } : {}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (recovery.kind === 'unsafe_to_replay' || recovery.kind === 'mismatched') {
|
|
131
|
+
return { taskId: task.id, status: 'unsafe_to_replay', binding_digest: recovery.binding_digest, run_id: binding.correlation.run_id, reason: recovery.reason };
|
|
132
|
+
}
|
|
133
|
+
await preflightExecutionBinding(binding, {
|
|
134
|
+
taskId: task.id,
|
|
135
|
+
runId: binding.correlation.run_id,
|
|
136
|
+
cycleId,
|
|
137
|
+
repoPath: task.repo,
|
|
138
|
+
target: task.target,
|
|
139
|
+
expectedEffect: task.expectedEffect,
|
|
140
|
+
allowedRoots: safety.allowedRoots,
|
|
141
|
+
now: deps.executionBinding.now ?? Date.now,
|
|
142
|
+
currentRevision: binding.target_descriptor.base_revision === null
|
|
143
|
+
? null
|
|
144
|
+
: (deps.git ?? defaultGitRunner)(['rev-parse', 'HEAD'], task.repo).then((revision) => revision.trim() || null),
|
|
145
|
+
maxRuntimeMs: deps.executionBinding.maxRuntimeMs ?? safety.timeoutMs,
|
|
146
|
+
maxFiles: deps.executionBinding.maxFiles,
|
|
147
|
+
maxLines: deps.executionBinding.maxLines,
|
|
148
|
+
requiredConsentScope: 'execution',
|
|
149
|
+
authoritative: deps.executionBinding.authority,
|
|
150
|
+
});
|
|
151
|
+
if (!deps.validate && binding.resource_grant.validation_commands.length > 0) {
|
|
152
|
+
throw new ExecutionBindingError('binding_acceptance_invalid', 'bound execution requires the declared validation plan to be wired to a validator');
|
|
153
|
+
}
|
|
154
|
+
baseValidate = deps.validate?.({ ...task, validationCmds: binding.resource_grant.validation_commands });
|
|
155
|
+
if (baseValidate && baseValidate.length < 4) {
|
|
156
|
+
throw new ExecutionBindingError('binding_acceptance_invalid', 'bound execution validator must accept AbortSignal');
|
|
157
|
+
}
|
|
158
|
+
if (recovery.kind === 'new')
|
|
159
|
+
await deps.executionBinding.journal.recordCreated(binding);
|
|
160
|
+
if (recovery.kind === 'claimed')
|
|
161
|
+
bindingClaimed = true;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
165
|
+
const unsafe = error instanceof ExecutionBindingError && error.unsafeToReplay;
|
|
166
|
+
return { taskId: task.id, status: unsafe ? 'unsafe_to_replay' : 'refused', ...(binding ? { binding_digest: binding.binding_digest, run_id: binding.correlation.run_id } : {}), reason: detail };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
99
169
|
// Open-PR dedup (opt-in): if an open PR already covers this task's signals, skip before spawning an agent
|
|
100
170
|
// so the daemon doesn't re-implement in-flight work. Graceful — a lister that returns [] is a no-op.
|
|
101
171
|
if (deps.prLister) {
|
|
@@ -135,7 +205,24 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
135
205
|
// in the same selection pool as local genes. Reuse is an optimization, never a hard dependency — a seam
|
|
136
206
|
// that throws degrades to solving fresh (no hub candidates) rather than failing the task.
|
|
137
207
|
let hubCandidates = [];
|
|
138
|
-
|
|
208
|
+
// Learning trace (slice 2): one recorder per task run, traceId = cycleId so the trace joins the event log.
|
|
209
|
+
// Purely observational — every recorder call and the packet submit are wrapped so they can never change
|
|
210
|
+
// the verdict or fail the task.
|
|
211
|
+
const traceRecorder = deps.learningTrace
|
|
212
|
+
? new AgentRunTraceRecorder({
|
|
213
|
+
runId: cycleId,
|
|
214
|
+
taskId: task.id,
|
|
215
|
+
...(deps.learningTrace.traceSink ? { sink: deps.learningTrace.traceSink } : {}),
|
|
216
|
+
})
|
|
217
|
+
: undefined;
|
|
218
|
+
// Wall-clock window of this run, used to correlate the proxy's llm_turn records (slice 5). Captured
|
|
219
|
+
// unconditionally-cheaply only when the fold is configured.
|
|
220
|
+
const proxyTraceClock = deps.learningTrace?.proxyTraces?.now ?? Date.now;
|
|
221
|
+
let runStartMs = 0;
|
|
222
|
+
try {
|
|
223
|
+
traceRecorder?.runStarted({ taskSummary: task.expectedEffect, signals: cycleSignals, metadata: { repo: task.repo, target: task.target } });
|
|
224
|
+
}
|
|
225
|
+
catch { /* observability only */ }
|
|
139
226
|
if (deps.hubReuse) {
|
|
140
227
|
try {
|
|
141
228
|
hubCandidates = await executableHubCandidates(deps, await deps.hubReuse(cycleSignals, { cycleId }));
|
|
@@ -144,16 +231,119 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
144
231
|
hubCandidates = [];
|
|
145
232
|
}
|
|
146
233
|
}
|
|
147
|
-
|
|
234
|
+
runStartMs = deps.learningTrace?.proxyTraces ? proxyTraceClock() : 0;
|
|
235
|
+
// evaluation fill-in (slice 6): the validate hook is the run's external verifier (sandboxed validation
|
|
236
|
+
// commands), so its result — when it actually RAN — becomes the packet's evaluation.verification
|
|
237
|
+
// (verifier 'automated_test'). Observation is a pass-through wrapper: the hook's result reaches the
|
|
238
|
+
// bridge unchanged, and a run where validation never fired keeps the evaluation placeholder.
|
|
239
|
+
let observedVerification;
|
|
240
|
+
baseValidate ??= deps.validate?.(task);
|
|
241
|
+
const observingValidate = baseValidate
|
|
242
|
+
? async (mutation, decision, cwd, signal) => {
|
|
243
|
+
const v = await baseValidate(mutation, decision, cwd, signal);
|
|
244
|
+
observedVerification = { verifier: 'automated_test', passed: v.passed, ...(v.score !== undefined ? { score: v.score } : {}) };
|
|
245
|
+
return v;
|
|
246
|
+
}
|
|
247
|
+
: undefined;
|
|
248
|
+
const observedProvenance = {
|
|
249
|
+
gene_ids: [], capsule_ids: [], tool_decisions: [],
|
|
250
|
+
policy_decisions: [], validator: null,
|
|
251
|
+
result_asset_refs: [], proof_refs: [], terminal_disposition: 'crashed',
|
|
252
|
+
};
|
|
253
|
+
const executionObserver = binding ? {
|
|
254
|
+
onToolDecision: (decision) => { observedProvenance.tool_decisions.push(decision); },
|
|
255
|
+
onPolicyDecision: (decision) => { observedProvenance.policy_decisions.push(decision); },
|
|
256
|
+
onValidatorDecision: (decision) => { observedProvenance.validator = decision; },
|
|
257
|
+
onProofReference: (reference) => { observedProvenance.proof_refs.push(reference); },
|
|
258
|
+
} : undefined;
|
|
259
|
+
const safeExecute = makeSafeExecute(task.repo, deps.store, safety, {
|
|
148
260
|
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
149
261
|
...(deps.review ? { review: deps.review } : {}),
|
|
150
262
|
...(deps.includeProbation ? { includeProbation: true } : {}),
|
|
151
263
|
...(task.validationCmds ? { validationCmds: task.validationCmds } : {}),
|
|
152
|
-
...(
|
|
264
|
+
...(observingValidate ? { validate: observingValidate } : {}),
|
|
153
265
|
...(deps.personality ? { personality: deps.personality } : {}),
|
|
154
266
|
...(deps.agent ? { agent: deps.agent } : {}),
|
|
155
267
|
...(deps.git ? { git: deps.git } : {}),
|
|
268
|
+
...(traceRecorder ? { traceRecorder } : {}),
|
|
269
|
+
...(executionObserver ? { executionObserver } : {}),
|
|
270
|
+
...(binding ? { executionLimits: {
|
|
271
|
+
maxRuntimeMs: binding.resource_grant.max_runtime_ms,
|
|
272
|
+
maxFiles: binding.resource_grant.max_files,
|
|
273
|
+
maxLines: binding.resource_grant.max_lines,
|
|
274
|
+
} } : {}),
|
|
156
275
|
});
|
|
276
|
+
const execute = binding && deps.executionBinding
|
|
277
|
+
? async (mutation, decision) => {
|
|
278
|
+
const selectedContext = binding.selected_context;
|
|
279
|
+
try {
|
|
280
|
+
if (selectedContext.capsule_id !== null || selectedContext.capsule_asset_id !== null) {
|
|
281
|
+
throw new ExecutionBindingError('binding_mismatched', 'preselected capsule context is not supported by the CycleEngine execution seam');
|
|
282
|
+
}
|
|
283
|
+
if (selectedContext.gene_id !== null && decision.selectedGeneId !== selectedContext.gene_id) {
|
|
284
|
+
throw new ExecutionBindingError('binding_mismatched', 'selected gene_id does not match frozen binding context');
|
|
285
|
+
}
|
|
286
|
+
if (selectedContext.gene_asset_id !== null && decision.selectedAssetId !== selectedContext.gene_asset_id) {
|
|
287
|
+
throw new ExecutionBindingError('binding_mismatched', 'selected gene_asset_id does not match frozen binding context');
|
|
288
|
+
}
|
|
289
|
+
if (!bindingClaimed) {
|
|
290
|
+
await preflightExecutionBinding(binding, {
|
|
291
|
+
taskId: task.id,
|
|
292
|
+
runId: binding.correlation.run_id,
|
|
293
|
+
cycleId,
|
|
294
|
+
repoPath: task.repo,
|
|
295
|
+
target: task.target,
|
|
296
|
+
expectedEffect: task.expectedEffect,
|
|
297
|
+
allowedRoots: safety.allowedRoots,
|
|
298
|
+
now: deps.executionBinding.now ?? Date.now,
|
|
299
|
+
currentRevision: binding.target_descriptor.base_revision === null
|
|
300
|
+
? null
|
|
301
|
+
: (deps.git ?? defaultGitRunner)(['rev-parse', 'HEAD'], task.repo).then((revision) => revision.trim() || null),
|
|
302
|
+
maxRuntimeMs: deps.executionBinding.maxRuntimeMs ?? safety.timeoutMs,
|
|
303
|
+
maxFiles: deps.executionBinding.maxFiles,
|
|
304
|
+
maxLines: deps.executionBinding.maxLines,
|
|
305
|
+
requiredConsentScope: 'execution',
|
|
306
|
+
authoritative: deps.executionBinding.authority,
|
|
307
|
+
});
|
|
308
|
+
const started = await deps.executionBinding.journal.claim(binding);
|
|
309
|
+
if (started.kind !== 'claimed')
|
|
310
|
+
throw new ExecutionBindingError('binding_replay_unsafe', `binding execution claim ended in ${started.kind}`, true);
|
|
311
|
+
bindingClaimed = true;
|
|
312
|
+
}
|
|
313
|
+
const result = await safeExecute(mutation, decision);
|
|
314
|
+
const policyDenied = observedProvenance.policy_decisions.some((policy) => !policy.allowed);
|
|
315
|
+
const disposition = result.outcome.status === 'success'
|
|
316
|
+
? 'completed'
|
|
317
|
+
: result.failureKind === 'timeout'
|
|
318
|
+
? 'timed_out'
|
|
319
|
+
: result.failureKind === 'cancelled'
|
|
320
|
+
? 'cancelled'
|
|
321
|
+
: policyDenied ? 'denied' : 'rejected';
|
|
322
|
+
observedProvenance.terminal_disposition = disposition;
|
|
323
|
+
return {
|
|
324
|
+
...result,
|
|
325
|
+
provenance: { ...observedProvenance, terminal_disposition: disposition },
|
|
326
|
+
bindingCorrelation: { bindingDigest: binding.binding_digest, runId: binding.correlation.run_id },
|
|
327
|
+
executionTerminal: { status: result.outcome.status, disposition },
|
|
328
|
+
hubLifecycle: { state: 'not_submitted' },
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
333
|
+
const disposition = error instanceof ExecutionBindingError
|
|
334
|
+
? error.unsafeToReplay ? 'unsafe_to_replay' : 'denied'
|
|
335
|
+
: 'crashed';
|
|
336
|
+
observedProvenance.terminal_disposition = disposition;
|
|
337
|
+
return {
|
|
338
|
+
outcome: { status: 'failed', score: 0, reason: message },
|
|
339
|
+
bindingCorrelation: { bindingDigest: binding.binding_digest, runId: binding.correlation.run_id },
|
|
340
|
+
executionTerminal: { status: 'failed', disposition },
|
|
341
|
+
provenance: { ...observedProvenance, terminal_disposition: disposition },
|
|
342
|
+
hubLifecycle: { state: 'not_submitted' },
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
: safeExecute;
|
|
157
347
|
const strategyName = task.strategyName ?? deps.strategyName;
|
|
158
348
|
// Intentional semantics (see #308 review M1): a task carrying `strategy` — even without an
|
|
159
349
|
// explicit forcedGeneId — force-selects the gene seeded from that strategy above, rather than
|
|
@@ -161,29 +351,192 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
161
351
|
// The forced pick still passes every hard gate downstream (candidate pool, ban, epigenetic
|
|
162
352
|
// suppression), so this never bypasses trust/review/inert filtering.
|
|
163
353
|
const cycleForcedGeneId = task.forcedGeneId ?? seededStrategyGeneId;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
354
|
+
let memoryGraphAdvice;
|
|
355
|
+
if (deps.memoryGraph) {
|
|
356
|
+
try {
|
|
357
|
+
memoryGraphAdvice = await deps.memoryGraph.query({ workspace: task.repo, signals: cycleSignals });
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
memoryGraphAdvice = undefined;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
let res;
|
|
364
|
+
try {
|
|
365
|
+
res = await runEvolutionCycle(deps.engine, deps.store, {
|
|
366
|
+
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
367
|
+
...(deps.review ? { review: deps.review } : {}),
|
|
368
|
+
...(deps.includeProbation ? { includeProbation: true } : {}),
|
|
369
|
+
...(hubCandidates.length > 0 ? { hubCandidates } : {}),
|
|
370
|
+
...(deps.solidifyPermit ? { solidifyPermit: deps.solidifyPermit } : {}),
|
|
371
|
+
...(binding ? { executionBinding: binding } : {}),
|
|
372
|
+
...(deps.reuseOutcomes ? { reuseOutcomes: deps.reuseOutcomes } : {}),
|
|
373
|
+
...(deps.recallEvents ? { recallEvents: deps.recallEvents } : {}),
|
|
374
|
+
...(memoryGraphAdvice ? { memoryGraphAdvice } : {}),
|
|
375
|
+
...(strategyName !== undefined ? { strategyName } : {}),
|
|
376
|
+
...(deps.disableSemanticIdf ? { disableSemanticIdf: true } : {}),
|
|
377
|
+
...(deps.selectionPolicy ? { selectionPolicy: deps.selectionPolicy } : {}),
|
|
378
|
+
...(deps.selectionGuard ? { selectionGuard: deps.selectionGuard } : {}),
|
|
379
|
+
...(deps.selectionFloor !== undefined ? { selectionFloor: deps.selectionFloor } : {}),
|
|
380
|
+
...(cycleForcedGeneId !== undefined ? { forcedGeneId: cycleForcedGeneId } : {}),
|
|
381
|
+
cycleId,
|
|
382
|
+
problem: {
|
|
383
|
+
id: task.id, signature: `sig:${task.id}`, signatureV: 1,
|
|
384
|
+
firstSeenAt: new Date(0).toISOString(), lastSeenAt: new Date(0).toISOString(),
|
|
385
|
+
occurrences: 1, linkedSignals: cycleSignals, resolvedBy: null, status: 'open',
|
|
386
|
+
value: { severity: 0.7, reach: 1, strategicFit: 0.9, novelty: 0, costEst: 0.2 },
|
|
387
|
+
consecutiveFailures: 0, cooldownUntil: null, extensions: {},
|
|
388
|
+
},
|
|
389
|
+
signals: cycleSignals, category: 'repair', target: task.target, expectedEffect: task.expectedEffect,
|
|
390
|
+
summary: `autonomous: ${task.id}`, confidence: 0.85, execute, consumePendingSignals: false,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
if (binding && deps.executionBinding) {
|
|
395
|
+
const recovery = deps.executionBinding.journal.recover(task.id, binding.binding_digest);
|
|
396
|
+
if (recovery.kind === 'unsafe_to_replay') {
|
|
397
|
+
try {
|
|
398
|
+
await deps.executionBinding.journal.recordTerminal({
|
|
399
|
+
binding_digest: binding.binding_digest,
|
|
400
|
+
task_id: task.id,
|
|
401
|
+
run_id: binding.correlation.run_id,
|
|
402
|
+
disposition: 'unsafe_to_replay',
|
|
403
|
+
outcome: { status: 'failed', score: 0, reason: recovery.reason },
|
|
404
|
+
provenance: { ...observedProvenance, terminal_disposition: 'unsafe_to_replay' },
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
catch { /* the existing started marker remains fail-closed on recovery */ }
|
|
408
|
+
return { taskId: task.id, status: 'unsafe_to_replay', binding_digest: binding.binding_digest, run_id: binding.correlation.run_id, reason: `binding_replay_unsafe: ${recovery.reason}` };
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
412
|
+
return { taskId: task.id, status: 'failed', ...(binding ? { binding_digest: binding.binding_digest, run_id: binding.correlation.run_id } : {}), reason: detail };
|
|
413
|
+
}
|
|
414
|
+
if (binding && deps.executionBinding) {
|
|
415
|
+
const execution = res.execution;
|
|
416
|
+
if (!execution?.provenance || !execution.executionTerminal) {
|
|
417
|
+
const deniedReason = res.reasons.join('; ') || `cycle ended at ${res.finalStage} before execution`;
|
|
418
|
+
try {
|
|
419
|
+
await deps.executionBinding.journal.recordTerminal({
|
|
420
|
+
binding_digest: binding.binding_digest,
|
|
421
|
+
task_id: task.id,
|
|
422
|
+
run_id: binding.correlation.run_id,
|
|
423
|
+
disposition: 'denied',
|
|
424
|
+
final_stage: res.finalStage,
|
|
425
|
+
outcome: { status: 'failed', score: 0, reason: deniedReason },
|
|
426
|
+
provenance: { ...observedProvenance, terminal_disposition: 'denied' },
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
431
|
+
return { taskId: task.id, status: 'failed', binding_digest: binding.binding_digest, run_id: binding.correlation.run_id, reason: `binding_provenance_unavailable: ${detail}` };
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
taskId: task.id,
|
|
435
|
+
status: 'refused',
|
|
436
|
+
binding_digest: binding.binding_digest,
|
|
437
|
+
run_id: binding.correlation.run_id,
|
|
438
|
+
execution_terminal: { status: 'failed', disposition: 'denied' },
|
|
439
|
+
hub_lifecycle: { state: 'not_submitted' },
|
|
440
|
+
reason: deniedReason,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
const terminal = {
|
|
444
|
+
binding_digest: binding.binding_digest,
|
|
445
|
+
task_id: task.id,
|
|
446
|
+
run_id: binding.correlation.run_id,
|
|
447
|
+
disposition: execution.executionTerminal.disposition,
|
|
448
|
+
final_stage: res.finalStage,
|
|
449
|
+
outcome: execution.outcome,
|
|
450
|
+
...(execution.proofOfWork ? { proof_of_work: execution.proofOfWork } : {}),
|
|
451
|
+
provenance: {
|
|
452
|
+
...execution.provenance,
|
|
453
|
+
gene_ids: res.decision?.selectedGeneId ? [res.decision.selectedGeneId] : [],
|
|
454
|
+
capsule_ids: res.capsule?.asset_id ? [res.capsule.asset_id] : [],
|
|
455
|
+
result_asset_refs: res.capsule?.asset_id ? [res.capsule.asset_id] : [],
|
|
456
|
+
proof_refs: execution.provenance.proof_refs.length > 0
|
|
457
|
+
? execution.provenance.proof_refs
|
|
458
|
+
: execution.proofOfWork?.kind === 'git_diff' && execution.proofOfWork.git_diff?.patch_ref
|
|
459
|
+
? [{ kind: 'git_diff', ref: execution.proofOfWork.git_diff.patch_ref }]
|
|
460
|
+
: execution.provenance.proof_refs,
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
try {
|
|
464
|
+
await deps.executionBinding.journal.recordTerminal(terminal);
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
468
|
+
return { taskId: task.id, status: 'failed', binding_digest: binding.binding_digest, run_id: binding.correlation.run_id, reason: `binding_provenance_unavailable: ${detail}` };
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const status = res.execution?.executionTerminal?.disposition === 'unsafe_to_replay'
|
|
472
|
+
? 'unsafe_to_replay'
|
|
473
|
+
: res.execution?.executionTerminal?.disposition === 'denied'
|
|
474
|
+
? 'refused'
|
|
475
|
+
: res.finalStage === 'solidified' ? 'solidified' : res.finalStage === 'failed' ? 'failed' : res.finalStage === 'aborted' ? 'refused' : 'innovated';
|
|
186
476
|
const cap = res.capsule;
|
|
477
|
+
if (traceRecorder && deps.learningTrace) {
|
|
478
|
+
// Proxy llm_turn fold (slice 5): fold the run window's per-request turns BEFORE run.completed so the
|
|
479
|
+
// trajectory stays sequence-ordered (model/tool detail inside the run, completion last). Own try — a
|
|
480
|
+
// throwing sink mid-fold must not cost the run its completion event or packet draft.
|
|
481
|
+
try {
|
|
482
|
+
const proxyTraces = deps.learningTrace.proxyTraces;
|
|
483
|
+
if (proxyTraces) {
|
|
484
|
+
const turns = collectRunLlmTurns(proxyTraces.dir, { startMs: runStartMs, endMs: proxyTraceClock() }, proxyTraces.readOptions ? { readOptions: proxyTraces.readOptions } : {});
|
|
485
|
+
// Exact-join key for Darwin: bind the unique proxy session before folding turns so
|
|
486
|
+
// every subsequent event (and backfilled earlier ones) carries the same sessionId.
|
|
487
|
+
// Fail closed when 0 or >1 sessions appear — never invent a correlation key.
|
|
488
|
+
const sid = uniqueSessionId(turns);
|
|
489
|
+
if (sid !== null) {
|
|
490
|
+
try {
|
|
491
|
+
traceRecorder.bindSessionId(sid);
|
|
492
|
+
}
|
|
493
|
+
catch { /* observability only */ }
|
|
494
|
+
}
|
|
495
|
+
for (const turn of turns)
|
|
496
|
+
traceRecorder.recordLlmTurn(turn);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
catch { /* observability only */ }
|
|
500
|
+
try {
|
|
501
|
+
traceRecorder.runCompleted({
|
|
502
|
+
status: res.finalStage === 'solidified' ? 'success' : 'failed',
|
|
503
|
+
...(cap?.outcome?.score !== undefined ? { score: cap.outcome.score } : {}),
|
|
504
|
+
...(res.reasons.length > 0 ? { reason: res.reasons.join('; ') } : {}),
|
|
505
|
+
...(res.producedValue !== undefined ? { producedValue: res.producedValue } : {}),
|
|
506
|
+
...(res.failureKind !== undefined ? { failureKind: res.failureKind } : {}),
|
|
507
|
+
});
|
|
508
|
+
await deps.learningTrace.packetSink.submit(buildLearningPacketDraft(traceRecorder, {
|
|
509
|
+
sourceRepo: deps.learningTrace.sourceRepo ?? 'evolver-v2',
|
|
510
|
+
taskSummary: task.expectedEffect,
|
|
511
|
+
signals: cycleSignals,
|
|
512
|
+
environment: {
|
|
513
|
+
repo: task.repo,
|
|
514
|
+
runner: safety.runner ?? (deps.agent ? 'claude' : 'codex'),
|
|
515
|
+
},
|
|
516
|
+
...(observedVerification !== undefined ? { verification: observedVerification } : {}),
|
|
517
|
+
}));
|
|
518
|
+
}
|
|
519
|
+
catch { /* packet delivery is best-effort; never fail the task */ }
|
|
520
|
+
}
|
|
521
|
+
if (deps.memoryGraph && res.decision?.selectedGeneId && (res.finalStage === 'solidified' || res.finalStage === 'failed')) {
|
|
522
|
+
const producedSuccess = res.finalStage === 'solidified' && res.producedValue === true;
|
|
523
|
+
try {
|
|
524
|
+
await deps.memoryGraph.recordOutcome({
|
|
525
|
+
workspace: task.repo,
|
|
526
|
+
signals: cycleSignals,
|
|
527
|
+
geneId: res.decision.selectedGeneId,
|
|
528
|
+
// MemoryGraph has no inert status yet, so record a no-op as conservative failed evidence instead of reward.
|
|
529
|
+
status: producedSuccess ? 'success' : 'failed',
|
|
530
|
+
score: res.finalStage === 'solidified' && !res.producedValue
|
|
531
|
+
? 0
|
|
532
|
+
: cap?.outcome?.score ?? (producedSuccess ? 1 : 0),
|
|
533
|
+
at: new Date().toISOString(),
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
// Memory persistence is advisory and must never fail the autonomous task.
|
|
538
|
+
}
|
|
539
|
+
}
|
|
187
540
|
const hubAssetIds = new Set(hubCandidates.map((c) => c.assetId).filter((id) => typeof id === 'string' && id.length > 0));
|
|
188
541
|
const selectedAssetId = res.decision?.selectedAssetId;
|
|
189
542
|
const usedAssetIds = selectedAssetId && hubAssetIds.has(selectedAssetId) ? [selectedAssetId] : [];
|
|
@@ -192,6 +545,12 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
192
545
|
...(res.reasons.length > 0 && status !== 'solidified' ? { reason: res.reasons.join('; ') } : {}),
|
|
193
546
|
...(cap?.outcome ? { outcome: cap.outcome } : {}),
|
|
194
547
|
...(cap?.proof_of_work ? { proofOfWork: cap.proof_of_work } : {}),
|
|
548
|
+
...(res.failureKind !== undefined ? { failureKind: res.failureKind } : {}),
|
|
549
|
+
...(res.exitCode !== undefined ? { exitCode: res.exitCode } : {}),
|
|
550
|
+
...(res.bindingDigest ? { binding_digest: res.bindingDigest } : {}),
|
|
551
|
+
...(res.runId ? { run_id: res.runId } : {}),
|
|
552
|
+
...(res.execution ? { execution_terminal: res.execution.executionTerminal } : {}),
|
|
553
|
+
...(res.execution?.hubLifecycle ? { hub_lifecycle: res.execution.hubLifecycle } : {}),
|
|
195
554
|
...(usedAssetIds.length > 0 ? { usedAssetIds } : {}),
|
|
196
555
|
};
|
|
197
556
|
}
|