Skip to content

Commit cac4b62

Browse files
KraHsuclaude
andcommitted
docs: refresh §9 refactor state — R0.1 merged, R0.2 is next
Tracks completion of PR #81 (CLI --help snapshot baseline). The checked-in source of truth (ROADMAP.md §9) now reflects: - Phase R0 row → 🟡 R0.1 ✅ / R0.2 + R0.3 pending. - Completed block — R0.1 file list, LoC, commit chain (95126e1 → 542b61a → 859657f), CHANGELOG entry. - Tests run — was "None"; now lists the four envs verified pre-merge plus final CI run 26228761027. - Dependency graph — was "None"; now records 3,829 → 3,851 nodes and 11,427 → 11,454 edges (delta from indexing the new test file, no production-code edges). - Two new risks discovered during R0.1: 1. Env-var-based pinning (NO_COLOR / TERM / COLUMNS) of Rich/Typer help output is not portable. GitHub Actions sets FORCE_COLOR=1 which Rich honours over NO_COLOR=1. Future Rich-output snapshot tests must pin typer.rich_utils.{MAX_WIDTH,FORCE_TERMINAL} in a `python -c` wrapper before importing the CLI. 2. §9.0 originally listed 9 CLI commands; the real surface is 11 (`prof` and the `project` subapp's own --help were missed). Corrected here; the R0.1 baseline locks all 11. - Suggested next slice rewritten from R0.1 → R0.2 (optional-dep subprocess test); scope, rationale, risk recorded. - Phase R0 section — PR0.1 marked ✅ merged with the merge SHA; completion criteria show 1/3 PRs done. Companion edits to CLAUDE.md and plans/adr/README.md (gitignored — agent-local) are also persisted on disk for the next session. No production code change. No tests added or modified. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8be2932 commit cac4b62

1 file changed

Lines changed: 52 additions & 30 deletions

File tree

‎ROADMAP.md‎

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -323,18 +323,18 @@ genelab export GeneLab-Franka-Pick-And-Place-v0 logs/.../model_500.pt \
323323
> *structural hygiene* that those features rest on. R-phases are
324324
> independent of M1–M3 sequencing — most can interleave with feature work.
325325
>
326-
> Last reviewed: 2026-05-21 · against `dev` @ `1c80b41`.
326+
> Last reviewed: 2026-05-21 · against `dev` @ `c3d851e`.
327327
328328
### 9.0 Status / 当前状态
329329

330-
**Phase:** Planning complete · Implementation not started.
330+
**Phase:** R0 in progress · R0.1 merged · R0.2 + R0.3 pending.
331331

332332
| What | Status | Artifact |
333333
|---|---|---|
334334
| Architecture assessment | ✅ written | [`plans/architecture/architecture-assessment.md`](plans/architecture/architecture-assessment.md) |
335335
| Target architecture | ✅ written | [`plans/architecture/target-architecture.md`](plans/architecture/target-architecture.md) |
336336
| ADRs 0001–0010 | ✅ drafted (all Status: Proposed) | [`plans/adr/`](plans/adr/) |
337-
| Phase R0 — baseline & tooling | ⬜ not started | — |
337+
| Phase R0 — baseline & tooling | 🟡 R0.1 ✅ merged · R0.2 + R0.3 pending | PR #81 (`c3d851e`) |
338338
| Phase R1 — break rl.runner ↔ rl.backends cycle | ⬜ not started | gated on ADR-0001 acceptance |
339339
| Phase R2 — small abstractions | ⬜ not started | gated on ADR-0002, ADR-0003 |
340340
| Phase R3 — domain-owned parsing | ⬜ not started | gated on ADR-0005 |
@@ -344,38 +344,51 @@ genelab export GeneLab-Franka-Pick-And-Place-v0 logs/.../model_500.pt \
344344
| Phase R7 — extensions API + importlinter blocking | ⬜ not started | gated on R0–R6 landing + ADR-0008, ADR-0009 |
345345
| Phase deferred — entity/articulation split | ⏸ deferred (criteria recorded) | [ADR-0010](plans/adr/0010-defer-articulation-split.md) |
346346

347-
**Completed in this planning round.**
347+
**Completed.**
348348

