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
2 changes: 1 addition & 1 deletion plugins/planning/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "planning",
"version": "0.52.2",
"version": "0.53.0",
"userConfig": {
"surface": {
"type": "string",
Expand Down
6 changes: 6 additions & 0 deletions plugins/planning/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to the `planning` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.53.0] - 2026-09-30

### Added

- **The interview surface records a hedged decision, and an accepted or hedged row with an unticked commitment exports as open.** The page has a Hedged choice that takes a required condition; it exports as `answer:: hedged: <recommendation>` with the condition in `note::` and imports back as `hedged`. A row whose counting decision is an accept or a hedge while any commitment is unticked, including after a revise replaces the commitment list, now grades `open` in the ledger, so `check-open-questions.sh` fails it under `lock` instead of passing it with the commitments only named as risks in the Brief ([#5471](https://github.com/melodic-software/claude-code-plugins/issues/5471)).

## [0.52.2] - 2026-09-30

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion plugins/planning/skills/audit-answers/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Validation needs a complete answer set. If the interview is already fully answer
- a Deferred question tagged **`USER-RESERVED`** stays **deferred**. It is a carry-forward item whose arbiter re-confirms at the `/planning:plan` approval gate *with plan-time context*, so it is not auto-accepted, not validated, and **not turned into an audit question here**; it passes through untouched, arbiter tag intact.
- a decision the interview's **auto-guard** class covers, a genuine user choice with real tradeoffs and no codebase answer, is held out of the auto-accept and routed to the human as a real question in the confirm round (Step 4).
- a register row at **`superseded-by-plan`** (a plan change displaced the user's answer) is held out of the auto-accept, never validated into `answered`, and routed to the human as a real question showing both the proposed and the displaced answer. Only the user's reply to that row moves it.
- a register row whose resolution carries `hedged:` anywhere (including the page's `free-text: hedged:` export) is validated, but it never closes on a CONFIRMED verdict: it is routed to the human in the Step 4 confirm round whatever the validators return. Its `open` commitment rows are held out of the auto-accept like any other floor item.
- a register row whose resolution carries `hedged:` anywhere (including the page's `hedged:` answer and the legacy `free-text: hedged:` export) is validated, but it never closes on a CONFIRMED verdict: it is routed to the human in the Step 4 confirm round whatever the validators return. Its `open` commitment rows are held out of the auto-accept like any other floor item.

A `free-text:` row is validated like any answer and flagged in its verdict, so the human sees which answers were given in the user's own words rather than picked from the authored options.

Expand Down
4 changes: 2 additions & 2 deletions plugins/planning/skills/interview/context/loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ Fields: `Q<N> | status | round | question | resolution`. Statuses:

**Commitment rows.** A recommendation's `Commits you to:` parts (SKILL.md Stance "Relentless mode") are rows of their own, written `open` at ask-time and numbered after their headline, so the ids stay contiguous and the gate grades each one. The question field names the headline: `- Q6 | open | round 2 | (part of Q5) token scope for the review step |`. An explicit acceptance of the headline resolves each to `answered` with `accepted via Q5: <value>`; choosing an alternative or rejecting the headline sets each to `withdrawn` with `pruned by Q5 = <answer>`. The read-only decision table gives each part its own row number, and the `me` decision tree gives each its own checkbox. Unattended, each part takes the ladder on its own: a codebase-resolvable headline does not make its parts resolvable, and a part that is the user's decision is `blocked` like any other row.

**Commitment parts on the page.** On the page surface a recommendation's parts are the question's `commits` entries ([`surface.md`](surface.md) R1 and R3), never rows of their own: `export-ledger` rewrites the register one row per page question at wrap-up. The page is stricter than the terminal rule: accepting the headline confirms only the parts the user ticks. An alternative withdraws the parts, so they do not reach the Brief; a defer's open row covers them. An `own` answer keeps its unticked parts, which reach the Brief as named risks through `export-brief`, as do an accept's; that over-counts an unhedged `own` answer, the safe direction. On its own, a terminal answer mirrored with `record-terminal` ticks none: after the user confirms parts in the terminal, tick them with a `confirm-commitments` op rather than leaving them unconfirmed. The register gate does not grade parts. Commitment rows from earlier terminal rounds become page questions of their own under `import-ledger`: resolve or withdraw each by hand when its headline is answered. When the page degrades to the terminal, register each `commits` entry of a still-open question as a commitment row before the next round.
**Commitment parts on the page.** On the page surface a recommendation's parts are the question's `commits` entries ([`surface.md`](surface.md) R1 and R3), never rows of their own: `export-ledger` rewrites the register one row per page question at wrap-up. The page is stricter than the terminal rule: accepting the headline confirms only the parts the user ticks, and an accepted or hedged row with an unticked part exports `open`, so the register gate holds it until each part is ticked or the decision changes. An alternative withdraws the parts, so they do not reach the Brief; a defer's open row covers them. An `own` answer keeps its unticked parts, which reach the Brief as named risks through `export-brief`, as do an accept's and a hedged row's; that over-counts an unhedged `own` answer, the safe direction. On its own, a terminal answer mirrored with `record-terminal` ticks none: after the user confirms parts in the terminal, tick them with a `confirm-commitments` op rather than leaving them unconfirmed. Commitment rows from earlier terminal rounds become page questions of their own under `import-ledger`: resolve or withdraw each by hand when its headline is answered. When the page degrades to the terminal, register each `commits` entry of a still-open question as a commitment row before the next round.

**Hedged flag.** A hedged reply (SKILL.md Stance "Relentless mode") resolves at most its headline, which resolves to `answered` with `hedged: <answer>`; its commitment rows stay `open` under the drift check. Downstream passes treat a row carrying `hedged:` with the same scrutiny as a `free-text:` one. On the page, mirror a hedged terminal reply with `record-terminal` as `own` with the text prefixed `hedged:`, never as `accept`, which records accept-all; it exports as `free-text: hedged: <answer>`. A hedged "Own answer" typed on the page gets the same echo on its wake and exports as plain `free-text: <answer>`. The Step 3 confirmation restate lists every row carrying `hedged:`, and every `free-text:` row whose answer is hedged, for explicit confirmation.
**Hedged flag.** A hedged reply (SKILL.md Stance "Relentless mode") resolves at most its headline, which resolves to `answered` with `hedged: <answer>`; its commitment rows stay `open` under the drift check. Downstream passes treat a row carrying `hedged:` with the same scrutiny as a `free-text:` one. On the page, mirror a hedged terminal reply with `record-terminal` as `hedged`, the condition in `text`, never as `accept`, which records accept-all; it exports as `hedged: <answer>` with the condition in `note::`, and a legacy `free-text: hedged: <answer>` row still imports as `own`. A hedged "Own answer" typed on the page gets the same echo on its wake and exports as plain `free-text: <answer>`. The Step 3 confirmation restate lists every row carrying `hedged:`, and every `free-text:` row whose answer is hedged, for explicit confirmation.

### Drift check: a reply that does not answer is not an answer

Expand Down
2 changes: 1 addition & 1 deletion plugins/planning/skills/interview/context/surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ When the work returns, clear both (`wait` with `"clear": true`, `set-status` wit

"Accept all and have agents check them" arrives as one `accept-audit` event plus its accepts; the page holds no validation logic, so the skill routes the round to `/planning:audit-answers`. The page leaves a question that carries a note out of that event, so every fanned-out accept is plain.

An accept whose note conditions the acceptance ("before we lock it in") is recorded as hedged, headline only, per SKILL.md "A hedged reply resolves only the headline". Accept all, per group and per round section in the Rounds view, arrives as one `accept` event per question, each with its own note `text`, usually in one wake; treat each as a single accept.
An accept whose note conditions the acceptance ("before we lock it in") is recorded as hedged, headline only, per SKILL.md "A hedged reply resolves only the headline": the page's Hedged choice records it directly, and a terminal reply is mirrored with `record-terminal` as `hedged`, the condition in `text`. An accepted or hedged row with an unticked commitment exports `open`, so the register gate holds it until each commitment is ticked. Accept all, per group and per round section in the Rounds view, arrives as one `accept` event per question, each with its own note `text`, usually in one wake; treat each as a single accept.

An accept (or a reconfirmed accept) and an `own` answer carry the recommendation's commitments; an `alt` withdraws them and a `defer` carries none (its open row covers them). Unticked commitments of an accepted or `own` question reach the Brief as named risks. When the user confirms commitments in the terminal, record them with `confirm-commitments` (`reason` says how, such as "confirmed in the terminal"); the page and `export-brief` count them as confirmed, like a page `confirm`. The summary's To confirm list holds only unconfirmed commitments; commitments confirmed this way are named below it with their reasons.

Expand Down
4 changes: 1 addition & 3 deletions plugins/planning/surface/DEFERRED.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ Reason for parking: the owner's scope guard, "we want these to be, in most cases

| Entry | Decision |
|---|---|
| 1. A `hedged` decision kind on the page: the skill records a conditional accept as hedged, and the page has no such state | Build: #5471, after #4611 |
| 2. The register gate grades a page export clean while commitments are unticked | Build: #5471, after #4611 |
| 3. Addendum wording lint: whether the coined-term check becomes a script check | Open: awaiting the owner |
| 1. Addendum wording lint: whether the coined-term check becomes a script check | Open: awaiting the owner |

## Deferred behaviors

Expand Down
Loading
Loading