feat(learn): candidate feature schema and builders (decision-engine task 1)

learn/schema.py is the closed, typed allow-list of candidate features: 66 features over
11 instruments (language one-hot, quick rules with 23 mechanism buckets and a prior count,
engine, repo-facts, source span, entry-point distance, roles, delta, verify, agree, model
sinks), two profiles (static 57; plane adds verify, agree and model sinks for 66), schema_version and a feature-set digest.
No repository, path, file, function, rule or commit identity is a feature; site_match,
in_fix_range, fixed-pin alerts, case.json fields and costs are refused. Missing is not zero:
each record carries per-instrument state (ran | none | failed | not_applicable), and every
feature of an instrument that did not run is null.

learn/features.py builds records on the host (build_for_scan, whole repository or base..head
delta); plane/tasks/features.py builds them per case in a Run from the delivered artifacts,
dropping site_match and in_fix_range on read and ignoring fixed-pin alerts. The generator
adds a model-free `features` entry per case before `remember`, which stores the records as
`features` rows (re-validated). memory KINDS gains features, label, decision, experiment,
arm_outcome and experiment_result. The committed validation-46 manifests are regenerated
(entries appended; the first Run's entries are unchanged). The runner image must be rebuilt
and re-pinned before a Run executes the new task.

Proof on real artifacts (scratch store, not committed): the recorded validation-46 run gives
75 feature records over 15 cases (43 verify candidates plus vulnerable-pin alerts), each
case's vulnerable pin exported and read (0.5k-9k files); remember stored 75 features rows
beside 43 verdict, 84 alert, 61 unit_cost, 15 facts and 8 coverage rows.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
Marius Ciepluch
2026-09-30 18:38:04 +02:00
co-authored by Claude Opus 5.5
parent edcf145b00
commit d1896cb8e7
17 changed files with 2129 additions and 31 deletions
@@ -1,7 +1,7 @@
{
"modules": 135,
"modules": 139,
"counts": {
"load_bearing": 128,
"load_bearing": 132,
"standalone_capability": 7
},
"orphaned": [],
@@ -346,6 +346,33 @@
"skills"
]
},
{
"module": "learn",
"classification": "load_bearing",
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
"importers": [
"learn.features",
"plane.tasks.features",
"plane.tasks.remember"
]
},
{
"module": "learn.features",
"classification": "load_bearing",
"reason": "imported by plane.tasks.features",
"importers": [
"plane.tasks.features"
]
},
{
"module": "learn.schema",
"classification": "load_bearing",
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
"importers": [
"learn.features",
"plane.tasks.remember"
]
},
{
"module": "map_gate",
"classification": "load_bearing",
@@ -361,6 +388,7 @@
"gate",
"hunter_tools",
"improve.evolve",
"learn.features",
"map_gate",
"model.scan",
"pairs",
@@ -386,6 +414,7 @@
"cli",
"cpg.backend",
"cpg.session",
"learn.features",
"model.candidates",
"model.config_value",
"model.dominance",
@@ -401,6 +430,7 @@
"model.taint",
"plane.budget",
"plane.generate",
"plane.tasks.features",
"plane.tasks.repo_facts",
"preprocess",
"push.assistance",
@@ -626,10 +656,12 @@
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
"importers": [
"cli",
"learn.features",
"model.candidates",
"model.report",
"model.scan",
"model.specs"
"model.specs",
"plane.tasks.features"
]
},
{
@@ -768,11 +800,13 @@
"reason": "ai-service-plane Req 4.1: the task entrypoint package the runner imports by name; runner integration pending (task 3)",
"importers": [
"cli",
"learn.features",
"plane.engine_alerts",
"plane.generate",
"plane.memory",
"plane.tasks.agree",
"plane.tasks.alerts",
"plane.tasks.features",
"plane.tasks.remember"
]
},
@@ -787,9 +821,17 @@
"classification": "load_bearing",
"reason": "harnessx-removal Req 6.3: quick-mode alerts on a case's vulnerable and fixed pins, model-free",
"importers": [
"plane.engine_alerts"
"learn.features",
"plane.engine_alerts",
"plane.tasks.features"
]
},
{
"module": "plane.tasks.features",
"classification": "load_bearing",
"reason": "learned-decision-engine Req 1.1-1.3/7.2: one allow-listed feature record per candidate, model-free",
"importers": []
},
{
"module": "plane.tasks.loop",
"classification": "load_bearing",
@@ -811,8 +853,10 @@
"classification": "load_bearing",
"reason": "ai-service-plane Req 5.1/5.2: source-only functions and callers per file; runner integration pending",
"importers": [
"learn.features",
"plane.generate",
"plane.tasks.alerts",
"plane.tasks.features",
"plane.tasks.remember"
]
},
@@ -872,6 +916,7 @@
"hunter_tools",
"improve.evolve",
"index",
"learn.features",
"map_gate",
"mapping",
"model.candidates",
@@ -879,6 +924,7 @@
"model.scan",
"pairs",
"plane.tasks.alerts",
"plane.tasks.features",
"plane.tasks.repo_facts",
"push.runner",
"rank",
@@ -1148,8 +1194,10 @@
"improve.evolve",
"improve.memory",
"improve.validator",
"learn.features",
"pairs",
"plane.tasks.alerts",
"plane.tasks.features",
"plane.tasks.loop",
"stage_processors"
]
@@ -1229,6 +1277,7 @@
"cli",
"cpg.capability",
"hunter_tools",
"learn.features",
"mapping",
"model.candidates",
"model.layout",
@@ -1283,6 +1332,7 @@
"importers": [
"cli",
"hunter_tools",
"learn.features",
"mapping",
"model.candidates",
"model.layout",