349-
- New: [`plans/architecture/architecture-assessment.md`](plans/architecture/architecture-assessment.md), [`plans/architecture/target-architecture.md`](plans/architecture/target-architecture.md), [`plans/adr/0001-…0010`](plans/adr/), [`plans/adr/README.md`](plans/adr/README.md), [`CLAUDE.md`](CLAUDE.md).
350-
- Modified: this `ROADMAP.md` (§9 added — refactor phases).
351-
- **Not modified:** any file under `src/genelab/`, `tests/`, `examples/`, `docs/`. Production code has not been touched as part of the refactor.
349+
- Planning round (commits `0b4474f` and prior):
350+
- New: [`plans/architecture/architecture-assessment.md`](plans/architecture/architecture-assessment.md), [`plans/architecture/target-architecture.md`](plans/architecture/target-architecture.md), [`plans/adr/0001-…0010`](plans/adr/), [`plans/adr/README.md`](plans/adr/README.md), [`CLAUDE.md`](CLAUDE.md).
351+
- Modified: this `ROADMAP.md` (§9 added — refactor phases).
352+
- **PR R0.1 — CLI `--help` snapshot baseline** (PR #81, merged `c3d851e`, 3 commits `c00d8c1` → `7dc47f8` → `c6c7ba1`):
353+
- New: `tests/test_cli_help_snapshots.py` (123 LoC), `tests/snapshots/help-{root,cache,prof,list,info,play,eval,export,train,project,project_new}.txt` (11 files / 277 lines).
354+
- Modified: `CHANGELOG.md` (+11 lines under `[Unreleased] · Added`).
355+
- **Not modified:** any file under `src/genelab/`. R0.1 is test scaffolding only.
352356

353-
**Tests run.** None — the refactor has not begun, so there is no refactor diff to validate. The pre-refactor M1 feature work that landed earlier on `dev` (eval / export / backends — see commits `99389d3..1c80b41`) was tested in its own PRs; those results stand and are not affected by this planning round.
357+
**Tests run.**
354358

355-
**Changes to the dependency graph.** None. Re-running `mcp__codebase-memory-mcp__index_repository` produces the same 3,829-node / 11,427-edge graph that was indexed at the start of the planning round. The hotspots and duplications flagged in the assessment are still present.
359+
- Pre-R0.1: none. The pre-refactor M1 feature work that landed earlier on `dev` (eval / export / backends — see commits `99389d3..1c80b41`) was tested in its own PRs; those results stand.
360+
- R0.1: 11 `--help` snapshot tests green locally (×3 byte-deterministic runs), green under `TERM=dumb COLUMNS=80` (CI-equivalent), green under `FORCE_COLOR=1 CI=true` (reproduces the run-2 ANSI failure mode), green under `env -u COLUMNS -u TERM -u FORCE_COLOR -u NO_COLOR` (stripped env). Final CI run `26228761027`: **test PASS / lint PASS / typecheck PASS**.
361+
362+
**Changes to the dependency graph.** `mcp__codebase-memory-mcp__index_status` reports **3,851 nodes / 11,454 edges** post-merge (was 3,842 / 11,441 immediately before R0.1). Delta +9 nodes / +13 edges comes from indexing `tests/test_cli_help_snapshots.py` — pure test surface, no production-code edges. The hotspots and duplications flagged in the assessment are still present.
356363

357364
**Risks identified (aggregate view).** Detailed per-ADR; the highest-attention items:
358365

359366
- **R1 (ADR-0001)** — quiescent `rl.runner ↔ rl.backends` cycle held together by lazy `importlib`. Any contributor "cleaning up" backend imports would break the package; R1 fixes this permanently.
360367
- **R2.5 (ADR-0002)** — `BaseTermManager._post_init` ordering must preserve current buffer-allocation timing in `RewardManager` / `TerminationManager`. Mitigation: pre-R2.5 assertion test gates the refactor.
361-
- **R4 (ADR-0004)** — CLI decomposition has large test surface (`test_cli.py` is 1,414 LoC). Mitigation: R0 `--help` snapshots gate every PR.
368+
- **R4 (ADR-0004)** — CLI decomposition has large test surface (`test_cli.py` is 1,414 LoC). Mitigation: R0.1 `--help` snapshots are now in place and gate every PR.
362369
- **R5.2 (ADR-0006)** — parameterizing motion-tracking rewards risks numerical drift. Mitigation: bit-equivalence test ships in the same PR.
363370
- **R7 (ADR-0009)** — flipping importlinter from lint-only to blocking may surface latent layering violations not caught in R0. Mitigation: R0 is lint-only for the entire R1–R6 window; baseline must be clean before R7 flips.
364371

372+
**Risks discovered during R0.1 (new, not in the original list).**
373+
374+
- **Rich/Typer help output is not deterministic under env-var pinning.** `TERM=dumb` / `COLUMNS=N` / `NO_COLOR=1` are honoured differently across Rich versions and CI runners. GitHub Actions sets `FORCE_COLOR=1` which Rich honours *over* `NO_COLOR=1`. The portable mechanism is pinning Typer's module-level constants in a `python -c` wrapper before import: `typer.rich_utils.MAX_WIDTH = 100`, `typer.rich_utils.FORCE_TERMINAL = False`. Any future test that diff-checks Rich-rendered output must follow this pattern. Captured in `tests/test_cli_help_snapshots.py`'s module docstring.
375+
- **Doc drift: ROADMAP §9.0 originally enumerated 9 CLI commands; the real surface has 11** (`prof` and the `project` subapp's own `--help` were missed). The R0.1 snapshot baseline covers all 11; this document has been updated. New CLI commands or subapps must be added to both `tests/test_cli_help_snapshots.py:HELP_COMMANDS` *and* the §9.0 list.
376+
365377
**Next steps.**
366378

367379
1. Maintainer review of ADRs 0001–0010. Approve / request-changes per ADR.
368380
2. Move accepted ADRs to `Status: Accepted` (one-line edit per file).
369-
3. Land **PR R0.1** — the suggested next slice (see below). R0.1 is the smallest possible starting move, unblocks R3 and R4, and changes no production code.
370-
4. After R0 lands, fan out: R1 / R5 / R6 can run in parallel; R3 → R4 serial.
381+
3. Land **PR R0.2** — optional-dep subprocess test (see below). Independent of R0.3; can run in parallel with R0.3 if reviewer bandwidth allows.
382+
4. Land **PR R0.3** — importlinter lint-only config + CI step.
383+
5. After R0 fully completes, fan out: R1 / R5 / R6 can run in parallel; R3 → R4 serial.
371384

372-
**Suggested next slice: PR R0.1 — CLI `--help` snapshot baseline.**
385+
**Suggested next slice: PR R0.2 — Optional-dep subprocess test.**
373386

374-
- **Scope.** Add `tests/snapshots/help-*.txt` (one per CLI command — root, `cache`, `list`, `info`, `play`, `eval`, `export`, `train`, `project_new`) + `tests/test_cli_help_snapshots.py` that captures `python -m genelab <cmd> --help` and asserts byte-equality against the snapshots.
375-
- **Why first.** ADR-0004 (CLI decomposition) and ADR-0005 (domain-owned parsing) both depend on having a frozen `--help` baseline. Without R0.1, regressions in those phases are invisible.
387+
- **Scope.** Add `tests/test_optional_deps.py` (one new test file). For each of `genelab.rl` and `genelab.rl.backends.{rsl_rl,skrl,sb3}`, spawn a subprocess with `rsl_rl` / `skrl` / `stable_baselines3` / `tensordict` poisoned in `sys.modules` (set to a `ModuleType` that raises `ImportError` on attribute access) and assert the import succeeds. Validates invariant #1 from [`CLAUDE.md`](CLAUDE.md) — that `import genelab.rl` does not transitively pull any optional RL library at module-load time.
388+
- **Why next.** R0.2 catches the optional-dep boundary regression that R7's importlinter contract will codify. Catching it now (runtime test) complements R0.3 (static lint) and gives the team months of lead time to fix any baseline violations before R7 flips importlinter to blocking.
376389
- **Production change.** None.
377-
- **Risk.** Low. The snapshots capture what Typer prints today; if a later PR changes the output, the diff is the signal.
378-
- **Reviewer effort.** Small — one new test file, nine snapshot files.
390+
- **Risk.** Low. If the test fails on `dev` today, it has surfaced a real invariant-#1 violation that R1 / R2 must fix.
391+
- **Reviewer effort.** Small — one new test file, ~40–80 LoC.
379392

380393
### 9.1 Cross-phase rules
381394

@@ -421,30 +434,39 @@ before R4 (smaller CLI seam). R7 is the closer.
421434
importlinter in lint-only mode) before touching production code.
422435
Nothing in `src/genelab/` changes.
423436
2. **Scope.**
424-
- CLI `--help` snapshot tests for every command (`tests/snapshots/help-*.txt`,
425-
`tests/test_cli_help_snapshots.py`).
426-
- Optional-dep subprocess test (`tests/test_optional_deps.py`) — boots
427-
`import genelab.rl` and each `genelab.rl.backends.<lib>` with
428-
`rsl_rl` / `skrl` / `stable_baselines3` / `tensordict` poisoned in
429-
`sys.modules`.
430-
- Layering contract scaffold (`pyproject.toml` `[tool.importlinter]`)
431-
in **lint-only** mode — runs in CI but does not fail the build yet.
437+
- **R0.1 ✅ merged** — CLI `--help` snapshot tests for all 11 commands
438+
(root, `cache`, `prof`, `list`, `info`, `play`, `eval`, `export`,
439+
`train`, `project`, `project new`). Test invokes the CLI via a
440+
`python -c` wrapper that pins `typer.rich_utils.MAX_WIDTH = 100`
441+
and `typer.rich_utils.FORCE_TERMINAL = False` before importing
442+
`genelab.cli`, bypassing every host-dependent Rich auto-detection
443+
branch. Regeneration: `UPDATE_SNAPSHOTS=1 pytest tests/test_cli_help_snapshots.py`.
444+
- **R0.2 ⬜ pending** — Optional-dep subprocess test
445+
(`tests/test_optional_deps.py`) that boots `import genelab.rl` and
446+
each `genelab.rl.backends.<lib>` with `rsl_rl` / `skrl` /
447+
`stable_baselines3` / `tensordict` poisoned in `sys.modules`.
448+
- **R0.3 ⬜ pending** — Layering contract scaffold (`pyproject.toml`
449+
`[tool.importlinter]`) in **lint-only** mode — runs in CI but does
450+
not fail the build yet.
432451
3. **Non-goals.** No production code change. No new public APIs. No
433452
importlinter rule is yet blocking.
434453
4. **Affected modules.** `tests/`, `pyproject.toml`,
435454
`.github/workflows/ci.yml`. **No file under `src/genelab/` is touched.**
436-
5. **Dependency changes.** Add `import-linter` to dev-deps.
455+
5. **Dependency changes.** Add `import-linter` to dev-deps (in R0.3).
437456
6. **PR slices.**
438-
- PR0.1: snapshot baseline (`tests/snapshots/` + reader test).
439-
- PR0.2: optional-dep test scaffold.
440-
- PR0.3: importlinter config (lint-only) + CI step (non-blocking).
457+
- PR0.1: snapshot baseline (`tests/snapshots/` + reader test). ✅ **Merged in PR #81 (`c3d851e`).** Final test file 123 LoC; 11 snapshots (277 lines). CHANGELOG `[Unreleased] · Added` entry included.
458+
- PR0.2: optional-dep test scaffold. ⬜ Pending.
459+
- PR0.3: importlinter config (lint-only) + CI step (non-blocking). ⬜ Pending.
441460
7. **Test strategy.** New tests must run green on the current `dev` —
442461
they are pure observations, not assertions about a target state.
462+
R0.1's snapshot test was verified green under four envs (clean,
463+
`TERM=dumb COLUMNS=80`, `FORCE_COLOR=1 CI=true`, stripped) before
464+
merge.
443465
8. **Risk level.** Low.
444466
9. **Rollback.** `git revert <merge-sha>` per PR. No source code is
445467
affected, so revert is trivial.
446468
10. **Completion criteria.**
447-
- 3 PRs merged.
469+
- 3 PRs merged. **Progress: 1 / 3** (R0.1 ✅; R0.2, R0.3 pending).
448470
- CI shows green snapshot diff and a non-blocking importlinter step.
449471
- `tests/test_optional_deps.py` passes on the matrix `{rsl_rl, skrl, sb3, tensordict} × {present, absent}`.
450472

0 commit comments

Comments
 (0)