Orchestrata Ultimate › Plans › plan_automated_porting_harness › master-plan

Harness Iteration 0: Automated Porting Pipeline

Source: plans/plan_automated_porting_harness/master-plan.md at 8a2cb42ad · last changed 2026-07-27 · first committed 2026-04-11 · 859 lines.

Prose pending.

Plan text

Harness Iteration 0: Automated Porting Pipeline

Reviewed: 4 rounds of Sonnet subagent review. 71 gaps found, all addressed.


Review History

Round 1 — 3 Sonnet agents (Porter gaps, Testing gaps, Workflow gaps)

# Gap Severity Fix
P1 Symbol rename table missing from prompt HIGH Added Table 1 (20 entries) injected in every prompt
P2 No forward-type/circular dependency resolution guide HIGH Added Table 6 (TYPE_CHECKING vs lazy vs conditional criteria)
P3 @traces decorator keep/translate instruction missing MEDIUM Added Rule 1 in Table 5
P4 Exception hierarchy mapping missing MEDIUM Added Rule 3 in Table 5
P5 Only 5 env vars, 24 exist HIGH Added Table 2 (24 keys with defaults)
P6 No knowledge of which modules ported HIGH Added available_modules + unavailable_imports in StepContext
P7 Dynamic string imports not flagged per-file MEDIUM Added Table 7 (6 files enumerated) + has_dynamic_imports flag
P8 Architecture layer rules not injected MEDIUM Added Table 8 (10 layers with forbidden imports)
P9 Pydantic **data super().init rule missing HIGH Added Rule 2 in Table 5
P10 Class-to-file rename mapping missing MEDIUM Added Table 4 (volk_registry -> agent_registry)
P11 gRPC skip list not injected MEDIUM Added Rule 6 in Table 5
P12 NEW FILE vs APPEND annotation missing MEDIUM Added Table 9 (3 file status types)
T1 Constructor instantiation knowledge missing HIGH Added constructor section in Tester prompt
T2 External service dependency map per method HIGH Added service_deps heuristic grep
T3 Async mode not confirmed LOW Added in Tester system prompt
T5 Side effect inventory missing HIGH Replaced with method body injection
T6 Available fixtures incomplete HIGH Added full catalog + gap fixtures with creation code
T7 Test file placement/naming missing MEDIUM Added TEST FILE NAMING section
T9 ClassVar isolation missing MEDIUM Added ClassVar reset note in Tester prompt
T11 Pydantic validator descriptions missing HIGH Replaced with validator_source (raw body)
T13 Import paths for types missing MEDIUM Added per-type import path section
T14 Dynamic port allocation missing MEDIUM Added in Tester system prompt
T15 Prolog fixture status missing MEDIUM Added with pytest.importorskip pattern
W1 Truncation threshold too permissive HIGH Set 85% for >200 lines, 50% for <=200
W2 depends_on parsed but never enforced HIGH Added dependency check in orchestration loop
W3 Shared file handling (Steps 2+3) HIGH Step 2 merges first, Step 3 branches from HEAD
W4 No pre-step shell commands HIGH Added pre_commands field + execution in loop
W5 Multi-file steps only read primary file HIGH StepContext reads ALL step.files
W6 Source files only read first HIGH StepContext reads ALL step.source_files
W7 No git commit before merge BLOCKER Added commit() step: git add + commit before merge
W8 Deletion steps have no model MEDIUM Added delete step type with safety check
W9 Gate steps don't assert prior steps HIGH Added assertion in gate logic
W10 Pytest baseline comparison missing HIGH Added baseline recording in harness init
W11 Test count regression unchecked HIGH Added collected count comparison
W12 Unported dependency scan missing MEDIUM Added available_modules scan in context_builder
W13 No rollback strategy HIGH Added rollback CLI command with git revert
W14 String literal imports not checked HIGH Added validation check 4
W15 No diagram/design phase MEDIUM Added scaffold step type with diagram2code
W17 Range continues past failures HIGH Added --stop-on-failure default
W18 Fixer sees corrupted state HIGH Fixer now gets original + errors only
W19 No targeted test runs MEDIUM Added validation check 8 (module-specific tests)
W20 Retry keeps stale worktree HIGH create() always discards stale first

