`malvin plan PLAN_PATH`

Send three prompts to the same agent, one prompt at a time, i.e.
 send first prompt, wait until response is done, then send second, wait, send 3rd, wait.
 
    - Prompt 1: Append a horizontal rule to `{{ plan_path }}` followed by "BEGIN_MALVIN"
        - Clearly restate the plan, appending to `{{ plan_path }}`
	- Write a critique of the plan, appending (further) to `{{ plan_path }}`
         - Are there errors?
         - Is the plan sound?
         - Is the plan as simple as it could be? 
         - Will each concept, behavior, and constraint be enforced by a unit test?
         - Does the plan guard against overfitting to a spec, test, or metric?
        - Append (further) any open questions you might have.
    - Prompt 2
        - Do research to answer any open questions. Draw upon the codebase, information about the user's preferences (from your logs, for example), and external research (e.g., arXiv or other sources) where appropriate.
        - Make your best decision about any unanswered questions. Favor correctness and require evidence wherever feasible.
    - Prompt 3
        - Rewrite the plan, incorporating criticisms and answers, overwriting everything including and below "BEGIN_MALVIN" `{{ plan_path }}`.
	
---
BEGIN_MALVIN

# `malvin plan` — revised specification

Design spec for a new malvin subcommand. Validated by manual dry-run (`plan_2.md` → this document). Implementation follows registration of `Commands::Plan` in `src/cli/args.rs`.

## Overview

`malvin plan PLAN_PATH` runs **four sequential agent prompts** on **one persistent session**. Each prompt completes before the next starts. The agent reads the plan file; malvin owns boundary writes and run-dir artifacts.

**Purpose:** Generic pre-`code` / pre-`constrain` step for any repo — reflect on a written plan, resolve uncertainty with cited evidence, emit a revised implementation plan.

**Scope:** Domain-agnostic by default. An optional **adversarial profile** activates when the plan path matches `*adversarial*`, `*adv_system*`, or `smell_registry.toml` exists in the work dir (see § Adversarial profile).

## CLI contract

```text
malvin plan [OPTIONS] <PLAN_PATH>
```

| Item | Contract |
|------|----------|
| `<PLAN_PATH>` | Existing `.md` file (same path rules as `malvin code`: no whitespace; case-sensitive `.md`). |
| Session | One persistent agent session for all prompts. |
| Re-run | **Replace** the machine block (from first `---` after user content through EOF) with a fresh Prompt-1→3 pass. User text above the horizontal rule is preserved. |
| Ambiguous markers | If the file has marker pairs without run metadata from a prior malvin run, **fail** with a clear error — do not append a second block. |
| Output | In-place update of `PLAN_PATH` after Prompt 3 splice (see § File shape). |
| Downstream | Post-Prompt-3 file is valid input for `malvin code @PLAN_PATH`. Content below the last `BEGIN_MALVIN` is the implementation plan; content above `---` is user context only. |

**Future enhancement (not required at launch):** `malvin code` may strip to the machine section or warn when `BEGIN_MALVIN` is absent. Document expected post-Prompt-3 shape in `default_prompts/docs/plan.md`.

## Prompt pipeline

### Prompt 1a — Restate only

The agent appends to `PLAN_PATH`:

1. Horizontal rule (`---`).
2. Marker line `BEGIN_MALVIN`.
3. Section `## Restatement` — clear restatement of the **user-authored plan** (text above `---`).

**Constraint:** No fixes, no critique, no preferred rewrites. Restatement is a comprehension check only.

Malvin records `user_span_end` (byte offset before `---`) in run metadata immediately after Prompt 1a completes.

Malvin snapshots the post-1a file to `.malvin/logs/<run>/plan.p1a.md`.

### Prompt 1b — Critique and open questions

The agent appends to `PLAN_PATH`:

1. Section `## Critique` — critique of the **original user text** above `---` (not the restatement). Use the restatement only to verify comprehension. Address at minimum:
   - Errors and gaps
   - Soundness
   - Simplicity (too simple / too complex)
   - Unit-test enforcement (will each concept, behavior, and constraint be enforced by a unit test?)
   - Overfitting guard (does the plan guard against overfitting to a spec, test, or metric?)
2. Section `## Open questions` — numbered list of unresolved items. Free prose allowed but numbering is required for Prompt 2 cross-reference.

**Adversarial profile additions** (when active): Critique must map plan bullets to `smell_registry.toml` row ids where applicable; flag missing MR/PBT obligations, null-plugin non-vacuity, and materialization-harness gaps from `summary.md` gate 3.

Malvin snapshots post-1b file to `.malvin/logs/<run>/plan.p1b.md`.

### Prompt 2 — Research and decide

The agent:

- Researches answers to numbered open questions using the codebase, malvin logs, and external sources where appropriate.
- Makes best-effort decisions on remaining questions; favors correctness; cites evidence (code path, log id, URL).

The agent **appends** section `## DECISIONS` to `PLAN_PATH` immediately after `## Open questions`. Each entry:

- Matches an open-question number (or `0` when there were no open questions — see null-decision stress below).
- States a verdict.
- Cites evidence.

Malvin copies consolidated decisions to `.malvin/logs/<run>/plan.p2.decisions.md`. Prompt 3 must read `DECISIONS` from the file, not session memory alone.

**Null-decision stress:** If Prompt 1b emits zero open questions, Prompt 2 still runs. Entry `0` documents that no numbered questions existed and records one deliberate attempt to falsify an implicit plan assumption (e.g., subcommand already exists).

**Large question sets:** If open questions exceed a configurable batch size (default 20), Prompt 2 may append batched subsections (`## DECISIONS (1–20)`, etc.). Malvin concatenates batches from the run dir before Prompt 3.

Prompt 2 does **not** rewrite the plan body; it resolves uncertainty for Prompt 3.

