@aperant/framework 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +64 -10
- package/agents/apt-improver.md +99 -0
- package/agents/apt-planner.md +115 -10
- package/dist/__test-helpers/run-cmd.d.mts +4 -2
- package/dist/__test-helpers/run-cmd.d.mts.map +1 -1
- package/dist/__test-helpers/run-cmd.mjs +56 -15
- package/dist/__test-helpers/run-cmd.mjs.map +1 -1
- package/dist/cli/ci-watch/lock.d.mts +53 -0
- package/dist/cli/ci-watch/lock.d.mts.map +1 -0
- package/dist/cli/ci-watch/lock.mjs +172 -0
- package/dist/cli/ci-watch/lock.mjs.map +1 -0
- package/dist/cli/ci-watch/state.d.mts +36 -0
- package/dist/cli/ci-watch/state.d.mts.map +1 -0
- package/dist/cli/ci-watch/state.mjs +103 -0
- package/dist/cli/ci-watch/state.mjs.map +1 -0
- package/dist/cli/ci-watch/stop-matrix.d.mts +58 -0
- package/dist/cli/ci-watch/stop-matrix.d.mts.map +1 -0
- package/dist/cli/ci-watch/stop-matrix.mjs +164 -0
- package/dist/cli/ci-watch/stop-matrix.mjs.map +1 -0
- package/dist/cli/cli-wrappers/ci-watch.d.mts +2 -0
- package/dist/cli/cli-wrappers/ci-watch.d.mts.map +1 -0
- package/dist/cli/cli-wrappers/ci-watch.mjs +9 -0
- package/dist/cli/cli-wrappers/ci-watch.mjs.map +1 -0
- package/dist/cli/commands/adr.d.mts +5 -0
- package/dist/cli/commands/adr.d.mts.map +1 -0
- package/dist/cli/commands/adr.mjs +228 -0
- package/dist/cli/commands/adr.mjs.map +1 -0
- package/dist/cli/commands/ci-watch.d.mts +7 -0
- package/dist/cli/commands/ci-watch.d.mts.map +1 -0
- package/dist/cli/commands/ci-watch.mjs +465 -0
- package/dist/cli/commands/ci-watch.mjs.map +1 -0
- package/dist/cli/commands/context.d.mts +7 -0
- package/dist/cli/commands/context.d.mts.map +1 -0
- package/dist/cli/commands/context.mjs +224 -0
- package/dist/cli/commands/context.mjs.map +1 -0
- package/dist/cli/commands/event.d.mts.map +1 -1
- package/dist/cli/commands/event.mjs +59 -24
- package/dist/cli/commands/event.mjs.map +1 -1
- package/dist/cli/commands/host-detect.d.mts +1 -1
- package/dist/cli/commands/host-detect.d.mts.map +1 -1
- package/dist/cli/commands/host-detect.mjs +30 -3
- package/dist/cli/commands/host-detect.mjs.map +1 -1
- package/dist/cli/commands/modes.d.mts +13 -0
- package/dist/cli/commands/modes.d.mts.map +1 -0
- package/dist/cli/commands/modes.mjs +220 -0
- package/dist/cli/commands/modes.mjs.map +1 -0
- package/dist/cli/commands/route.mjs +1 -1
- package/dist/cli/commands/route.mjs.map +1 -1
- package/dist/cli/commands/task.d.mts.map +1 -1
- package/dist/cli/commands/task.mjs +108 -6
- package/dist/cli/commands/task.mjs.map +1 -1
- package/dist/cli/commands/tokens.d.mts.map +1 -1
- package/dist/cli/commands/tokens.mjs +150 -6
- package/dist/cli/commands/tokens.mjs.map +1 -1
- package/dist/cli/commands/triage.d.mts +8 -0
- package/dist/cli/commands/triage.d.mts.map +1 -0
- package/dist/cli/commands/triage.mjs +259 -0
- package/dist/cli/commands/triage.mjs.map +1 -0
- package/dist/cli/config/post-merge-sweep.d.mts +18 -0
- package/dist/cli/config/post-merge-sweep.d.mts.map +1 -1
- package/dist/cli/config/post-merge-sweep.mjs +48 -3
- package/dist/cli/config/post-merge-sweep.mjs.map +1 -1
- package/dist/cli/consistency/registry.d.mts +11 -0
- package/dist/cli/consistency/registry.d.mts.map +1 -1
- package/dist/cli/consistency/registry.mjs +13 -0
- package/dist/cli/consistency/registry.mjs.map +1 -1
- package/dist/cli/coordination/agent-identity.d.mts +9 -0
- package/dist/cli/coordination/agent-identity.d.mts.map +1 -1
- package/dist/cli/coordination/agent-identity.mjs +11 -0
- package/dist/cli/coordination/agent-identity.mjs.map +1 -1
- package/dist/cli/coordination/event-log.d.mts +27 -0
- package/dist/cli/coordination/event-log.d.mts.map +1 -1
- package/dist/cli/coordination/event-log.mjs +72 -2
- package/dist/cli/coordination/event-log.mjs.map +1 -1
- package/dist/cli/dispatch.d.mts.map +1 -1
- package/dist/cli/dispatch.mjs +14 -1
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/gate/registry.d.mts +11 -0
- package/dist/cli/gate/registry.d.mts.map +1 -1
- package/dist/cli/gate/registry.mjs +13 -0
- package/dist/cli/gate/registry.mjs.map +1 -1
- package/dist/cli/help.d.mts.map +1 -1
- package/dist/cli/help.mjs +1 -0
- package/dist/cli/help.mjs.map +1 -1
- package/dist/cli/host/detect.d.mts +1 -0
- package/dist/cli/host/detect.d.mts.map +1 -1
- package/dist/cli/host/detect.mjs +5 -0
- package/dist/cli/host/detect.mjs.map +1 -1
- package/dist/cli/route/envelope.d.mts +68 -4
- package/dist/cli/route/envelope.d.mts.map +1 -1
- package/dist/cli/route/envelope.mjs +140 -103
- package/dist/cli/route/envelope.mjs.map +1 -1
- package/dist/cli/route/skill-discover.d.mts +9 -0
- package/dist/cli/route/skill-discover.d.mts.map +1 -1
- package/dist/cli/route/skill-discover.mjs +11 -0
- package/dist/cli/route/skill-discover.mjs.map +1 -1
- package/dist/cli/skill-author/contract.d.mts +1 -0
- package/dist/cli/skill-author/contract.d.mts.map +1 -1
- package/dist/cli/skill-author/contract.mjs +7 -0
- package/dist/cli/skill-author/contract.mjs.map +1 -1
- package/dist/cli/task/worktree-cleanup.d.mts +9 -1
- package/dist/cli/task/worktree-cleanup.d.mts.map +1 -1
- package/dist/cli/task/worktree-cleanup.mjs +190 -9
- package/dist/cli/task/worktree-cleanup.mjs.map +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/agents/apt-planner.md +1 -1
- package/dist/plugin/skills/apt/SKILL.md +111 -5
- package/dist/plugin/skills/apt-author-skill/SKILL.md +11 -0
- package/dist/plugin/skills/apt-bootstrap/SKILL.md +1 -0
- package/dist/plugin/skills/apt-classify/SKILL.md +1 -0
- package/dist/plugin/skills/apt-close-task/SKILL.md +1 -0
- package/dist/plugin/skills/apt-create-docs/SKILL.md +1 -0
- package/dist/plugin/skills/apt-debug/SKILL.md +2 -0
- package/dist/plugin/skills/apt-design/SKILL.md +2 -0
- package/dist/plugin/skills/apt-discuss/SKILL.md +2 -0
- package/dist/plugin/skills/apt-docs/SKILL.md +2 -0
- package/dist/plugin/skills/apt-execute/SKILL.md +1 -0
- package/dist/plugin/skills/apt-mockup/SKILL.md +2 -0
- package/dist/plugin/skills/apt-pause/SKILL.md +1 -0
- package/dist/plugin/skills/apt-personas/SKILL.md +1 -0
- package/dist/plugin/skills/apt-plan/SKILL.md +2 -0
- package/dist/plugin/skills/apt-pr-review/SKILL.md +1 -0
- package/dist/plugin/skills/apt-quick/SKILL.md +2 -0
- package/dist/plugin/skills/apt-resume/SKILL.md +1 -0
- package/dist/plugin/skills/apt-review/SKILL.md +1 -0
- package/dist/plugin/skills/apt-roadmap/SKILL.md +1 -0
- package/dist/plugin/skills/apt-roundtable/SKILL.md +2 -0
- package/dist/plugin/skills/apt-run/SKILL.md +1 -0
- package/dist/plugin/skills/apt-scan/SKILL.md +1 -0
- package/dist/plugin/skills/apt-setup/SKILL.md +1 -0
- package/dist/plugin/skills/apt-ship/SKILL.md +6 -5
- package/dist/plugin/skills/apt-stress-test/SKILL.md +1 -0
- package/dist/plugin/skills/apt-terminal/SKILL.md +1 -0
- package/dist/plugin/skills/apt-update/SKILL.md +5 -0
- package/dist/plugin/skills/apt-verify/SKILL.md +1 -0
- package/dist/plugin/skills/apt-verify-proof/SKILL.md +1 -0
- package/dist/types/config.d.ts +85 -0
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +125 -125
- package/prompts/coder.md +2 -0
- package/prompts/planner.md +12 -0
- package/prompts/spec_writer.md +9 -0
- package/skills/apt/SKILL.md +1 -0
- package/skills/apt-close-task/SKILL.md +32 -1
- package/skills/apt-debug/SKILL.md +39 -6
- package/skills/apt-debug/appendices/diagnose-discipline.md +119 -0
- package/skills/apt-diagram/SKILL.md +342 -0
- package/skills/apt-diagram/appendices/design-discipline.md +97 -0
- package/skills/apt-discuss/SKILL.md +25 -0
- package/skills/apt-discuss/appendices/grill-discipline.md +104 -0
- package/skills/apt-discuss/appendices/zoom-out-helper.md +79 -0
- package/skills/apt-execute/SKILL.md +48 -5
- package/skills/apt-execute/appendices/tdd-mode.md +107 -0
- package/skills/apt-improve/DEEPENING.md +84 -0
- package/skills/apt-improve/INTERFACE-DESIGN.md +97 -0
- package/skills/apt-improve/LANGUAGE.md +104 -0
- package/skills/apt-improve/SKILL.md +141 -0
- package/skills/apt-plan/SKILL.md +147 -4
- package/skills/apt-planner.md +42 -1
- package/skills/apt-pr-review/SKILL.md +46 -16
- package/skills/apt-prototype/LOGIC.md +109 -0
- package/skills/apt-prototype/SKILL.md +143 -0
- package/skills/apt-prototype/UI.md +90 -0
- package/skills/apt-quick/SKILL.md +30 -0
- package/skills/apt-review/SKILL.md +2 -0
- package/skills/apt-run/SKILL.md +32 -4
- package/skills/apt-setup/SKILL.md +128 -2
- package/skills/apt-ship/SKILL.md +47 -0
- package/skills/apt-triage/AGENT-BRIEF.md +84 -0
- package/skills/apt-triage/OUT-OF-SCOPE.md +75 -0
- package/skills/apt-triage/SKILL.md +169 -0
- package/skills/apt-verify/SKILL.md +3 -0
- package/skills/apt-verify-proof/SKILL.md +3 -0
- package/skills/apt-watch-ci/SKILL.md +163 -0
- package/skills/apt-zoom-out/SKILL.md +130 -0
- package/src/cli/ci-watch/lock.mjs +178 -0
- package/src/cli/ci-watch/state.mjs +103 -0
- package/src/cli/ci-watch/stop-matrix.mjs +181 -0
- package/src/cli/cli-wrappers/ci-watch.mjs +9 -0
- package/src/cli/commands/adr.mjs +243 -0
- package/src/cli/commands/ci-watch.mjs +503 -0
- package/src/cli/commands/context.mjs +244 -0
- package/src/cli/commands/event.mjs +63 -24
- package/src/cli/commands/host-detect.mjs +33 -7
- package/src/cli/commands/modes.mjs +215 -0
- package/src/cli/commands/route.mjs +1 -1
- package/src/cli/commands/task.mjs +125 -18
- package/src/cli/commands/tokens.mjs +157 -6
- package/src/cli/commands/triage.mjs +277 -0
- package/src/cli/config/post-merge-sweep.mjs +49 -3
- package/src/cli/consistency/registry.mjs +14 -0
- package/src/cli/coordination/agent-identity.mjs +12 -0
- package/src/cli/coordination/event-log.mjs +73 -2
- package/src/cli/dispatch.mjs +15 -1
- package/src/cli/gate/registry.mjs +14 -0
- package/src/cli/help.mjs +1 -0
- package/src/cli/host/detect.mjs +5 -0
- package/src/cli/route/envelope.mjs +140 -106
- package/src/cli/route/skill-discover.mjs +12 -0
- package/src/cli/skill-author/contract.mjs +7 -0
- package/src/cli/task/worktree-cleanup.mjs +191 -9
- package/templates/adr-format.md +56 -0
- package/templates/config.json +4 -0
- package/templates/context-format.md +34 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apt:improve
|
|
3
|
+
description: "Proactive refactor discovery — scan a named area through DEEPENING / INTERFACE-DESIGN / LANGUAGE lenses, present top candidates, deepen via grill loop."
|
|
4
|
+
apt-skill-version: {{APT_VERSION}}
|
|
5
|
+
stage: plan
|
|
6
|
+
intent: investigate
|
|
7
|
+
when_to_use: "The user feels code has rotted and wants a refactor surface (not a feature). Triggers: 'this part of the codebase needs work', 'I want to refactor X but don't know where to start', 'show me what's worth refactoring in Y'."
|
|
8
|
+
user_invocable: true
|
|
9
|
+
internal: false
|
|
10
|
+
spawns_agent: true
|
|
11
|
+
agent_name: "apt-improver"
|
|
12
|
+
task_context: create-new
|
|
13
|
+
default_track: DEEP
|
|
14
|
+
default_execution_mode: step
|
|
15
|
+
execution_modes:
|
|
16
|
+
- auto
|
|
17
|
+
- step
|
|
18
|
+
allowed-tools: "Read, Grep, Glob, Bash"
|
|
19
|
+
argument-hint: "apt:improve [area-name]"
|
|
20
|
+
gates: []
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Improve — Proactive Refactor Discovery
|
|
24
|
+
|
|
25
|
+
Open question #2 in the Pocock adoption spec was answered concretely:
|
|
26
|
+
`apt:review` Pass 4 (architecture) is strictly **reactive** — it audits
|
|
27
|
+
the current diff for boundary violations. The work-intent "look at this
|
|
28
|
+
codebase and tell me what to refactor proactively" has no home today
|
|
29
|
+
(users retrofit it onto `apt:discuss --brainstorm` or `/apt:roundtable`,
|
|
30
|
+
both scope-mismatched). This skill is that home.
|
|
31
|
+
|
|
32
|
+
**Pocock adoption attribution.** 3-phase workflow + DEEPENING /
|
|
33
|
+
INTERFACE-DESIGN / LANGUAGE lenses ported from Matt Pocock's MIT-licensed
|
|
34
|
+
`improve-codebase-architecture` skill. Aperant-specific: spawns the
|
|
35
|
+
`apt-improver` agent and references `apt-discuss/appendices/grill-discipline.md`
|
|
36
|
+
as the canonical source for the autonomy-aware deepening loop rather than
|
|
37
|
+
re-stating the policy here.
|
|
38
|
+
|
|
39
|
+
## When to Use
|
|
40
|
+
|
|
41
|
+
- Feeling that an area of the codebase has rotted but unsure where to
|
|
42
|
+
start (proactive discovery)
|
|
43
|
+
- Before a multi-task refactor cycle, to surface the highest-leverage
|
|
44
|
+
candidates first
|
|
45
|
+
- After a feature has bedded in and the user wants to consolidate
|
|
46
|
+
|
|
47
|
+
## When NOT to Use
|
|
48
|
+
|
|
49
|
+
- Auditing a current diff for boundary violations — that's `/apt:review`
|
|
50
|
+
Pass 4 (reactive)
|
|
51
|
+
- Locking a specific refactor decision — use `/apt:discuss` instead
|
|
52
|
+
- Renaming or restructuring without proactive discovery — use
|
|
53
|
+
`/apt:plan` directly
|
|
54
|
+
|
|
55
|
+
## 3-Phase workflow
|
|
56
|
+
|
|
57
|
+
### Phase 1 — Explore (scan a named area for candidate refactors)
|
|
58
|
+
|
|
59
|
+
Sub-agent `apt-improver` reads:
|
|
60
|
+
|
|
61
|
+
- The named area (a noun phrase like "sparring engine", "feature
|
|
62
|
+
registry", "auth flow")
|
|
63
|
+
- `CONTEXT.md` term-blocks matching the area (if present)
|
|
64
|
+
- Relevant files via Glob/Grep
|
|
65
|
+
|
|
66
|
+
It applies three lenses, each described in its own sub-file:
|
|
67
|
+
|
|
68
|
+
- **DEEPENING** (`DEEPENING.md`) — does this area model the domain at
|
|
69
|
+
the right depth? Are abstractions earning their keep, or are they
|
|
70
|
+
shallow wrappers hiding nothing?
|
|
71
|
+
- **INTERFACE-DESIGN** (`INTERFACE-DESIGN.md`) — are the boundaries
|
|
72
|
+
between modules well-shaped? Are there feature-envy patterns? Hidden
|
|
73
|
+
coupling? Async leakage?
|
|
74
|
+
- **LANGUAGE** (`LANGUAGE.md`) — does the codebase use the same word
|
|
75
|
+
for the same thing? Do field names match domain language? Is
|
|
76
|
+
CONTEXT.md's "aliases to avoid" list violated anywhere?
|
|
77
|
+
|
|
78
|
+
Output: a Phase-1 inventory of **candidate refactors** with one-line
|
|
79
|
+
diagnoses per candidate.
|
|
80
|
+
|
|
81
|
+
### Phase 2 — Present candidates (top 3-5 with deletion-test rationale)
|
|
82
|
+
|
|
83
|
+
The skill body filters the Phase-1 inventory down to 3-5 candidates
|
|
84
|
+
using the **deletion test**: for each candidate, ask "if I deleted this
|
|
85
|
+
abstraction, what would break?" If the answer is "nothing important",
|
|
86
|
+
the candidate is high-priority (the abstraction was paying no rent).
|
|
87
|
+
|
|
88
|
+
Output to the user:
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
## Refactor candidates for {area}
|
|
92
|
+
|
|
93
|
+
1. **{Candidate title}** — {one-line diagnosis}.
|
|
94
|
+
Deletion test: {what breaks if removed} → {priority: high/med/low}.
|
|
95
|
+
|
|
96
|
+
2. ...
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Phase 3 — Deepen via grill loop (autonomy-aware)
|
|
100
|
+
|
|
101
|
+
The user picks one or more candidates. For each picked candidate, the
|
|
102
|
+
skill enters a deepening loop. **This loop references
|
|
103
|
+
`apt-discuss/appendices/grill-discipline.md` as the canonical source**
|
|
104
|
+
for autonomy-aware degradation:
|
|
105
|
+
|
|
106
|
+
- Autonomy 1: ask the user about every load-bearing design question
|
|
107
|
+
- Autonomy 2: batch-recommend per decision, user reviews at end
|
|
108
|
+
- Autonomy 3: auto-lock with the 3 escalation triggers (conflict with
|
|
109
|
+
prior locked decision; critical-path file touched; no defensible
|
|
110
|
+
default)
|
|
111
|
+
|
|
112
|
+
The deepening loop produces a concrete refactor plan (which becomes
|
|
113
|
+
`/apt:plan`'s input on a subsequent invocation).
|
|
114
|
+
|
|
115
|
+
## Sub-files (MIT-attributed)
|
|
116
|
+
|
|
117
|
+
- `DEEPENING.md` — domain-modeling depth lens
|
|
118
|
+
- `INTERFACE-DESIGN.md` — boundary-shape lens
|
|
119
|
+
- `LANGUAGE.md` — naming-consistency lens
|
|
120
|
+
|
|
121
|
+
All three are ported from Matt Pocock's improve-codebase-architecture
|
|
122
|
+
skill with MIT attribution per AC15.
|
|
123
|
+
|
|
124
|
+
## Agent spawned
|
|
125
|
+
|
|
126
|
+
`apt-improver` (definition at `packages/framework/agents/apt-improver.md`)
|
|
127
|
+
runs Phase 1 — the codebase scan. Phases 2 and 3 run inline in the
|
|
128
|
+
parent agent (no separate sub-agent) because they require user
|
|
129
|
+
interaction for the candidate filter + the deepening loop.
|
|
130
|
+
|
|
131
|
+
## Output contract
|
|
132
|
+
|
|
133
|
+
- Phase 1 outputs a candidate inventory to stdout (not persisted).
|
|
134
|
+
- Phase 2 outputs the top 3-5 to stdout for user selection.
|
|
135
|
+
- Phase 3 (deepening loop) writes locked decisions to
|
|
136
|
+
`.aperant/context/notes/{task-id}.md` via `apt-tools context write`
|
|
137
|
+
and `apt-tools adr write` (the latter only when Nygard's 3-gate
|
|
138
|
+
filter passes — most refactor decisions are reversible and stay in
|
|
139
|
+
context-notes).
|
|
140
|
+
- The skill does NOT emit an implementation plan — that's `/apt:plan`'s
|
|
141
|
+
job. apt:improve produces *what to refactor*; apt:plan produces *how*.
|
package/skills/apt-plan/SKILL.md
CHANGED
|
@@ -110,7 +110,17 @@ If `{task_dir}/design.md` exists (emitted by a prior `/apt:design` run), load it
|
|
|
110
110
|
|
|
111
111
|
## 5. Write Specification
|
|
112
112
|
|
|
113
|
-
Create `spec.md` in the task directory (`{task_dir}` passed from the router, e.g. `.aperant/tasks/{task-id}/spec.md`)
|
|
113
|
+
Create `spec.md` in the task directory (`{task_dir}` passed from the router, e.g. `.aperant/tasks/{task-id}/spec.md`).
|
|
114
|
+
|
|
115
|
+
**Content format branches on track (Fast Path Guarantee — Pocock adoption ID-05):**
|
|
116
|
+
|
|
117
|
+
### 5.A. QUICK track — legacy 4-section format (hard-exempt from PRD upgrade)
|
|
118
|
+
|
|
119
|
+
When `track === "QUICK"` (the `apt:classify` rubric routed this as a one-shot
|
|
120
|
+
task) OR the complexity is `SIMPLE`, write the existing minimal 4-section
|
|
121
|
+
spec. Do NOT promote to PRD shape. The QUICK path is a constraint, not a
|
|
122
|
+
toggle — the user opted into one-shot speed; PRD ceremony would violate
|
|
123
|
+
that contract.
|
|
114
124
|
|
|
115
125
|
```markdown
|
|
116
126
|
# Task: {task description}
|
|
@@ -131,6 +141,79 @@ Create `spec.md` in the task directory (`{task_dir}` passed from the router, e.g
|
|
|
131
141
|
{What this task explicitly does NOT cover}
|
|
132
142
|
```
|
|
133
143
|
|
|
144
|
+
### 5.B. STANDARD / DEEP / COMPLEX tracks — PRD-shaped spec.md
|
|
145
|
+
|
|
146
|
+
When `track ∈ {"STANDARD", "DEEP"}` OR complexity is `STANDARD` or
|
|
147
|
+
`COMPLEX`, write a PRD-shaped spec.md so the artifact survives the task
|
|
148
|
+
and is committable as a second-consumer document. Section ordering is
|
|
149
|
+
**load-bearing** — downstream tooling (`apt-tools coverage-check`,
|
|
150
|
+
`apt-tools consistency check`) reads sections by header.
|
|
151
|
+
|
|
152
|
+
```markdown
|
|
153
|
+
# Spec: {task title}
|
|
154
|
+
|
|
155
|
+
**Task ID:** {task-id}
|
|
156
|
+
**Track:** {STANDARD | DEEP}
|
|
157
|
+
**Scope:** {framework | desktop | web | core | ui | backend | docs}
|
|
158
|
+
|
|
159
|
+
## Problem Statement
|
|
160
|
+
|
|
161
|
+
{What pain are we solving? Cite empirical evidence, prior decisions, or
|
|
162
|
+
codebase artifacts where possible. State what's broken or missing today.}
|
|
163
|
+
|
|
164
|
+
## Solution
|
|
165
|
+
|
|
166
|
+
{One paragraph: the chosen approach. Then a bulleted net delta of what
|
|
167
|
+
ships: new files, modified files, new flags, new config, new skills.}
|
|
168
|
+
|
|
169
|
+
## User Stories
|
|
170
|
+
|
|
171
|
+
{One story per user value slice. Format: "**US-NN (persona).** As a
|
|
172
|
+
{persona}, when I {trigger}, I want {behavior} so I can {outcome}."
|
|
173
|
+
Stories map 1:1 onto subtasks in implementation_plan.json.}
|
|
174
|
+
|
|
175
|
+
## Implementation Decisions
|
|
176
|
+
|
|
177
|
+
{Load-bearing principles carried forward into every subtask. Format:
|
|
178
|
+
"### ID-NN: {decision title}" + rationale + practical consequence. Each
|
|
179
|
+
ID-NN is referenced from subtask descriptions where relevant.}
|
|
180
|
+
|
|
181
|
+
## Testing Decisions
|
|
182
|
+
|
|
183
|
+
{One block per test family: "### TD-NN: {test family name}" + what's
|
|
184
|
+
covered + which subtask owns the test file. Critical: Fast Path Guarantee
|
|
185
|
+
regression tests (QUICK-exempt assertions) MUST be enumerated here.}
|
|
186
|
+
|
|
187
|
+
## Out of Scope
|
|
188
|
+
|
|
189
|
+
{Explicit non-goals. Each bullet names what is deferred + where it
|
|
190
|
+
belongs (parallel track, v2 follow-up, separate task).}
|
|
191
|
+
|
|
192
|
+
## Further Notes
|
|
193
|
+
|
|
194
|
+
{Sequencing rationale, risk surface, dependencies on other parts of the
|
|
195
|
+
codebase, files-affected preview, and any other context the executor
|
|
196
|
+
needs but that doesn't fit the seven primary sections.}
|
|
197
|
+
|
|
198
|
+
### Acceptance Criteria
|
|
199
|
+
|
|
200
|
+
{Cross-cutting AC1..ACN list — each acceptance criterion gets a stable
|
|
201
|
+
ID. Subtasks reference these IDs via their per-subtask
|
|
202
|
+
`acceptance_criteria` field (see Section 6). This list IS the
|
|
203
|
+
plan-coverage-check input.}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Constraint — do NOT interview the user.** The PRD is synthesized from
|
|
207
|
+
the task description + codebase investigation + AGENTS.md, not from a
|
|
208
|
+
clarifying interview. If a section truly cannot be filled, write
|
|
209
|
+
`{TBD — needs user input}` so the gap is visible; do NOT pause for
|
|
210
|
+
clarification (that's `apt:discuss`'s job, not the planner's).
|
|
211
|
+
|
|
212
|
+
**Section ordering is mandatory.** `apt-tools coverage-check validate`
|
|
213
|
+
greps `## Acceptance Criteria` for AC IDs; `apt-tools consistency check`
|
|
214
|
+
greps `## Solution` and `## User Stories`. Renaming or reordering these
|
|
215
|
+
breaks downstream tooling.
|
|
216
|
+
|
|
134
217
|
### 5.1. Design Reference section (C24 — when design.md exists)
|
|
135
218
|
|
|
136
219
|
When `{task_dir}/design.md` exists, `spec.md` MUST include a `## Design Reference` section **directly below `## Requirements`**. The section cites the design artifact by relative path and enumerates which screens and components the subtasks cover. Shape:
|
|
@@ -212,35 +295,95 @@ When `status: warn` (non-blocking enforcement) and the user is in **auto mode**
|
|
|
212
295
|
|
|
213
296
|
## 6. Create Implementation Plan
|
|
214
297
|
|
|
215
|
-
Create `implementation_plan.json` in the task directory (`{task_dir}/implementation_plan.json`)
|
|
298
|
+
Create `implementation_plan.json` in the task directory (`{task_dir}/implementation_plan.json`).
|
|
299
|
+
|
|
300
|
+
**Subtask schema branches on track (Pocock adoption ID-05 — Fast Path Guarantee).**
|
|
301
|
+
|
|
302
|
+
### 6.A. QUICK track / SIMPLE complexity — legacy flat subtask schema
|
|
303
|
+
|
|
304
|
+
```json
|
|
305
|
+
{
|
|
306
|
+
"task": "{task description}",
|
|
307
|
+
"complexity": "simple",
|
|
308
|
+
"spec": "spec.md",
|
|
309
|
+
"subtasks": [
|
|
310
|
+
{
|
|
311
|
+
"id": "1",
|
|
312
|
+
"title": "{subtask title}",
|
|
313
|
+
"description": "{what to do — concrete, not vague}",
|
|
314
|
+
"files": ["path/to/file1.ts", "path/to/file2.ts"],
|
|
315
|
+
"dependencies": [],
|
|
316
|
+
"status": "pending",
|
|
317
|
+
"verification": "{command or check to verify completion}"
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
QUICK subtasks omit `hitl`, `afk`, `acceptance_criteria`, and `user_value`
|
|
324
|
+
fields. The one-shot path doesn't need user-value framing or per-subtask
|
|
325
|
+
HITL gates.
|
|
326
|
+
|
|
327
|
+
### 6.B. STANDARD / DEEP / COMPLEX — vertical-slice subtask schema
|
|
216
328
|
|
|
217
329
|
```json
|
|
218
330
|
{
|
|
219
331
|
"task": "{task description}",
|
|
220
|
-
"complexity": "
|
|
332
|
+
"complexity": "standard|complex",
|
|
221
333
|
"spec": "spec.md",
|
|
334
|
+
"vertical_slice_schema_version": "1",
|
|
222
335
|
"declared_persona_tier": "primary",
|
|
223
336
|
"declared_personas": ["mobile-dev"],
|
|
224
337
|
"tier_confidence": "high",
|
|
225
338
|
"subtasks": [
|
|
226
339
|
{
|
|
227
340
|
"id": "1",
|
|
228
|
-
"title": "{subtask title}",
|
|
341
|
+
"title": "{subtask title — user-value framing, not 'add UI'}",
|
|
229
342
|
"description": "{what to do — concrete, not vague}",
|
|
230
343
|
"files": ["path/to/file1.ts", "path/to/file2.ts"],
|
|
344
|
+
"acceptance_criteria": ["AC1", "AC3"],
|
|
231
345
|
"dependencies": [],
|
|
232
346
|
"status": "pending",
|
|
347
|
+
"hitl": "required | review | none",
|
|
348
|
+
"afk": "safe | unsafe",
|
|
349
|
+
"user_value": "{one-line user-value framing — who benefits, how}",
|
|
233
350
|
"verification": "{command or check to verify completion}"
|
|
234
351
|
}
|
|
235
352
|
]
|
|
236
353
|
}
|
|
237
354
|
```
|
|
238
355
|
|
|
356
|
+
**Mandatory STANDARD/DEEP fields (per subtask):**
|
|
357
|
+
|
|
358
|
+
- `hitl` — `"required" | "review" | "none"`. `required` means a human MUST
|
|
359
|
+
approve the subtask before proceeding (autonomy 1 always pauses;
|
|
360
|
+
autonomy 2 batches recommendations; autonomy 3 escalates only on
|
|
361
|
+
conflict). `review` means the human reviews the diff after the agent
|
|
362
|
+
ships it (post-hoc, not blocking). `none` means agent-only.
|
|
363
|
+
- `afk` — `"safe" | "unsafe"`. `safe` means the agent may proceed
|
|
364
|
+
unattended without supervision. `unsafe` means the agent should pause
|
|
365
|
+
at the start of this subtask if no human is present (autonomy < 3).
|
|
366
|
+
- `acceptance_criteria` — `string[]` of id-refs (`"AC1"`, `"AC3"`, …)
|
|
367
|
+
into the spec.md `## Acceptance Criteria` section. Every AC in spec.md
|
|
368
|
+
MUST be referenced by at least one subtask (gate G8 consistency-check
|
|
369
|
+
enforces this on ship).
|
|
370
|
+
- `user_value` — one-line framing of WHO benefits and HOW. Prevents
|
|
371
|
+
horizontal slicing ("add UI" / "add backend") — every subtask must be
|
|
372
|
+
a vertical user-shippable slice with a defensible value framing.
|
|
373
|
+
|
|
374
|
+
**Plan-level fields for STANDARD/DEEP:**
|
|
375
|
+
|
|
376
|
+
- `vertical_slice_schema_version` — `"1"` (current). Stable across the
|
|
377
|
+
v1 schema window; bumped when the subtask shape changes incompatibly.
|
|
378
|
+
Plans without this field are treated as legacy flat schema.
|
|
379
|
+
|
|
239
380
|
Reference `prompts/planner.md` for subtask decomposition patterns:
|
|
240
381
|
- Each subtask should be completable in one focused session
|
|
241
382
|
- Dependencies must form a DAG (no circular deps)
|
|
242
383
|
- Verification must be automated (test command, grep check, type check)
|
|
243
384
|
- Files list must be exhaustive — every file the subtask touches
|
|
385
|
+
- Subtask title MUST frame user value, not file scope (e.g., "Solo
|
|
386
|
+
dogfooder gets PRD-shaped spec on STANDARD", NOT "edit apt-plan SKILL.md")
|
|
244
387
|
|
|
245
388
|
**Framework-scope doc-sync rule (C33).** When `task.scope === "framework"` AND any subtask's `files` intersect `packages/framework/src/cli/**`, the plan MUST end with a subtask whose title contains `Doc sync` (case-insensitive) and whose `files` list includes at least one of `packages/framework/skills/apt-*/SKILL.md`, `packages/framework/agents/apt-*.md`, `packages/framework/templates/agents-*.md`, or `CLAUDE.md`. The detailed rule and rationale live in `packages/framework/agents/apt-planner.md` §5.1; the planner agent appends this subtask automatically when it would otherwise be missing. Smoke-drain emits a warn-only signal for plans that violate the rule.
|
|
246
389
|
|
package/skills/apt-planner.md
CHANGED
|
@@ -59,7 +59,10 @@ For STANDARD and COMPLEX tasks:
|
|
|
59
59
|
|
|
60
60
|
## 4. Write Specification
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
Content format branches on track (Pocock adoption ID-05, Fast Path Guarantee).
|
|
63
|
+
|
|
64
|
+
### 4.A. QUICK track / SIMPLE complexity — legacy 4-section spec
|
|
65
|
+
|
|
63
66
|
```markdown
|
|
64
67
|
# Task: {task description}
|
|
65
68
|
|
|
@@ -79,6 +82,44 @@ Create `{task_dir}/spec.md`:
|
|
|
79
82
|
{What this task explicitly does NOT cover}
|
|
80
83
|
```
|
|
81
84
|
|
|
85
|
+
### 4.B. STANDARD / DEEP / COMPLEX — PRD-shaped spec.md
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
# Spec: {task title}
|
|
89
|
+
|
|
90
|
+
**Task ID:** {task-id}
|
|
91
|
+
**Track:** {STANDARD | DEEP}
|
|
92
|
+
**Scope:** {framework | desktop | web | core | ui | backend | docs}
|
|
93
|
+
|
|
94
|
+
## Problem Statement
|
|
95
|
+
{What pain are we solving?}
|
|
96
|
+
|
|
97
|
+
## Solution
|
|
98
|
+
{Chosen approach + bulleted net delta.}
|
|
99
|
+
|
|
100
|
+
## User Stories
|
|
101
|
+
{**US-NN (persona).** stories, 1:1 onto subtasks.}
|
|
102
|
+
|
|
103
|
+
## Implementation Decisions
|
|
104
|
+
{### ID-NN load-bearing principles.}
|
|
105
|
+
|
|
106
|
+
## Testing Decisions
|
|
107
|
+
{### TD-NN test families. Fast Path regressions enumerated here.}
|
|
108
|
+
|
|
109
|
+
## Out of Scope
|
|
110
|
+
{Non-goals with deferral target.}
|
|
111
|
+
|
|
112
|
+
## Further Notes
|
|
113
|
+
{Sequencing, risk surface, dependencies, files-affected preview.}
|
|
114
|
+
|
|
115
|
+
### Acceptance Criteria
|
|
116
|
+
{**AC1..ACN** stable IDs referenced by subtasks.}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
PRD section ordering is load-bearing — downstream tooling greps by header.
|
|
120
|
+
Do NOT interview the user; synthesize from task description + codebase +
|
|
121
|
+
AGENTS.md.
|
|
122
|
+
|
|
82
123
|
## 5. Create Implementation Plan
|
|
83
124
|
|
|
84
125
|
Create `{task_dir}/implementation_plan.json`:
|
|
@@ -1454,33 +1454,63 @@ node packages/framework/bin/apt-tools.mjs workflow advance . --id ${REVIEW_ID} -
|
|
|
1454
1454
|
|
|
1455
1455
|
If `WORKTREE_PATH != .` AND fixes were applied in Phase 6/7:
|
|
1456
1456
|
|
|
1457
|
+
Get the PR head ref (for branch reviews, use the branch name directly):
|
|
1457
1458
|
```bash
|
|
1458
|
-
|
|
1459
|
+
PR_HEAD_REF=$(gh pr view ${PR_NUMBER} --json headRefName -q .headRefName)
|
|
1460
|
+
```
|
|
1459
1461
|
|
|
1460
|
-
|
|
1461
|
-
git add -A
|
|
1462
|
-
git commit -m "fix: auto-fix review findings from /apt:pr-review (review ${REVIEW_ID})"
|
|
1462
|
+
#### Confirmation gate (BUG-009 fix)
|
|
1463
1463
|
|
|
1464
|
-
|
|
1465
|
-
# For PRs: push to the PR's head ref
|
|
1466
|
-
git push origin HEAD:${PR_HEAD_REF}
|
|
1464
|
+
Whether the push prompts for confirmation is controlled by `pr_review.confirm_before_push` in `.aperant/config.json` (tri-state: `ask` | `auto` | `never`; default when absent: `auto` at autonomy ≥ 2, `ask` at autonomy < 2). Mirrors the `pr_review.suggest_after_ship` precedent in `/apt:ship` Section 7.1 — `ask` is honest about the irreversible-ish nature of the push (re-triggers CI on origin, visible to teammates); `auto` honors yolo pipelines.
|
|
1467
1465
|
|
|
1468
|
-
|
|
1466
|
+
```bash
|
|
1467
|
+
confirm_mode=$(jq -r '.pr_review.confirm_before_push // empty' .aperant/config.json)
|
|
1468
|
+
autonomy=$(jq -r '.autonomy.default // 2' .aperant/config.json)
|
|
1469
|
+
if [ -z "$confirm_mode" ]; then
|
|
1470
|
+
if [ "${autonomy}" -ge 2 ]; then confirm_mode="auto"; else confirm_mode="ask"; fi
|
|
1471
|
+
fi
|
|
1469
1472
|
```
|
|
1470
1473
|
|
|
1471
|
-
|
|
1474
|
+
Branch on `confirm_mode`:
|
|
1475
|
+
|
|
1476
|
+
- **`never`** — Skip push entirely. Print "fixes left in worktree; push manually with `git -C ${WORKTREE_PATH} push origin HEAD:${PR_HEAD_REF}`". Proceed to Step 0b cleanup.
|
|
1477
|
+
- **`auto`** — Proceed silently to the catch-all + push below. No prompt.
|
|
1478
|
+
- **`ask`** — Emit the structured question: `Fixes are ready in the worktree. Push to ${PR_HEAD_REF}? (y/n)`. On `n` or any non-`y`: same skip behavior as `never`. On `y` (or empty enter): proceed.
|
|
1479
|
+
|
|
1480
|
+
`confirm_before_push` is purely additive — it does not affect `authorship_override`, `authorship_overrides`, `max_rounds`, or `suggest_after_ship` in the same `pr_review` block.
|
|
1481
|
+
|
|
1482
|
+
#### Catch-all + push (BUG-010 fix)
|
|
1483
|
+
|
|
1484
|
+
The fixer pipeline normally produces atomic per-finding commits, so the worktree is clean by the time Step 0 runs. The catch-all commit below exists ONLY to capture uncommitted residue (rare — e.g. a fixer's pre-return self-audit failed to detect a stray edit). Guard it before committing:
|
|
1485
|
+
|
|
1472
1486
|
```bash
|
|
1473
|
-
|
|
1474
|
-
```
|
|
1487
|
+
cd ${WORKTREE_PATH}
|
|
1475
1488
|
|
|
1476
|
-
|
|
1489
|
+
# Guard 1: skip the catch-all entirely if the tree is clean.
|
|
1490
|
+
# Per-finding commits with proper messages are strictly better history than a single catch-all.
|
|
1491
|
+
if ! git diff --quiet || ! git diff --cached --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]; then
|
|
1492
|
+
# Guard 2: explicit allowlist instead of `git add -A`.
|
|
1493
|
+
# `git add -A` would sweep orchestrator-level Read/Write side-effects
|
|
1494
|
+
# (metadata.json, audit.json, validated.md, etc.) into the PR. Bad.
|
|
1495
|
+
# Stage ONLY files in the review's touched set, computed from the iteration diffs.
|
|
1496
|
+
REVIEW_TOUCHED=$(git diff --name-only ${ITERATION_START_SHA:-HEAD~4}..HEAD 2>/dev/null \
|
|
1497
|
+
| grep -v '^\.aperant/' \
|
|
1498
|
+
| tr '\n' ' ')
|
|
1499
|
+
if [ -n "$REVIEW_TOUCHED" ]; then
|
|
1500
|
+
# shellcheck disable=SC2086
|
|
1501
|
+
git add -- $REVIEW_TOUCHED
|
|
1502
|
+
fi
|
|
1503
|
+
# Only commit if `git add --` actually staged something.
|
|
1504
|
+
if ! git diff --cached --quiet; then
|
|
1505
|
+
git commit -m "fix: auto-fix review findings from /apt:pr-review (review ${REVIEW_ID})"
|
|
1506
|
+
fi
|
|
1507
|
+
fi
|
|
1477
1508
|
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
Fixes are ready in the worktree. Push to ${PR_HEAD_REF}? (y/n)
|
|
1509
|
+
git push origin HEAD:${PR_HEAD_REF}
|
|
1510
|
+
cd -
|
|
1481
1511
|
```
|
|
1482
1512
|
|
|
1483
|
-
|
|
1513
|
+
Two guards. The outer `if` skips the whole catch-all path when the tree is clean. The inner allowlist (filter to files in the iteration-diff scope, minus anything under `.aperant/`) prevents `git add` from sweeping arbitrary orchestrator side-effects into the PR. Both guards default to the safe no-op shape on the happy path (fixers committed atomically, clean tree).
|
|
1484
1514
|
|
|
1485
1515
|
### Step 0b: Cleanup Worktree
|
|
1486
1516
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Adapted from Matt Pocock's MIT-licensed skill suite:
|
|
3
|
+
https://github.com/mattpocock/skills/blob/main/skills/engineering/prototype/LOGIC.md
|
|
4
|
+
Licensed under MIT. Modifications: scoped to terminal-app prototypes
|
|
5
|
+
that validate state machines, protocols, and control flow. Aligned with
|
|
6
|
+
the 5 universal rules in apt-prototype/SKILL.md.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# LOGIC branch — Terminal app for state-machine validation
|
|
10
|
+
|
|
11
|
+
When the user's question is about **behavior**, the prototype is a
|
|
12
|
+
single terminal app that the user runs and watches. The output prints
|
|
13
|
+
every state transition so the user can FEEL whether the logic works,
|
|
14
|
+
not just reason about it.
|
|
15
|
+
|
|
16
|
+
## When this branch fires
|
|
17
|
+
|
|
18
|
+
Question types that route here:
|
|
19
|
+
|
|
20
|
+
- "Does this state machine work?"
|
|
21
|
+
- "Does this control flow handle edge case X?"
|
|
22
|
+
- "Can this protocol handle out-of-order messages?"
|
|
23
|
+
- "What does the worker pool do under back-pressure?"
|
|
24
|
+
- "Does this retry policy actually converge?"
|
|
25
|
+
|
|
26
|
+
Question types that DO NOT route here (use UI branch instead):
|
|
27
|
+
|
|
28
|
+
- "Does this UI shape feel right?"
|
|
29
|
+
- "Is this flow discoverable?"
|
|
30
|
+
- "Does this layout work on mobile?"
|
|
31
|
+
|
|
32
|
+
## File shape
|
|
33
|
+
|
|
34
|
+
ONE file. Pick the project's primary runtime (TypeScript via `tsx`,
|
|
35
|
+
JavaScript via `node`, Python via `python3`, etc.). The shape:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
// THROWAWAY PROTOTYPE — do not merge, do not extend, do not test.
|
|
39
|
+
// Question: "{verbatim question from user}"
|
|
40
|
+
// Decision criterion: "{what does 'yes' look like? what does 'no' look like?}"
|
|
41
|
+
|
|
42
|
+
// --- State machine model ---
|
|
43
|
+
// {Declare states, transitions, and any guards.}
|
|
44
|
+
|
|
45
|
+
// --- Transition driver ---
|
|
46
|
+
// {A function that takes (currentState, event) and returns nextState,
|
|
47
|
+
// PRINTING every transition so the user can see what's happening.}
|
|
48
|
+
|
|
49
|
+
// --- Scripted run ---
|
|
50
|
+
// {5-10 sequential transitions that exercise the interesting paths.}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Single-command invocation
|
|
54
|
+
|
|
55
|
+
The prototype runs with ONE command. Examples:
|
|
56
|
+
|
|
57
|
+
- `node prototype.mjs` — no transpile, no build, no install
|
|
58
|
+
- `pnpm dlx tsx prototype.ts` — uses dlx so no dependency added to the project
|
|
59
|
+
- `python3 prototype.py` — no virtualenv setup
|
|
60
|
+
|
|
61
|
+
If your prototype needs any of: webpack, vite, esbuild, a database
|
|
62
|
+
connection, an environment variable — you are prototyping the wrong
|
|
63
|
+
question. Re-scope to the BEHAVIOR question; the infrastructure is a
|
|
64
|
+
separate concern.
|
|
65
|
+
|
|
66
|
+
## Surface-state-transparently — concrete examples
|
|
67
|
+
|
|
68
|
+
A terminal app prints state transitions inline:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
[T+0] state=IDLE
|
|
72
|
+
[T+1] event=user.click.submit → state=SUBMITTING
|
|
73
|
+
[T+2] event=network.timeout → state=RETRYING (attempt 1)
|
|
74
|
+
[T+3] event=network.timeout → state=RETRYING (attempt 2)
|
|
75
|
+
[T+4] event=network.timeout → state=FAILED (exceeded retries)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The user reads this output and either says "yes that's what I wanted"
|
|
79
|
+
or "no, the retry policy needs jitter" — and the question is answered
|
|
80
|
+
in 30 seconds of looking, not 3 hours of staring at a flowchart.
|
|
81
|
+
|
|
82
|
+
If the state machine has parallel regions or hierarchical states, print
|
|
83
|
+
the full state vector at each transition, not just the leaf state.
|
|
84
|
+
|
|
85
|
+
## When the scripted run isn't enough
|
|
86
|
+
|
|
87
|
+
If the user needs to drive the state machine interactively (the
|
|
88
|
+
question is "what happens when I hit submit twice quickly?"), add a
|
|
89
|
+
tiny REPL loop:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
> submit
|
|
93
|
+
[T+1] event=user.click.submit → state=SUBMITTING
|
|
94
|
+
> submit
|
|
95
|
+
[T+2] event=user.click.submit (REJECTED — already submitting)
|
|
96
|
+
[T+2] state=SUBMITTING
|
|
97
|
+
> timeout
|
|
98
|
+
[T+3] event=network.timeout → state=RETRYING (attempt 1)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Keep the REPL parser dumb (split on space, no quoting, no escape
|
|
102
|
+
handling). The user isn't testing your parser; they're testing the
|
|
103
|
+
state machine.
|
|
104
|
+
|
|
105
|
+
## Throwaway discipline reminder
|
|
106
|
+
|
|
107
|
+
When the question is answered, delete the prototype file. Do not let it
|
|
108
|
+
linger as "documentation of the design decision" — that's what
|
|
109
|
+
`apt-tools adr write` or `.aperant/context/notes/` are for.
|