Round 2 — 1 Sonnet agent (verification of Round 1 fixes)

# Gap Status Fix
P2 TYPE_CHECKING resolution criteria undefined PARTIAL Added Table 6 with 3 resolution patterns
P7 6 dynamic import files not enumerated PARTIAL Added Table 7 with all 6 files listed
P8 Layer hierarchy not defined PARTIAL Added Table 8 with 10 layers
P12 APPEND vs MODIFY distinction PARTIAL Added Table 9 with APPEND_TO_EXISTING
W15 Scaffold workflow not detailed PARTIAL Added step 5b in orchestration loop
W19 Targeted test runs not in pipeline MISSING Added validation check 8

Round 3 — 2 Sonnet agents (hostile execution simulation + prompt placeholder audit)

# Gap Severity Fix
H1 init.py import chain breaks ALL verify cmds BLOCKER Added PREREQUISITE Step 0
H2 Gate passes vacuously with 0 tests collected BLOCKER harness init records error count, gate checks errors
H3 Step 3 wrong method name + sync/await mismatch BLOCKER Added PREREQUISITE table (5 execution plan corrections)
H4 Step 5 references nonexistent _completed_tasks HIGH In PREREQUISITE table
H5 Step 9 identifies nonexistent bug HIGH In PREREQUISITE table
H6 Step 6 verify missing required field HIGH In PREREQUISITE table
H7 Output truncation for 861-line files HIGH Set max_tokens=16384 in dispatcher
H8 $ULT shell var not expanded at runtime HIGH Expand at parse time
H9 Nested fences confuse applicator regex MEDIUM Regex requires .py path suffix
H10 Worktree branches entire workspace (61 dirs) MEDIUM git add uses explicit paths, not -A
H11 Step 8 references nonexistent metric variable LOW In PREREQUISITE table
TP1 needs_creation pairs: methods_to_add empty CRITICAL context_builder branches on readiness
TP2 constructor_side_effects unsourced MISSING Replaced with constructor body injection
TP3 side_effects unsourced MISSING Replaced with method body injection
TP4 validator_descriptions unsourced MISSING Replaced with validator_source (raw body)
TP5 service_deps unsourced MISSING Heuristic grep on method body
TP6 orchestrata_test_contents no lookup MISSING context_builder path lookup added
TP7 Reviewer prompt completely empty GAP Added full Reviewer system + user prompts
TP8 Fixer broken state contamination risk DESIGN Removed broken state from Fixer prompt

Cumulative Stats

Round Gaps Found Fixed Carried Forward
Round 1 48 48 0
Round 2 6 6 0
Round 3 18 18 0
Total 72 72 0

PREREQUISITE: Fix Broken Import Chain (Step 0)

BLOCKER: Every python -c "from orchestrata_ultimate.X import ..." fails because:

Before running ANY harness step, fix this:

  1. Either add a stub src/orchestrata_ultimate/core/traceability_utils.py that re-exports from core.tracing
  2. Or fix core/tracing/__init__.py to not import traceability_utils
  3. Or change __init__.py to lazy-import UltimateOrchestrator

This must be done MANUALLY before harness init. The harness cannot fix it because it's a prerequisite for all verification commands.

Also: pytest currently has ~25 collection errors from the same root cause. harness init must record these as the baseline error count. Gate checks must fail if error count INCREASES, not just if passed count decreases.

PREREQUISITE: Fix Execution Plan Steps with Wrong Information

These steps describe code that doesn't match reality. Fix BEFORE running harness:

Step Plan Says Actual Code Fix
3 self._transition_to_open() _record() (local async nested def). Also record_success/record_failure are sync, not async. Correct method name. Note sync->async change needed.
5 self._completed_tasks No such attribute. Real structure is self._tasks: dict[str, ThreadPoolTask] Fix to reference self._tasks, filter by completed status
6 Verify: Node(name='test') node_type is required (no default). Fails with ValidationError. Fix verify: Node(node_type='TestNode', name='test')
8 metric.observe(duration) No metric variable. Use record_request_metrics(..., duration_seconds=duration) Fix to use correct API
9 def stop(): pass stub at lines 304-307 No such stub. _stop_system_metrics_collection is intentional no-op for daemon threads. Remove or redefine the bug

