@evomap/evolver-core 2.0.0-beta.19 → 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 +143 -20
- package/dist/algo/capabilityCandidates.js +10 -0
- package/dist/algo/cycleEngine.d.ts +40 -5
- package/dist/algo/cycleEngine.js +277 -37
- 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 +34 -1
- package/dist/algo/geneHealth.js +42 -0
- package/dist/algo/geneIntake.d.ts +46 -1
- package/dist/algo/geneIntake.js +121 -10
- package/dist/algo/geneSelection.d.ts +115 -6
- package/dist/algo/geneSelection.js +459 -32
- package/dist/algo/index.d.ts +4 -1
- package/dist/algo/index.js +4 -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/orchestrator.d.ts +14 -1
- package/dist/algo/orchestrator.js +9 -2
- 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.js +5 -1
- package/dist/assetstore/assetStoreHealth.d.ts +2 -3
- package/dist/assetstore/assetStoreHealth.js +4 -10
- package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
- package/dist/assetstore/foreignJsonlSource.js +150 -0
- package/dist/assetstore/index.d.ts +3 -0
- package/dist/assetstore/index.js +3 -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 +8 -0
- package/dist/assetstore/localJsonl.js +128 -3
- package/dist/assetstore/provenance.d.ts +38 -3
- package/dist/assetstore/provenance.js +103 -45
- package/dist/assetstore/provider.d.ts +4 -0
- package/dist/assetstore/reviewFilter.d.ts +19 -1
- package/dist/assetstore/reviewFilter.js +36 -0
- 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 +2 -1
- package/dist/benchmark/index.js +2 -1
- package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
- package/dist/benchmark/selectionFlatAbstention.js +481 -0
- package/dist/bootstrap/envFingerprint.d.ts +9 -0
- package/dist/bootstrap/envFingerprint.js +5 -0
- package/dist/bootstrap/index.d.ts +2 -1
- package/dist/bootstrap/index.js +2 -1
- package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
- package/dist/bootstrap/lifecycleBootstrap.js +433 -0
- package/dist/bootstrap/v1EnvCompat.d.ts +3 -0
- package/dist/bootstrap/v1EnvCompat.js +48 -1
- 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 +6 -0
- package/dist/exec/autoExec.d.ts +30 -3
- package/dist/exec/autoExec.js +294 -29
- package/dist/exec/autonomousCycle.d.ts +7 -0
- package/dist/exec/autonomousCycle.js +2 -0
- package/dist/exec/claudeBridge.d.ts +28 -6
- package/dist/exec/claudeBridge.js +411 -258
- 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/proofOfWork.d.ts +1 -1
- package/dist/exec/proofOfWork.js +2 -2
- package/dist/exec/runnerRegistry.d.ts +5 -0
- package/dist/exec/runnerRegistry.js +54 -14
- package/dist/hub/capability.d.ts +40 -1
- package/dist/hub/conversationDistiller.d.ts +19 -0
- package/dist/hub/conversationDistiller.js +115 -37
- package/dist/hub/fake.d.ts +1 -0
- package/dist/hub/fake.js +1 -0
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/hub/recipeCompose.d.ts +27 -0
- package/dist/hub/recipeCompose.js +90 -0
- package/dist/hub/sanitize.js +119 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mailbox/ipcServer.d.ts +2 -0
- package/dist/mailbox/ipcServer.js +20 -0
- package/dist/mailbox/store.d.ts +52 -2
- package/dist/mailbox/store.js +546 -81
- 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/selfUpdate.d.ts +8 -0
- package/dist/ops/selfUpdate.js +24 -8
- package/dist/ops/valueOutreach.d.ts +3 -1
- package/dist/ops/valueOutreach.js +5 -1
- package/dist/personality/schema.d.ts +18 -18
- 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/shadow/shadowHub.js +1 -0
- package/dist/signals/expand.d.ts +15 -1
- package/dist/signals/expand.js +148 -0
- package/dist/signals/index.d.ts +3 -1
- package/dist/signals/index.js +3 -1
- package/dist/signals/scopeVocabulary.d.ts +75 -0
- package/dist/signals/scopeVocabulary.js +91 -0
- package/dist/signals/taskDomain.d.ts +22 -0
- package/dist/signals/taskDomain.js +43 -0
- package/dist/trace/learningTrace.d.ts +7 -0
- package/dist/trace/learningTrace.js +22 -0
- package/dist/trace/trajectory.d.ts +8 -0
- package/dist/trace/trajectory.js +14 -2
- package/dist/util/fileLock.d.ts +92 -5
- package/dist/util/fileLock.js +809 -70
- package/dist/util/index.d.ts +2 -1
- package/dist/util/index.js +1 -1
- package/dist/verify/index.d.ts +2 -1
- package/dist/verify/index.js +1 -1
- package/dist/verify/sandboxRunner.d.ts +2 -0
- package/dist/verify/sandboxRunner.js +154 -10
- package/dist/verify/sandboxedValidation.d.ts +7 -2
- package/dist/verify/sandboxedValidation.js +102 -24
- package/dist/verify/validation.d.ts +24 -3
- package/dist/verify/validation.js +141 -24
- 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/package.json +5 -4
package/assets/gep/genes.jsonl
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
{"type":"Gene","schema_version":"1.
|
|
2
|
-
{"type":"Gene","schema_version":"1.
|
|
3
|
-
{"type":"Gene","schema_version":"1.
|
|
4
|
-
{"type":"Gene","schema_version":"1.
|
|
5
|
-
{"type":"Gene","schema_version":"1.
|
|
1
|
+
{"type":"Gene","schema_version":"1.13.0","id":"gene_seed_publish_feishu_doc","category":"innovate","signals_match":["publish_markdown_to_feishu","create_feishu_doc","export_report_to_feishu","publish_results_to_lark_doc","feishu_doc","lark_doc"],"preconditions":["lark-cli is installed and available on PATH.","lark-cli auth status reports a ready user or bot identity."],"strategy":["Run lark-cli doctor and require an ok result before publishing.","Use the Docs v2 API and avoid deprecated Docs v1 flags.","Write long Markdown content to a temporary file and pass it as an @file input.","Create or update the document with the intended user or bot identity, then return the document URL.","Never overwrite local lark-cli credential files while preparing the document."],"constraints":{"max_files":2,"forbidden_paths":[".git","node_modules","~/.lark-cli/config.json"]},"validation":["node --version"],"summary":"Publish Markdown content as a Feishu/Lark document through the official CLI, using file-backed content and Docs v2.","asset_id":"sha256:7a8f6c4217ab2594b1412e4db1eccd4c3ac30d3a689054b956c0da6477c154bd"}
|
|
2
|
+
{"type":"Gene","schema_version":"1.13.0","id":"gene_seed_conventional_git_commit","category":"optimize","signals_match":["git_commit","create_commit","commit_changes","conventional_commit","stage_and_commit","write_commit_message"],"preconditions":["A git repository has staged or unstaged changes that should become one logical commit."],"strategy":["Inspect git status plus the staged or unstaged diff before choosing a commit shape.","Pick a Conventional Commits type and optional scope from the actual changed files.","Stage only the intended logical files and never stage credentials or unrelated changes.","Write a present-tense imperative subject under 72 characters, with body or footer when needed.","Do not amend, force-push, hard-reset, or bypass hooks without explicit operator approval."],"constraints":{"max_files":50,"forbidden_paths":[".git","node_modules"]},"validation":["node --version"],"summary":"Create a focused Conventional Commits-style git commit from the real diff while avoiding secrets and unrelated changes.","asset_id":"sha256:46b34569c273b60d84501764ae20e15c6b7eb52a743db1a393e0d52272212574"}
|
|
3
|
+
{"type":"Gene","schema_version":"1.13.0","id":"gene_seed_poll_bugbot_review","category":"optimize","signals_match":["poll_bugbot","bugbot_review","wait_for_ci_review","pr_review_gate","cursor_bugbot","pr_opened"],"preconditions":["An open GitHub PR exists and Cursor Bugbot is expected to review it."],"strategy":["Poll the Cursor Bugbot check by name until it reaches a terminal conclusion or the operator timeout is reached.","Treat SUCCESS as mergeable only when required checks are green and there are no unresolved Bugbot comments.","Treat NEUTRAL as not passed; fetch and summarize Cursor Bugbot inline comments for the operator.","On FAILURE or ACTION_REQUIRED, surface the findings and do not merge automatically.","Only squash-merge when the operator explicitly asked for merge and the review gate is clean."],"constraints":{"max_files":1,"forbidden_paths":[".git","node_modules"]},"validation":["node --version"],"summary":"Wait for Cursor Bugbot on a GitHub PR and gate merge decisions on the actual check conclusion and comments.","asset_id":"sha256:e137a220e84e08c784f438186c100d785c45bcc3d327082fc5661f5a76cb8de1"}
|
|
4
|
+
{"type":"Gene","schema_version":"1.13.0","id":"gene_seed_gateway_timeout_recovery","category":"repair","signals_match":["gateway_timeout","upstream_timeout","http_524","http_504","request_timed_out","retry_on_timeout"],"preconditions":["A tool call, fetch, subagent request, or long command returned a gateway-class timeout."],"strategy":["Treat gateway timeout as transient or size-driven until one bounded recovery attempt proves otherwise.","Retry the exact same operation once, then stop retrying the monolithic call.","If the retry also times out, split the work by file, directory, endpoint, record, section, or time window.","Run independent slices in parallel when safe and merge the results.","Apply the same decomposition recursively only to the slice that still times out."],"constraints":{"max_files":1,"forbidden_paths":[".git","node_modules"]},"validation":["node --version"],"summary":"Recover from gateway or upstream timeouts by retrying once, then decomposing the work instead of looping the same large call.","asset_id":"sha256:72177d7186fe623de4d9fcc440e1e6d36055467e7f86b248a97318db04be26e5"}
|
|
5
|
+
{"type":"Gene","schema_version":"1.13.0","id":"gene_seed_github_webhook_listener","category":"innovate","signals_match":["github_webhook_listener","bugbot_webhook","passive_pr_notifications","notify_when_bugbot_finishes","webhook_tunnel","github_pr_inbox"],"preconditions":["A developer machine can run a local listener and an outbound tunnel for GitHub webhook delivery."],"strategy":["Use an HMAC-validated local listener for GitHub webhook payloads and deduplicate delivery ids.","Expose the listener through an outbound-only tunnel rather than an inbound public port.","Write vetted notifications into a local inbox with restrictive permissions; never execute webhook payloads.","On session start, re-fetch PR state through GitHub before surfacing any inbox item.","Rotate webhook secrets periodically and immediately after suspected exposure."],"constraints":{"max_files":20,"forbidden_paths":[".git","node_modules"]},"validation":["node --version"],"summary":"Deploy a local HMAC-validated GitHub webhook listener that turns PR and Bugbot events into safe operator notifications.","asset_id":"sha256:dc6f0573c360e8e31b41142e3e4d782dcfb848a2256a4187079c3cea7edba584"}
|
package/dist/algo/bans.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export interface FailedCapsuleRef {
|
|
2
2
|
gene?: string;
|
|
3
3
|
trigger?: readonly string[];
|
|
4
|
+
/** Stable logical FailureRecord id; duplicate deliveries of the same record count once. */
|
|
5
|
+
failureId?: string;
|
|
6
|
+
/** Root attempt shared by automatic retries; sharing this id makes retry fan-out count once. */
|
|
7
|
+
rootAttemptId?: string;
|
|
8
|
+
/** Execution/run id; duplicate deliveries of one execution count once even if other metadata diverges. */
|
|
9
|
+
executionId?: string;
|
|
10
|
+
/** Optional verifier+artifact digest pair refines legacy evidence when no direct failure/root/execution id exists. */
|
|
11
|
+
verifierDigest?: string;
|
|
12
|
+
artifactDigest?: string;
|
|
4
13
|
}
|
|
5
|
-
/** Gene ids with >=2 failed capsules whose trigger covers >=60% of the current signals. */
|
|
14
|
+
/** Gene ids with >=2 independent failed capsules whose trigger covers >=60% of the current signals. */
|
|
6
15
|
export declare function bannedGenesFromFailures(failures: readonly FailedCapsuleRef[], signals: readonly string[]): Set<string>;
|
package/dist/algo/bans.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Ban genes that have repeatedly failed on the SAME signals (ported from v1 selector.js
|
|
2
2
|
// banGenesFromFailedCapsules). Complements epigenetic suppression (which is per-environment): this is a
|
|
3
|
-
// hard, signal-overlap-based exclusion —
|
|
4
|
-
//
|
|
3
|
+
// hard, signal-overlap-based exclusion — but only when the failures carry counted identity quality. Legacy raw
|
|
4
|
+
// or partial-digest rows remain audit/advisory evidence and cannot satisfy the automatic tau=2 quarantine.
|
|
5
5
|
const BAN_THRESHOLD = 2;
|
|
6
6
|
const OVERLAP_MIN = 0.6;
|
|
7
7
|
/** Fraction of the current signals covered by a failure's trigger (how much it is "the same problem"). */
|
|
@@ -15,7 +15,52 @@ function signalCoverage(signals, trigger) {
|
|
|
15
15
|
hit += 1;
|
|
16
16
|
return hit / signals.length;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
function nonEmpty(s) {
|
|
19
|
+
return typeof s === 'string' && s.trim().length > 0 ? s.trim() : undefined;
|
|
20
|
+
}
|
|
21
|
+
function failureEvidenceIdentity(fc) {
|
|
22
|
+
const failure = nonEmpty(fc.failureId);
|
|
23
|
+
const root = nonEmpty(fc.rootAttemptId);
|
|
24
|
+
const execution = nonEmpty(fc.executionId);
|
|
25
|
+
const direct = [
|
|
26
|
+
failure ? `failure:${failure}` : undefined,
|
|
27
|
+
root ? `root:${root}` : undefined,
|
|
28
|
+
execution ? `execution:${execution}` : undefined,
|
|
29
|
+
].filter((key) => key !== undefined);
|
|
30
|
+
if (direct.length > 0)
|
|
31
|
+
return { quality: 'strong_id', keys: direct };
|
|
32
|
+
const verifier = nonEmpty(fc.verifierDigest);
|
|
33
|
+
const artifact = nonEmpty(fc.artifactDigest);
|
|
34
|
+
if (verifier && artifact)
|
|
35
|
+
return { quality: 'complete_verifier_artifact_digest', keys: [`evidence:${verifier}:${artifact}`] };
|
|
36
|
+
if (verifier || artifact)
|
|
37
|
+
return { quality: 'legacy_partial', keys: [] };
|
|
38
|
+
return { quality: 'legacy_raw', keys: [] };
|
|
39
|
+
}
|
|
40
|
+
function isCountedIdentity(identity) {
|
|
41
|
+
return identity.quality === 'strong_id' || identity.quality === 'complete_verifier_artifact_digest';
|
|
42
|
+
}
|
|
43
|
+
function addFailureIdentity(clusters, keys) {
|
|
44
|
+
const matches = [];
|
|
45
|
+
for (let i = 0; i < clusters.length; i++) {
|
|
46
|
+
if (keys.some((key) => clusters[i].has(key)))
|
|
47
|
+
matches.push(i);
|
|
48
|
+
}
|
|
49
|
+
if (matches.length === 0) {
|
|
50
|
+
clusters.push(new Set(keys));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const target = clusters[matches[0]];
|
|
54
|
+
for (const key of keys)
|
|
55
|
+
target.add(key);
|
|
56
|
+
for (let i = matches.length - 1; i > 0; i--) {
|
|
57
|
+
const index = matches[i];
|
|
58
|
+
for (const key of clusters[index])
|
|
59
|
+
target.add(key);
|
|
60
|
+
clusters.splice(index, 1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Gene ids with >=2 independent failed capsules whose trigger covers >=60% of the current signals. */
|
|
19
64
|
export function bannedGenesFromFailures(failures, signals) {
|
|
20
65
|
const counts = new Map();
|
|
21
66
|
for (const fc of failures) {
|
|
@@ -23,11 +68,16 @@ export function bannedGenesFromFailures(failures, signals) {
|
|
|
23
68
|
continue;
|
|
24
69
|
if (signalCoverage(signals, fc.trigger ?? []) < OVERLAP_MIN)
|
|
25
70
|
continue;
|
|
26
|
-
|
|
71
|
+
const identity = failureEvidenceIdentity(fc);
|
|
72
|
+
if (!isCountedIdentity(identity))
|
|
73
|
+
continue;
|
|
74
|
+
const clusters = counts.get(fc.gene) ?? [];
|
|
75
|
+
addFailureIdentity(clusters, identity.keys);
|
|
76
|
+
counts.set(fc.gene, clusters);
|
|
27
77
|
}
|
|
28
78
|
const banned = new Set();
|
|
29
|
-
for (const [gene,
|
|
30
|
-
if (
|
|
79
|
+
for (const [gene, clusters] of counts)
|
|
80
|
+
if (clusters.length >= BAN_THRESHOLD)
|
|
31
81
|
banned.add(gene);
|
|
32
82
|
return banned;
|
|
33
83
|
}
|
|
@@ -3,8 +3,12 @@ import { type ReuseCounts } from '../ops/reuseOutcomes.js';
|
|
|
3
3
|
import type { ProvenanceStore } from '../assetstore/provenance.js';
|
|
4
4
|
import type { ReviewLedger } from '../assetstore/reviewLedger.js';
|
|
5
5
|
import type { AntiWarning, GeneCandidateInput } from './geneSelection.js';
|
|
6
|
+
import { type RuntimeRegistry } from './kautoValidator.js';
|
|
7
|
+
import { type CompatibilityEvidenceIndex } from '../modelCompatibility.js';
|
|
6
8
|
export interface AssembleOptions {
|
|
7
9
|
limit?: number;
|
|
10
|
+
/** Build the bounded trusted pre-admission corpus used by semantic IDF. Default true. */
|
|
11
|
+
includeSemanticCorpus?: boolean;
|
|
8
12
|
provenance?: ProvenanceStore;
|
|
9
13
|
includeUntrusted?: boolean;
|
|
10
14
|
review?: ReviewLedger;
|
|
@@ -31,6 +35,22 @@ export interface AssembleOptions {
|
|
|
31
35
|
* (default-off). Never resurrects a hard-gated gene (the trust/review/ban filters above run first).
|
|
32
36
|
*/
|
|
33
37
|
reuseCounts?: ReadonlyMap<string, ReuseCounts>;
|
|
38
|
+
/** Exact compatibility evidence; only quarantine decisions remove candidates. */
|
|
39
|
+
compatibility?: CompatibilityEvidenceIndex;
|
|
40
|
+
/**
|
|
41
|
+
* K_auto EvidenceProjection revocation guard (T1, default-OFF). When provided, a candidate whose five
|
|
42
|
+
* coordinates are all machine-decidable AND whose current projection touches a revoked (coordinate, value)
|
|
43
|
+
* pair is treated as NOT eligible — the fail-safe "a revoked projection is not eligible" rule, applied
|
|
44
|
+
* coordinate-locally (a sibling that differs on the revoked coordinate stays eligible). `revoked` is the set
|
|
45
|
+
* produced by `projectRevocations(rootEvents)` (algo/kautoProjection). Absent (default) = deployed T2 behavior
|
|
46
|
+
* unchanged: no projection guard runs, so signal-scoped `bannedGenesFromFailures` + the soft λ preference are
|
|
47
|
+
* the only K_auto-related effects. `runtimeRegistry` is forwarded to `decideKauto` so the runtime coordinate
|
|
48
|
+
* resolves against the same registry the caller uses elsewhere.
|
|
49
|
+
*/
|
|
50
|
+
kautoProjection?: {
|
|
51
|
+
revoked: ReadonlySet<string>;
|
|
52
|
+
runtimeRegistry?: RuntimeRegistry;
|
|
53
|
+
};
|
|
34
54
|
}
|
|
35
55
|
/** The selection pool for one cycle: the normal scored candidates + the last-resort distilled fallback (#97). */
|
|
36
56
|
export interface SelectionPool {
|
|
@@ -39,10 +59,13 @@ export interface SelectionPool {
|
|
|
39
59
|
/**
|
|
40
60
|
* Distilled genes that passed the trust/review/ban gates but do NOT match the live signals. Surfaced
|
|
41
61
|
* separately (NOT in `candidates`, so they never compete in normal scoring) for the v1 #97 fallback: when no
|
|
42
|
-
*
|
|
43
|
-
* falling through to a blind innovate. Kept lightweight (no learning-history aggregation)
|
|
62
|
+
* normal selection has no reusable positive choice, selection reuses one of these broadly-applicable distilled
|
|
63
|
+
* strategies instead of falling through to a blind innovate. Kept lightweight (no learning-history aggregation)
|
|
64
|
+
* — picked first-match.
|
|
44
65
|
*/
|
|
45
66
|
distilledFallback: GeneCandidateInput[];
|
|
67
|
+
/** Trust-filtered library documents captured before live-signal relevance admission. */
|
|
68
|
+
semanticCorpus: GeneCandidateInput[];
|
|
46
69
|
/**
|
|
47
70
|
* Matched AntiGene guardrails for the live signals. This list is advisory-only and is kept out of candidates and
|
|
48
71
|
* distilledFallback so negative memory cannot be selected as a strategy.
|
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
import { aggregateLearningHistory } from '../assetstore/learningHistory.js';
|
|
2
2
|
import { reuseSentiment } from '../ops/reuseOutcomes.js';
|
|
3
|
+
import { decideKauto } from './kautoValidator.js';
|
|
4
|
+
import { isProjectionRevoked } from './kautoProjection.js';
|
|
3
5
|
import { expandSignals, geneTags, tagOverlapScore, } from '../signals/expand.js';
|
|
6
|
+
import { resolveTaskDomainSignals, withoutTaskDomainSignals } from '../signals/taskDomain.js';
|
|
4
7
|
import { bannedGenesFromFailures } from './bans.js';
|
|
5
8
|
import { geneGenerationSource } from './geneIntake.js';
|
|
9
|
+
import { isCompatibilityBlocked } from '../modelCompatibility.js';
|
|
10
|
+
const SEMANTIC_CORPUS_LIMIT = 1_000;
|
|
6
11
|
function asStrings(v) {
|
|
7
12
|
return Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
|
|
8
13
|
}
|
|
9
14
|
function stringField(v) {
|
|
10
15
|
return typeof v === 'string' && v.trim().length > 0 ? v.trim() : undefined;
|
|
11
16
|
}
|
|
17
|
+
function firstStringField(record, keys) {
|
|
18
|
+
for (const key of keys) {
|
|
19
|
+
const value = stringField(record[key]);
|
|
20
|
+
if (value)
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
function recordList(v) {
|
|
26
|
+
return Array.isArray(v) ? v.filter((x) => x !== null && typeof x === 'object' && !Array.isArray(x)) : [];
|
|
27
|
+
}
|
|
28
|
+
function failureIdentitySource(record) {
|
|
29
|
+
for (const trace of recordList(record['execution_trace'])) {
|
|
30
|
+
const stage = stringField(trace['stage']);
|
|
31
|
+
if (stage === 'validate' && firstStringField(trace, ['root_attempt_id', 'rootAttemptId', 'execution_id', 'executionId', 'failure_id', 'failureId', 'verifier_digest', 'verifierDigest', 'artifact_digest', 'artifactDigest']))
|
|
32
|
+
return trace;
|
|
33
|
+
}
|
|
34
|
+
return record;
|
|
35
|
+
}
|
|
36
|
+
function failureRefFromCapsule(record) {
|
|
37
|
+
const identity = failureIdentitySource(record);
|
|
38
|
+
return {
|
|
39
|
+
gene: stringField(record['gene']),
|
|
40
|
+
trigger: asStrings(record['trigger']),
|
|
41
|
+
failureId: firstStringField(identity, ['failure_id', 'failureId']),
|
|
42
|
+
rootAttemptId: firstStringField(identity, ['root_attempt_id', 'rootAttemptId', 'attempt_root_id', 'attemptRootId']),
|
|
43
|
+
executionId: firstStringField(identity, ['execution_id', 'executionId', 'run_id', 'runId', 'cycle_id', 'cycleId']),
|
|
44
|
+
verifierDigest: firstStringField(identity, ['verifier_digest', 'verifierDigest']),
|
|
45
|
+
artifactDigest: firstStringField(identity, ['artifact_digest', 'artifactDigest']),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
12
48
|
function severityOf(v) {
|
|
13
49
|
return v === 'low' || v === 'medium' || v === 'high' ? v : undefined;
|
|
14
50
|
}
|
|
@@ -18,6 +54,25 @@ function candidateIds(geneId, assetId) {
|
|
|
18
54
|
function isBannedCandidate(banned, geneId, assetId) {
|
|
19
55
|
return candidateIds(geneId, assetId).some((id) => banned.has(id));
|
|
20
56
|
}
|
|
57
|
+
function requiredSignals(signalsMatch) {
|
|
58
|
+
return signalsMatch.flatMap((signal) => signal.startsWith('required:') ? [signal.slice('required:'.length).trim()] : []).filter(Boolean);
|
|
59
|
+
}
|
|
60
|
+
function matchSignals(signalsMatch) {
|
|
61
|
+
return signalsMatch.map((signal) => signal.startsWith('required:') ? signal.slice('required:'.length).trim() : signal).filter(Boolean);
|
|
62
|
+
}
|
|
63
|
+
function passesRequiredSignals(signalsMatch, liveSignals) {
|
|
64
|
+
const required = requiredSignals(signalsMatch);
|
|
65
|
+
return required.length === 0 || required.every((signal) => liveSignals.has(signal));
|
|
66
|
+
}
|
|
67
|
+
function passesFallbackTaskDomain(liveSignals, candidateSignals) {
|
|
68
|
+
const candidateDomain = resolveTaskDomainSignals(candidateSignals);
|
|
69
|
+
if (candidateDomain.status === 'absent')
|
|
70
|
+
return true;
|
|
71
|
+
if (candidateDomain.status !== 'resolved')
|
|
72
|
+
return false;
|
|
73
|
+
const liveDomain = resolveTaskDomainSignals(liveSignals);
|
|
74
|
+
return liveDomain.status === 'resolved' && liveDomain.slug === candidateDomain.slug;
|
|
75
|
+
}
|
|
21
76
|
function passesInjectedCandidateGates(candidate, opts, provenance, review) {
|
|
22
77
|
const assetId = candidate.assetId;
|
|
23
78
|
if (opts.provenance && !opts.includeUntrusted) {
|
|
@@ -59,13 +114,12 @@ function combinedReuseSentiment(map, ...ids) {
|
|
|
59
114
|
}
|
|
60
115
|
/** Genes banned by repeated signal-matched failures (>=2 failed capsules covering the signals). */
|
|
61
116
|
async function computeBans(store, signals, limit) {
|
|
117
|
+
if (signals.length === 0)
|
|
118
|
+
return new Set();
|
|
62
119
|
const caps = await store.search({ kind: 'Capsule', signalsAny: [...signals], limit });
|
|
63
120
|
const failures = caps
|
|
64
121
|
.filter((c) => c['outcome']?.status === 'failed')
|
|
65
|
-
.map((c) => (
|
|
66
|
-
gene: typeof c['gene'] === 'string' ? String(c['gene']) : undefined,
|
|
67
|
-
trigger: asStrings(c['trigger']),
|
|
68
|
-
}));
|
|
122
|
+
.map((c) => failureRefFromCapsule(c));
|
|
69
123
|
return bannedGenesFromFailures(failures, signals);
|
|
70
124
|
}
|
|
71
125
|
const GENERIC_NAMESPACE_TAGS = new Set(['action', 'area', 'problem', 'risk', 'signal']);
|
|
@@ -95,18 +149,36 @@ function hasSelectionAdmissionEvidence(liveSignals, gene) {
|
|
|
95
149
|
*/
|
|
96
150
|
export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
97
151
|
const limit = opts.limit ?? 500;
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const
|
|
152
|
+
const includeSemanticCorpus = opts.includeSemanticCorpus !== false;
|
|
153
|
+
const scanLimit = includeSemanticCorpus ? Math.max(limit, SEMANTIC_CORPUS_LIMIT) : limit;
|
|
154
|
+
const genes = await store.list('Gene', scanLimit);
|
|
155
|
+
const matchingSignals = withoutTaskDomainSignals(signals);
|
|
156
|
+
const banned = await computeBans(store, matchingSignals, limit);
|
|
157
|
+
const liveSignalSet = new Set(signals);
|
|
158
|
+
const sigSet = new Set(matchingSignals);
|
|
101
159
|
const provenance = opts.provenance?.snapshot();
|
|
102
160
|
const review = opts.review?.snapshot();
|
|
103
161
|
const out = [];
|
|
104
162
|
const distilledFallback = [];
|
|
163
|
+
const semanticCorpus = [];
|
|
164
|
+
const semanticIdentities = new Set();
|
|
165
|
+
const addSemanticCandidate = (candidate) => {
|
|
166
|
+
if (!includeSemanticCorpus || semanticCorpus.length >= SEMANTIC_CORPUS_LIMIT)
|
|
167
|
+
return;
|
|
168
|
+
const identity = candidate.assetId ?? candidate.geneId;
|
|
169
|
+
if (semanticIdentities.has(identity))
|
|
170
|
+
return;
|
|
171
|
+
semanticIdentities.add(identity);
|
|
172
|
+
semanticCorpus.push(candidate);
|
|
173
|
+
};
|
|
105
174
|
const antiWarnings = [];
|
|
106
|
-
for (const g of genes) {
|
|
175
|
+
for (const [geneIndex, g] of genes.entries()) {
|
|
176
|
+
const provenanceRecord = provenance?.get(String(g.asset_id));
|
|
177
|
+
if (isCompatibilityBlocked({ assetType: 'Gene', assetId: String(g.asset_id), revision: stringField(g['revision']) ?? '' }, opts.compatibility))
|
|
178
|
+
continue;
|
|
107
179
|
// Trust-first (#30): untrusted (e.g. hub-ingested) genes are excluded from the candidate pool by default;
|
|
108
180
|
// they enter only with includeUntrusted or after an explicit promotion. Provenance is keyed by asset_id.
|
|
109
|
-
if (opts.provenance && !opts.includeUntrusted &&
|
|
181
|
+
if (opts.provenance && !opts.includeUntrusted && provenanceRecord?.trusted === false)
|
|
110
182
|
continue;
|
|
111
183
|
// Review-first (#89/#91): auto-distilled drafts land quarantined until a human approves; rejected drafts stay
|
|
112
184
|
// out too. No record → eligible (cycle/migrate genes). Symmetric to the provenance trust-first filter above.
|
|
@@ -120,12 +192,38 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
120
192
|
const assetId = String(g.asset_id);
|
|
121
193
|
if (isBannedCandidate(banned, geneId, assetId))
|
|
122
194
|
continue; // repeated signal-matched failures → not a candidate (nor a fallback)
|
|
195
|
+
// K_auto projection revocation (T1, opt-in). A decidable record whose current five-coordinate projection
|
|
196
|
+
// touches a revoked (coordinate, value) pair is not eligible — coordinate-locally, so a sibling differing on
|
|
197
|
+
// the revoked coordinate is unaffected. Runs AFTER trust/review/ban (those are the deployed hard gates) and
|
|
198
|
+
// before signal matching, so a revoked projection is dropped from both the candidate and #97 fallback pools.
|
|
199
|
+
// Default-off: without opts.kautoProjection the deployed T2 path is unchanged.
|
|
200
|
+
if (opts.kautoProjection
|
|
201
|
+
&& isProjectionRevoked(decideKauto(g, opts.kautoProjection.runtimeRegistry ? { runtimeRegistry: opts.kautoProjection.runtimeRegistry } : undefined), opts.kautoProjection.revoked))
|
|
202
|
+
continue;
|
|
123
203
|
const signalsMatch = asStrings(g['signals_match']);
|
|
204
|
+
const effectiveSignalsMatch = matchSignals(signalsMatch);
|
|
124
205
|
const category = typeof g['category'] === 'string' ? String(g['category']) : undefined;
|
|
125
206
|
const summary = typeof g['summary'] === 'string' ? String(g['summary']) : undefined;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
207
|
+
// Experimental probation and explicitly untrusted records may be selectable by opt-in, but never shape global
|
|
208
|
+
// document frequency. Only trusted, approved/legacy-local records enter the pre-admission semantic corpus.
|
|
209
|
+
if (provenanceRecord?.trusted !== false && (reviewRecord === undefined || reviewRecord.state === 'approved')) {
|
|
210
|
+
addSemanticCandidate({
|
|
211
|
+
geneId,
|
|
212
|
+
assetId,
|
|
213
|
+
signalsMatch: effectiveSignalsMatch,
|
|
214
|
+
view: emptyLearningView(geneId),
|
|
215
|
+
...(category ? { category } : {}),
|
|
216
|
+
...(summary ? { summary } : {}),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (geneIndex >= limit)
|
|
220
|
+
continue;
|
|
221
|
+
if (!passesRequiredSignals(signalsMatch, liveSignalSet))
|
|
222
|
+
continue;
|
|
223
|
+
const matchingSignalsForGene = withoutTaskDomainSignals(effectiveSignalsMatch);
|
|
224
|
+
const literal = matchingSignalsForGene.some((m) => sigSet.has(m));
|
|
225
|
+
const tagInput = { signalsMatch: matchingSignalsForGene, geneId, category, summary };
|
|
226
|
+
const relevant = literal || hasSelectionAdmissionEvidence(matchingSignals, tagInput);
|
|
129
227
|
if (!relevant) {
|
|
130
228
|
// #97: a trusted, approved, non-banned distilled (or evolved) gene that doesn't match the live signals is not
|
|
131
229
|
// a normal candidate, but it IS eligible as a last-resort fallback (selection uses it only when nothing clears
|
|
@@ -133,11 +231,12 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
133
231
|
// generation_meta (V1 #302); a legacy gene without it falls back to the `gene_distilled_` id namespace.
|
|
134
232
|
// Lightweight: no learning-history aggregation — it is picked first-match, not ranked by health.
|
|
135
233
|
const gsrc = geneGenerationSource(g, geneId);
|
|
136
|
-
if (gsrc === 'distilled' || gsrc === 'evolved')
|
|
234
|
+
if ((gsrc === 'distilled' || gsrc === 'evolved')
|
|
235
|
+
&& passesFallbackTaskDomain(signals, effectiveSignalsMatch)) {
|
|
137
236
|
distilledFallback.push({
|
|
138
237
|
geneId,
|
|
139
238
|
assetId,
|
|
140
|
-
signalsMatch,
|
|
239
|
+
signalsMatch: effectiveSignalsMatch,
|
|
141
240
|
view: emptyLearningView(geneId),
|
|
142
241
|
reuseCount: 0,
|
|
143
242
|
generationSource: gsrc,
|
|
@@ -148,14 +247,19 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
148
247
|
continue;
|
|
149
248
|
}
|
|
150
249
|
const view = await aggregateLearningHistory(store, geneId);
|
|
250
|
+
const explorationEligible = provenanceRecord?.trusted !== false
|
|
251
|
+
&& (reviewRecord === undefined || reviewRecord.state === 'approved');
|
|
151
252
|
// #268 Bugbot: reuse events key by assetId, which may be the content asset_id (sha256:…) OR the logical id —
|
|
152
253
|
// candidates key by the logical geneId. Look the sentiment up by BOTH so the soft re-order actually matches
|
|
153
254
|
// regardless of which form the reuse-result carried (recall's resolveGene accepts both for the same reason).
|
|
154
255
|
const reuseAdjustVal = combinedReuseSentiment(opts.reuseCounts, geneId, String(g.asset_id));
|
|
256
|
+
// Soft K_auto preference: stamp only when the source record clears the strict five-coordinate bar.
|
|
257
|
+
// Absent/false leaves score unchanged so the historical non-member catalogue is not zeroed.
|
|
258
|
+
const kautoMember = decideKauto(g).inKauto;
|
|
155
259
|
out.push({
|
|
156
260
|
geneId,
|
|
157
261
|
assetId: String(g.asset_id),
|
|
158
|
-
signalsMatch,
|
|
262
|
+
signalsMatch: effectiveSignalsMatch,
|
|
159
263
|
view,
|
|
160
264
|
// #195: inert (zero-work) cycles are not productive reuse — exclude them so a do-nothing gene can't earn
|
|
161
265
|
// the reuse bonus. success + failed === total when there are no inert cycles (back-compat).
|
|
@@ -163,25 +267,40 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
163
267
|
...(category ? { category } : {}),
|
|
164
268
|
...(summary ? { summary } : {}),
|
|
165
269
|
...(reuseAdjustVal !== undefined ? { reuseAdjust: reuseAdjustVal } : {}),
|
|
270
|
+
...(kautoMember ? { kautoMember: true } : {}),
|
|
271
|
+
explorationEligible,
|
|
166
272
|
});
|
|
167
273
|
}
|
|
168
274
|
// #110: merge hub reuse candidates into the same pool, trust-first — local (trusted) genes win on a
|
|
169
275
|
// geneId collision, and a hub candidate banned by repeated signal-matched failures stays out too.
|
|
170
276
|
if (opts.hubCandidates && opts.hubCandidates.length > 0) {
|
|
171
277
|
const localIds = new Set(out.map((c) => c.geneId));
|
|
278
|
+
const localAssetIds = new Set(out.map((c) => c.assetId).filter((id) => id !== undefined));
|
|
172
279
|
for (const h of opts.hubCandidates) {
|
|
280
|
+
if (isCompatibilityBlocked({ assetType: 'Gene', assetId: h.assetId ?? h.geneId, revision: String(h.hubAsset?.['revision'] ?? '') }, opts.compatibility))
|
|
281
|
+
continue;
|
|
173
282
|
if (!passesInjectedCandidateGates(h, opts, provenance, review))
|
|
174
283
|
continue;
|
|
284
|
+
if (!passesRequiredSignals(h.signalsMatch, sigSet))
|
|
285
|
+
continue;
|
|
175
286
|
if (localIds.has(h.geneId))
|
|
176
287
|
continue; // a trusted local gene already covers this id
|
|
288
|
+
if (h.assetId && localAssetIds.has(h.assetId))
|
|
289
|
+
continue; // the same content identity is already local/trusted
|
|
177
290
|
if (isBannedCandidate(banned, h.geneId, h.assetId))
|
|
178
291
|
continue;
|
|
179
292
|
// Stamp the reuse sentiment onto a hub candidate too (only when it didn't carry one), matched by its geneId
|
|
180
293
|
// OR its asset_id — symmetric with local genes, so a map keyed like reuse events (often sha256:…) still hits
|
|
181
294
|
// (#268 Bugbot). A hub candidate that exposes neither matching id is simply left unstamped.
|
|
295
|
+
const hubSignalsMatch = matchSignals(h.signalsMatch);
|
|
182
296
|
const hubAdj = h.reuseAdjust === undefined ? combinedReuseSentiment(opts.reuseCounts, h.geneId, h.assetId) : undefined;
|
|
183
|
-
|
|
297
|
+
// A transient Hub candidate must never self-assert active-bandit cold-start eligibility. It still competes
|
|
298
|
+
// under the existing base score and legacy drift; UCB1 fails safe for a mixed window.
|
|
299
|
+
const guarded = { ...h, signalsMatch: hubSignalsMatch, explorationEligible: false };
|
|
300
|
+
out.push(hubAdj !== undefined ? { ...guarded, reuseAdjust: hubAdj } : guarded);
|
|
184
301
|
localIds.add(h.geneId);
|
|
302
|
+
if (h.assetId)
|
|
303
|
+
localAssetIds.add(h.assetId);
|
|
185
304
|
}
|
|
186
305
|
}
|
|
187
306
|
for (const a of await store.list('AntiGene', limit)) {
|
|
@@ -196,8 +315,10 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
196
315
|
continue;
|
|
197
316
|
const antiGeneId = stringField(a['id']) ?? String(a.asset_id);
|
|
198
317
|
const summary = stringField(a['summary']);
|
|
199
|
-
const
|
|
200
|
-
|
|
318
|
+
const matchingTrigger = withoutTaskDomainSignals(trigger);
|
|
319
|
+
// This is a safety inclusion gate: ubiquitous evidence must still emit warnings.
|
|
320
|
+
const relevant = matchingTrigger.some((m) => sigSet.has(m))
|
|
321
|
+
|| tagOverlapScore(matchingSignals, { signalsMatch: matchingTrigger, geneId: antiGeneId, summary }) > 0;
|
|
201
322
|
if (!relevant)
|
|
202
323
|
continue;
|
|
203
324
|
const severity = severityOf(a['severity']);
|
|
@@ -212,7 +333,7 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
212
333
|
...(rationale ? { rationale } : {}),
|
|
213
334
|
});
|
|
214
335
|
}
|
|
215
|
-
return { candidates: out, distilledFallback, antiWarnings };
|
|
336
|
+
return { candidates: out, distilledFallback, semanticCorpus, antiWarnings };
|
|
216
337
|
}
|
|
217
338
|
/**
|
|
218
339
|
* Assemble selection candidates from the store for the given signals (the relevant scored set only).
|
|
@@ -220,5 +341,7 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
|
|
|
220
341
|
* distilled-gene fallback pool.
|
|
221
342
|
*/
|
|
222
343
|
export async function assembleCandidates(store, signals, opts = {}) {
|
|
223
|
-
|
|
344
|
+
// This compatibility wrapper discards semanticCorpus, so preserve its legacy I/O bound instead of scanning
|
|
345
|
+
// 1,000 records for data the caller cannot consume.
|
|
346
|
+
return (await assembleSelectionPool(store, signals, { ...opts, includeSemanticCorpus: false })).candidates;
|
|
224
347
|
}
|
|
@@ -20,6 +20,16 @@ const SIGNAL_CANDIDATES = [
|
|
|
20
20
|
{ signal: 'capability_gap', title: 'Fill capability gap' },
|
|
21
21
|
{ signal: 'stable_success_plateau', title: 'Explore new strategies during stability plateau' },
|
|
22
22
|
{ signal: 'external_opportunity', title: 'Evaluate external A2A asset for local adoption' },
|
|
23
|
+
// Harness context-budget family (v1 context-compression gene family port). v2 ships no seed-gene catalog, so
|
|
24
|
+
// the reusable strategies arrive as ADVISORY candidates the runtime may distill into genes — one per bloat
|
|
25
|
+
// source, because a single "shorten the prompt" proposal loses the distinction that decides what is safe to
|
|
26
|
+
// drop (an always-on tool schema is lazy-loadable; an approval gate is not).
|
|
27
|
+
{ signal: 'prompt_budget_measurement', title: 'Measure the prompt budget per source before compressing context' },
|
|
28
|
+
{ signal: 'context_explosion', title: 'Attribute a context-window overflow to its largest prompt source' },
|
|
29
|
+
{ signal: 'tool_schema_bloat', title: 'Load exact tool/MCP schemas from the runtime loader instead of always-on prompt text' },
|
|
30
|
+
{ signal: 'skill_list_bloat', title: 'Compress skill and agent-type descriptions into selectable route cards' },
|
|
31
|
+
{ signal: 'transcript_context_bloat', title: 'Compress a pasted transcript into a session handoff packet' },
|
|
32
|
+
{ signal: 'memory_index_budget', title: 'Keep the memory index lean and rely on relevance recall for detail' },
|
|
23
33
|
];
|
|
24
34
|
/** Highest → lowest priority problem class used to pick a failure cluster's grouping key (ported v1). */
|
|
25
35
|
const PROBLEM_PRIORITY = ['problem:performance', 'problem:protocol', 'problem:reliability', 'problem:stagnation', 'problem:capability'];
|
|
@@ -4,13 +4,15 @@ import type { GepCategory, Mutation, Capsule, EvolutionEvent } from '../wire/ind
|
|
|
4
4
|
import type { AssetStoreProvider } from '../assetstore/provider.js';
|
|
5
5
|
import type { StrategyPoint } from '../strategy/strategyPoint.js';
|
|
6
6
|
import { type CycleStage } from '../cycle/stateMachine.js';
|
|
7
|
-
import { type GeneDecision, type SelectionInput, type GeneCandidateInput, type AntiWarning } from './geneSelection.js';
|
|
7
|
+
import { type GeneDecision, type SelectionInput, type GeneCandidateInput, type AntiWarning, type SelectionGuardMode } from './geneSelection.js';
|
|
8
8
|
import { type EnvFingerprint } from '../bootstrap/envFingerprint.js';
|
|
9
9
|
import type { PersonalityStore } from '../personality/store.js';
|
|
10
|
-
import { type ResolutionStatus } from './solidify.js';
|
|
10
|
+
import { type FailureEvidenceIdentityInput, type ResolutionStatus } from './solidify.js';
|
|
11
11
|
import type { ProofOfWork } from '../schema/proofOfWork.js';
|
|
12
|
+
import type { ExecutionTerminalDisposition, FrozenExecutionBinding, ImmutableExecutionProvenance } from '../exec/executionBinding.js';
|
|
12
13
|
import { type ClassifyRecentEvent } from './cycleFailureClassifier.js';
|
|
13
14
|
import type { MemoryGraphGeneEvidence } from './memoryGraph.js';
|
|
15
|
+
import { type SelectionPolicy } from './ucb1.js';
|
|
14
16
|
export interface TriggerEval {
|
|
15
17
|
trigger: boolean;
|
|
16
18
|
reasons: string[];
|
|
@@ -23,8 +25,23 @@ export interface ExecutionResult {
|
|
|
23
25
|
score: number;
|
|
24
26
|
reason?: string;
|
|
25
27
|
};
|
|
28
|
+
bindingCorrelation?: {
|
|
29
|
+
bindingDigest: `sha256:${string}`;
|
|
30
|
+
runId: string;
|
|
31
|
+
};
|
|
32
|
+
executionTerminal?: {
|
|
33
|
+
status: 'success' | 'failed';
|
|
34
|
+
disposition: ExecutionTerminalDisposition;
|
|
35
|
+
};
|
|
36
|
+
provenance?: ImmutableExecutionProvenance;
|
|
37
|
+
hubLifecycle?: {
|
|
38
|
+
state: 'not_submitted';
|
|
39
|
+
};
|
|
40
|
+
nativeSessionId?: string;
|
|
26
41
|
proofOfWork?: ProofOfWork;
|
|
27
42
|
strongEvidence?: boolean;
|
|
43
|
+
/** Optional logical failure identity supplied by the runner; absent keeps the failure as legacy advisory evidence. */
|
|
44
|
+
failureIdentity?: FailureEvidenceIdentityInput;
|
|
28
45
|
/** Structured runner failure metadata. Safe to persist; unlike sessionLog it contains no transcript text. */
|
|
29
46
|
failureKind?: ExecutionFailureKind;
|
|
30
47
|
exitCode?: number | null;
|
|
@@ -33,13 +50,17 @@ export interface ExecutionResult {
|
|
|
33
50
|
* outcome. It is the host-side context classifyCycleFailure needs to reach the host_no_transcript /
|
|
34
51
|
* host_provider_error buckets on the PRODUCTION path (#279): an empty transcript means the host gave evolver
|
|
35
52
|
* nothing to evolve from; a provider-error string (429 / quota / context-length) means the host's LLM call
|
|
36
|
-
* failed, not the gene. Consumed only for failure triage and NEVER persisted to event payloads
|
|
37
|
-
* writes only the derived failure_class
|
|
53
|
+
* failed, not the gene. Consumed only for failure triage and NEVER persisted to event payloads; the engine
|
|
54
|
+
* writes only the derived failure_class, so it adds no root_events bloat and leaks no transcript content.
|
|
38
55
|
*/
|
|
39
56
|
sessionLog?: string;
|
|
40
57
|
}
|
|
41
58
|
export interface SolidifyPermitContext {
|
|
42
59
|
cycleId: string;
|
|
60
|
+
bindingDigest?: `sha256:${string}`;
|
|
61
|
+
runId?: string;
|
|
62
|
+
executionTerminal?: ExecutionResult['executionTerminal'];
|
|
63
|
+
provenance?: ImmutableExecutionProvenance;
|
|
43
64
|
geneId: string;
|
|
44
65
|
signals: readonly string[];
|
|
45
66
|
mutation: Mutation;
|
|
@@ -90,6 +111,14 @@ export interface CycleInput {
|
|
|
90
111
|
/** Optional explicit strategy preset name; when set, it wins over history-derived meta-signal auto-detection. */
|
|
91
112
|
strategyName?: string;
|
|
92
113
|
candidates: readonly GeneCandidateInput[];
|
|
114
|
+
/** Trust-filtered library corpus captured before relevance admission for stable semantic IDF. */
|
|
115
|
+
semanticCorpus?: readonly GeneCandidateInput[];
|
|
116
|
+
/** Emergency rollback: use the pre-IDF semantic scorer for this cycle. */
|
|
117
|
+
disableSemanticIdf?: boolean;
|
|
118
|
+
/** Experimental plateau selection policy. Default preserves engine-health + legacy random drift. */
|
|
119
|
+
selectionPolicy?: SelectionPolicy;
|
|
120
|
+
/** Versioned relevance-guard rollout. Omit for legacy direct-call behavior. */
|
|
121
|
+
selectionGuard?: SelectionGuardMode;
|
|
93
122
|
selectionFloor?: number;
|
|
94
123
|
/**
|
|
95
124
|
* Explicit GEP/runtime-selected gene. Forwarded after candidate assembly and local hard filters, so it cannot
|
|
@@ -101,12 +130,14 @@ export interface CycleInput {
|
|
|
101
130
|
summary: string;
|
|
102
131
|
confidence: number;
|
|
103
132
|
execute: (mutation: Mutation, decision: GeneDecision) => Promise<ExecutionResult> | ExecutionResult;
|
|
133
|
+
/** Immutable external execution binding; omitted for legacy local cycles. */
|
|
134
|
+
executionBinding?: FrozenExecutionBinding;
|
|
104
135
|
/** Optional adapter/runtime permit gate. Runs after execute succeeds and before solidify writes assets. */
|
|
105
136
|
solidifyPermit?: SolidifyPermitGate;
|
|
106
137
|
/**
|
|
107
138
|
* Distilled-gene fallback pool (ported from v1 #97): broadly-applicable distilled genes that do NOT match the
|
|
108
139
|
* live signals, assembled (trust/review/ban-filtered) upstream. Forwarded to selection, which uses one only as a
|
|
109
|
-
* last resort when no
|
|
140
|
+
* last resort when normal selection has no reusable positive choice — reusing a known distilled strategy instead of a blind innovate.
|
|
110
141
|
*/
|
|
111
142
|
distilledFallback?: readonly GeneCandidateInput[];
|
|
112
143
|
/** Advisory-only AntiGene warnings matched upstream for this cycle's base signals. */
|
|
@@ -134,6 +165,10 @@ export interface CycleInput {
|
|
|
134
165
|
}
|
|
135
166
|
export interface CycleResult {
|
|
136
167
|
cycleId: string;
|
|
168
|
+
bindingDigest?: `sha256:${string}`;
|
|
169
|
+
runId?: string;
|
|
170
|
+
terminalDisposition?: ExecutionTerminalDisposition;
|
|
171
|
+
execution?: ExecutionResult;
|
|
137
172
|
triggered: boolean;
|
|
138
173
|
finalStage: CycleStage;
|
|
139
174
|
/** Real CycleEngine returns this on every path; optional keeps injected legacy engines source-compatible. */
|