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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

All notable changes to the code-et plugin will be documented in this file.

## [4.3.0] - 2026-05-13

### Changed — `/code:plan` emits structured `files[]` entries; `/code:ship` consumes them

`metadata.files` was an array of `path:line` strings — flat, lossy, and a tax the subagent paid in tokens. Plan-time LSP already resolved each acceptance criterion to a qualified symbol (per the existing "LSP for symbols" rule), but the symbol name was thrown away before `TaskCreate`, leaving the implementer subagent to rediscover it with `Grep` + `Read` on a cold start. On an 8-task `/code:ship` run that's 16-48k tokens of pure rediscovery — paid every time, for information the orchestrator already had.

**Changed.** Each `files[]` entry is now `{path, symbol, line, op}` where `op ∈ {add, modify, replace, delete}`. `path` + `op` are required; `symbol` is required for `modify|replace|delete` and recommended for `add`; `line` is an LSP-resolved hint. The contract is `symbol` — if the line drifts between plan and ship, the implementer re-resolves via `documentSymbol`. Deletion of superseded code, previously buried in prose under `rationale`, is now an explicit `op: "delete"` entry — typed action, not a narrative aside.

**Plan-time validation.** Before `TaskCreate`, every `path` is checked against `git ls-files` (for `modify|replace|delete`) or against `FILE-REFERENCE.md`'s documented top-level areas when that file exists (for `add`). Stale references caught at plan time are subagent dispatches not wasted.

**Ship-side rendering.** `/code:ship`'s dispatch prompt renders each entry as `- <op> <path>[:<line>] → <symbol>`, so the subagent receives a typed action list rather than a bare path list. The cold-start cost drops from "find the symbol" to "open the file, jump to the symbol."

**Token math.** ~35 extra tokens per entry × ~8 tasks = ~280 tokens at plan time, against 15-45k saved per `/code:ship` dispatch. The LSP work was already happening; the change is to *persist* it instead of recomputing it inside every subagent.

Files touched: `commands/plan.md`, `commands/ship.md`, `CLAUDE.md`.

## [4.2.3] - 2026-05-12