These execution plan corrections must be applied to plans/execution-plan.md before the harness runs Steps 1-11.


Goal

A host-side harness that picks steps from execution-plan.md, generates rich context from AST data + diagrams + source code, dispatches to cheap models (DeepSeek/Qwen via OpenRouter), validates with the 20 existing scripts + AST re-comparison, and merges via git worktrees.

Iteration 0 scope: Phase 0 Steps 1-11 (bug fixes). If it works, extend to porting steps.


Architecture

scripts/harness/
    __init__.py
    __main__.py            # python -m scripts.harness
    cli.py                 # Typer CLI: run, status, retry, report, validate, init, rollback
    config.py              # All paths, models, API keys, static tables
    plan_parser.py         # Parse execution-plan.md -> Step dataclasses
    context_builder.py     # Build rich context per step from AST + files + diagrams
    worktree.py            # Git worktree create/commit/merge/discard
    dispatcher.py          # OpenRouter API client (httpx async)
    applicator.py          # Parse model output -> file writes
    validator.py           # 8-stage validation pipeline
    reporter.py            # State persistence + dashboard
    volks.py               # Volk definitions: role, model, static context
    prompts/
        __init__.py
        porter.py          # Porter system/user templates
        reviewer.py        # Reviewer templates
        fixer.py           # Fixer templates
        tester.py          # Testing volk templates

Step Types

Each step in the execution plan has a type that determines its workflow:

Type Description Model Dispatch? Example
bug_fix Modify existing file to fix a bug Yes (Porter) Steps 1-3, 5-10
port Copy from orchestrata + translate Yes (Porter) Steps 12-26, 40-44
scaffold Generate skeleton from diagram diagram2code tool Step 77
shell_only mkdir, cp, touch - no model needed No Steps 39, 48, 63, 79
delete Remove stub files (with safety check) No Steps 59, 96, 185
gate Validation-only, no file changes No Steps 11, 27, 38, 97
skip Verified as not needed No Step 4
multi_file Port multiple files in one step Yes (Porter, multi-fence) Steps 42, 80-82
test_gen Generate tests for ported code Yes (Tester) Steps 96b, 173b

The parser detects type from step content:


Data Structures

@dataclass
class Step:
    number: str           # "1", "44b", "96b"
    title: str            # "Fix wrong import path in logging_config.py"
    goal: str             # Text after **Goal:**
    step_type: str        # bug_fix, port, scaffold, shell_only, delete, gate, skip, multi_file, test_gen
    files: list[str]      # ALL resolved target paths from **File:**/**Destination:**
    source_files: list[str]  # ALL resolved paths from **Source:** (porting steps)
    deleted_files: list[str] # Files to delete (delete steps)
    pre_commands: list[str]  # Shell commands to run before model dispatch
    actions: str          # Full text between **Actions:** and **Verify:**
    verify_command: str   # Content of bash fence after **Verify:**
    expected_output: str  # Text after **Expect:**
    failure_hint: str     # Text after **If it fails:**
    is_gate: bool
    is_skip: bool
    phase: str            # "Phase 0", "Tier 1"
    sub_phase: str        # "0.1", "1.1"
    depends_on: list[str] # Inferred from sub_phase ordering

@dataclass
class StepContext:
    step: Step
    target_contents: dict[str, str]    # {path: contents} for ALL step.files
    source_contents: dict[str, str]    # {path: contents} for ALL step.source_files
    original_contents: dict[str, str]  # Snapshot at worktree creation (for Fixer)
    pair: dict | None                  # The class pair from ast-deep-comparison.json
    methods_to_add: list[dict]         # method_diff.only_in_orchestrata
    methods_to_fix: list[dict]         # shared methods with signature mismatches
    vars_to_add: list[dict]            # var_diff.only_orchestrata
    readiness_before: str              # stub/partial/needs_creation
    available_modules: set[str]        # Ultimate modules that exist on disk RIGHT NOW
    unavailable_imports: list[str]     # Translated imports pointing to non-existent modules
    import_resolution: dict[str, str]  # For each unavailable: TYPE_CHECKING/lazy/conditional
    layer_rules: str                   # "Layer: X. Cannot import: [Y, Z]"
    has_dynamic_imports: bool          # Is this file in the 6-file dynamic imports list?
    file_status: str                   # "NEW_FILE" or "MODIFY_EXISTING"

