feat(harness): F6/F7 close on their last approval — no echo phase gate

Where completeness is machine-detectable, the reviewer's last substantive
approval now closes the phase itself (same pattern as F3/F4/F8):

- F6: approving the LAST CTE of the plan (kind:"cte_result" with next_cte
  now empty) advances the phase; a non-final CTE keeps the phase open and
  names the next one.
- F7: kind:"sql" records sql_approved — which IS F7's only advance
  prerequisite — and advances immediately.

Two reviewer interactions per session removed, both pure echoes. The
summary phase gate remains only where completeness is a human judgment
(F1, F2 with recorded memories, F5). SKILL.md states the rule and the
five self-closing gates; L1 tests cover last/non-last CTE and sql close.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 02:23:45 +02:00
co-authored by Claude Fable 5
parent c4951e2aa5
commit 83942c0b5c
3 changed files with 161 additions and 19 deletions
+20 -17
View File
@@ -26,13 +26,16 @@ about a domain term, ask the reviewer.
## Phase map (advance cheat-sheet)
A phase advances ONLY when a `phase_approved:phase:N` decision is recorded for the current
phase — written by `reviewer_confirm kind:"phase"`. (F7 is two-step: `kind:"sql"` records
`sql_approved`, then `kind:"phase"` advances.) A `reviewer_decide`/
phase. THE RULE: where completeness is machine-detectable, the LAST substantive approval
closes the phase itself; a `reviewer_confirm kind:"phase"` summary gate exists only where
completeness is a human judgment (F1, F2 with recorded memories, F5). A `reviewer_decide`/
`reviewer_select` choice records its OWN decision but does NOT advance the phase. `advance:true`
on `reviewer_decide` auto-advances only F2 (empty memory) and F6 (skipped/empty) — never a
phase that recorded substantive decisions. Exactly three gates close their phase themselves,
because there the human interaction IS the phase approval: `rewrite_question` (F3),
`reviewer_schema_linking` with `advance:true` (F4), and `reviewer_memory_promote` (F8).
phase that recorded substantive decisions. FIVE gates close their phase themselves, because
there the human interaction IS the phase approval: `rewrite_question` (F3),
`reviewer_schema_linking` with `advance:true` (F4), the LAST `reviewer_confirm
kind:"cte_result"` of the plan (F6), `reviewer_confirm kind:"sql"` (F7), and
`reviewer_memory_promote` (F8).
| Phase | Artifact out | Advance / close by |
|-------|--------------|--------------------|
@@ -41,8 +44,8 @@ because there the human interaction IS the phase approval: `rewrite_question` (F
| F3 riscrittura | `question.md` | `rewrite_question` records approval and advances automatically |
| F4 schema_linking | `schema_linking.json` | `reviewer_schema_linking` with `advance:true` closes the phase itself (the curation IS the approval; `reviewer_confirm kind:"phase"` only as fallback if it reports an error). Promoted columns are the reviewer-approved OUTPUT columns — project exactly those in the final SELECT. |
| F5 sintesi | — | `reviewer_confirm kind:"phase"` (after `tht session check`) |
| F6 cte | `cte_plan.json`, `ctes/`, `cte_tests.json` | approve each CTE `kind:"cte_result"`, then `reviewer_confirm kind:"phase"` |
| F7 sql_finale | `sql_final.sql` | `kind:"sql"` records `sql_approved`, then `reviewer_confirm kind:"phase"` |
| F6 cte | `cte_plan.json`, `ctes/`, `cte_tests.json` | approve each CTE with `kind:"cte_result"`; approving the LAST CTE of the plan closes the phase automatically (`kind:"phase"` only as fallback if the auto-close reports an error) |
| F7 sql_finale | `sql_final.sql` | `kind:"sql"` records `sql_approved` AND closes the phase automatically (`kind:"phase"` only as fallback if it reports an error) |
| F8 datamart | — | auto: the `reviewer_memory_promote` gate advances F8 and finalizes the session itself (`reviewer_confirm kind:"phase"` only as fallback if it reports an error) |
## Disciplines (hold in every phase)
@@ -51,17 +54,17 @@ because there the human interaction IS the phase approval: `rewrite_question` (F
command (you invoke `tht ...` via the shell tool). NEVER run `tht phase advance`
or `tht decision add` from the shell — they are blocked by the gate's anti-bypass
hook; the gate extension records every decision via the `reviewer_*` tools.
2. **The choice records; the phase gate advances.** A `reviewer_decide`, or a
2. **The choice records; the closing gate advances.** A `reviewer_decide`, or a
`reviewer_select` whose chosen option carries a `decision`, PERSISTS that decision — it
does NOT by itself advance the phase. To move to the next phase you MUST issue
`reviewer_confirm kind:"phase"` (for F7, first `kind:"sql"` to record `sql_approved`, then
`kind:"phase"` to advance), the deliberate "this phase is
done" gate. The `advance:true` flag on `reviewer_decide` is a shortcut that auto-advances
ONLY F2 when the memory phase recorded nothing and F6 when it is skipped/empty; everywhere
else it is a silent no-op, so never rely on it to advance. The self-closing gates are the
three listed above (F3 `rewrite_question`, F4 `reviewer_schema_linking` `advance:true`,
F8 `reviewer_memory_promote`) — after one of those, do NOT add a `reviewer_confirm` that
merely echoes it; the phase is already closed.
does NOT by itself advance the phase. In F1, F2-with-memories and F5 the phase closes
with the deliberate `reviewer_confirm kind:"phase"` summary gate. The `advance:true`
flag on `reviewer_decide` is a shortcut that auto-advances ONLY F2 when the memory phase
recorded nothing and F6 when it is skipped/empty; everywhere else it is a silent no-op,
so never rely on it to advance. The self-closing gates are the five listed above
(F3 `rewrite_question`, F4 `reviewer_schema_linking` `advance:true`, F6 last
`kind:"cte_result"`, F7 `kind:"sql"`, F8 `reviewer_memory_promote`) — after one of
those, do NOT add a `reviewer_confirm kind:"phase"` that merely echoes it; the phase is
already closed.
3. **Single pick vs multi-answer.** For a single-pick clarification or decision, use
`reviewer_select` and attach a `decision` payload (`{type, subject, detail?,
rationale?}`) to each concrete option: picking it persists that decision directly —