Files
rune/scripts/fake_worker.py
Nick ca4f7593d7
CI Pipeline / best-practices (push) Successful in 8s
Auto-version and Release / release (push) Failing after 14s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / canary (push) Successful in 37s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m4s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 48s
feat(corrections): #314 defect fix, credential rotation, release guard, task lifecycle, route scoping, PL1 records + metrics
CORRECTION 1: #314 reopened — recall_with_associations mode field defect
CONFIRMED in current source and FIXED (mode: association_merged).

CORRECTION 3: Gitea credential removed from remote URL (credential helper).
TOKEN EXPOSED: yes (in diagnostic output). TOKEN ROTATED: not yet (requires
Gitea web UI access). Remote URL now shows username only, no secret.

CORRECTION 4: duplicate-release-commit defect ROOT CAUSE: convergence
computed warranted bump from commits-since-tag without checking if master
version already satisfies the bump. FIX: already-converged guard in
version_convergence.py (master version > last tag → no commit). Repo-aware
(args.repo passed to read_version/latest_tag).

CORRECTION 6: lifecycle terminalization — execution exception now
guarantees task terminalizes as failed with evidence (no immortal RUNNING).

CORRECTION 7: route instruction task-scoped on RuneTask.route_instruction
(NOT shared operator state). Read-only leading-verb override. Isolation
tests prove no cross-contamination between interleaved tasks.

PL1-01/02/03/05: pl1_records.py (route resolution, proof level, failure
class, candidate status), metrics with honest NOT_YET_MEASURABLE semantics,
route-instruction learning loop (PE-1789102658-0269 SEED).

1253 tests green; ratchet 352/80 (shrink); henxels clean.
2026-09-11 15:36:08 +01:00

277 lines
10 KiB
Python

