@evomap/evolver 1.88.1 → 1.88.3
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/index.js +159 -3
- package/package.json +2 -1
- package/src/adapters/claudeCode.js +21 -1
- package/src/adapters/hookAdapter.js +4 -2
- package/src/adapters/scripts/_runtimePaths.js +160 -36
- package/src/adapters/scripts/evolver-session-start.js +14 -10
- package/src/adapters/scripts/evolver-task-recall.js +173 -0
- package/src/atp/atpExecute.js +20 -7
- package/src/atp/cli.js +17 -9
- package/src/atp/protocol.js +41 -0
- package/src/config.js +29 -0
- package/src/evolve/guards.js +1 -1
- package/src/evolve/pipeline/collect.js +1 -1
- package/src/evolve/pipeline/dispatch.js +1 -1
- package/src/evolve/pipeline/enrich.js +1 -1
- package/src/evolve/pipeline/hub.js +1 -1
- package/src/evolve/pipeline/select.js +1 -1
- package/src/evolve/pipeline/signals.js +1 -1
- package/src/evolve/utils.js +1 -1
- package/src/evolve.js +1 -1
- package/src/forceUpdate.js +108 -3
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/assetCallLog.js +40 -1
- package/src/gep/autoDistillConv.js +1 -1
- package/src/gep/autoDistillLlm.js +1 -1
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/contentHash.js +1 -1
- package/src/gep/conversationSniffer.js +1 -1
- package/src/gep/crypto.js +1 -1
- package/src/gep/curriculum.js +1 -1
- package/src/gep/deviceId.js +1 -1
- package/src/gep/envFingerprint.js +1 -1
- package/src/gep/epigenetics.js +1 -1
- package/src/gep/execBridge.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hash.js +1 -1
- package/src/gep/hubFetch.js +1 -1
- package/src/gep/hubReview.js +1 -1
- package/src/gep/hubSearch.js +1 -1
- package/src/gep/hubVerify.js +1 -1
- package/src/gep/learningSignals.js +1 -1
- package/src/gep/memoryGraph.js +1 -1
- package/src/gep/memoryGraphAdapter.js +1 -1
- package/src/gep/mutation.js +1 -1
- package/src/gep/narrativeMemory.js +1 -1
- package/src/gep/openPRRegistry.js +1 -1
- package/src/gep/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/recallInject.js +1 -0
- package/src/gep/recallVerifier.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/sanitize.js +5 -0
- package/src/gep/selector.js +1 -1
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/workspaceKeychain.js +1 -1
- package/src/proxy/extensions/traceControl.js +1 -0
- package/src/proxy/index.js +46 -4
- package/src/proxy/inject.js +1 -0
- package/src/proxy/lifecycle/manager.js +457 -2
- package/src/proxy/mailbox/store.js +1 -0
- package/src/proxy/router/messages_route.js +57 -8
- package/src/proxy/trace/extractor.js +1 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// evolver-task-recall.js
|
|
3
|
+
// UserPromptSubmit hook: on each user prompt, find GEP assets (Hub genes +
|
|
4
|
+
// local genes) that match the task and inject a distilled hint so a GENERAL
|
|
5
|
+
// agent benefits from prior distilled capabilities without manually calling
|
|
6
|
+
// MCP tools. This is the per-harness shell around src/gep/recallInject.js.
|
|
7
|
+
//
|
|
8
|
+
// Input (stdin JSON, Claude Code UserPromptSubmit):
|
|
9
|
+
// { "prompt": "...", "session_id", "cwd", "transcript_path", ... }
|
|
10
|
+
// Output (stdout JSON, exit 0 ALWAYS):
|
|
11
|
+
// enforce + match -> { agent_message, additionalContext,
|
|
12
|
+
// hookSpecificOutput: { hookEventName, additionalContext } }
|
|
13
|
+
// everything else -> {} (injects nothing)
|
|
14
|
+
//
|
|
15
|
+
// DESIGN CONTRACT (the fail-open core — see also recallInject.js invariants):
|
|
16
|
+
// - DEFAULT off. off finishes {} WITHOUT parsing the prompt body.
|
|
17
|
+
// - shadow computes + logs what WOULD inject but injects nothing.
|
|
18
|
+
// - enforce injects the distilled hint.
|
|
19
|
+
// - FAIL-OPEN: any error/timeout/empty -> exactly one finish({}). The hook
|
|
20
|
+
// blocks the user's prompt, so it must NEVER hang or crash the session.
|
|
21
|
+
// Claude Code's timeout fail-open behaviour is UNDOCUMENTED, so we own the
|
|
22
|
+
// deadline ourselves with a single watchdog + latch (never rely on the
|
|
23
|
+
// host to kill us gracefully).
|
|
24
|
+
// - STDOUT is a single JSON object. Any stray console.log() from a
|
|
25
|
+
// transitively-required module (e.g. signals._mergeSignals, hubSearch
|
|
26
|
+
// fetch-cost log, assetStore seeding) would corrupt it — so we redirect
|
|
27
|
+
// console.* to stderr before requiring anything heavy.
|
|
28
|
+
|
|
29
|
+
'use strict';
|
|
30
|
+
|
|
31
|
+
// --- stdout-poison defense: route all console.* to stderr ------------------
|
|
32
|
+
// Modules we require (hubSearch, signals, assetStore, …) call console.log,
|
|
33
|
+
// which writes to stdout. The hook contract is ONE JSON object on stdout, so
|
|
34
|
+
// we redirect every console method to stderr. stderr on exit 0 is not fed to
|
|
35
|
+
// the model for UserPromptSubmit; on non-2 exit only its first line shows in
|
|
36
|
+
// the transcript as a hook-error notice — acceptable and we exit 0 anyway.
|
|
37
|
+
for (const m of ['log', 'info', 'warn', 'error', 'debug']) {
|
|
38
|
+
try { console[m] = function () { try { process.stderr.write(''); } catch (_) {} }; } catch (_) {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const path = require('path');
|
|
42
|
+
|
|
43
|
+
// ---- Timing budget, coherent with the host kill ---------------------------
|
|
44
|
+
// The host (Claude Code) kills this process at the hook's `timeout` (5s in
|
|
45
|
+
// buildClaudeHooks -> 5000ms). Our OWN absolute watchdog MUST fire comfortably
|
|
46
|
+
// BEFORE that, or the host could kill us mid-write and break the fail-open
|
|
47
|
+
// stdout contract. So:
|
|
48
|
+
// ABSOLUTE_DEADLINE_MS (3300) < host 5000ms -> ~1.7s headroom for finish().
|
|
49
|
+
// EVOLVER_RECALL_TIMEOUT_MS is the Hub SEARCH budget only (clamped well under
|
|
50
|
+
// the absolute deadline). The actual budget handed to the search is computed
|
|
51
|
+
// DYNAMICALLY at search-start as (deadline - already-elapsed - safety), so
|
|
52
|
+
// slow stdin/require can never let the search run past the watchdog (which
|
|
53
|
+
// would otherwise spuriously return {} — Bugbot #183 medium findings).
|
|
54
|
+
const T0 = Date.now();
|
|
55
|
+
const ABSOLUTE_DEADLINE_MS = 3300; // watchdog; strictly < host timeout (5000ms)
|
|
56
|
+
const SEARCH_SAFETY_MS = 250; // leave room for finish() after the search
|
|
57
|
+
const MIN_SEARCH_MS = 300; // below this, skip the search (finish {})
|
|
58
|
+
|
|
59
|
+
function getSearchBudgetMs() {
|
|
60
|
+
const n = parseInt(process.env.EVOLVER_RECALL_TIMEOUT_MS, 10);
|
|
61
|
+
// Hard cap at 2800 so even a max-budget search starts and ends before the
|
|
62
|
+
// 3300ms watchdog under any realistic startup cost.
|
|
63
|
+
return Number.isFinite(n) && n >= 500 && n <= 2800 ? n : 2000;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getMode() {
|
|
67
|
+
const v = String(process.env.EVOLVER_RECALL_MODE || '').toLowerCase().trim();
|
|
68
|
+
return v === 'shadow' || v === 'enforce' ? v : 'off';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let handled = false;
|
|
72
|
+
let watchdog = null;
|
|
73
|
+
|
|
74
|
+
// Single-writer latch: exactly one stdout write, exactly one exit. Mirrors the
|
|
75
|
+
// proven pattern in evolver-signal-detect.js / evolver-session-end.js.
|
|
76
|
+
function finish(obj) {
|
|
77
|
+
if (handled) return;
|
|
78
|
+
handled = true;
|
|
79
|
+
if (watchdog) { try { clearTimeout(watchdog); } catch (_) {} }
|
|
80
|
+
try { process.stdout.write(JSON.stringify(obj || {})); } catch (_) {}
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function main() {
|
|
85
|
+
const mode = getMode();
|
|
86
|
+
|
|
87
|
+
// Absolute watchdog, armed at process entry and INDEPENDENT of the search
|
|
88
|
+
// budget. Fires at ABSOLUTE_DEADLINE_MS (3300ms) — strictly under the host's
|
|
89
|
+
// timeout (5000ms) so the host can never kill us mid-write. If stdin never
|
|
90
|
+
// closes OR anything hangs, we emit {} and exit cleanly first.
|
|
91
|
+
watchdog = setTimeout(() => finish({}), ABSOLUTE_DEADLINE_MS);
|
|
92
|
+
|
|
93
|
+
let buf = '';
|
|
94
|
+
try {
|
|
95
|
+
process.stdin.setEncoding('utf8');
|
|
96
|
+
} catch (_) { /* some hosts pass no stdin */ }
|
|
97
|
+
process.stdin.on('data', (c) => { buf += c; });
|
|
98
|
+
process.stdin.on('error', () => finish({}));
|
|
99
|
+
process.stdin.on('end', () => {
|
|
100
|
+
if (handled) return;
|
|
101
|
+
|
|
102
|
+
// off: do NOT even parse the prompt body (privacy: nothing read/sent).
|
|
103
|
+
if (mode === 'off') return finish({});
|
|
104
|
+
|
|
105
|
+
let prompt = '';
|
|
106
|
+
let sessionId = '';
|
|
107
|
+
try {
|
|
108
|
+
const input = buf.trim() ? JSON.parse(buf) : {};
|
|
109
|
+
prompt = String(input.prompt || '').trim();
|
|
110
|
+
sessionId = String(input.session_id || input.sessionId || '').trim();
|
|
111
|
+
} catch (_) {
|
|
112
|
+
return finish({});
|
|
113
|
+
}
|
|
114
|
+
if (prompt.length < 8) return finish({}); // trivial prompt -> skip
|
|
115
|
+
|
|
116
|
+
// Heavy require INSIDE try/catch: a broken require graph must fail open,
|
|
117
|
+
// not crash the user's prompt (this is also why the e2e test runs the
|
|
118
|
+
// copied hook with mode=off and asserts exit 0 + parseable stdout).
|
|
119
|
+
let core;
|
|
120
|
+
try {
|
|
121
|
+
const { findEvolverRoot } = require('./_runtimePaths');
|
|
122
|
+
const root = findEvolverRoot();
|
|
123
|
+
if (!root) return finish({});
|
|
124
|
+
core = require(path.join(root, 'src', 'gep', 'recallInject.js'));
|
|
125
|
+
} catch (_) {
|
|
126
|
+
return finish({});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Pass the ABSOLUTE deadline (T0 + watchdog window) plus the configured
|
|
130
|
+
// search cap. The core bounds the Hub call by the time REMAINING to that
|
|
131
|
+
// deadline (minus its own post-await safety margin) and runs local-gene
|
|
132
|
+
// disk I/O BEFORE the Hub await — so neither the Hub search nor the
|
|
133
|
+
// post-processing can overrun the watchdog (Bugbot #183: slow startup or a
|
|
134
|
+
// budget-eating Hub call must not let the timer fire mid-work). If too
|
|
135
|
+
// little time remains even before starting, skip and fail open.
|
|
136
|
+
const elapsed = Date.now() - T0;
|
|
137
|
+
const remaining = ABSOLUTE_DEADLINE_MS - elapsed - SEARCH_SAFETY_MS;
|
|
138
|
+
if (remaining < MIN_SEARCH_MS) return finish({});
|
|
139
|
+
const deadlineMs = T0 + ABSOLUTE_DEADLINE_MS;
|
|
140
|
+
|
|
141
|
+
Promise.resolve()
|
|
142
|
+
.then(() => core.recallForTask({ prompt, mode, sessionId, timeoutMs: getSearchBudgetMs(), deadlineMs }))
|
|
143
|
+
.then((r) => {
|
|
144
|
+
if (r && r.inject && r.text) {
|
|
145
|
+
// Emit BOTH shapes:
|
|
146
|
+
// - nested hookSpecificOutput.additionalContext is the DOCUMENTED
|
|
147
|
+
// canonical UserPromptSubmit injection shape (system-reminder,
|
|
148
|
+
// no transcript noise).
|
|
149
|
+
// - flat additionalContext / agent_message match the in-repo
|
|
150
|
+
// precedent (session-start.js) for hosts that read the flat key.
|
|
151
|
+
// Extra keys are tolerated/ignored by hosts; whichever wins, the
|
|
152
|
+
// other is harmless.
|
|
153
|
+
return finish({
|
|
154
|
+
agent_message: r.text,
|
|
155
|
+
additionalContext: r.text,
|
|
156
|
+
hookSpecificOutput: {
|
|
157
|
+
hookEventName: 'UserPromptSubmit',
|
|
158
|
+
additionalContext: r.text,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// shadow (logged inside the core) and no-match both inject nothing.
|
|
163
|
+
return finish({});
|
|
164
|
+
})
|
|
165
|
+
.catch(() => finish({}));
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (require.main === module) {
|
|
170
|
+
main();
|
|
171
|
+
} else {
|
|
172
|
+
module.exports = { getMode, getSearchBudgetMs };
|
|
173
|
+
}
|
package/src/atp/atpExecute.js
CHANGED
|
@@ -59,7 +59,7 @@ function _buildGene(capabilities, signals) {
|
|
|
59
59
|
: ['atp_task'];
|
|
60
60
|
const gene = {
|
|
61
61
|
type: 'Gene',
|
|
62
|
-
schema_version: '1.0',
|
|
62
|
+
schema_version: '1.0.0',
|
|
63
63
|
id: 'gene_atp_answer_' + caps.sort().join('_').slice(0, 40),
|
|
64
64
|
summary: 'Deliver an ATP task answer for capabilities: ' + caps.join(', '),
|
|
65
65
|
signals_match: sig,
|
|
@@ -69,6 +69,9 @@ function _buildGene(capabilities, signals) {
|
|
|
69
69
|
'Produce a concrete, actionable answer addressing the question directly.',
|
|
70
70
|
'Return the answer as Capsule content for verifiable delivery.',
|
|
71
71
|
],
|
|
72
|
+
// gep-sdk Gene schema requires `constraints`; an ATP answer edits no
|
|
73
|
+
// files, so the blast radius is empty rather than left unbounded.
|
|
74
|
+
constraints: { max_files: 0, forbidden_paths: [] },
|
|
72
75
|
validation: [
|
|
73
76
|
'Answer is non-empty and directly addresses the buyer question.',
|
|
74
77
|
'Answer references the requested capabilities where relevant.',
|
|
@@ -86,7 +89,7 @@ function _buildCapsule({ gene, answer, summary, orderId, taskId, capabilities, s
|
|
|
86
89
|
|| 'ATP merchant delivery for order ' + String(orderId || '').slice(0, 24);
|
|
87
90
|
const capsule = {
|
|
88
91
|
type: 'Capsule',
|
|
89
|
-
schema_version: '1.0',
|
|
92
|
+
schema_version: '1.0.0',
|
|
90
93
|
id: 'capsule_atp_' + String(orderId || taskId || Date.now()).replace(/[^a-zA-Z0-9_\-]/g, '_').slice(0, 40),
|
|
91
94
|
trigger: sig,
|
|
92
95
|
gene: gene.id,
|
|
@@ -96,11 +99,21 @@ function _buildCapsule({ gene, answer, summary, orderId, taskId, capabilities, s
|
|
|
96
99
|
outcome: { status: 'success', score: confidence },
|
|
97
100
|
env_fingerprint: { platform: process.platform, arch: process.arch, runtime: 'evolver-atp' },
|
|
98
101
|
content: answer,
|
|
99
|
-
|
|
100
|
-
atp
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
// 'generated' is the gep-sdk source_type enum value for a freshly
|
|
103
|
+
// produced asset; the ATP-specific provenance rides in `a2a.atp` below.
|
|
104
|
+
source_type: 'generated',
|
|
105
|
+
// The order/task association MUST live under `a2a`, not as a top-level
|
|
106
|
+
// `atp` key: the Hub's payload sanitizer allow-lists `a2a` but not `atp`
|
|
107
|
+
// (CAPSULE_ALLOWED_FIELDS), so a top-level `atp` was being silently
|
|
108
|
+
// stripped on publish and the association never reached the Hub. `a2a`
|
|
109
|
+
// is also an open object in gep-sdk's Capsule schema, so this keeps the
|
|
110
|
+
// bundle GEP-valid.
|
|
111
|
+
a2a: {
|
|
112
|
+
atp: {
|
|
113
|
+
order_id: orderId || null,
|
|
114
|
+
task_id: taskId || null,
|
|
115
|
+
capabilities: caps,
|
|
116
|
+
},
|
|
104
117
|
},
|
|
105
118
|
};
|
|
106
119
|
capsule.asset_id = computeAssetId(capsule);
|
package/src/atp/cli.js
CHANGED
|
@@ -14,6 +14,14 @@
|
|
|
14
14
|
// injectable for tests. Each runner returns a Promise that resolves to
|
|
15
15
|
// { exitCode: number, output?: string, data?: object }.
|
|
16
16
|
|
|
17
|
+
const {
|
|
18
|
+
ATP_VERIFY_MODES,
|
|
19
|
+
ATP_VERIFY_ACTIONS,
|
|
20
|
+
ATP_ROUTING_MODES,
|
|
21
|
+
ATP_PROOF_STATUSES,
|
|
22
|
+
ATP_ROLES,
|
|
23
|
+
} = require('./protocol');
|
|
24
|
+
|
|
17
25
|
function _parseNamed(args, longFlag, shortFlag) {
|
|
18
26
|
const long = args.findIndex(a => typeof a === 'string' && (a === longFlag || a.startsWith(longFlag + '=')));
|
|
19
27
|
if (long !== -1) {
|
|
@@ -83,11 +91,11 @@ function parseBuyArgs(args) {
|
|
|
83
91
|
|
|
84
92
|
function parseOrdersArgs(args) {
|
|
85
93
|
const role = _parseNamed(args, '--role', null);
|
|
86
|
-
if (role && !
|
|
87
|
-
return { ok: false, error: 'invalid --role: ' + role + ' (expected
|
|
94
|
+
if (role && !ATP_ROLES.includes(role)) {
|
|
95
|
+
return { ok: false, error: 'invalid --role: ' + role + ' (expected ' + ATP_ROLES.join('|') + ')' };
|
|
88
96
|
}
|
|
89
97
|
const status = _parseNamed(args, '--status', null);
|
|
90
|
-
if (status && !
|
|
98
|
+
if (status && !ATP_PROOF_STATUSES.includes(status)) {
|
|
91
99
|
return { ok: false, error: 'invalid --status: ' + status };
|
|
92
100
|
}
|
|
93
101
|
const limitRaw = _parseNamed(args, '--limit', null);
|
|
@@ -112,8 +120,8 @@ function parseVerifyArgs(args) {
|
|
|
112
120
|
return { ok: false, error: 'verify requires <orderId>' };
|
|
113
121
|
}
|
|
114
122
|
const action = _parseNamed(args, '--action', null) || 'confirm';
|
|
115
|
-
if (!
|
|
116
|
-
return { ok: false, error: 'invalid --action: ' + action + ' (expected
|
|
123
|
+
if (!ATP_VERIFY_ACTIONS.includes(action)) {
|
|
124
|
+
return { ok: false, error: 'invalid --action: ' + action + ' (expected ' + ATP_VERIFY_ACTIONS.join('|') + ')' };
|
|
117
125
|
}
|
|
118
126
|
return { ok: true, opts: { orderId, action } };
|
|
119
127
|
}
|
|
@@ -324,11 +332,11 @@ async function runAtp(opts, deps) {
|
|
|
324
332
|
function printUsage() {
|
|
325
333
|
return [
|
|
326
334
|
'ATP subcommands:',
|
|
327
|
-
' evolver buy <caps> [--budget=N] [--question "..."] [--routing=
|
|
328
|
-
' [--verify=
|
|
329
|
-
' evolver orders [--role=
|
|
335
|
+
' evolver buy <caps> [--budget=N] [--question "..."] [--routing=' + ATP_ROUTING_MODES.join('|') + ']',
|
|
336
|
+
' [--verify=' + ATP_VERIFY_MODES.join('|') + '] [--no-wait] [--timeout=<seconds>]',
|
|
337
|
+
' evolver orders [--role=' + ATP_ROLES.join('|') + '] [--status=' + ATP_PROOF_STATUSES.join('|') + ']',
|
|
330
338
|
' [--limit=N] [--json]',
|
|
331
|
-
' evolver verify <orderId> [--action=
|
|
339
|
+
' evolver verify <orderId> [--action=' + ATP_VERIFY_ACTIONS.join('|') + ']',
|
|
332
340
|
' evolver atp <enable|disable|status> -- manage auto-spend consent',
|
|
333
341
|
].join('\n');
|
|
334
342
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Protocol-level enum constants for the Agent Transaction Protocol.
|
|
2
|
+
//
|
|
3
|
+
// These values (verify modes, routing modes, proof statuses, roles,
|
|
4
|
+
// execution modes) live in @evomap/atp-sdk. This module is a thin
|
|
5
|
+
// CommonJS facade so callsites in src/atp/ can `require('./protocol')`
|
|
6
|
+
// for the authoritative sets instead of re-spelling the literals.
|
|
7
|
+
//
|
|
8
|
+
// Why move them out: ATP is the wire contract between this engine, the
|
|
9
|
+
// EvoMap Hub, and (in future) evox-Rust. Hand-maintaining the allowed
|
|
10
|
+
// value sets in each implementation is exactly the drift that the
|
|
11
|
+
// v1.80.8 "explore" enum incident taught us to avoid for GEP. The ATP
|
|
12
|
+
// contract is extracted into its own SDK before a second runtime wires
|
|
13
|
+
// in, while it is still cheap. If you find yourself writing an enum
|
|
14
|
+
// list literal here again (e.g. ['pending','verified',...]), stop --
|
|
15
|
+
// import the constant from this facade instead, and bump
|
|
16
|
+
// @evomap/atp-sdk if the set itself needs to change.
|
|
17
|
+
//
|
|
18
|
+
// Implementation note: @evomap/atp-sdk is published as ESM
|
|
19
|
+
// (`"type": "module"`). Node supports `require()` of synchronous ESM
|
|
20
|
+
// packages on 22.12.0 and later. The SDK itself stays permissive
|
|
21
|
+
// (`engines.node >=18`) so `import`-based consumers on 18/20 aren't
|
|
22
|
+
// blocked; the `>=22.12` guarantee that makes the require() below work
|
|
23
|
+
// is pinned in THIS package's (evolver's) `engines.node`, not the SDK's.
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
ATP_VERIFY_MODES,
|
|
27
|
+
ATP_VERIFY_ACTIONS,
|
|
28
|
+
ATP_ROUTING_MODES,
|
|
29
|
+
ATP_PROOF_STATUSES,
|
|
30
|
+
ATP_ROLES,
|
|
31
|
+
ATP_EXECUTION_MODES,
|
|
32
|
+
} = require('@evomap/atp-sdk');
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
ATP_VERIFY_MODES,
|
|
36
|
+
ATP_VERIFY_ACTIONS,
|
|
37
|
+
ATP_ROUTING_MODES,
|
|
38
|
+
ATP_PROOF_STATUSES,
|
|
39
|
+
ATP_ROLES,
|
|
40
|
+
ATP_EXECUTION_MODES,
|
|
41
|
+
};
|
package/src/config.js
CHANGED
|
@@ -136,9 +136,14 @@ const REPAIR_LOOP_THRESHOLD = envInt('EVOLVER_REPAIR_LOOP_THRESHOLD', 3);
|
|
|
136
136
|
//
|
|
137
137
|
// GENE_BAN_PER_KEY_ATTEMPTS: minimum attempts on the same signal key
|
|
138
138
|
// GENE_BAN_BEST_THRESHOLD: best success rate at or below which the Gene is banned
|
|
139
|
+
// GENE_INERT_BAN_STREAK: consecutive inert (stable_no_error, zero-work) outcomes
|
|
140
|
+
// on a signal key after which a Gene with no real
|
|
141
|
+
// success is banned, so --loop selection explores
|
|
142
|
+
// instead of re-running a do-nothing gene (#562)
|
|
139
143
|
// GENE_EPIGENETIC_HARD_BOOST: epigenetic boost at or below which the Gene is hard-suppressed
|
|
140
144
|
const GENE_BAN_PER_KEY_ATTEMPTS = envInt('EVOLVER_GENE_BAN_PER_KEY_ATTEMPTS', 4);
|
|
141
145
|
const GENE_BAN_BEST_THRESHOLD = envFloat('EVOLVER_GENE_BAN_BEST_THRESHOLD', 0.15);
|
|
146
|
+
const GENE_INERT_BAN_STREAK = envInt('EVOLVER_GENE_INERT_BAN_STREAK', 8);
|
|
142
147
|
const GENE_EPIGENETIC_HARD_BOOST = envFloat('EVOLVER_GENE_EPIGENETIC_HARD_BOOST', -0.3);
|
|
143
148
|
const SESSION_ARCHIVE_TRIGGER = envInt('EVOLVER_SESSION_ARCHIVE_TRIGGER', 100);
|
|
144
149
|
const SESSION_ARCHIVE_KEEP = envInt('EVOLVER_SESSION_ARCHIVE_KEEP', 50);
|
|
@@ -177,6 +182,26 @@ const SELF_PR_TIMEOUT_MS = envInt('EVOLVER_SELF_PR_TIMEOUT_MS', 30000);
|
|
|
177
182
|
|
|
178
183
|
const LEAK_CHECK_MODE = envStr('EVOLVER_LEAK_CHECK', 'strict');
|
|
179
184
|
|
|
185
|
+
// --- Reuse attribution (P4-a, Slice A) ---
|
|
186
|
+
// Controls whether the evolver attaches a `reuse_attribution` block to the
|
|
187
|
+
// synced `outcome` MemoryGraphEvent so the Hub can LATER (P4-a Slice B, gated +
|
|
188
|
+
// team-signed-off) credit the SOURCE node when its asset is reused. Modes:
|
|
189
|
+
// off (default) — attach nothing; byte-identical to pre-P4-a behavior.
|
|
190
|
+
// shadow — attach the attribution block; it rides the existing
|
|
191
|
+
// syncEventToHub -> /a2a/memory/event into the Hub's
|
|
192
|
+
// MemoryGraphEvent.payload blob, which is GDI-inert and
|
|
193
|
+
// read by NO payout path today.
|
|
194
|
+
// There is intentionally NO `enforce` on the CLIENT: the evolver cannot move
|
|
195
|
+
// money, so an enforce word would be a lie. The report stays economy-inert
|
|
196
|
+
// until a SIGNED-OFF Hub reader converts it to credit (which MUST add the
|
|
197
|
+
// anti-sybil gating — see P4-a Slice B). Until then it only emits honest,
|
|
198
|
+
// runtime-observed attribution data (never agent-supplied identity).
|
|
199
|
+
const REUSE_ATTRIBUTION_MODE = envStr('EVOLVER_REUSE_ATTRIBUTION', 'off');
|
|
200
|
+
function reuseAttributionMode() {
|
|
201
|
+
const v = String(process.env.EVOLVER_REUSE_ATTRIBUTION || REUSE_ATTRIBUTION_MODE || 'off').toLowerCase().trim();
|
|
202
|
+
return v === 'shadow' ? 'shadow' : 'off';
|
|
203
|
+
}
|
|
204
|
+
|
|
180
205
|
// --- Validator mode (opt-out) ---
|
|
181
206
|
// Node role: the evolver periodically fetches assigned validation tasks from
|
|
182
207
|
// the Hub, runs the commands in an isolated sandbox, and submits
|
|
@@ -223,6 +248,7 @@ module.exports = {
|
|
|
223
248
|
REPAIR_LOOP_THRESHOLD,
|
|
224
249
|
GENE_BAN_PER_KEY_ATTEMPTS,
|
|
225
250
|
GENE_BAN_BEST_THRESHOLD,
|
|
251
|
+
GENE_INERT_BAN_STREAK,
|
|
226
252
|
GENE_EPIGENETIC_HARD_BOOST,
|
|
227
253
|
SESSION_ARCHIVE_TRIGGER,
|
|
228
254
|
SESSION_ARCHIVE_KEEP,
|
|
@@ -257,6 +283,9 @@ module.exports = {
|
|
|
257
283
|
BLAST_RADIUS_HARD_CAP_LINES,
|
|
258
284
|
// Security
|
|
259
285
|
LEAK_CHECK_MODE,
|
|
286
|
+
// Reuse attribution (P4-a Slice A)
|
|
287
|
+
REUSE_ATTRIBUTION_MODE,
|
|
288
|
+
reuseAttributionMode,
|
|
260
289
|
// Validator (opt-in role)
|
|
261
290
|
VALIDATOR_ENABLED,
|
|
262
291
|
VALIDATOR_STAKE_AMOUNT,
|