@dataclass
class StepResult:
    step_number: str
    status: str           # passed, failed, skipped, blocked
    attempts: int
    model_used: str
    merged_sha: str | None  # For rollback
    validation: dict      # Per-check pass/fail
    tokens_used: dict     # {input: N, output: M}
    cost_usd: float
    ast_delta: dict | None  # Methods added, signatures matched
    test_coverage: float | None
    errors: list[str]

Static Context Tables (injected into EVERY prompt)

Table 1: Symbol Rename Map (20 entries)

VolkRuntime -> AgentRuntime
VolkPool -> AgentPool
VolkRegistry -> AgentRegistry
VolkCoordinator -> AgentCoordinator
BaseVolk -> BaseAgent
BaseEntity -> DomainEntity
AnalystVolk -> AnalystAgent
SeniorDevVolk -> SeniorDevAgent
JuniorVolk -> JuniorAgent
CodeDirectorVolk -> CodeDirectorAgent
QaVolk -> QualityAssuranceAgent
ArchitectVolk -> ArchitectAgent
UXVolk -> UserExperienceAgent
PMVolk -> ProjectManagerAgent
ConciergeVolk -> ConciergeAgent
ComplianceVolk -> ComplianceAgent
OrchestrationKernel -> OrchestrataKernel
Orchestrator -> UltimateOrchestrator
PolicyEngine -> GovernanceEngine
Neo4jClient -> Neo4jGraph
WebSocketGateway -> VizIntWebUI

Plus regex rule: Any I interface -> Protocol (PEP 544).

Table 2: Complete Environment Variable Defaults (24 keys)

REDIS_HOST = "localhost"
REDIS_PORT = "6379"
REDIS_URL = "redis://localhost:6379"
REDIS_DB = "0"
NEO4J_URI = "bolt://localhost:7687"
NEO4J_USERNAME = "neo4j"
NEO4J_PASSWORD = ""
LOG_LEVEL = "INFO"
PROLOG_STACK_LIMIT = "4000000000"
ORCHESTRATA_ENV = "development"
ORCHESTRATA_WORKSPACE = ""
ORCHESTRATA_LLM_PROVIDER = "anthropic"
ORCHESTRATA_TRACE = "false"
ANTHROPIC_API_KEY = ""
DEEPSEEK_API_KEY = ""
OPENROUTER_API_KEY = ""
KIMI_API_KEY = ""
OLLAMA_BASE_URL = "http://localhost:11434"
AIDER_MODEL = ""
PROJECT_ROOT = ""
PROJECT_NAME = ""
GOVERNANCE_STRICT_MODE = "false"
POSTMAN_PORT = "8080"
POSTMAN_MAX_MESSAGE_SIZE = "10000000"

Table 3: Import Translation (top entries + full appendix reference)

from orchestrata.core.interfaces -> from orchestrata_ultimate.core.protocols
from orchestrata.core.traceability -> from orchestrata_ultimate.core.tracing.traceability
from orchestrata.core.traceability_utils -> from orchestrata_ultimate.core.tracing.traceability
from orchestrata.core.infra_config -> from orchestrata_ultimate.core.config.infra
from orchestrata.core.base.entity -> from orchestrata_ultimate.core.domain.domain_entity
from orchestrata.core.base -> from orchestrata_ultimate.core.domain
from orchestrata.core.redis_factory -> from orchestrata_ultimate.core.redis
from orchestrata.core.lru_cache -> from orchestrata_ultimate.core.cache
from orchestrata.core.monitoring -> from orchestrata_ultimate.core.metrics
from orchestrata.volks.<role> -> from orchestrata_ultimate.agents.volks.<role>
from orchestrata.agents.volks.<role> -> from orchestrata_ultimate.agents.volks.<role>
from orchestrata.provider -> from orchestrata_ultimate.providers
from orchestrata.knowledge -> from orchestrata_ultimate.knowledge_graph
from orchestrata.kernel.volk_registry -> from orchestrata_ultimate.kernel.agent_registry
(full 240 translations in ast-deep-comparison.json import_audit section)

Table 4: File-Level Renames

orchestrata.kernel.volk_registry -> orchestrata_ultimate.kernel.agent_registry
(all others keep same filename within translated module path)

