M10: ProcessingRunner skeleton (#27)

* M10: ProcessingRunner skeleton

- Add modules/runtime/runner.py with ProcessingRunner and ProcessingRequest
- Wire process_images to delegate through runner (internal only)
- Add test/quality/test_processing_runner.py contract test

Behavior-preserving. Zero blast radius. All callers unchanged.

Made-with: Cursor

* M10: Add run1 and toolcalls update

Made-with: Cursor

* M10: Update Phase III roadmap, add closeout prompt

- Phase III: M11 lifecycle, M12 instrumentation, M13 txt2img, M14 API, M15 queue
- Phase IV-VII renumbered (M16-M33)
- Add M10_closeout_prompt.md for Cursor

Made-with: Cursor
This commit is contained in:
m-cahill 2026-03-11 22:46:56 -07:00 committed by GitHub
parent 11b9e0f16e
commit 880723f100
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 403 additions and 28 deletions

View file

@ -0,0 +1,44 @@
# M10 Closeout Prompt for Cursor
**Use this once PR CI is green against m-cahill/serena.**
---
```
M10 PR CI is complete.
Proceed with M10 closeout.
Steps:
1. Verify CI status
- Linter ✓
- Smoke Tests ✓
2. Merge PR into main.
3. Monitor post-merge CI:
- Quality Tests must pass.
4. Generate milestone artifacts:
docs/milestones/M10/M10_run2.md
docs/milestones/M10/M10_summary.md
docs/milestones/M10/M10_audit.md
5. Update ledger:
docs/serena.md
Add row:
| M10 | ProcessingRunner skeleton | Closed | m10-processing-runner | PR # | <merge_commit> | <quality_run_id> | 5.0 |
6. Create tag:
v0.0.10-m10
7. Push tag.
Follow the RefactorWorkflowPrompt and RefactorSummaryPrompt formats.
```

View file

@ -0,0 +1,125 @@
# M10 — ProcessingRunner Skeleton
Phase: **Phase III — Runner & Service Boundary**
Status: Planned
---
# 1. Intent / Target
Introduce the **ProcessingRunner** abstraction that will become the unified execution surface for Serena.
Currently the pipeline is invoked directly through internal orchestration code.
This milestone introduces a **runner boundary** that:
- encapsulates pipeline execution
- standardizes runtime entrypoints
- prepares Serena for CLI / API / service mode
The runner initially acts as a **thin adapter** around existing behavior.
No behavior changes are permitted.
---
# 2. Scope Boundaries
### In scope
- Create `ProcessingRunner` skeleton at `modules/runtime/runner.py`
- Define `ProcessingRequest` wrapping `StableDiffusionProcessing`
- Wire `process_images` to delegate through runner (internal only)
- Maintain existing CLI/UI/API/scripts behavior
- Add minimal contract test at `test/quality/test_processing_runner.py`
### Out of scope
- No runtime behavior changes
- No async processing yet
- No service layer
- No multiprocessing
- No new configuration surfaces
- No performance changes
- No RuntimeContext in runner (M10)
---
# 3. Clarifications (Authoritative)
| Decision | Choice |
|----------|--------|
| Module path | `modules/runtime/runner.py` |
| ProcessingRequest | Wraps `p`: `ProcessingRequest(processing=p)` |
| RuntimeContext | Not passed to runner; omit from constructor |
| Wiring | Inside `process_images` only; all callers unchanged |
| Test location | `test/quality/test_processing_runner.py` |
---
# 4. Invariants
| Surface | Invariant | Verification |
|---------|-----------|--------------|
| CLI behavior | Identical outputs and execution path | smoke tests |
| API responses | No schema changes | tests |
| Processing results | Byte-identical outputs | golden comparison |
| Runtime state | No side effects introduced | test suite |
| CI coverage | ≥ 40% | CI gate |
---
# 5. Implementation Steps
## Step 1 — Create runner module
Create `modules/runtime/runner.py`:
```python
class ProcessingRequest:
def __init__(self, processing):
self.processing = processing
class ProcessingRunner:
def run(self, request):
from modules.processing import process_images_inner
return process_images_inner(request.processing)
```
## Step 2 — Wire process_images
Inside `process_images`, replace:
```python
res = process_images_inner(p)
```
With:
```python
from modules.runtime.runner import ProcessingRunner, ProcessingRequest
runner = ProcessingRunner()
request = ProcessingRequest(p)
res = runner.run(request)
```
## Step 3 — Add contract test
Add `test/quality/test_processing_runner.py` with delegation test.
---
# 6. Risk & Rollback Plan
Risk level: **Low**
Mechanical refactor. Rollback: revert wiring commit.
---
# 7. Deliverables
Code: `modules/runtime/runner.py`, wiring in `process_images`
Tests: `test/quality/test_processing_runner.py`
Docs: M10_toolcalls.md, M10_run1.md, M10_summary.md, M10_audit.md
Ledger: Update `docs/serena.md`
Tag: `v0.0.10-m10`

View file

@ -0,0 +1,138 @@
# M10 CI Run 1 — ProcessingRunner Skeleton
**Date:** 2026-03-11
**Branch:** m10-processing-runner
**PR:** (verify target repo — gh may have created against upstream)
**Trigger:** pull_request (PR to main)
**Commit:** 59e46fa0
---
## 1. Workflow Identity
| Workflow | Run ID | Trigger | Branch | Commit | Status |
|----------|--------|---------|--------|--------|--------|
| Linter | (pending) | pull_request | m10-processing-runner | 59e46fa0 | — |
| Smoke Tests | (pending) | pull_request | m10-processing-runner | 59e46fa0 | — |
| Quality Tests | (post-merge) | push | main | — | — |
**Note:** PR created via `gh pr create`. Monitor CI at GitHub Actions. Quality Tests run on push to main after merge.
---
## 2. Change Context
| Item | Value |
|------|-------|
| Milestone | M10 — ProcessingRunner Skeleton |
| Phase | Phase III — Runner & Service Boundary |
| Posture | Behavior-preserving |
| Refactor target | `modules/runtime/runner.py` (new), `modules/processing.py` (delegation) |
| Run type | First CI verification of M10 implementation |
---
## 3. Step 1 — Workflow Inventory
(To be populated after CI run completes.)
### Linter
| Job | Required? | Purpose | Pass/Fail |
|-----|-----------|---------|-----------|
| ruff | Yes | Python lint | — |
| eslint | Yes | JS lint | — |
### Smoke Tests
| Job / Step | Required? | Purpose | Pass/Fail |
|------------|-----------|---------|-----------|
| Run smoke tests | Yes | pytest test/smoke | — |
### Quality Tests (post-merge)
| Job / Step | Required? | Purpose | Pass/Fail |
|------------|-----------|---------|-----------|
| Run quality tests | Yes | pytest test/quality, coverage ≥40% | — |
---
## 4. Step 2 — Refactor Signal Integrity
### A) Tests
- **Tier:** Smoke + Quality (new contract test: `test_processing_runner_delegates`)
- **Coverage of refactor target:** Smoke tests exercise txt2img/img2img API → `process_images()` → runner → `process_images_inner()`. Contract test verifies runner delegates correctly.
- **Failures:** (to be filled after CI)
- **Golden/snapshot:** Behavior-preserving; no output changes.
### B) Coverage
- Quality tier enforces ≥40%. New test adds minimal coverage for runner module.
### C) Static Gates
- Ruff, eslint: (to be filled after CI)
---
## 5. Step 3 — Delta Analysis
### Change Inventory
| File | Change |
|------|--------|
| modules/runtime/__init__.py | **New:** Package init |
| modules/runtime/runner.py | **New:** ProcessingRunner, ProcessingRequest |
| modules/processing.py | Delegate to runner inside process_images |
| test/quality/test_processing_runner.py | **New:** Contract test |
| docs/milestones/M10/* | Plan, toolcalls |
**Call graph (unchanged from caller perspective):**
```
UI/API/scripts
process_images(p)
ProcessingRunner.run(request)
process_images_inner(p)
```
---
## 6. Step 4 — Invariant Verification
| Invariant | Verification | Status |
|-----------|--------------|--------|
| CLI behavior | No CLI changes | ✓ |
| API responses | Same path; smoke tests | — |
| Processing results | Byte-identical (runner is thin adapter) | — |
| Runtime state | No new side effects | ✓ |
| CI coverage | ≥40% (Quality gate) | — |
---
## 7. Blast Radius
**Files changed:**
- `modules/runtime/` (new)
- `modules/processing.py` (modified)
- `test/quality/test_processing_runner.py` (new)
- `docs/milestones/M10/*`
**Zero blast radius to callers.** All UI, API, scripts call `process_images(p)` unchanged.
---
## 8. Verdict
**CI Status:** (pending — monitor GitHub Actions)
**Refactor posture:** Behavior-preserving. First Phase III execution boundary. Runner is thin adapter; no behavior change.
**Next step:** Monitor CI. After green: await merge permission. Post-merge: Quality Tests, then audit/summary/ledger/tag per governance.

View file

@ -0,0 +1,12 @@
# M10 Toolcalls — ProcessingRunner Skeleton
Implementation toolcalls for Cursor execution.
| Timestamp | Tool | Purpose | Files/Target | Status |
|-----------|------|---------|--------------|--------|
| 2026-03-11 | write | Create M10_plan.md, M10_toolcalls.md | docs/milestones/M10/ | done |
| 2026-03-11 | write | Create modules/runtime/runner.py | modules/runtime/ | done |
| 2026-03-11 | search_replace | Wire process_images to delegate through runner | modules/processing.py | done |
| 2026-03-11 | write | Add contract test for ProcessingRunner | test/quality/test_processing_runner.py | done |
| 2026-03-11 | run | Create branch m10-processing-runner | git | done |
| 2026-03-11 | run | git add, commit, push, gh pr create | git, gh | done |

View file

@ -80,48 +80,49 @@ Core principles:
| M08 | process_images_inner snapshot threading |
| M09 | Execution context/state seam |
### Phase III — Runner & Service Boundary (M10M14)
### Phase III — Runner & Service Boundary (M10M15)
| Milestone | Title |
|-----------|-------|
| M10 | ProcessingRunner skeleton |
| M11 | txt2img via runner |
| M12 | img2img via runner |
| M13 | API adoption of runner |
| M14 | UI adoption of runner |
| M11 | Runner lifecycle surface (prepare / execute / finalize) |
| M12 | Runtime instrumentation hooks |
| M13 | txt2img path through runner |
| M14 | API integration |
| M15 | background/queue runner preparation |
### Phase IV — Runtime Extraction (M15M19)
### Phase IV — Runtime Extraction (M16M20)
| Milestone | Title |
|-----------|-------|
| M15 | Runtime module extraction |
| M16 | Sampler runner extraction |
| M17 | Decode/save separation |
| M18 | Model provider interface |
| M19 | Runtime tests with mockable boundaries |
| M16 | Runtime module extraction |
| M17 | Sampler runner extraction |
| M18 | Decode/save separation |
| M19 | Model provider interface |
| M20 | Runtime tests with mockable boundaries |
### Phase V — UI & Extension Stabilization (M20M24)
### Phase V — UI & Extension Stabilization (M21M25)
| Milestone | Title |
|-----------|-------|
| M20 | UI tab registry |
| M21 | txt2img/img2img tab modularization |
| M22 | Settings/extensions modularization |
| M23 | Extension API version/contract |
| M24 | Deprecation/compatibility scaffolding |
| M21 | UI tab registry |
| M22 | txt2img/img2img tab modularization |
| M23 | Settings/extensions modularization |
| M24 | Extension API version/contract |
| M25 | Deprecation/compatibility scaffolding |
### Phase VI — Hardening & Reproducibility (M25M29)
### Phase VI — Hardening & Reproducibility (M26M30)
| Milestone | Title |
|-----------|-------|
| M25 | Locked manifests / npm ci / CI env stabilization |
| M26 | Coverage and complexity gates |
| M27 | Security/supply-chain evidence |
| M28 | Health/perf verification |
| M29 | QA/evidence publishing |
| M26 | Locked manifests / npm ci / CI env stabilization |
| M27 | Coverage and complexity gates |
| M28 | Security/supply-chain evidence |
| M29 | Health/perf verification |
| M30 | QA/evidence publishing |
### Phase VII — Release Lock / 5.0 Closure (M30M32)
### Phase VII — Release Lock / 5.0 Closure (M31M33)
| Milestone | Title |
|-----------|-------|
| M30 | Architecture lock |
| M31 | Evidence/audit closure |
| M32 | Release-ready 5/5 close |
| M31 | Architecture lock |
| M32 | Evidence/audit closure |
| M33 | Release-ready 5/5 close |
---

View file

@ -844,7 +844,10 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
sd_samplers.fix_p_invalid_sampler_and_scheduler(p)
with profiling.Profiler():
res = process_images_inner(p)
from modules.runtime.runner import ProcessingRunner, ProcessingRequest
runner = ProcessingRunner()
request = ProcessingRequest(p)
res = runner.run(request)
finally:
sd_models.apply_token_merging(p.sd_model, 0)

View file

@ -0,0 +1,4 @@
"""Runtime execution boundary for Serena.
M10: ProcessingRunner skeleton. Thin adapter around process_images_inner.
"""

22
modules/runtime/runner.py Normal file
View file

@ -0,0 +1,22 @@
"""ProcessingRunner — unified execution entrypoint for Serena pipeline.
M10: Thin adapter around process_images_inner. No behavior changes.
"""
class ProcessingRequest:
"""Wraps StableDiffusionProcessing for runner boundary."""
def __init__(self, processing):
self.processing = processing
class ProcessingRunner:
"""
Unified execution entrypoint for Serena processing pipeline.
"""
def run(self, request):
"""Execute processing pipeline."""
from modules.processing import process_images_inner
return process_images_inner(request.processing)

View file

@ -0,0 +1,26 @@
"""Contract tests for ProcessingRunner (M10 runner skeleton)."""
import modules.processing
from modules.runtime.runner import ProcessingRunner, ProcessingRequest
def test_processing_runner_delegates(monkeypatch):
"""ProcessingRunner.run delegates to process_images_inner."""
called = {}
def fake_process_images_inner(p):
called["ok"] = True
return "result"
monkeypatch.setattr(
modules.processing,
"process_images_inner",
fake_process_images_inner,
)
runner = ProcessingRunner()
request = ProcessingRequest(processing="dummy")
result = runner.run(request)
assert called["ok"]
assert result == "result"