#!/usr/bin/env python3
"""fake_worker.py — deterministic fake MiMo for pipeline integration testing.
NOT the production research worker. This worker produces known, structured
artifacts for each stage so the pipeline plumbing (persistence, handoff,
gating, retry) can be tested in seconds instead of 20-minute real MiMo runs.
Canonical pipeline (RP2, handoff 2026-09-08):
ISSUE → INWARD → OUTWARD → APPLICABILITY
→ optional INNOVATION → ADVERSARIAL → SYNTHESIS → QUALIFY
Per the authoritative build prompt §18:
"DETERMINISTIC TESTS PROVE THE PIPE. REAL MIMO DOES THE RESEARCH."
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from research_task_tree import ResearchTaskTree, STAGES
def fake_issue_gate(tree: ResearchTaskTree) -> dict:
"""ISSUE is deterministic: the Gitea issue content is the DEFINE replacement.
The fake worker emits the compiled gate artifact directly."""
issue = tree.issue
return {
"goal": f"Capability from issue #{issue}",
"why": "recorded in issue body",
"constraints": ["must not regress existing behavior"],
"acceptance": ["issue acceptance criteria"],
"quality": "BUILDABLE",
}
def fake_inward(tree: ResearchTaskTree) -> dict:
# Assert ISSUE-gate artifact was actually supplied
prior = tree.get_prior_artifacts("INWARD")
issue_gate = prior.get("ISSUE", {})
assert issue_gate.get("goal"), "INWARD: ISSUE-gate artifact missing — evidence handoff broken"
return {
"claims": [
{
"id": "I1",
"claim": "memory_store uses FTS5",
"evidence": ["src/rune/memory_store.py:86"],
"status": "CURRENT",
},
{
"id": "I2",
"claim": "shard routing is present",
"evidence": ["src/rune/shard_manager.py:114"],
"status": "CURRENT",
},
],
}
def fake_outward(tree: ResearchTaskTree) -> dict:
"""Unified OUTWARD (RP3): one research task, discovery + reading as
SUBSECTIONS of one artifact — not separate stages."""
prior = tree.get_prior_artifacts("OUTWARD")
inward = prior.get("INWARD", {})
claims = inward.get("claims", [])
assert len(claims) >= 2, f"OUTWARD: expected ≥2 INWARD claims, got {len(claims)}"
return {
"discovery": {
"queries": ["fts5 hybrid search", "sqlite-vec alternatives"],
"tool_receipts": [{"tool": "webfetch", "query": "fts5 hybrid search", "status": "completed"}],
"sources": [
{"id": "O1", "url": "https://sqlite.org/fts5.html", "title": "FTS5", "source_class": "software"},
{
"id": "O2",
"url": "https://github.com/asg017/sqlite-vec",
"title": "sqlite-vec",
"source_class": "software",
},
],
},
"reading": {
"evidence": [
{
"id": "E1",
"source_id": "O1",
"url": "https://sqlite.org/fts5.html",
"claim": "FTS5 supports external content tables",
"limitations": ["token porter only"],
},
{
"id": "E2",
"source_id": "O2",
"url": "https://github.com/asg017/sqlite-vec",
"claim": "vec0 virtual tables for embedding search",
"limitations": [],
},
],
},
}
def fake_applicability(tree: ResearchTaskTree) -> dict:
"""APPLICABILITY (RP4): classify researched mechanisms against Rune's reality."""
prior = tree.get_prior_artifacts("APPLICABILITY")
outward = prior.get("OUTWARD", {})
sources = outward.get("discovery", {}).get("sources", [])
assert len(sources) >= 2, f"APPLICABILITY: expected ≥2 OUTWARD sources, got {len(sources)}"
return {
"route": "INNOVATION_WARRANTED",
"candidates": [
{
"id": "M1",
"source_ids": ["O1", "O2"],
"classification": "APPLICABLE_WITH_ADAPTATION",
"integration_point": "memory_store.recall",
"benefit": "hybrid recall",
"cost": "low",
"architectural_fit": "fits memory authority",
"authority_implications": "none",
"risks": ["extension availability"],
"required_adaptation": ["fallback when extension missing"],
"evidence": ["E1", "E2"],
},
],
}
def fake_adversarial(tree: ResearchTaskTree) -> dict:
prior = tree.get_prior_artifacts("ADVERSARIAL")
outward = prior.get("OUTWARD", {})
evidence = outward.get("reading", {}).get("evidence", [])
assert len(evidence) >= 2, f"ADVERSARIAL: expected ≥2 evidence items, got {len(evidence)}"
return {
"disposition": "SURVIVES_WITH_MITIGATIONS",
"counter_evidence": [
{
"id": "A1",
"source_id": "O1",
"claim": "FTS5 porter tokenizer may not handle all languages",
"derived_from": ["E1"],
"limitations": ["minor"],
},
],
"surviving_candidates": ["M1"],
"rejected_candidates": [],
"required_mitigations": ["mode labeling"],
"falsification_tests": ["FT1: harness run with embedding backend unreachable"],
"attacks": [
{
"id": "A1",
"target_candidate": "M1",
"dimension": "failure modes",
"finding": "tokenizer coverage",
"evidence": ["E1"],
"severity": "minor",
},
],
}
def fake_innovation(tree: ResearchTaskTree) -> dict:
prior = tree.get_prior_artifacts("INNOVATION")
inward = prior.get("INWARD", {})
outward = prior.get("OUTWARD", {})
applicability = prior.get("APPLICABILITY", {})
inward_claims = [c["id"] for c in inward.get("claims", [])]
evidence_ids = [e["id"] for e in outward.get("reading", {}).get("evidence", [])]
applicable = [c["id"] for c in applicability.get("candidates", [])]
assert inward_claims, "INNOVATION: no INWARD claims received"
assert evidence_ids, "INNOVATION: no OUTWARD evidence received"
assert applicable, "INNOVATION: no APPLICABILITY candidates received"
return {
"conclusion": "ADOPT",
"candidates": [
{
"id": "C1",
"category": "ADAPT",
"proposal": "hybrid FTS+vec recall",
"derived_from": inward_claims[:1] + evidence_ids[:1] + applicable[:1],
"composition_of": [],
"novelty": "adapted",
"expected_gain": "better recall",
"risks": ["latency"],
"kill_test": "recall returns >0 rows",
},
],
}
def fake_synthesis(tree: ResearchTaskTree) -> dict:
prior = tree.get_prior_artifacts("SYNTHESIS")
innovation = prior.get("INNOVATION", {})
candidates = innovation.get("candidates", [])
assert candidates, "SYNTHESIS: no INNOVATION candidates received"
return {
"selected_design": "hybrid FTS+vec recall",
"rejected_alternatives": [{"design": "pure FTS", "reason": "E2 shows vec adds value"}],
"evidence_used": ["I1", "E1", "E2", "A1", "M1", "C1"],
"architecture_implications": ["memory_store.recall modified"],
"files_affected": ["src/rune/memory_store.py"],
"contracts": ["recall returns thresholded rows"],
"tests_required": ["test_recall_hybrid"],
"failure_modes": ["sqlite-vec not installed"],
"kill_conditions": ["recall returns 0 rows on seeded store"],
"build_instructions": ["modify recall() in memory_store.py", "add tests"],
}
def fake_qualify(tree: ResearchTaskTree) -> dict:
prior = tree.get_prior_artifacts("QUALIFY")
synthesis = prior.get("SYNTHESIS", {})
assert synthesis.get("selected_design"), "QUALIFY: no synthesis received"
# First QUALIFY pass: build instructions incomplete → REFINE_SYNTHESIS
# (narrowed semantics: synthesis-only refinement, no research repeat).
# Record the refine round in the tree so the workflow records a 2nd round.
if tree.state.get("qualify_outcome") != "REFINE_SYNTHESIS":
return {
"outcome": "REFINE_SYNTHESIS",
"reason": "rollback/recovery not specified",
"build_instructions": synthesis.get("build_instructions", []),
}
# After synthesis refinement: PROCEED
return {
"outcome": "PROCEED",
"selected_design": synthesis.get("selected_design", ""),
"evidence_used": synthesis.get("evidence_used", []),
}
FAKE_WORKERS = {
"ISSUE": fake_issue_gate,
"INWARD": fake_inward,
"OUTWARD": fake_outward,
"APPLICABILITY": fake_applicability,
"ADVERSARIAL": fake_adversarial,
"INNOVATION": fake_innovation,
"SYNTHESIS": fake_synthesis,
"QUALIFY": fake_qualify,
}
def run_fake_stage(tree: ResearchTaskTree) -> dict:
stage = tree.current_stage
worker = FAKE_WORKERS.get(stage)
if not worker:
raise ValueError(f"no fake worker for stage {stage}")
return worker(tree)
def main_with(argv: list[str]) -> int:
import argparse
parser = argparse.ArgumentParser(description="Fake stage worker for pipeline testing")
parser.add_argument("--issue", type=int, required=True)
parser.add_argument("--round", type=int, default=1)
parser.add_argument("--artifact-dir", required=True)
parser.add_argument("--out-dir", required=True)
args = parser.parse_args(argv[1:])
tree = ResearchTaskTree(issue=args.issue, round_no=args.round, artifact_dir=args.artifact_dir)
if tree.is_complete:
print("research tree already complete")
return 0
artifact = run_fake_stage(tree)
out_dir = Path(args.out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
stage = tree.current_stage
(out_dir / f"stage_{stage}.json").write_text(json.dumps(artifact, indent=2))
print(f"fake stage {stage} complete")
return 0
if __name__ == "__main__":
raise SystemExit(main_with(sys.argv))