### Prompt 3 — Rewrite

The agent emits the **revised plan** inside a single fenced markdown block in the session response. It must:

- Incorporate critique fixes and every `DECISIONS` entry.
- Under adversarial profile: include explicit links to smell-registry row ids (`principle`, `invariant`, `counterexample_shape`), MR/PBT obligation class per row, and materialization-harness milestones from `summary.md` gate 3.
- Name unit tests or smell-registry rows for each concept, behavior, and constraint (acceptance checklist below).

Malvin **splices** the file:

```text
PLAN_PATH := bytes[0..user_span_end) + fenced_block_content
```

Malvin performs the splice — do not trust the agent to overwrite the correct span when user content contains `---` or `BEGIN_MALVIN`.

After splice, the file contains only user header + `---` + `BEGIN_MALVIN` + revised plan. Restatement, critique, open questions, and decisions are recoverable from run-dir snapshots (`plan.p1a.md`, `plan.p1b.md`, `plan.p2.decisions.md`), not from `PLAN_PATH`.

## File shape

### After Prompt 1b

```text
[user-authored plan]

---
BEGIN_MALVIN
## Restatement
[comprehension restatement — no fixes]

## Critique
[critique of user plan]

## Open questions
1. ...
```

### After Prompt 2

```text
[as above]

## DECISIONS
1. **Verdict:** ... **Evidence:** ...
```

### After Prompt 3 (final)

```text
[user-authored plan]

---
BEGIN_MALVIN
[revised implementation plan — normative spec only]
```

## Run-dir artifacts

| Artifact | When | Role |
|----------|------|------|
| `plan.p1a.md` | After Prompt 1a | Snapshot before critique |
| `plan.p1b.md` | After Prompt 1b | Snapshot before decisions |
| `plan.p2.decisions.md` | After Prompt 2 | Authoritative decisions copy |
| `metadata.json` (or equivalent) | After Prompt 1a | `user_span_end`, optional user-span hash |
| `trace.jsonl`, `kpop.log` | Throughout | Audit trail |

Pattern matches existing malvin run-dir authority (`exp_log`, `kpop.log`).

## Adversarial profile

Activated when any of:

- Plan path glob matches `*adversarial*` or `*adv_system*`
- `smell_registry.toml` exists in work dir

When active, Prompt 1b and Prompt 3 gain obligations from `adversarial.md` and `summary.md`:

- Map plan items to smell-registry rows.
- Require MR/PBT obligation class per row.
- Require materialization-harness milestones (gate 3).
- Overfitting checklist becomes operational — not rhetorical.

Generic plans omit these requirements. No separate `plan-adv` subcommand unless profile hook proves insufficient in practice.

## Acceptance criteria (implementation)

Each item must have a unit test or CLI smoke test before `Commands::Plan` ships:

| # | Criterion | Test idea |
|---|-----------|-----------|
| 1 | `malvin plan --help` and `malvin --doc plan` render | CLI smoke |
| 2 | Prompt 1a restatement forbids fixes (prompt contract) | Prompt render test |
| 3 | Prompt 1b critiques user span, not restatement | Prompt render test |
| 4 | `user_span_end` recorded after 1a | Metadata unit test |
| 5 | Splice replaces `[user_span_end..EOF)` with fenced block | Splice unit test with embedded `---` / `BEGIN_MALVIN` in user span |
| 6 | Re-run replaces machine block; preserves user header | Integration test |
| 7 | Ambiguous markers without metadata → error | Integration test |
| 8 | `DECISIONS` appended after open questions; numbered | Prompt + file-shape test |
| 9 | Run-dir snapshots written (`plan.p1a.md`, etc.) | Artifact test |
| 10 | Adversarial profile detection (glob + registry file) | Unit test |
| 11 | Post-splice file valid for `malvin code` copy path | Smoke: `create_run_artifacts` on spliced file |

## Prompt files (new)

| File | Role |
|------|------|
| `default_prompts/plan_1a_restate.md` | Restate-only contract |
| `default_prompts/plan_1b_critique.md` | Critique + open questions (+ adversarial overlay) |
| `default_prompts/plan_2_decisions.md` | Research + DECISIONS append contract |
| `default_prompts/plan_3_rewrite.md` | Fenced-block rewrite (+ adversarial overlay) |
| `default_prompts/docs/plan.md` | User-facing command documentation |

Register in `src/cli/command_docs.rs` alongside existing commands.

## Implementation sketch

1. Add `PlanArgs { plan_path: PathBuf }` and `Commands::Plan` in `src/cli/args.rs`.
2. Add `plan_flow.rs` modeled on `ideas_flow.rs` / `do_flow.rs`: create run artifacts, single-session orchestrator, sequential prompt dispatch.
3. Add splice helper in `src/artifacts/` (or dedicated module): read `user_span_end`, extract fenced block from agent response, atomic write.
4. Add adversarial-profile detector (shared with future `malvin adversarial` if useful).
5. Wire entrypoint in `src/cli/entrypoint_commands.rs`.
6. Add tests per acceptance table.

## Non-goals (this version)

- Metamorphic re-run contract comparing against `plan.mr.prior.md` (future enhancement; see invent session `20260531_232155_gi82onwr`).
- Agent-free intermediate artifacts (agent still appends during 1a/1b/2; malvin splices at 3).
- Pre-validation gate inside `malvin code` for `BEGIN_MALVIN` presence.

## Relationship to manual dry-run

| Artifact | Role |
|----------|------|
| `plan.md` | Original user sketch |
| `plan_2.md` | Prompt 1 + 2 output (audit trail) |
| `plan_3.md` | Prompt 3 output (this spec) |

The dry-run validated prompt contracts before CLI registration. It does not replace shipping `malvin plan`.