Table 5: Rules

1. Preserve @traces(...) decorators exactly as in orchestrata source. Import already translated.
2. Any class inheriting BaseAgent must call super().__init__(**data) (Pydantic keyword propagation).
3. BaseError -> UltimateBaseError. Drop error_code parameter on exception constructors.
4. Factory pattern: Redis, Neo4j, Prolog - always provide in-memory fallback. Guard with try/except ImportError.
5. For TYPE_CHECKING imports of not-yet-ported modules: use from __future__ import annotations + TYPE_CHECKING block.
6. gRPC files (grpc_client.py, grpc_server.py, binary_serializer.py, proto/) are SKIPPED. Wrap gRPC imports in try/except ImportError.
7. No relative imports. Absolute only.
8. No mocking. Real implementations only.

Table 6: Forward Reference Resolution Criteria

When context_builder finds an import pointing to a module that doesn't exist yet on disk:

Condition Resolution Example
Type used ONLY in annotations (param types, return types) TYPE_CHECKING AgentRegistry in a type hint
Type used in runtime code (instantiation, isinstance, method calls) lazy (import inside the function that uses it) from orchestrata_ultimate.kernel.agent_registry import AgentRegistry inside register()
Optional service (Redis, Neo4j, Prolog, gRPC) conditional (try/except ImportError with None fallback) try: from neo4j import GraphDatabase except ImportError: GraphDatabase = None

Table 7: Dynamic String Import Files (6 files)

agents/task_executor.py       — 9 string module refs ("orchestrata.volks.<name>.volk")
governance/constitutional.py  — 1 __import__() call ("orchestrata.core.enums")
plugin/loader.py              — 1 string prefix ("orchestrata.plugins.")
plugin/config.py              — 2 string prefixes ("orchestrata.plugins.", "orchestrata_plugin_")
plugin/context.py             — 1 f-string logger name
kernel/cli.py                 — 1 logging name (non-functional but should still be translated)

Table 8: Architecture Layer Hierarchy

Layer Modules Cannot Import From
domain core/domain/, exceptions/ redis, neo4j, httpx, fastapi, anthropic, pyswip, websockets
core core/logging/, core/metrics/, core/tracing/, core/threading/, core/patterns/, core/config/ agents, kernel, orchestrator, postman, governance, session, gateway, plugin
protocol cxp/, core/protocols.py agents (runtime), kernel, orchestrator, governance
providers providers/, llm/, drivers/ kernel, orchestrator, postman, governance, session
agents agents/ (volks only, not infra) kernel, orchestrator (use TYPE_CHECKING for forward refs)
agents_infra agents/ (runtime, pool, coordinator) (can import from kernel, orchestrator — these are Tier 2)
coordination kernel/, orchestrator/, postman/, governance/ gateway, plugin, session (except via interfaces)
knowledge knowledge_graph/ gateway, plugin
persistence session/, memory/ gateway, plugin
surface gateway/, plugin/, integrations/ (can import from anything)

Table 9: Step File Status Types

Status Meaning Applicator Behavior
NEW_FILE File doesn't exist in ultimate yet Model creates full file. No truncation check.
MODIFY_EXISTING File exists, model replaces entire content Truncation check applies (85%/50% thresholds).
APPEND_TO_EXISTING File exists, model adds to it (multi-class consolidation) Model output must include ALL existing content plus additions. Truncation check uses original length as baseline.

Porter Volk Prompt

System Prompt

You are a Python engineer executing a specific porting step for orchestrata-ultimate.
Python >=3.14. Absolute imports only. No mocking. No relative imports.

OUTPUT FORMAT:
- One ```python <file_path> fence per modified file
- Output the COMPLETE file - never truncate, never use "... rest of file ..."
- If multiple files, output multiple fences

RULES:
{TABLE_5_RULES}

SYMBOL RENAMES (apply to all class references, imports, type annotations):
{TABLE_1_SYMBOL_RENAMES}

ENVIRONMENT VARIABLES (replace os.environ["X"] with os.environ.get("X", default)):
{TABLE_2_ENV_VARS}

User Prompt (bug_fix steps)

## Step {number}: {title}

### Goal
{goal}

### Actions
{actions}

### File: `{file_path}` ({line_count} lines)
```python
{file_contents}

