Skip to content

Commit 71e643a

Browse files
docs(plan-integration): T5.1 — design §5 reviewed against the code; three amendments
Item 5 (D-F) was designed on 2026-09-16 before its RED. Read against learning/decision.py at 7208eb6, three of its sentences do not fit the tree; each is amended under §5 with the source it rests on, so T5.2's RED is written against a design the code can carry. 1. "recovered / gentle review -> low" names a row _struggle_candidates never emits: it selects only confidence in ("struggling", "learning") or last_teachback_score < 14. The low-demand class is the `learning` row; fresh `struggling` (last_seen <= 14 days) is high, old `struggling` or a weak-teach-back-only row is medium. Demand is derived once in the collector and carried in candidate metadata. 2. "listed in energy_deferred" cannot hold a repair: DeferredMilestone has a mandatory milestone_index and all three renderers (cli/_now.py, learning/recap.py, today-panel.js deferredNotes) print `milestone {index + 1} "{title}"`. A deferred repair gets its own frozen DeferredRepair in a new additive key, energy_deferred_repairs, and each renderer gains one line for it. 3. "opens the existing body-double session route (web/routes/body_double.py)" names the read-only focus reader. The session door is `studyloop study "<topic>" --mode co-study` on the CLI and the Body Double view's session start on the Web; _evidence_command has no conversation branch and would fall through to `studyloop progress … -c learning` (a write), so the body-double candidate sets its evidence_command explicitly. tasks.md T5.1 ticked with the receipt. Full suite on this branch: 30 failed / 5120 passed / 14 errors, the 44 failed+errored ids byte-identical to the item-4 control's committed environmental set (run - control = empty).
1 parent 7208eb6 commit 71e643a

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

‎openspec/changes/plan-integration-followons/design.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,36 @@ among what MCP revises and the row names every schema property.
238238
- **Rubric row 3b** (owner scores): scenario 3's fixture at low energy now yields the deferred repair named in
239239
`energy_deferred` and a body-double primary (or the due recall if one exists).
240240

241+
**T5.1 review against the code (2026-09-18, tree `7208eb67`) — three amendments, each from reading
242+
`learning/decision.py`, not the text above:**
243+
244+
1. **Demand classes are the struggle collector's classes.** `_struggle_candidates` emits a row only when
245+
`confidence in ("struggling", "learning")` or `last_teachback_score < 14`; "recovered / gentle review" is not a
246+
row it produces. So: `struggling` with `last_seen` ≤ 14 days → `high`; `struggling` older than 14 days, or any
247+
row whose only signal is a weak teach-back → `medium`; `learning` → `low`. Demand is derived once, in the
248+
collector, and carried in the candidate's `metadata` beside `confidence` so the scorer and the renderers read
249+
one value. Required capability `high → 6`, `medium → 4`, `low → 0` stands (the `low` class is what "repair is
250+
cheaper than encoding" was always about).
251+
2. **`energy_deferred` is milestone-shaped and cannot carry a repair as it is.** `DeferredMilestone` has a
252+
mandatory `milestone_index`, and all three renderers (`cli/_now.py`, `learning/recap.py`,
253+
`today-panel.js::deferredNotes`) print `milestone {index + 1} "{title}" needs energy {floor}/10`. A deferred
254+
repair gets its own frozen `DeferredRepair` (`plan_id`/`plan_title` when plan-related, else `None`, `concept`,
255+
`topic`, `confidence`, `energy_demand`, `required_capability`, `energy_capability`, `reason` naming the
256+
struggle), carried in a **new additive key `energy_deferred_repairs`** — not folded into `energy_deferred`,
257+
whose consumers would print "milestone None". Same "readable off the top" rule as the closing review's
258+
evidence lines: each renderer gains one line per deferred repair.
259+
3. **The body-double door is a session start, not `web/routes/body_double.py`.** That route is the read-only focus
260+
reader (`GET /api/body-double/focus`). The session door is `studyloop study "<topic>" --mode co-study` on the
261+
CLI and a session start from the Body Double view (origin `body-double`) on the Web. `_evidence_command` has
262+
no branch for a `conversation` candidate and would fall through to `studyloop progress … -c learning`, which is
263+
a write, not a door — so the body-double candidate carries `evidence_command = 'studyloop study "<plan title>"
264+
--mode co-study'` set explicitly, and `_evidence_command` is not asked to guess. `source="body_double"`,
265+
`action_type="conversation"`, base score below `MILESTONE_BASE_SCORE` (48) so any real candidate outranks it.
266+
267+
Rule 3's *deferral* of repair is the change; rule 3's *eligibility* of plan-related due recall is untouched. The
268+
no-plan golden stays byte-identical because a body-double candidate requires an active plan and the golden world
269+
has none; `INTERLEAVE_RATIOS["low"]` unchanged.
270+
241271
## 6. Verification
242272

243273
`scripts/verify/plan_integration.py` gains registered checks for: the two architect grants (the ten names in

‎openspec/changes/plan-integration-followons/tasks.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,13 @@ writer, through the existing gate, closes that. Kept out of item 3 so item 3's f
192192

193193
## Item 5 — energy demand + body-doubling floor (D-F) · own round
194194

195-
- [ ] **T5.1** Design §5 reviewed against the code (`_struggle_candidates`, `_score_candidates`, rule 3) — amend if
196-
the code contradicts it.
195+
- [x] **T5.1** Design §5 reviewed against the code (`_struggle_candidates`, `_score_candidates`, rule 3) — amend if
196+
the code contradicts it. (2026-09-18: three amendments recorded under §5 — the demand classes are the struggle
197+
collector's own (`struggling` fresh/old, weak teach-back, `learning`; no "recovered" row exists); a deferred
198+
repair needs its own `DeferredRepair` in a new additive `energy_deferred_repairs` key because `DeferredMilestone`
199+
and its three renderers are milestone-shaped; the body-double door is `studyloop study … --mode co-study` /
200+
the Body Double view's session start, not the read-only `body_double.py` focus route, so the candidate sets
201+
its `evidence_command` explicitly. T5.2's RED names hold; a sixth test pins the new key's rendering.)
197202
- [ ] **T5.2** RED `tests/test_now_plan_guidance.py`: `test_live_struggle_repair_defers_at_low_energy_like_new_work`,
198203
`test_recovered_repair_stays_eligible_at_low_energy`, `test_body_double_candidate_is_synthesised_when_nothing_plan_related_fits`,
199204
`test_body_double_is_a_proposal_not_a_filter`, `test_body_double_never_appears_without_an_active_plan`,

0 commit comments

Comments
 (0)