### Fixed — task-metadata hook was wired to the wrong event
Expand Down
2 changes: 1 addition & 1 deletion code-et-implementer/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "code",
"version": "4.2.3",
"version": "4.3.0",
"description": "Pure-Rust Clean Architecture workflow. Six commands: start, fix, plan, ship, review, install-ci. Always-latest deps, CI audit gate, anti-slop enforced.",
"author": {
"name": "Kennet Kusk"
Expand Down
8 changes: 7 additions & 1 deletion code-et-implementer/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,20 @@ Tasks created with `TaskCreate` carry:
```
metadata: {
verification: "cargo nextest run && cargo clippy --all-targets -- -D warnings",
files: ["crates/<layer>/src/path/to/file.rs:42"],
files: [
{"path": "crates/<layer>/src/path/to/file.rs", "symbol": "Type::method", "line": 42, "op": "modify"},
{"path": "crates/<layer>/src/new.rs", "symbol": "NewType", "op": "add"},
{"path": "crates/<layer>/src/legacy.rs", "symbol": "old_fn", "line": 89, "op": "delete"}
],
expected_outcome: "what success looks like",
rationale: "why this task exists — the constraint or decision driving it",
user_story: "US-N" | "AC-N.M" | "chore:<reason>",
layer: "domain" | "application" | "infrastructure" | "interface" | "chore"
}
```

`files[]` entries: `path` + `op` always required; `symbol` required for `modify|replace|delete`; `line` is an LSP-resolved hint (drift-tolerant — `symbol` is the contract). Full schema and validation rules in `commands/plan.md` §"TaskCreate metadata".

`rationale` is mandatory. Subagents in `/code:ship` start cold — they need the *why*, not just the *what*, to make judgment calls.

`layer` is mandatory. Each *file* declares its layer; vertical slices may span layers.
Expand Down
27 changes: 23 additions & 4 deletions code-et-implementer/commands/plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,13 @@ Read the PRD (it is the authoritative spec).

**Replace, don't accumulate.** When a slice supersedes existing logic, the task scope **includes deletion of the superseded code**. State the `path:line` being replaced in `metadata.rationale`. No parallel utilities, no `// TODO: remove old X`.

**LSP for symbols.** Use `documentSymbol` / `findReferences` / `definition` to anchor each US/AC to `file:line`. Grep/Glob for discovery; LSP for precision. Never use LSP to enumerate the project. For 3+ independent areas, spawn parallel `Agent(subagent_type: "Explore", model: "haiku")` queries in a single message — Haiku 4.5 is the right tier for breadth scans.
**LSP for symbols.** Use `documentSymbol` / `findReferences` / `definition` to resolve each US/AC to a `{path, symbol, line, op}` entry — persist the result in `metadata.files[]` (schema below). Do not throw away the symbol name; that's the contract the subagent edits against if `line` drifts. Grep/Glob for discovery; LSP for precision. Never use LSP to enumerate the project. For 3+ independent areas, spawn parallel `Agent(subagent_type: "Explore", model: "haiku")` queries in a single message — Haiku 4.5 is the right tier for breadth scans.

**Path validation.** Before `TaskCreate`, validate every `files[].path`:
- `op ∈ {modify, replace, delete}` → path must appear in `git ls-files`. If not, the symbol moved or was deleted — re-resolve via LSP or drop the entry.
- `op = add` → path must either appear in `git ls-files` (append to existing file) or, if `FILE-REFERENCE.md` exists at repo root, sit under a documented top-level area there. Reject paths under undocumented top-level directories when `FILE-REFERENCE.md` is present; otherwise accept any path the workspace `Cargo.toml` covers.

Path drift caught at plan time is one less wasted subagent dispatch.

### Anti-slop self-critique (before TaskCreate)

Expand All @@ -150,15 +156,28 @@ The list lives in `code-et-implementer/docs/anti-slop.md`; the inline summary ab
```json
{
"verification": "<cmd that exercises the slice end-to-end>",
"files": ["crates/<layer>/src/path.rs:42", ...],
"files": [
{"path": "crates/<layer>/src/path.rs", "symbol": "Type::method", "line": 42, "op": "modify"},
{"path": "crates/<layer>/src/new_file.rs", "symbol": "NewType", "op": "add"},
{"path": "crates/<layer>/src/legacy.rs", "symbol": "deprecated_fn", "line": 89, "op": "delete"}
],
"expected_outcome": "<observable end-to-end behaviour>",
"rationale": "<1-2 sentences: why this slice exists, the constraint driving it. If replacing existing code, name the path:line being deleted.>",
"rationale": "<1-2 sentences: why this slice exists, the constraint driving it.>",
"user_story": "US-N | AC-N.M | chore:<reason>",
"layer": "domain | application | infrastructure | interface | chore"
}
```

`rationale` is mandatory — the subagent starts cold and needs the *why*. `layer` is mandatory; the per-file layer also feeds the validator on every file the task touches. `verification` exercises the full slice — `cargo nextest run -p <crate>` for unit, `cargo nextest run --workspace` for cross-layer.
**`files[]` entry shape:**

| Field | Required | Notes |
|---|---|---|
| `path` | always | Workspace-relative. Validated against `git ls-files` (`modify\|replace\|delete`) or `FILE-REFERENCE.md` modules (`add`). |
| `op` | always | `add` (create symbol), `modify` (edit body), `replace` (full rewrite — pair with sibling `delete` if cross-file supersession), `delete` (remove symbol). |
| `symbol` | for `modify\|replace\|delete`; recommended for `add` | Qualified Rust path: `User::validate`, `db::pool`, `routes::auth::login`. Resolved via LSP `documentSymbol`. |
| `line` | optional hint | Current line at plan time. Implementer re-resolves via LSP if it drifts. Omit for `add` on a new file. |

`rationale` is mandatory — the subagent starts cold and needs the *why*. `layer` is mandatory; the per-file layer also feeds the validator on every file the task touches. Deletion of superseded code is encoded as explicit `op: "delete"` entries in `files[]`, not prose in `rationale`. `verification` exercises the full slice — `cargo nextest run -p <crate>` for unit, `cargo nextest run --workspace` for cross-layer.

Set dependencies with `TaskUpdate(addBlockedBy)`. Independent slices stay parallel.

Expand Down
8 changes: 7 additions & 1 deletion code-et-implementer/commands/ship.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ Each subagent starts cold. Send one comprehensive first turn — intent, constra
<metadata.rationale — verbatim from plan. The why, not the what.>

## Files to touch
<metadata.files — exact file:line anchors. Read these before editing.>
<For each metadata.files[] entry, render one bullet:
"- <op> <path>[:<line>] → <symbol>"
omitting ":<line>" if absent and "→ <symbol>" if absent. Examples:
- modify crates/domain/src/user.rs:42 → User::validate
- add crates/infrastructure/src/db/users.rs → UserRepository
- delete crates/infrastructure/src/legacy.rs:89 → old_validate_fn
Read each entry's file (sliced) before editing. `line` is a hint — if the symbol has moved, re-resolve via LSP `documentSymbol`; `symbol` is the contract. Apply each op exactly: `add` creates, `modify` edits in place, `replace` full-rewrites the symbol, `delete` removes it (plus all references).>

## Layer
<metadata.layer — domain | application | infrastructure | interface | chore. Imports point inward; `cargo build` enforces this.>
Expand Down
Loading