Verification

{verify_command}

Expected: {expected_output}

Output the complete modified file.


#### User Prompt (port steps)

Step {number}: {title}

Goal

{goal}

Actions

{actions}

Destination file: {dest_path} (currently {line_count} lines, status: {file_status})

{target_contents}

Source file: {source_path} ({source_lines} lines)

{source_contents}

{FOR EACH additional source file:}

Source file: {source_path_N}

{source_contents_N}

{END FOR}

AST Analysis - Methods to add:

{FOR EACH method in methods_to_add:}

AST Analysis - Signature mismatches to fix:

{FOR EACH method in methods_to_fix:}

Import translations for this file:

{FILTERED translations appearing in this source file}

Forward references (modules not yet ported - use TYPE_CHECKING):

{FOR EACH unavailable_import:}

Layer rules

{layer_rules}

{IF has_dynamic_imports:}

WARNING: Dynamic string imports

This file contains string-based module references. Translate ALL string literals containing 'orchestrata.' to 'orchestrata_ultimate.' and apply symbol renames. {END IF}

Verification

{verify_command}

Output the complete file(s).


---

### Testing Volk Prompt

#### System Prompt

You are a Python test engineer writing tests for orchestrata-ultimate. Target: 99% line coverage on the module under test. Python >=3.14. pytest with asyncio_mode = "auto" (no @pytest.mark.asyncio needed).

RULES:

AVAILABLE FIXTURES (from conftest.py):

FIXTURES NOT YET IN CONFTEST (create inline if needed):

TEST FILE NAMING:

SYMBOL RENAMES: {TABLE_1}


#### User Prompt

Generate tests for: {module_path}

Implementation ({line_count} lines):

{implemented_code}

Class: {class_name}

SOURCE for these fields: context_builder derives them from AST + source code reading:

Constructor:

{constructor_body}

Methods to test: {FOR EACH method:}

{method_body}

{END FOR}

Import paths for types in signatures:

{FOR EACH type:}

Reference tests from orchestrata:

SOURCE: context_builder looks up orchestrata/tests/<matching_dir>/test_<module_name>.py. If no match found, this section is "No reference tests available — generate from scratch."

{orchestrata_test_contents_or_empty}

Coverage target: 99% line coverage on {module_path}

Output the complete test file.


---

### Fixer Volk Prompt

#### System Prompt

Same as Porter system prompt, plus:

You are fixing a failed porting step. You receive the ORIGINAL file and the validation errors. Apply the step's required changes to the ORIGINAL file while avoiding the errors. Output the complete corrected file in a ```python fence.


#### User Prompt

Fixing Step {number}: {title}

Original file (the ONLY starting point — apply changes to THIS):

{original_contents}

What the step requires:

{actions}

Validation errors from the previous attempt (avoid these mistakes):

{error_output}

Apply the step's changes to the original file. Avoid the listed errors. Output the complete corrected file.


**Design decision:** The broken state is NOT included. Including it causes model contamination — the model mixes correct and broken code unpredictably. Instead, the Fixer gets: original (clean starting point) + step actions (what to do) + error output (what to avoid). This produces cleaner results.

---

### Reviewer Volk Prompt

#### System Prompt

You are reviewing a code diff from an automated porting step. Output ONLY one of:

Check for:

  1. Remaining from orchestrata. imports (must be orchestrata_ultimate)
  2. Bare os.environ["X"] reads (must use .get())
  3. Missed symbol renames (Volk->Agent, BaseEntity->DomainEntity, etc.)
  4. Relative imports (must be absolute)
  5. Mocking (unittest.mock, MagicMock, @patch)
  6. Truncated methods (pass/... where implementation should be)
  7. Correct base class (BaseAgent subclasses use Pydantic, not dataclass)

#### User Prompt

Review Step {number}: {title}

Diff:

{git_diff}

AST expectations:

Verdict?


**When used:** Optionally after Porter pass + validation pass, before merge. Adds confidence but costs one extra API call. Configurable via `config.run_reviewer = True/False`.

---

### Context Builder (context_builder.py)

Assembles StepContext from multiple sources. Runs BEFORE model dispatch.

