Follow-up mission preparation debrief — tasks.py render-seam + shim relocation
Predecessor: tasks-py-degod-01KWF08S (Wave 1 degod; branch design/degod-tasks-2116) — decomposed the agent tasks god-command's decision logic into pure tested cores behind injected ports, thinned all fat command bodies, byte-identical behavior. It deferred two goals to this follow-up (spec Deferred section + the 8/9 scoping decision).
This follow-up's charter: finish turning tasks.py into a true registration shim — unify rendering behind the Render seam (former FR-008) and relocate the accumulated orchestration out of tasks.py to hit the whole-file LOC ceiling (former SC-005/NFR-004 ≤1400). Behavior-preserving (pure parity), same as the predecessor — the golden CLI-characterization harness is the guard.
Why it was deferred (not a failure — a deliberate slice)
The predecessor delivered the high-value, high-risk work: the change-magnet decision logic is now in four pure, tested sibling modules (tasks_transition_core 574, tasks_ports 383, tasks_status_view 229, tasks_mapping_core 156 LOC), and every fat body is a thin orchestrator (move_task 88, map_requirements 56, status 24, mark_status 39, finalize_tasks 25 LOC). But tasks.py grew 3617 → ~4547 LOC during the rewrites: the decision logic left for the cores, while the _do_<cmd> orchestrators, ~50 small glue helpers, and the port-seam adapter classes accumulated in tasks.py. Hitting ≤1400 means relocating ~3150 LOC — mechanically large, orthogonal to the decision-extraction, and (unlike the cores) low-risk-per-move. Cramming it into the predecessor's closeout risked a sloppy 3000-LOC move; it earns its own reviewed mission.
Scope (two work streams)
Stream A — Render seam unification (former FR-008)
- 13 inline
json.dumpssites intasks.py(live at predecessor time: lines 442/480/493/2035/2235/2726/2751/2765/2854/2926/3022/3264/3605 — re-census at start, they will have moved) → route through theRenderport (Render.json_envelope/Render.human). - The generic
RealRender.json_envelopeuses compactjson.dumps(byte-identical to the many compact inline sites).statusis the one site needingindent=2— the predecessor scoped a_StatusRender(RealRender)override for it. Unify: parameterize the Render seam's indent (or ajson_envelope_indentedcapability) so the status override collapses into the generic seam. Byte-identity per site is the bar. - Add an AST-based "0 inline
json.dumps/aliaseddumps" gate (a literal grep is bypassed byfrom json import dumps).
Stream B — Shim relocation (former SC-005/NFR-004 ≤1400)
- Relocate out of
tasks.pyto sibling modules (themission.py-degod per-command-module pattern is the template):- the
_do_<cmd>orchestrators (_do_move_task,_do_map_requirements,_do_status,_do_mark_status,_do_finalize_tasks) + their_mt_*/_mr_*/_st_*/_ms_*glue helpers; - the port-seam adapter classes
_MoveTaskCoordRouter,_MapReqCoordRouter,_MarkStatusCoordRouter,_StatusRender— fold these intotasks_ports.py(or atasks_command_adapters.py), removing the "bound-to-tasks.py-module-symbols for@patch" trick if the tests can be re-pointed, OR preserve it deliberately.
- the
- Leave
tasks.pyas thin@app.commandregistration wrappers delegating to the relocated orchestrators + a re-export sweep for any symbol imported elsewhere. - Add the
tests/architectural/whole-file LOC gate:tasks.pytotal ≤ (target — re-derive; ≤1400 was the predecessor's estimate — validate it against the real relocated size, or set an honest achievable ceiling with rationale). Per-body/per-helper ≤150 is already met by the predecessor. - The 4 already-small bodies (
list_tasks,add_history,validate_workflow,list_dependents) remain intasks.pyand count against the ceiling.
Preconditions
- The predecessor mission (
design/degod-tasks-2116) must be merged first — this follow-up bases on it.tasks.py= the merged WP01–WP09 state. tasks.pywill be unowned after the predecessor (WP09 was descoped off it); this follow-up ownstasks.pyend-to-end.- The predecessor's golden harness (
test_tasks_cli_contract.py, 42 cases) + the per-core unit tests + the WP03/WP04 timing regression tests + the WP08 non-import AST gate are all the guards — this follow-up keeps them green.
Approach (low-risk-per-move discipline)
- Golden-first, always green. Unlike the predecessor's cores, these are pure relocations — cut a function/class from
tasks.py, paste into a sibling module, add an import. No logic change → golden stays byte-identical at every step. Any golden delta = a botched move, revert. - One command family per WP (the
mission.pytemplate): e.g. WP-move_task-relocate, WP-mapping+status-relocate, WP-coreless-relocate, then WP-render-seam, then WP-shim-finalize+LOC-gate. Each independently reviewable + golden-guarded. - Preserve the
@patchseams (~900 tests patchtasks.<sym>): when moving the adapter classes / the seam-bound symbols, either re-point the patches or keep the module-level re-exports. Decide per-WP; the golden + the full suite catch breakage. - Strict-mypy on src+test together at every step (the predecessor's hard-won lesson — attr-defined on imported return types only surfaces when both are in mypy scope).
Risks
- Big mechanical move → merge-conflict / import-cycle risk. Relocating adapters into
tasks_ports.pycould create an import cycle (ports ↔ command modules). Mitigate: a dedicatedtasks_command_adapters.pyrather than overloadingtasks_ports.py. - The
@patch-seam trick is load-bearing for ~900 tests. Moving the bound symbols without re-pointing patches breaks them en masse. Handle deliberately, per-WP. - LOC ceiling may need re-baselining. ≤1400 was a planning estimate. If the honest relocated
tasks.py(registration wrappers + 4 small bodies + necessary module glue) lands higher, record the honest number + rationale rather than force an unsafe over-relocation.
Reference
- Predecessor spec + Deferred section:
kitty-specs/tasks-py-degod-01KWF08S/spec.md. - Predecessor tracers:
kitty-specs/tasks-py-degod-01KWF08S/tracers/(approach / design-decisions / tooling-friction — readtooling-friction.mdbefore starting; it lists the traps). - Template: the completed
mission.pydegod,kitty-specs/decompose-mission-god-module-01KVXHF8/(per-command sibling modules + shim finalization).