Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions docs/plans/gh-201-pre-build-ask-timing/artifacts/scope-boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Scope Boundary: Pre-build ask timing (issue #201)

## Work Item

GitHub issue #201 in `testdouble/han`, "Han Feedback: pairing-tdd-han-feedback (2026-09-03)", read through
`gh issue view 201 --repo testdouble/han` on 2026-09-11. It is a feedback report from a pairing session that drove a
four-behavior TDD rewrite. The issue is open, unlabeled, and has no comments.

## Stated Scope

The issue's "Suggested fix" paragraph, quoted word for word:

> Add an explicit rule to `collaborative-stop-rule.md` (and echo it in pairing Step 5): the pre-build ask for piece N is
> its own turn, presented only after the person has responded to the piece N−1 stop. A stop presents exactly one piece
> and asks nothing about future pieces. Corollary: a response to a stop is a response to that stop's piece only — it
> must never be read as answering, or declining, a question about a later piece. If a run has already bundled the ask
> and the reply addresses only the previous piece, the ask is unanswered: re-present it in its own turn before building.

The issue's "Overall" paragraph restates the fix as:

> The fix is a sequencing rule: one stop, one piece, no forward-looking questions; the ask for a marked piece opens that
> piece's turn, after the previous piece is approved, and a reply to a stop never answers a question about a later
> piece.

The issue also names a second effect of the defect, under "What didn't work":

> The misread compounded silently. The run recorded "ask declined" in the feedback record as if it were the person's
> decision, so the record itself carried the wrong fact until the person corrected it.

## Stated Exclusions

None stated.

## Operator-Stated Scope

The operator invoked `/han-planning:plan-a-change for https://github.com/testdouble/han/issues/201` and, at the
confirmation turn, accepted the area as proposed with "looks good". The proposed area was:

- `han-core/references/collaborative-stop-rule.md`, the canonical rule, plus its two byte-identical vendored copies in
`han-coding/references/` and `han-planning/references/`
- `han-core/skills/pairing/SKILL.md`, Steps 5 and 6
- `han-core/docs/skills/pairing.md`, the long-form doc

The five backing skills (`tdd`, `refactor`, `design-an-api`, `iterative-plan-review`, `plan-implementation`) were
proposed as outside the area, on the ground that they read only the "Detecting the flag" and "What a stop presents"
sections of the rule and the ask belongs to the driving loop. The operator accepted that exclusion.

## Direction of Travel

Unanswered. The confirmation turn did not ask whether the pre-build ask or the collaborative stop rule is being
deprecated, replaced, or migrated away from. Nothing in the issue or the conversation suggests it is: the issue asks for
the ask protocol's timing to be tightened, not for the protocol to go.

## Visual Material Received

None received.

## Record Provenance

Established by `plan-a-change` in this run on 2026-09-11. Not inherited.
519 changes: 519 additions & 0 deletions docs/plans/gh-201-pre-build-ask-timing/change-plan.md

Large diffs are not rendered by default.

23 changes: 22 additions & 1 deletion han-coding/references/collaborative-stop-rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ The reasoning behind the choices comes last or not at all. State in one line tha
stop there BECAUSE an unannounced affordance in a conversation is the same as no affordance, while a volunteered
rationale is the thing that suppresses scrutiny.

A stop covers what just closed and asks nothing about a later piece. Its position line reports what remains, and naming
the work that comes next is a report, not a question. The one question this convention poses about a piece not yet
built is the pre-build ask, and it has a turn of its own.

Then end the turn. Nothing further is built until the person responds.

That last instruction is a directive, not a guarantee. Nothing in the platform enforces it. When a run does build past a
Expand Down Expand Up @@ -93,8 +97,21 @@ test as provisional and revisit it once real runs show whether it marks the piec
**The ask itself** names the dimension the choice turns on and stops there. Do not pose a blank question, and do not
offer candidate answers, BECAUSE named candidates anchor the guess and the point is an independent read.

**The ask is a turn of its own.** It opens the marked piece's turn, after the person has responded to the previous
stop, or to the plan when the marked piece is the first, and it is the whole turn: pose it and end the turn. Never
append it to that stop or plan, BECAUSE a reply to a stop or a plan is a reply to that alone, and answers nothing about
a later piece.

**Declining is a first-class answer.** "I don't know" and "just show me" advance the piece exactly as a considered
answer does. Never re-prompt, and never require an answer before building.
answer does. Never re-prompt once the person has replied to the ask, and never hold the build for a fuller answer than
the one given. A decline is a reply to the ask. A reply to the previous stop, or to the plan, is a reply to that alone,
and never counts as declining an ask the person has not yet answered. A question about the ask holds it open: answer
the question and end the turn again.

**A bundled ask is an unanswered ask.** When an earlier turn put the ask into a stop or the plan and the reply spoke
only to that, the ask was never posed on its own: present it now, on its own, before building. That is the first ask,
not a re-prompt. If the piece was already built when this comes to light, do not ask now; say that the run put the ask
under an earlier turn so it went unanswered, and continue from the stop in hand.

**After the build, the reveal is an ordinary stop.** It does not restate the person's read, score it, or defend a
divergence from it. A stop that grades you teaches you to answer noncommittally, and a stop that argues with you leads
Expand All @@ -105,6 +122,10 @@ with the reasoning this convention keeps out of the lead.
Write every piece of feedback into the running record before acting on it. A correction given at the second stop has to
still apply at the seventh, and mid-context material is the least reliably recalled.

An entry holds the person's words and names the stop or ask they answered. A reading the run adds, such as "declined"
or "approved", follows the words and is marked as the run's, never written as what the person decided. An entry reads,
for example, "Piece 2 stop: 'commit and next' (run's reading: approved)". An ask with no entry is an ask with no answer.

The person can read the record whenever they ask. When a recorded entry shapes a later piece, name which entry it was,
so a misrecorded correction surfaces while it is still cheap to fix rather than quietly governing the rest of the
session.
Expand Down
20 changes: 13 additions & 7 deletions han-core/docs/skills/pairing.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ use the skill. For what the skill does internally, read the skill definition at
- **The plan.** A short list of the concerns and the pieces inside each, proposed before any work begins, that you
accept or change. It also names which pieces carry a choice that is expensive to walk back.
- **A stop.** The end of a turn. You get your position in the plan, what was built, what you can check, and what
changed. The reasoning does not lead.
changed. The reasoning does not lead, and the stop asks you nothing about a later piece.
- **The pre-build ask.** For a piece the plan marked expensive to walk back, the skill asks what you expect before it
builds. Declining is a complete answer.
builds. The ask is a turn of its own: it arrives after you have responded to the previous stop, or to the plan when
the marked piece is the first, and nothing is built until you answer it or decline. Declining is a complete answer.
- **The feedback record.** A file holding everything you said, so a correction you gave at the second stop still applies
at the seventh. You can read it whenever you ask.
- **A backing skill.** An existing skill that does the work while this one handles the pacing. The skills that carry the
Expand Down Expand Up @@ -82,8 +83,9 @@ Alongside it, one file: the running feedback record. It lives under the output b
configuration. Each run gets its own file, so a second run does not overwrite the first. The skill names the path in the
plan it proposes, and again when the loop ends.

The record holds each piece of feedback you gave and which piece prompted it. When the skill applies a recorded entry to
a later piece, it names which entry, so a misrecorded correction surfaces while it is still cheap to fix.
The record holds each piece of feedback you gave, in your words, and which stop or ask prompted it, and any reading the
skill adds is labeled as its own. When the skill applies a recorded entry to a later piece, it names which entry, so a
misrecorded correction surfaces while it is still cheap to fix.

## How to get the most out of it

Expand All @@ -96,8 +98,11 @@ a later piece, it names which entry, so a misrecorded correction surfaces while
- **Ask for several pieces at once when you are moving fast.** "Show me the next three" is honored as asked, and the
loop returns to its normal pace afterward without being asked. This is the middle gear between full ceremony and
turning review off.
- **Answer the pre-build ask honestly, including with "I don't know."** Declining advances the stop exactly as a
considered answer does. The ask exists to get an independent read, and a manufactured guess is worth less than none.
- **Answer the pre-build ask honestly, including with "I don't know."** Declining advances the piece exactly as a
considered answer does, and only a reply to the ask counts as one: approving the previous piece never declines an ask
you have not answered. If a run folds the ask into a stop anyway, it poses the ask again on its own before building,
or, when the piece is already built, tells you the ask went unanswered rather than asking after the fact. The ask
exists to get an independent read, and a manufactured guess is worth less than none.
- **Read the feedback record if a later piece feels subtly wrong.** That is usually a correction recorded in a way you
did not intend, and it is much easier to spot in the file than to reconstruct from memory.
- **Pair with `/code-review` afterward.** Reviewing as it goes catches direction; a review pass at the end catches
Expand All @@ -115,7 +120,8 @@ establishes what a run of approvals means. See [YAGNI](../../../docs/yagni.md).
## Cost and latency

Runs on the session model with no dispatch fan-out of its own. The skill itself is thin: the cost is whatever the
backing skill would have cost, plus one turn per stop.
backing skill would have cost, plus one turn per stop, and one more for each piece the plan marked expensive to walk
back.

The expensive part is your attention, not tokens. A long session with many stops is the shape this is built for, and the
several-pieces-at-once gear exists so you can spend that attention unevenly. Built for tight-loop iteration, not for a
Expand Down
23 changes: 22 additions & 1 deletion han-core/references/collaborative-stop-rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ The reasoning behind the choices comes last or not at all. State in one line tha
stop there BECAUSE an unannounced affordance in a conversation is the same as no affordance, while a volunteered
rationale is the thing that suppresses scrutiny.

A stop covers what just closed and asks nothing about a later piece. Its position line reports what remains, and naming
the work that comes next is a report, not a question. The one question this convention poses about a piece not yet
built is the pre-build ask, and it has a turn of its own.

Then end the turn. Nothing further is built until the person responds.

That last instruction is a directive, not a guarantee. Nothing in the platform enforces it. When a run does build past a
Expand Down Expand Up @@ -93,8 +97,21 @@ test as provisional and revisit it once real runs show whether it marks the piec
**The ask itself** names the dimension the choice turns on and stops there. Do not pose a blank question, and do not
offer candidate answers, BECAUSE named candidates anchor the guess and the point is an independent read.

**The ask is a turn of its own.** It opens the marked piece's turn, after the person has responded to the previous
stop, or to the plan when the marked piece is the first, and it is the whole turn: pose it and end the turn. Never
append it to that stop or plan, BECAUSE a reply to a stop or a plan is a reply to that alone, and answers nothing about
a later piece.

**Declining is a first-class answer.** "I don't know" and "just show me" advance the piece exactly as a considered
answer does. Never re-prompt, and never require an answer before building.
answer does. Never re-prompt once the person has replied to the ask, and never hold the build for a fuller answer than
the one given. A decline is a reply to the ask. A reply to the previous stop, or to the plan, is a reply to that alone,
and never counts as declining an ask the person has not yet answered. A question about the ask holds it open: answer
the question and end the turn again.

**A bundled ask is an unanswered ask.** When an earlier turn put the ask into a stop or the plan and the reply spoke
only to that, the ask was never posed on its own: present it now, on its own, before building. That is the first ask,
not a re-prompt. If the piece was already built when this comes to light, do not ask now; say that the run put the ask
under an earlier turn so it went unanswered, and continue from the stop in hand.

**After the build, the reveal is an ordinary stop.** It does not restate the person's read, score it, or defend a
divergence from it. A stop that grades you teaches you to answer noncommittally, and a stop that argues with you leads
Expand All @@ -105,6 +122,10 @@ with the reasoning this convention keeps out of the lead.
Write every piece of feedback into the running record before acting on it. A correction given at the second stop has to
still apply at the seventh, and mid-context material is the least reliably recalled.

An entry holds the person's words and names the stop or ask they answered. A reading the run adds, such as "declined"
or "approved", follows the words and is marked as the run's, never written as what the person decided. An entry reads,
for example, "Piece 2 stop: 'commit and next' (run's reading: approved)". An ask with no entry is an ask with no answer.

The person can read the record whenever they ask. When a recorded entry shapes a later piece, name which entry it was,
so a misrecorded correction surfaces while it is still cheap to fix rather than quietly governing the rest of the
session.
Expand Down
21 changes: 15 additions & 6 deletions han-core/skills/pairing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,17 @@ Then wait. The person accepts the plan, changes it, or replaces it.
Repeat until the plan is finished or the person ends it. The loop walks the concerns in the order the plan named, and
the pieces inside each one in the order the plan named.

1. **If the plan marked this piece expensive to walk back, ask first.** Follow the ask protocol in the stop rule: name
the dimension the choice turns on, offer no candidate answers, and accept a declined answer as a complete one. The ask
comes before the build, never after.
1. **If the plan marked this piece expensive to walk back, ask first, in a turn of its own.** The ask opens this piece's
turn, after the person has responded to the previous stop, or to the plan when this is the first piece. Name the
dimension the choice turns on, offer no candidate answers, and end the turn. Never append the ask to that stop or
plan, BECAUSE a reply to it is a reply to that alone and answers nothing about this piece.

When the reply arrives, write it into the record in the person's words, against this ask, then build. A declined
answer is a complete one, and a question about the ask holds it open: answer it and end the turn again. The reply is
not routed through Step 6, which handles replies to a stop.

When an earlier turn already bundled the ask into a stop or the plan and the reply spoke only to that, the ask was
never posed on its own: present it now, on its own, before building.

2. **Build one piece.**

Expand All @@ -170,15 +178,16 @@ the pieces inside each one in the order the plan named.
checked, what changed, and one line saying the reasoning is available for the asking.

When the piece closes a concern, say so in the position line and name the concern that comes next. That tells the
person the next response starts different work, which is the moment their review matters most.
person the next response starts different work, which is the moment their review matters most. That is a report
about what comes next, never a question about it.

4. **End the turn.** Nothing further is built until the person responds. **Starting the next concern is not an
exception**, however directly it follows from the one that just closed.

## Step 6: Act on the Response

Write the response into the record before acting on it. When a recorded entry shapes this piece, name which entry it
was.
Write the response into the record, in the person's words and against the stop or ask it answers, before acting on it.
When a recorded entry shapes this piece, name which entry it was.

Then route by what the feedback touches, per the stop rule:

Expand Down
Loading