Key operations:
1. Read ALL target files from worktree (not repo root)
2. Read ALL source files from orchestrata
3. Snapshot originals at worktree creation time (stored in .harness/step-N/original/)
4. Find AST pair from ast-deep-comparison.json by matching class names in step title/files
5. **For `needs_creation` pairs** (ultimate_exists=false): populate `methods_to_add` from `pair['orchestrata_methods']` (ALL methods), not from `method_diff.only_in_orchestrata` (which doesn't exist for these pairs). Set `readiness_before = "needs_creation"` and include it in the prompt so the model knows it's creating from scratch.
6. Scan disk for available_modules (which ultimate modules exist NOW)
6. For each source import, translate and check if dest module exists -> unavailable list
7. Determine layer rules from file path
8. Check if file is in the 6-file dynamic imports list
9. Determine NEW_FILE vs MODIFY_EXISTING

---

### Worktree Manager

Key operations:
- create(): Always fresh. Removes stale worktree/branch from previous attempt first.
- commit(): `git add orchestrata-ultimate/src orchestrata-ultimate/tests` (NOT -A — repo root is workspace with 61 subdirs). Then `git commit` in worktree. MUST be called before merge.
- merge(): git merge --no-ff, returns SHA. Then discards worktree.
- discard(): Force remove worktree + delete branch.
- rollback(sha): git revert <sha> on main.

**CRITICAL:** The git root is `/home/mohamed/workspace` (not orchestrata-ultimate). Worktrees branch the ENTIRE workspace. `git add -A` would capture changes from all 61 projects. Always use explicit paths: `git add orchestrata-ultimate/src/ orchestrata-ultimate/tests/ orchestrata-ultimate/plans/`.

---

### Validation Pipeline (8 checks)

| # | Check | Severity | Stop? |
|---|-------|----------|-------|
| 1 | Syntax (py_compile) | CRITICAL | Yes |
| 2 | Step verify command | CRITICAL | Yes |
| 3 | Import grep (from orchestrata. without _ultimate) | ERROR | No |
| 4 | String literal imports ("orchestrata." in non-import lines) | ERROR | No |
| 5 | Bare os.environ["X"] grep | ERROR | No |
| 6 | Architecture checker | WARNING | No |
| 7 | AST signature comparison (port steps only) | ERROR | No |
| 8 | Targeted module tests (tests/<module>/test_<file>.py) | CRITICAL | Yes |
| 9 | Full pytest (compare against baseline, new failures only) | CRITICAL | Yes |

Check 8 (targeted tests): Auto-detected from file path. If step modifies `src/orchestrata_ultimate/core/logging/logging_config.py`, run `pytest tests/test_logging.py tests/core/ -x -q`. Fast (~2s). Catches regressions in the specific module. Runs BEFORE the full suite.

Check 9 (full pytest): Baseline recorded by `harness init` using `--continue-on-collection-errors`. Baseline records: `collected`, `passed`, `failed`, `errors` (collection errors). Pre-existing failures AND pre-existing collection errors are ignored. Only NEW failures or NEW errors are CRITICAL. Test count regression: if collected < baseline_collected, flag as ERROR (model deleted a test). Error count regression: if errors > baseline_errors, flag as ERROR.

**Dispatcher max_tokens:** Set `max_tokens=16384` in all OpenRouter requests. DeepSeek V3 default is 8192 which truncates files >600 lines. thread_pool.py (861 lines) needs ~7.6K output tokens — 8192 is too tight. 16384 gives safe headroom.

---

### Orchestration Loop

For each step in range:
1. Skip check (is_skip -> mark skipped, continue)
2. Dependency check (all depends_on must be passed/skipped, else mark blocked, stop if --stop-on-failure)
3. Gate check (no model, just run validation against repo root, assert all prior steps passed)
4. Shell-only (run pre_commands, mark passed)
5. Delete (safety check imports, git rm, mark passed)
5b. **Scaffold** (design phase for scaffold step_type):
    a. Generate destination class diagram from AST pair data (Mermaid)
    b. Run `diagram_generator.py diagram2code --diagram <mermaid> --output-dir <worktree>`
    c. The skeleton has correct signatures, empty bodies
    d. Then continue to step 8 (model dispatch) — Porter fills in bodies from orchestrata source
    e. This is the DESIGN -> SCAFFOLD -> IMPLEMENT flow
6. Create worktree (fresh, discards stale)
7. Run pre_commands in worktree
8. Build StepContext from AST + files + disk state
9. Attempt loop (max 3):
   - Attempt 1: Porter (DeepSeek)
   - Attempt 2: Fixer (Sonnet) with original + broken + errors
   - Attempt 3: Porter fallback (Qwen)
   - Each: dispatch -> apply -> validate -> pass or collect errors
10. If passed: commit in worktree, merge to main, record SHA, discard worktree
11. If failed: preserve worktree, record errors, stop if --stop-on-failure

---

### Applicator

Parses model output fences:
- Regex: `` ```python\s+(\S+\.py)\n(.*?)``` `` (DOTALL) — fence info string MUST end in `.py` to be treated as a file path. This prevents matching code examples inside model explanatory text (e.g., `` ```python\n# Before:\n... `` which has no file path).
- Fallback: if one file and no `.py` path in fence, use step's primary file
- Reject truncated: check for "... rest of" markers
- Reject too-short: >200 line files must be >=85% of original, <=200 line files >=50%
- Write to worktree path, creating parent dirs as needed

---

### State Tracking (.harness/state.json)

Atomic writes (write to .tmp then rename).

Contains:
- baseline: pytest counts recorded at init
- steps: per-step status, attempts, model, merged_sha, validation, tokens, cost, errors
- summary: total/passed/failed/skipped/blocked counts, total cost

---

### CLI Commands

```bash
python -m scripts.harness init              # Record pytest baseline
python -m scripts.harness run --step 1      # Run single step
python -m scripts.harness run --steps 1-11  # Run range (stops on failure)
python -m scripts.harness run --steps 1-11 --no-stop  # Continue past failures
python -m scripts.harness status            # Show step statuses
python -m scripts.harness retry --step 5    # Retry (fresh worktree)
python -m scripts.harness retry --step 5 --model qwen/qwen-2.5-coder-32b-instruct
python -m scripts.harness rollback --step 3 # git revert merged SHA
python -m scripts.harness validate --step 1 # Validation only, no model
python -m scripts.harness report            # Full dashboard
python -m scripts.harness coverage          # Re-run AST comparison, show delta

Iteration 0: Steps 1-11

Step Type File (lines) Tokens Notes
1 bug_fix logging_config.py (251) ~2.5K Import path fix
2 bug_fix error_handling.py (728) ~7K 7x iscoroutinefunction
3 bug_fix error_handling.py (728) ~7K Await circuit breaker. Reads Step 2 output.
4 skip - 0 Not a bug
5 bug_fix thread_pool.py (861) ~8K Memory leak cleanup
6 bug_fix node.py (110) ~1.5K Pydantic v1->v2
7 bug_fix domain_entity.py (88) ~1.2K .dict()->.model_dump()
8 bug_fix decorators.py (314) ~3.5K Record duration
9 bug_fix metrics_config.py (424) ~4K Implement stop()
10 bug_fix audit.py (445) ~5K Real after_state
11 gate - 0 Full pytest run

Steps 2->3 share error_handling.py. Step 2 merges first. Step 3 worktree branches from HEAD (includes Step 2). No conflict.

Cost: ~$0.01 | Time: ~5 minutes

Success Criteria


File List for Builder

File LOC Key
init.py 5 Package
main.py 5 Entry
config.py 120 Config, env, static tables
plan_parser.py 250 Regex parser, Step, variable expansion, type detection
context_builder.py 200 StepContext from AST + files + disk
worktree.py 100 Create/commit/merge/discard
dispatcher.py 130 httpx async, OpenRouter, tokens, errors
applicator.py 120 Fence parsing, truncation detect, write
validator.py 250 8-check pipeline, baseline, AST sig
reporter.py 150 State persistence, dashboard
volks.py 50 Porter/Reviewer/Fixer/Tester
prompts/init.py 5 -
prompts/porter.py 120 System + user with all context slots
prompts/reviewer.py 60 Review templates
prompts/fixer.py 80 Original + broken + errors
prompts/tester.py 120 Fixtures, coverage target
cli.py 250 init/run/status/retry/rollback/validate/report/coverage
Total ~2,015