/landscape-loop-promote skill — contract¶
Project-local Claude Code skill at .claude/skills/landscape-loop-promote/SKILL.md. Invoked with /landscape-loop-promote [run-dir-or-slug ...] to harvest the adaptation logs from completed landscape-loop-gt / landscape-loop-explore runs, decide which per-landscape adaptations generalise into the class-neutral backend, and launch a new session that lands them as a draft PR behind the cross-deck regression gate.
Why this exists¶
The two loop skills each emit an adaptations log — every derivation-axis edit made during a run, recorded (in their own words) as "proposals to be accepted or reverted by a human later." Nothing consumes those proposals. The generalisable ones — edits a future landscape would inherit too — accumulate stranded in per-run archived_data/<slug>_explore/adaptations-log.md files while the backend stays behind.
This skill closes that loop. It reads the adaptation logs across runs, separates generalises-into-the-backend from class-specific-by-design (and from already-reverted), and hands off a focused session that promotes the winners into ogur/engine/discovery_modality/. It is the promotion pipeline the configure_class_vocab() seam went through by hand (proposed in Polygon, reverted, committed in GNS561) — now a repeatable step.
It runs no loop. No discovery, no seed, no scorer. Input = loop outputs; output = a promotion proposal + a spawned draft-PR session.
The one judgment it makes¶
The architecture drew the promotion line already (commit 842e274): ogur/engine/discovery_modality/ holds the class-neutral core (types, concept_queries, refine, cache, sources, matching, aliases); scripts/eval/<class>_discovery/ holds the class-specific siblings (scope_fit vocab, decompose, bio_targets, assemble, runner). An adaptation generalises iff its mechanism (not its vocab values) belongs on the class-neutral side. The tell: would a future 4th class inherit this without re-editing it?
The canonical promoted shape is sources.configure_class_vocab() — an additive injection seam that preserves the siRNA + Monitor behaviour byte-for-byte (reset_class_vocab() restores the defaults; every existing test passes). Every promotion this skill proposes must match that shape.
The five-point generalise test (hard go/no-go)¶
An adaptation is PROMOTE only if all five hold; miss one and it drops to a lesser bucket, not to the engine:
- Recurrence or self-annotated graduation — seen in ≥2 runs across ≥2 classes, or the log/code explicitly flags it landscape-agnostic ("can graduate into the shared matcher later"; "the answer to run X's unsolved Y").
- Class-neutral mechanism — the mechanism lives in
discovery_modality/(or the shared matcher/scorer), even if a value it consumes is class-specific. Promote the seam; leave the vocab. - Additive + defaults-preserving — a seam / optional param / opt-in path that leaves siRNA + Monitor byte-for-byte unchanged.
- Cross-deck-regression-safe — can survive the
archived_data/landscape_loop_benchmarks.mdreplay (re-score every prior deck; regress one ⇒ revert). - Evidence-backed, kept — the loop kept it (not a reverted lever); every bind is retrieval-first + two-factor.
Honesty rule: a single run of only class-vocab edits yields "nothing to promote yet — needs a second class to corroborate." No manufactured generalisations.
The four buckets¶
| Bucket | Meaning | Fate |
|---|---|---|
| PROMOTE | passes all five | in the proposal + the spawned PR |
| KEEP-SIBLING | class content (a modality/target/off vocab, a class matcher) | never promoted — "never fork the matcher" |
| DEFER | plausibly neutral but seen in one run only | held for a second corroborating class |
| REVERTED / REJECTED | the loop backed it out | never promoted; recorded so it isn't re-proposed |
The KEEP-SIBLING / DEFER / REVERTED rows are the honesty surface — a reviewer must see what was consciously not promoted, or the proposal reads as cherry-picking.
I/O expectations¶
| Input | one or more loop-run outputs — -explore: archived_data/<slug>_explore/adaptations-log.md (+ RUN_SUMMARY.md); -gt: no adaptations log — its report doc's recall-by-pass trajectory + the benchmark-registry row. No args ⇒ harvest every *_explore/adaptations-log.md. (The loop contracts name loop-workspace/…; the real on-disk home is archived_data/.) |
| Output | a promotion plan doc (docs/development/<theme>_promotion_plan.md, the /new-source plan-doc skeleton — review surface and self-contained handoff) + a spawned implementation session that opens the draft PR. |
| Never mutates | ogur/engine/ (own run is read-only), the loop outputs, the production ogur.db, the gold decks, the benchmark registry. |
The three-phase shape¶
- Phase 0 (read + classify, read-only): gather the logs → parse each pass (Symptom/Change/Effect + the "graduate later" annotations) → cross-reference recurrences → apply the five-point test → sort into four buckets → resolve the class-neutral target file + additive-seam shape for each PROMOTE. Empty PROMOTE set ⇒ stop, report "nothing to promote yet".
- Phase 1 (proposal): write the promotion proposal — per PROMOTE item: source refs, target file + seam, byte-for-byte default to preserve, cross-deck decks that must stay green, acceptance test, before→after deltas; plus the KEEP-SIBLING / DEFER / REVERTED ledger.
- Phase 2 (handoff):
spawn_taska new session pointed at the plan doc, onfeat/promote-<theme>offmain(nopromote/prefix convention yet; commit typerefactor(engine):, per842e274), whose contract is: implement each item as an additive seam indiscovery_modality/, re-point the siblings at the promoted core via a re-export shim (one canonical copy underogur/, never a fork),make check+ re-score every benchmark deck (regress one ⇒ revert that item), open a draft PR. This skill stops at surfacing the plan + chip; it does not edit the engine or open the PR.
Relationship to the loop skills¶
-gt |
-explore |
-promote (this) |
|
|---|---|---|---|
| Input | gold deck + thesis | lead asset / thesis | the loops' adaptation logs |
| Runs discovery? | yes | yes | no — reads outputs |
| Output | recall scorecard + reports | discovered landscape + adaptations log | promotion proposal + draft-PR session |
| Mutates engine? | via proposed levers | via proposed adaptations | never in its own run (spawns a gated session) |
-gt/-explore produce the adaptation proposals; -promote reviews and lands the generalisable subset. It is the third leg of the toolchain, not a third loop.
Reference corpus¶
The first harvest input is the two completed -explore runs: Polygon PLG-101 (antibody / immunology, archived_data/polygon_plg101_explore/) and GNS561 (small-molecule autophagy, archived_data/gns561_explore/). Together they already exhibit the promote signals the skill keys on — the configure_class_vocab seam (recurs across both), the company-grade evidence gate (GNS561's answer to Polygon's unsolved OpenAlex-org gate), the international research-org supplement (both flag it "graduate later"), and the --patents-by-target auto cost gate.
Honesty note¶
Like -explore, this skill has not yet been run. It is the intended procedure, extracted from the loops' "proposals for later review" contract + the class-neutral/class-specific architecture split (842e274) + the configure_class_vocab promotion precedent. The five-point test and the bucket mapping are a starting hypothesis; the first real harvest will refine which adaptations are genuinely neutral versus class-shaped.