@aperant/framework 0.16.0 → 0.19.0
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 +185 -1
- package/dist/cli/commands/ci-watch.mjs +49 -2
- package/dist/cli/commands/ci-watch.mjs.map +1 -1
- package/dist/cli/commands/commit.mjs +3 -3
- package/dist/cli/commands/commit.mjs.map +1 -1
- package/dist/cli/commands/event.mjs +16 -16
- package/dist/cli/commands/event.mjs.map +1 -1
- package/dist/cli/commands/merge-integrate.mjs +3 -3
- package/dist/cli/commands/merge-integrate.mjs.map +1 -1
- package/dist/cli/commands/produce.d.mts +9 -0
- package/dist/cli/commands/produce.d.mts.map +1 -0
- package/dist/cli/commands/produce.mjs +1345 -0
- package/dist/cli/commands/produce.mjs.map +1 -0
- package/dist/cli/commands/spar-resolve-partner.d.mts +9 -0
- package/dist/cli/commands/spar-resolve-partner.d.mts.map +1 -0
- package/dist/cli/commands/spar-resolve-partner.mjs +82 -0
- package/dist/cli/commands/spar-resolve-partner.mjs.map +1 -0
- package/dist/cli/commands/task.d.mts +16 -1
- package/dist/cli/commands/task.d.mts.map +1 -1
- package/dist/cli/commands/task.mjs +434 -266
- package/dist/cli/commands/task.mjs.map +1 -1
- package/dist/cli/config/gitignore-drift.d.mts.map +1 -1
- package/dist/cli/config/gitignore-drift.mjs +1 -0
- package/dist/cli/config/gitignore-drift.mjs.map +1 -1
- package/dist/cli/config/post-merge-sweep.d.mts.map +1 -1
- package/dist/cli/config/post-merge-sweep.mjs +1 -0
- package/dist/cli/config/post-merge-sweep.mjs.map +1 -1
- package/dist/cli/coordination/auto-emit-artifact-ready.mjs +5 -5
- package/dist/cli/coordination/auto-emit-artifact-ready.mjs.map +1 -1
- package/dist/cli/coordination/event-schema.d.mts +5 -3
- package/dist/cli/coordination/event-schema.d.mts.map +1 -1
- package/dist/cli/coordination/event-schema.mjs +245 -21
- package/dist/cli/coordination/event-schema.mjs.map +1 -1
- package/dist/cli/coordination/store.d.mts +2 -2
- package/dist/cli/coordination/store.mjs +4 -4
- package/dist/cli/coordination/store.mjs.map +1 -1
- package/dist/cli/dispatch.d.mts.map +1 -1
- package/dist/cli/dispatch.mjs +4 -0
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/help.d.mts.map +1 -1
- package/dist/cli/help.mjs +31 -0
- package/dist/cli/help.mjs.map +1 -1
- package/dist/cli/host/codex-config.d.mts +78 -0
- package/dist/cli/host/codex-config.d.mts.map +1 -0
- package/dist/cli/host/codex-config.mjs +169 -0
- package/dist/cli/host/codex-config.mjs.map +1 -0
- package/dist/cli/install/legacy-paths.d.mts.map +1 -1
- package/dist/cli/install/legacy-paths.mjs +2 -0
- package/dist/cli/install/legacy-paths.mjs.map +1 -1
- package/dist/cli/produce/blind-probe.d.mts +85 -0
- package/dist/cli/produce/blind-probe.d.mts.map +1 -0
- package/dist/cli/produce/blind-probe.mjs +217 -0
- package/dist/cli/produce/blind-probe.mjs.map +1 -0
- package/dist/cli/produce/claim.d.mts +188 -0
- package/dist/cli/produce/claim.d.mts.map +1 -0
- package/dist/cli/produce/claim.mjs +518 -0
- package/dist/cli/produce/claim.mjs.map +1 -0
- package/dist/cli/produce/done-gate.d.mts +87 -0
- package/dist/cli/produce/done-gate.d.mts.map +1 -0
- package/dist/cli/produce/done-gate.mjs +200 -0
- package/dist/cli/produce/done-gate.mjs.map +1 -0
- package/dist/cli/produce/events.d.mts +77 -0
- package/dist/cli/produce/events.d.mts.map +1 -0
- package/dist/cli/produce/events.mjs +126 -0
- package/dist/cli/produce/events.mjs.map +1 -0
- package/dist/cli/produce/evidence-oracle.d.mts +63 -0
- package/dist/cli/produce/evidence-oracle.d.mts.map +1 -0
- package/dist/cli/produce/evidence-oracle.mjs +122 -0
- package/dist/cli/produce/evidence-oracle.mjs.map +1 -0
- package/dist/cli/produce/ledger.d.mts +140 -0
- package/dist/cli/produce/ledger.d.mts.map +1 -0
- package/dist/cli/produce/ledger.mjs +272 -0
- package/dist/cli/produce/ledger.mjs.map +1 -0
- package/dist/cli/produce/probe-family.d.mts +53 -0
- package/dist/cli/produce/probe-family.d.mts.map +1 -0
- package/dist/cli/produce/probe-family.mjs +160 -0
- package/dist/cli/produce/probe-family.mjs.map +1 -0
- package/dist/cli/produce/projection.d.mts +55 -0
- package/dist/cli/produce/projection.d.mts.map +1 -0
- package/dist/cli/produce/projection.mjs +97 -0
- package/dist/cli/produce/projection.mjs.map +1 -0
- package/dist/cli/produce/run-id.d.mts +42 -0
- package/dist/cli/produce/run-id.d.mts.map +1 -0
- package/dist/cli/produce/run-id.mjs +79 -0
- package/dist/cli/produce/run-id.mjs.map +1 -0
- package/dist/cli/produce/saga.d.mts +180 -0
- package/dist/cli/produce/saga.d.mts.map +1 -0
- package/dist/cli/produce/saga.mjs +290 -0
- package/dist/cli/produce/saga.mjs.map +1 -0
- package/dist/cli/produce/scheduler.d.mts +165 -0
- package/dist/cli/produce/scheduler.d.mts.map +1 -0
- package/dist/cli/produce/scheduler.mjs +399 -0
- package/dist/cli/produce/scheduler.mjs.map +1 -0
- package/dist/cli/produce/setpoint.d.mts +52 -0
- package/dist/cli/produce/setpoint.d.mts.map +1 -0
- package/dist/cli/produce/setpoint.mjs +113 -0
- package/dist/cli/produce/setpoint.mjs.map +1 -0
- package/dist/cli/produce/verification-ttl.d.mts +75 -0
- package/dist/cli/produce/verification-ttl.d.mts.map +1 -0
- package/dist/cli/produce/verification-ttl.mjs +169 -0
- package/dist/cli/produce/verification-ttl.mjs.map +1 -0
- package/dist/cli/roadmap/{conductor-view.d.mts → showrunner-view.d.mts} +3 -3
- package/dist/cli/roadmap/showrunner-view.d.mts.map +1 -0
- package/dist/cli/roadmap/{conductor-view.mjs → showrunner-view.mjs} +7 -7
- package/dist/cli/roadmap/showrunner-view.mjs.map +1 -0
- package/dist/cli/wfrun/run.d.mts.map +1 -1
- package/dist/cli/wfrun/run.mjs +1 -0
- package/dist/cli/wfrun/run.mjs.map +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +2 -1
- package/dist/plugin/skills/apt/SKILL.md +112 -38
- package/dist/plugin/skills/apt-debug/SKILL.md +14 -24
- package/dist/plugin/skills/apt-fan-out/SKILL.md +4 -4
- package/dist/plugin/skills/apt-handoff/SKILL.md +1 -1
- package/dist/plugin/skills/apt-plan/SKILL.md +5 -5
- package/dist/plugin/skills/apt-plan/adapters/{conductor.md → showrunner.md} +16 -16
- package/dist/plugin/skills/apt-produce/SKILL.md +606 -0
- package/dist/plugin/skills/apt-quick/SKILL.md +14 -22
- package/dist/plugin/skills/apt-run/SKILL.md +126 -3
- package/dist/plugin/skills/apt-ship/SKILL.md +2 -0
- package/dist/plugin/skills/apt-spar/SKILL.md +19 -9
- package/dist/plugin/skills/apt-watch-ci/SKILL.md +4 -4
- package/package.json +4 -4
- package/prompts/{conductor-framework-context.md → showrunner-framework-context.md} +1 -1
- package/prompts/{conductor-status-check.md → showrunner-status-check.md} +1 -1
- package/prompts/{conductor-sub-agent.md → showrunner-sub-agent.md} +6 -6
- package/prompts/{conductor-system.md → showrunner-system.md} +8 -8
- package/skills/apt/SKILL.md +112 -38
- package/skills/apt-debug/SKILL.md +14 -24
- package/skills/apt-fan-out/SKILL.md +4 -4
- package/skills/apt-handoff/SKILL.md +1 -1
- package/skills/apt-plan/SKILL.md +5 -5
- package/skills/apt-plan/adapters/{conductor.md → showrunner.md} +16 -16
- package/skills/apt-produce/SKILL.md +606 -0
- package/skills/apt-quick/SKILL.md +14 -22
- package/skills/apt-run/SKILL.md +126 -3
- package/skills/apt-ship/SKILL.md +2 -0
- package/skills/apt-spar/SKILL.md +19 -9
- package/skills/apt-watch-ci/SKILL.md +4 -4
- package/src/cli/commands/ci-watch.mjs +51 -2
- package/src/cli/commands/commit.mjs +3 -3
- package/src/cli/commands/event.mjs +16 -16
- package/src/cli/commands/merge-integrate.mjs +3 -3
- package/src/cli/commands/produce.mjs +1466 -0
- package/src/cli/commands/spar-resolve-partner.mjs +85 -0
- package/src/cli/commands/task.mjs +482 -285
- package/src/cli/config/gitignore-drift.mjs +1 -0
- package/src/cli/config/post-merge-sweep.mjs +1 -0
- package/src/cli/coordination/auto-emit-artifact-ready.mjs +5 -5
- package/src/cli/coordination/event-schema.d.ts +4 -2
- package/src/cli/coordination/event-schema.mjs +276 -21
- package/src/cli/coordination/store.mjs +4 -4
- package/src/cli/dispatch.mjs +4 -0
- package/src/cli/help.mjs +31 -0
- package/src/cli/host/codex-config.mjs +165 -0
- package/src/cli/install/legacy-paths.mjs +2 -0
- package/src/cli/produce/blind-probe.mjs +245 -0
- package/src/cli/produce/claim.mjs +543 -0
- package/src/cli/produce/done-gate.mjs +238 -0
- package/src/cli/produce/events.mjs +131 -0
- package/src/cli/produce/evidence-oracle.mjs +133 -0
- package/src/cli/produce/ledger.mjs +284 -0
- package/src/cli/produce/probe-family.mjs +168 -0
- package/src/cli/produce/projection.mjs +105 -0
- package/src/cli/produce/run-id.mjs +84 -0
- package/src/cli/produce/saga.mjs +303 -0
- package/src/cli/produce/scheduler.mjs +423 -0
- package/src/cli/produce/setpoint.mjs +122 -0
- package/src/cli/produce/verification-ttl.mjs +191 -0
- package/src/cli/roadmap/showrunner-view.d.ts +10 -0
- package/src/cli/roadmap/{conductor-view.mjs → showrunner-view.mjs} +6 -6
- package/src/cli/wfrun/run.mjs +1 -0
- package/dist/cli/roadmap/conductor-view.d.mts.map +0 -1
- package/dist/cli/roadmap/conductor-view.mjs.map +0 -1
- package/src/cli/roadmap/conductor-view.d.ts +0 -10
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apt:produce
|
|
3
|
+
description: "Outer loop (M1+M2) — freeze an outcome as an immutable setpoint, project a crash-safe roadmap from the append-only event log, one wake tick per invocation, gate `done` behind a cross-family oracle + a held-out blind probe."
|
|
4
|
+
apt-skill-version: {{APT_VERSION}}
|
|
5
|
+
stage: ops
|
|
6
|
+
intent: x-produce
|
|
7
|
+
when_to_use: "You have ONE outcome to drive over time and want a frozen acceptance setpoint plus a crash-safe, event-sourced roadmap that a host wake-beat re-reads from disk one tick at a time — no daemon, no in-skill polling loop. M2 unlocks `done` behind a two-gate adjudication: the visible oracle (verify-proof `approved` + an independent cross-family evidence-quality judge) AND a held-out blind cross-family probe must both pass; otherwise the milestone stays open and a reward-hacking canary logs the gap."
|
|
8
|
+
user_invocable: true
|
|
9
|
+
internal: false
|
|
10
|
+
spawns_agent: false
|
|
11
|
+
agent_name: null
|
|
12
|
+
task_context: self-managed
|
|
13
|
+
default_execution_mode: auto
|
|
14
|
+
execution_modes:
|
|
15
|
+
- auto
|
|
16
|
+
- step
|
|
17
|
+
allowed-tools: "Bash, Read, Write, Edit, Grep, Glob"
|
|
18
|
+
argument-hint: "apt:produce \"<outcome>\" | apt:produce --tick --run-id <id>"
|
|
19
|
+
gates: []
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# /apt:produce — Outer loop (M1 + M2 + M3 + M4 + M5 + M6)
|
|
23
|
+
|
|
24
|
+
You take **one outcome** and stand up the minimum viable outer loop: a **frozen
|
|
25
|
+
acceptance setpoint** written once and never mutated, and an **event-sourced
|
|
26
|
+
roadmap** projected from the existing append-only substrate. The long run is a
|
|
27
|
+
**host wake-beat** — one tick per invocation. No daemon. No in-skill polling
|
|
28
|
+
loop.
|
|
29
|
+
|
|
30
|
+
This skill is **one-tick-per-invocation** (ID-05). It MUST NOT enter a polling
|
|
31
|
+
loop. The recurring beat is delivered externally — by Claude Code's
|
|
32
|
+
`CronCreate` on cron-capable hosts, or by the user re-invoking
|
|
33
|
+
`/apt:produce --tick --run-id <id>` on non-cron hosts. Each wake invocation does
|
|
34
|
+
exactly one tick, then exits.
|
|
35
|
+
|
|
36
|
+
**Scope.** M1 freezes the setpoint, seeds + projects the roadmap crash-safely,
|
|
37
|
+
and re-reads from disk on each wake tick. **M2** unlocks `done` behind a
|
|
38
|
+
two-gate adjudication — an independent cross-family evidence-quality oracle over
|
|
39
|
+
verify-proof's captured evidence AND a held-out blind cross-family probe the
|
|
40
|
+
implementer never sees. **M3** adds closed-loop convergence: an
|
|
41
|
+
acceptance-criteria ledger whose open count **V** must strictly decrease across
|
|
42
|
+
shipped milestones (the Lyapunov property), with an anti-windup guard that
|
|
43
|
+
rejects any un-sanctioned increase. **M4** is the anti-degradation layer: the
|
|
44
|
+
loop is a **saga** (plan→execute→verify→review→ship) where each phase declares a
|
|
45
|
+
**FORWARD compensator** (a failed verify **ships a revert** + reopens + re-plans;
|
|
46
|
+
you NEVER roll back a merged PR), a **verification-TTL** re-verifies a rotating
|
|
47
|
+
sample of OLD done milestones against HEAD **each tick** and flags regressions,
|
|
48
|
+
and **provider-diverse review** is a RULE (reviewer family ≠ implementer). **M5**
|
|
49
|
+
is the **WSJF/WIP scheduler**: the wake tick now advances the highest-leverage
|
|
50
|
+
READY milestone under a WIP budget — ranked by `WSJF = cost-of-delay / job-size`
|
|
51
|
+
(regression > blocking > open-value > priority), dependency-aware (a milestone
|
|
52
|
+
whose deps aren't `done` is `blocked`, a cycle is surfaced, never a silent idle),
|
|
53
|
+
and M4-regression-aware (a regressed `done` milestone re-enters the ready queue).
|
|
54
|
+
**M6** is the **Claim Envelope**: a durable, bounded, expiring way to CAPTURE a
|
|
55
|
+
review-lesson as a first-class claim and CONSUME it as a concrete AC / subtask /
|
|
56
|
+
proof-obligation DELTA — never a lesson-text context paste. It is interop, not a
|
|
57
|
+
4th store (a fold + a per-record content file on the SAME substrate), it
|
|
58
|
+
generalizes past `lesson` as a data-driven profile registry, and expiry + HEAD
|
|
59
|
+
re-validation keep the corrective loop from corroding. The outer loop is now
|
|
60
|
+
**feature-complete** (M1–M6). See §5 (done-adjudication) + §6 (cross-family
|
|
61
|
+
dispatch) + §7 (probe-blindness) + §8 (Lyapunov monotone progress) + §9 (saga +
|
|
62
|
+
forward compensators) + §10 (provider-diverse review) + §11 (verification-TTL) +
|
|
63
|
+
§12 (WSJF/WIP scheduler) + §13 (Claim Envelope).
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Your environment
|
|
68
|
+
|
|
69
|
+
- **Working directory:** the project root (or any worktree — the run dir
|
|
70
|
+
resolves to the shared main repo).
|
|
71
|
+
- **apt-tools path:** `node .aperant/deps/node_modules/@aperant/framework/bin/apt-tools.mjs`
|
|
72
|
+
(or `node packages/framework/bin/apt-tools.mjs` when developing the framework).
|
|
73
|
+
- **Run artifacts:** `.aperant/produce/<run-id>/setpoint.json` (frozen,
|
|
74
|
+
immutable) + `.aperant/produce/<run-id>/roadmap.json` (a DERIVED cache,
|
|
75
|
+
regenerable from the log — never the authority).
|
|
76
|
+
- **Events:** every mutation appends one line to `.aperant/events/{today}.jsonl`
|
|
77
|
+
— `produce.run.started` + `produce.setpoint.frozen` at start,
|
|
78
|
+
`produce.roadmap.milestone_added` / `produce.roadmap.milestone_status_changed`
|
|
79
|
+
on roadmap edits, `produce.tick` on each wake beat. M2 adds the oracle/probe
|
|
80
|
+
forensic trail: `produce.milestone.implemented`, `produce.probe.frozen`
|
|
81
|
+
(hash + author family only — NEVER probe content), `produce.probe.run`
|
|
82
|
+
(result/family/head_sha only), `produce.oracle.judged`, `produce.oracle.verdict`,
|
|
83
|
+
`produce.oracle.probe_gap`. M3 adds the Lyapunov acceptance-criteria ledger:
|
|
84
|
+
`produce.criteria.declared` / `produce.criteria.closed` / `produce.scope.changed`.
|
|
85
|
+
M4 adds the saga + verification-TTL trail: `produce.saga.phase_entered` /
|
|
86
|
+
`produce.saga.phase_completed` / `produce.saga.compensated` /
|
|
87
|
+
`produce.saga.reviewed` / `produce.ttl.reverified` /
|
|
88
|
+
`produce.ttl.regression_detected` (the saga-phase ops enforce a closed
|
|
89
|
+
`plan|execute|verify|review|ship` vocabulary; no op carries probe/review
|
|
90
|
+
content). M5 adds `produce.schedule.computed` (emitted once per `tick` — the
|
|
91
|
+
scheduler's recorded pick; content-blind: `picked` ids + `wip_limit` only, never
|
|
92
|
+
folded by the roadmap projection). Schema-gated (`event-schema.mjs`) so a
|
|
93
|
+
malformed event is rejected fail-closed.
|
|
94
|
+
- **CLI surface:** `apt-tools produce <start|add-milestone|set-milestone-status|status|tick>`
|
|
95
|
+
(M1) + `<record-implementer|resolve-probe-family|oracle prepare|oracle record|probe freeze|probe record|probe sweep|canary>`
|
|
96
|
+
(M2) + `<declare-criteria|progress>` (M3) +
|
|
97
|
+
`<saga enter|saga complete|saga compensate|saga review|saga resolve-reviewer|saga status|ttl select|ttl reverify>`
|
|
98
|
+
(M4) + `<schedule>` (M5 — the WSJF/WIP ranking + WIP-limited pick; `add-milestone`
|
|
99
|
+
gains OPTIONAL `--depends-on`/`--priority`/`--size`). The subcommands do the
|
|
100
|
+
deterministic work — DO NOT re-implement the projection, the setpoint freeze, the
|
|
101
|
+
probe hash, the gate, the ledger fold, the compensator table, the TTL rotation,
|
|
102
|
+
or the WSJF math in your prompt.
|
|
103
|
+
- **Probe artifacts:** `.aperant/produce/<run-id>/probes/<milestone>.json` (the
|
|
104
|
+
frozen blind-probe set — immutable, hash-stamped; its CONTENT is blind to the
|
|
105
|
+
event log + roadmap projection).
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## §1. First invocation — freeze the setpoint + seed the roadmap
|
|
110
|
+
|
|
111
|
+
Given one outcome string:
|
|
112
|
+
|
|
113
|
+
1. **Freeze the setpoint.** Run:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
apt-tools produce start . --outcome "<outcome>"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
This writes an immutable `setpoint.json` (hash-stamped, exclusive-create) and
|
|
120
|
+
returns `{ run_id, setpoint_hash, setpoint_path }`. **Record the `run_id`** —
|
|
121
|
+
every later invocation needs it. Re-running `start` with `--run-id <id>` is
|
|
122
|
+
idempotent-reuse: it returns the byte-identical setpoint, never an overwrite
|
|
123
|
+
(ID-02). The setpoint is the fixed external reference — it cannot drift.
|
|
124
|
+
|
|
125
|
+
2. **Seed milestones.** For each milestone the outcome decomposes into:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
apt-tools produce add-milestone . --run-id <id> --title "<milestone title>"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Each append lands a `produce.roadmap.milestone_added` event and refreshes the
|
|
132
|
+
derived roadmap projection. Milestones seed at status `planned`.
|
|
133
|
+
|
|
134
|
+
3. **Reschedule the first wake tick** — see §3.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## §2. Wake beat — one tick
|
|
139
|
+
|
|
140
|
+
On each wake beat run exactly ONE tick and then exit:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
apt-tools produce tick . --run-id <id>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The `tick` subcommand does exactly one of the following, once, then returns:
|
|
147
|
+
|
|
148
|
+
- re-projects the roadmap from the append-only event log (ID-01 — no in-memory
|
|
149
|
+
authority, re-read from disk every time);
|
|
150
|
+
- folds the M5 WSJF/WIP **schedule** (dependency-aware, regression-aware) under
|
|
151
|
+
the resolved WIP budget (`--wip N` → config `produce.wip` → default 1);
|
|
152
|
+
- appends a `produce.tick` event + ONE `produce.schedule.computed`;
|
|
153
|
+
- computes `next_action` from the schedule (§12): `continue_milestone` for an
|
|
154
|
+
in-progress one (unconditional), else `start_milestone` for the **top WSJF ready
|
|
155
|
+
pick under the WIP budget**, else `idle` (carrying the schedule's reason);
|
|
156
|
+
- returns `{ run_id, roadmap, next_action, schedule, next_tick_hint }`.
|
|
157
|
+
|
|
158
|
+
Act on `next_action` (advance the named milestone via `set-milestone-status`, or
|
|
159
|
+
dispatch its work), then **reschedule** per §3 and **exit**. You may also mark a
|
|
160
|
+
milestone `in_progress` when you begin it:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
apt-tools produce set-milestone-status . --run-id <id> --milestone <mid> --status in_progress
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## §3. Reschedule — the host beat (two branches)
|
|
169
|
+
|
|
170
|
+
The recurring beat is the HOST's, never yours. Pick the branch for your host:
|
|
171
|
+
|
|
172
|
+
- **Cron-capable host (Claude Code).** Refresh the `CronCreate` entry's
|
|
173
|
+
next-fire timestamp so the next tick fires automatically (CronCreate is
|
|
174
|
+
idempotent on the same payload). This mirrors `apt-watch-ci` §3 step 4. The
|
|
175
|
+
cron payload's invocation form is `/apt:produce --tick --run-id <id>`.
|
|
176
|
+
|
|
177
|
+
- **Non-cron host.** Print the honest manual line and stop — do NOT register a
|
|
178
|
+
cron the host cannot honor, and do NOT fake a scheduler (the framework would
|
|
179
|
+
be lying). This mirrors `apt-watch-ci` §8:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
Next tick: run `apt-tools produce tick . --run-id <id>` again when you return.
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## §4. Single-execution-mode contract (the most easily-broken invariant)
|
|
188
|
+
|
|
189
|
+
- One tick = one invocation. Do NOT wrap the §2 tick in a polling loop.
|
|
190
|
+
- Do NOT sleep and then re-invoke yourself inside a single session.
|
|
191
|
+
- The recurring beat is delivered by host cron OR by the user re-invoking the
|
|
192
|
+
skill manually. The loop's value comes from the host scheduler — it does not
|
|
193
|
+
impersonate one.
|
|
194
|
+
|
|
195
|
+
If you find yourself wanting to add "and then wait N minutes and run again",
|
|
196
|
+
STOP. The skill is finished after one tick. Exit.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## §5. Done-adjudication (M2) — the Showrunner never self-attests "done" (ID-03)
|
|
201
|
+
|
|
202
|
+
The Showrunner is planner + prosecutor, **never** the judge. `done` is reachable
|
|
203
|
+
ONLY through recorded external evidence + a blind cross-family probe — the skill
|
|
204
|
+
physically cannot let the Showrunner's prose mark a milestone done. A milestone
|
|
205
|
+
flips to `done` ONLY when the **visible gate** AND the **blind gate** both pass;
|
|
206
|
+
otherwise it stays open and a reward-hacking canary logs the gap.
|
|
207
|
+
|
|
208
|
+
When a milestone's implementation is claimed done, walk these steps IN ORDER:
|
|
209
|
+
|
|
210
|
+
1. **Record who implemented it** (the cross-family disjointness anchor, ID-M2-02):
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
apt-tools produce record-implementer . --run-id <id> --milestone <mid> --implementer-family <fam>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`<fam>` is one of `claude | codex | gemini` (the family that did the work).
|
|
217
|
+
Every later cross-family check reads this recorded fact; if it is absent,
|
|
218
|
+
adjudication is impossible (fail-closed).
|
|
219
|
+
|
|
220
|
+
2. **Resolve a probe/oracle family DISJOINT from the implementer** (§6):
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
apt-tools produce resolve-probe-family . --run-id <id> --milestone <mid> [--host-family <fam>]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Returns a `probe_family` ≠ the implementer family plus a LIVE-resolved model
|
|
227
|
+
(never a hardcoded id) + a `transport_hint`. `available:false` when no
|
|
228
|
+
disjoint family exists (a single-family setup cannot satisfy the rule by
|
|
229
|
+
design — it CANNOT reach done).
|
|
230
|
+
|
|
231
|
+
3. **Author 10–20 behavioral probes in that disjoint family + freeze them**
|
|
232
|
+
(probe-blindness, §7):
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
apt-tools produce probe freeze . --run-id <id> --milestone <mid> --probe-file <path> --author-family <probe_family>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The probe set is immutable (a second freeze returns the byte-identical set)
|
|
239
|
+
and its CONTENT never enters the event log or the roadmap projection.
|
|
240
|
+
|
|
241
|
+
4. **Run the cross-family evidence-quality oracle over verify-proof's
|
|
242
|
+
`verification.json` + record it:**
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
apt-tools produce oracle prepare . --run-id <id> --milestone <mid> --verdict-path <path/to/verification.json>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`prepare` extracts the v2 verdict (must be EXACTLY `approved`) + the tests[]
|
|
249
|
+
evidence into a judge payload. Dispatch that payload to the disjoint family
|
|
250
|
+
(§6) for a pass/fail evidence-quality judgement, then record it:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
apt-tools produce oracle record . --run-id <id> --milestone <mid> --verdict <pass|fail> --oracle-family <probe_family>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`record` is REFUSED when `oracle_family` equals the implementer family.
|
|
257
|
+
|
|
258
|
+
5. **Run the frozen blind probe against HEAD in the disjoint family + record the
|
|
259
|
+
result** (result/family/head-sha only — never content):
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
apt-tools produce probe record . --run-id <id> --milestone <mid> --result <pass|fail> --probe-family <probe_family> --head-sha <sha>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
6. **Adjudicate `done`:**
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
apt-tools produce set-milestone-status . --run-id <id> --milestone <mid> --status done --verdict-path <path/to/verification.json>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Accepted (flips to `done` + appends `produce.oracle.verdict{done}`) ONLY when
|
|
272
|
+
the **visible gate** (verify-proof `approved` AND a recorded cross-family
|
|
273
|
+
oracle pass) AND the **blind gate** (a recorded cross-family probe pass + a
|
|
274
|
+
cross-family frozen probe set) both pass. A visible-pass + blind-fail is
|
|
275
|
+
REFUSED — the milestone stays open and a `produce.oracle.probe_gap` canary
|
|
276
|
+
event is logged (the reward-hacking near-miss).
|
|
277
|
+
|
|
278
|
+
**Canary + rotating blind re-probe:**
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
apt-tools produce canary . --run-id <id> # green-on-visible MINUS green-on-blind + per-milestone breakdown
|
|
282
|
+
apt-tools produce probe sweep . --run-id <id> --sample N # deterministic rotating sample of already-done milestones to blind-re-probe against HEAD
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
`produce probe sweep` selects already-`done` milestones (fewest / oldest
|
|
286
|
+
last-probe-run first) so a milestone that silently regressed after done is
|
|
287
|
+
caught; re-run the blind probe (steps 3+5) against those, and a fresh failure is
|
|
288
|
+
a real regression.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## §6. Cross-family dispatch recipe — REUSE the apt-spar mechanism (ID-M2-01)
|
|
293
|
+
|
|
294
|
+
M2 does NOT invent a second cross-family path. The probe/oracle family + model
|
|
295
|
+
resolve through the SAME primitives `apt:spar` uses — provider is an OUTPUT,
|
|
296
|
+
Aperant holds ZERO model ids:
|
|
297
|
+
|
|
298
|
+
- `apt-tools produce resolve-probe-family` picks a family DISJOINT from the
|
|
299
|
+
implementer (the one new rule) using the apt-spar §3 partner-map shape, and
|
|
300
|
+
delegates model resolution to `spar-resolve-partner` /
|
|
301
|
+
`resolveCodexSparModel` — for `codex` it reads the model LIVE from
|
|
302
|
+
`~/.codex/config.toml`; `claude` / `gemini` self-resolve (`model: null`).
|
|
303
|
+
- Dispatch the oracle-judge + probe-run to the resolved family via the
|
|
304
|
+
**transport ladder** (MCP tool → plugin shim → raw CLI), following the
|
|
305
|
+
returned `transport_hint.recommended_walk` (codex prefers the self-resolving
|
|
306
|
+
plugin/CLI rungs — see `apt:spar` §3). NEVER name a model id yourself; NEVER
|
|
307
|
+
hardcode one in a prompt (the `produce-no-hardcoded-models.guard` test fails
|
|
308
|
+
CI on any `gpt-*` / `claude-*` / `gemini-*` / `grok-*` / `glm-*` literal in a
|
|
309
|
+
produce module or this SKILL).
|
|
310
|
+
|
|
311
|
+
## §7. Probe-blindness — the invariant you must never break
|
|
312
|
+
|
|
313
|
+
The held-out probe set is what makes the blind gate meaningful. The probe
|
|
314
|
+
CONTENT lives ONLY in the frozen `probes/<milestone>.json` file; the event log +
|
|
315
|
+
roadmap projection carry ONLY the probe-set hash + families. **NEVER paste probe
|
|
316
|
+
content into any Showrunner or implementer context** — not into a plan, a prompt,
|
|
317
|
+
a commit, or a chat message. A Showrunner re-anchoring from disk each tick
|
|
318
|
+
physically cannot see the probe questions (the projection folds
|
|
319
|
+
`produce.roadmap.*` ONLY); do not defeat that by hand. Author the probes in the
|
|
320
|
+
disjoint family, freeze them, and reference them only by running them
|
|
321
|
+
cross-family.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## §8. Lyapunov monotone progress (M3) — V must strictly decrease
|
|
326
|
+
|
|
327
|
+
M3 adds the closed-loop convergence measure: **V = open acceptance criteria**
|
|
328
|
+
(declared − closed), folded from the append-only log on every read. The run
|
|
329
|
+
converges when V reaches 0. Two guarantees, enforced at two different times.
|
|
330
|
+
|
|
331
|
+
1. **Declare a milestone's acceptance criteria at seed time — BEFORE it ships:**
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
apt-tools produce declare-criteria . --run-id <id> --milestone <mid> --criterion "<text>"
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Each declaration opens one criterion bound to the milestone (V += 1). Declare
|
|
338
|
+
a milestone's criteria while defining/seeding it (§1) so they land in the
|
|
339
|
+
baseline scope-definition window — before the run has closed anything.
|
|
340
|
+
|
|
341
|
+
2. **Monotone-decrease is enforced at WRITE time (the anti-windup guard).** Once
|
|
342
|
+
the run has begun closing criteria (it is **in descent**), a `declare-criteria`
|
|
343
|
+
that would raise V is **REJECTED fail-closed** — the criterion is not added —
|
|
344
|
+
unless it carries the scope-change escape hatch:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
apt-tools produce declare-criteria . --run-id <id> --milestone <mid> --criterion "<text>" --scope-change "<why the outcome genuinely grew>"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
`--scope-change "<reason>"` is the **ONLY** sanctioned way V may rise after
|
|
351
|
+
descent — it appends a `produce.scope.changed` event immediately before the new
|
|
352
|
+
criterion, so every post-descent increase carries its own logged justification
|
|
353
|
+
on the trail. There is NO permanent unlock: the flag justifies exactly the
|
|
354
|
+
criteria declared in that one call. Honest scope growth is allowed; it is
|
|
355
|
+
ALWAYS audited.
|
|
356
|
+
|
|
357
|
+
3. **Criteria close as a CONSEQUENCE of a milestone shipping.** When a milestone
|
|
358
|
+
flips to `done` (the §5 two-gate), its still-open criteria auto-close, so V
|
|
359
|
+
strictly decreases. A milestone with zero declared criteria closes zero
|
|
360
|
+
(byte-identical to M2).
|
|
361
|
+
|
|
362
|
+
4. **Monotone-progress is REPORTED at READ time:**
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
apt-tools produce progress . --run-id <id>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
`progress` re-reads the ledger from disk every invocation (no in-memory
|
|
369
|
+
authority) and returns `{ v_open_now, v_series:[{milestone_id, v_before,
|
|
370
|
+
v_after, delta, decreased}], strictly_decreasing, lyapunov_ok,
|
|
371
|
+
lyapunov_violations[], scope_changes[] }`. The V-series must be **strictly
|
|
372
|
+
decreasing** across shipped milestones. A milestone that shipped without
|
|
373
|
+
closing any criterion (`delta === 0`) is a soft **stall**
|
|
374
|
+
(`strictly_decreasing: false`), not a hard failure. A `produce.criteria.declared`
|
|
375
|
+
that raised V after descent WITHOUT an accompanying `produce.scope.changed` is
|
|
376
|
+
a hard **Lyapunov violation** (`lyapunov_ok: false`). `progress` FLAGS these —
|
|
377
|
+
it never rejects (the rejection is the write-time guard in step 2); a
|
|
378
|
+
scope-changed increase is audited, NOT a hard violation.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## §9. Saga + forward compensators (M4) — ship a revert, never roll back a merged PR
|
|
383
|
+
|
|
384
|
+
M4 models the loop as a **saga**: `plan → execute → verify → review → ship`. Each
|
|
385
|
+
phase transition is recorded; each phase declares a **FORWARD compensator** that
|
|
386
|
+
recovers the run WITHOUT a destructive rollback. Record the transitions as you
|
|
387
|
+
drive a milestone:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
apt-tools produce saga enter . --run-id <id> --milestone <mid> --phase <plan|execute|verify|review|ship>
|
|
391
|
+
apt-tools produce saga complete . --run-id <id> --milestone <mid> --phase <plan|execute|verify|review|ship>
|
|
392
|
+
apt-tools produce saga status . --run-id <id>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
When a phase FAILS, fire its compensator:
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
apt-tools produce saga compensate . --run-id <id> --milestone <mid> --phase <p> --reason "<why it failed>"
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
The **load-bearing rule (ID-10 / ID-M4-02):** EVERY compensator is FORWARD —
|
|
402
|
+
`rolls_back_merged_pr: false` on every phase. `plan`/`execute` (pre-merge) reopen
|
|
403
|
+
+ re-plan without a revert; `verify`/`review`/`ship` are `revert_reopen_replan` —
|
|
404
|
+
they **ship a revert** (a new forward commit/branch) + reopen the task + re-plan.
|
|
405
|
+
**You NEVER roll back a merged PR** — you cannot un-merge history other agents or
|
|
406
|
+
humans already built on. The CLI RECORDS the forward-compensator descriptor; it
|
|
407
|
+
does NOT execute the revert / reopen / re-plan (that is the dispatch layer's job)
|
|
408
|
+
and it NEVER mutates the roadmap milestone status (the saga fold is SEPARATE from
|
|
409
|
+
the roadmap projection — blindness preserved).
|
|
410
|
+
|
|
411
|
+
## §10. Provider-diverse review (M4) — reviewer family ≠ implementer (ID-08)
|
|
412
|
+
|
|
413
|
+
The saga's REVIEW phase reviewer must be a provider family DISJOINT from the
|
|
414
|
+
implementer's — a same-family reviewer rubber-stamps its own family's work. This
|
|
415
|
+
REUSES the SAME `resolveProbeFamily` M2 uses on the probe/oracle path (no second
|
|
416
|
+
cross-family mechanism; provider is an OUTPUT; the model resolves LIVE, never a
|
|
417
|
+
hardcoded id):
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
apt-tools produce saga resolve-reviewer . --run-id <id> --milestone <mid> [--host-family <fam>] [--available-families a,b,c]
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Returns a `reviewer_family` DISJOINT from the recorded implementer + a
|
|
424
|
+
LIVE-resolved model + a `transport_hint`; `available:false` when no disjoint
|
|
425
|
+
family exists (single-family setup — the review-diversity rule cannot be
|
|
426
|
+
satisfied by design). Dispatch the review to that family via the same **transport
|
|
427
|
+
ladder** as §6, then record the verdict:
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
apt-tools produce saga review . --run-id <id> --milestone <mid> --verdict <pass|fail> --reviewer-family <reviewer_family>
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
`saga review` is REFUSED fail-closed when `reviewer_family` equals the recorded
|
|
434
|
+
implementer family (or when no implementer family is recorded, ID-M2-02) — the
|
|
435
|
+
review-path analog of `oracle record`.
|
|
436
|
+
|
|
437
|
+
## §11. Verification-TTL (M4) — re-verify OLD done milestones against HEAD each tick
|
|
438
|
+
|
|
439
|
+
Verification is not permanent: a milestone marked `done` at HEAD-sha `A` can
|
|
440
|
+
silently regress as HEAD advances to `B`. **Each tick**, re-verify a rotating
|
|
441
|
+
sample of OLD done milestones against the current HEAD. Pass the current HEAD sha
|
|
442
|
+
on the tick to surface the sample (additive — a tick WITHOUT `--head-sha` is
|
|
443
|
+
byte-identical to M1/M2/M3, still one tick, no loop):
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
apt-tools produce tick . --run-id <id> --head-sha <sha> # surfaces the additive ttl_reverify sample
|
|
447
|
+
apt-tools produce ttl select . --run-id <id> --head-sha <sha> [--sample N]
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
`ttl select` REUSES the M2 rotating-sample primitive and returns a deterministic
|
|
451
|
+
sample of already-`done` milestones **STALE** against HEAD — a milestone last
|
|
452
|
+
re-verified against the current HEAD is EXCLUDED as fresh. Re-run the frozen blind
|
|
453
|
+
probe (§5 steps 3+5) against each, then record the re-verify result cross-family:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
apt-tools produce ttl reverify . --run-id <id> --milestone <mid> --result <pass|fail> --probe-family <fam> --head-sha <sha>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
`ttl reverify` REUSES the M2 cross-family guard (a same-family re-verify is
|
|
460
|
+
refused). A `pass` refreshes verification against the new HEAD. A **`fail`** flags
|
|
461
|
+
the milestone — it appends `produce.ttl.regression_detected` AND **fires the
|
|
462
|
+
FORWARD compensator** (`saga compensate --phase verify` → `revert_reopen_replan`:
|
|
463
|
+
ship a revert + reopen + re-plan, never a merged-PR rollback). The re-verify RUN +
|
|
464
|
+
the revert-ship/reopen/re-plan EXECUTION is the dispatch layer's job; the CLI
|
|
465
|
+
records + computes.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## §12. WSJF/WIP scheduler (M5) — what to advance next, under budget
|
|
470
|
+
|
|
471
|
+
M5 replaces the naive "first planned" tick heuristic with a deterministic
|
|
472
|
+
**WSJF** (Weighted Shortest Job First) ranking of the READY milestones + a
|
|
473
|
+
**WIP-limited pick**. Ask the scheduler what to advance next:
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
apt-tools produce schedule . --run-id <id> [--wip N]
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Read-only (emits nothing — mirrors `status`/`progress`/`canary`). It returns
|
|
480
|
+
`{ wip_limit, wip_in_use, wip_available, ready_queue[], blocked[], in_progress[],
|
|
481
|
+
pick[], reason, cycle }`.
|
|
482
|
+
|
|
483
|
+
**The formula (fixed integer weights — deterministic, no LLM):**
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
WSJF(m) = CostOfDelay(m) / JobSize(m)
|
|
487
|
+
CostOfDelay(m) = 5·regression_flag(m) // W_REGRESS — user-facing breakage, most urgent
|
|
488
|
+
+ 3·blocking_count(m) // W_BLOCK — # milestones depending on m
|
|
489
|
+
+ 2·open_criteria(m) // W_VALUE — M3 open criteria bound to m
|
|
490
|
+
+ priority(m) // optional declared --priority (default 0)
|
|
491
|
+
JobSize(m) = declared_size(m) > 0 ? declared_size(m) : max(open_criteria(m), 1)
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
`open_criteria` deliberately appears in BOTH the value term of CoD and (as the
|
|
495
|
+
fallback) in JobSize — standard WSJF (prefer small, high-value jobs); a declared
|
|
496
|
+
`--size` decouples them. `ready_queue` is sorted **WSJF desc → roadmap first-seen
|
|
497
|
+
order → milestone_id** — a total, stable order, so two folds of the same log are
|
|
498
|
+
byte-identical.
|
|
499
|
+
|
|
500
|
+
**Ready-set membership + WIP budget:**
|
|
501
|
+
|
|
502
|
+
- A `planned` milestone is READY iff every `depends_on` id resolves to a roadmap
|
|
503
|
+
milestone with status `done` (an unknown dep fails closed = unmet); otherwise it
|
|
504
|
+
is in `blocked` with `blocked_by` = the not-done deps. A dependency **cycle**
|
|
505
|
+
among not-done milestones surfaces `reason: "dependency_cycle_detected"` + the
|
|
506
|
+
offending `cycle` — never a silent idle.
|
|
507
|
+
- A `done` milestone with an **unresolved M4 regression** (§11) re-enters the ready
|
|
508
|
+
queue tagged `regressed: true` with the `W_REGRESS=5` weight — the loop defends
|
|
509
|
+
what it shipped. A subsequent `ttl reverify --result pass` resolves it.
|
|
510
|
+
- The WIP cap resolves `--wip N` → `.aperant/config.json :: produce.wip` →
|
|
511
|
+
default **1**. `wip_available = max(0, wip_limit − in_progress_count)`; `pick` is
|
|
512
|
+
the top `wip_available` of `ready_queue`. WIP-saturated → empty `pick`,
|
|
513
|
+
`reason: "wip_saturated"`. WIP counts roadmap `in_progress` status ONLY (a
|
|
514
|
+
regressed `done` candidate is not counted as in_progress).
|
|
515
|
+
|
|
516
|
+
Declare a milestone's dependencies / priority / size at seed time (additive on the
|
|
517
|
+
existing `milestone_added` event — an M1-style add is byte-identical):
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
apt-tools produce add-milestone . --run-id <id> --title "<t>" [--depends-on a,b] [--priority <int>] [--size <positive int>]
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**Scheduler-driven tick.** The §2 `tick` folds this schedule and sets
|
|
524
|
+
`next_action` to the scheduler's pick (top WSJF ready under the WIP budget), still
|
|
525
|
+
one tick per invocation. The `pick` is **advisory scheduling input** — the M5 CLI
|
|
526
|
+
does NOT dispatch plan→execute→verify→review→ship of the picked milestone (that
|
|
527
|
+
closed-loop dispatch is out of scope; the scheduler tells the loop *what* to
|
|
528
|
+
advance next). A **token/cost budget** is deferred — the substrate records no cost
|
|
529
|
+
data; WIP is the honest, substrate-native budget.
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## §13. Claim Envelope (M6) — capture a lesson, consume it as a plan delta
|
|
534
|
+
|
|
535
|
+
M6 turns "we learned this once" into "every future plan in this family is
|
|
536
|
+
pre-corrected." A **Claim Envelope** is a durable, provider-neutral, bounded,
|
|
537
|
+
expiring claim (the `lesson` profile is the only one shipped). Four subcommands
|
|
538
|
+
drive its lifecycle:
|
|
539
|
+
|
|
540
|
+
```bash
|
|
541
|
+
apt-tools produce claim declare . --run-id <id> --profile lesson --claim-file <path> [--claim-id <id>]
|
|
542
|
+
apt-tools produce claim list . --run-id <id>
|
|
543
|
+
apt-tools produce claim expire . --run-id <id> --claim-id <id> [--reason "<r>"]
|
|
544
|
+
apt-tools produce claim consume . --run-id <id> [--milestone <mid>]
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
- **`declare`** VALIDATES the envelope (the `lesson` profile requires
|
|
548
|
+
`provenance` + a non-empty `preconditions` trigger + a **bounded** `scope`
|
|
549
|
+
(`global !== true`) + an `expiry` (`expires_at` OR `revalidate_against_head`) +
|
|
550
|
+
a `negative_evidence` field + a non-empty `resolution_verifier`), then FREEZES
|
|
551
|
+
it once to `claims/<claim-id>.json` (exclusive-create, immutable) and logs
|
|
552
|
+
`produce.claim.declared` carrying the **content_hash only** — the claim content
|
|
553
|
+
NEVER touches the event log. A global/unbounded scope, an empty precondition,
|
|
554
|
+
or a missing expiry is REJECTED fail-closed with a reason.
|
|
555
|
+
- **`list`** re-projects the claim ledger (`declared − expired`) folded from the
|
|
556
|
+
append-only log. The `produce.claim.*` ops are a SEPARATE fold — they NEVER
|
|
557
|
+
enter the roadmap projection the Showrunner re-reads each tick.
|
|
558
|
+
- **`expire`** logs `produce.claim.expired`; the claim leaves the active set.
|
|
559
|
+
- **`consume`** emits a STRUCTURED delta
|
|
560
|
+
`{claim_id, targets:[{kind: acceptance_criterion|subtask|proof_obligation, requirement, ref?}]}`
|
|
561
|
+
derived FROM the claim's `resolution_verifier`.
|
|
562
|
+
|
|
563
|
+
**Consumption is a DELTA, never a context paste (the M6 invariant).** "Consuming
|
|
564
|
+
a lesson" means applying a concrete AC / subtask / proof-obligation requirement to
|
|
565
|
+
a plan — it does NOT mean pasting the lesson's prose (`provenance` /
|
|
566
|
+
`negative_evidence` / body) into the planner's context. Pasting lesson text
|
|
567
|
+
re-introduces the context-rot the loop is trying to escape and is FORBIDDEN. The
|
|
568
|
+
consume output is a projection DOWN to `{claim_id, targets}` and carries none of
|
|
569
|
+
the envelope's non-delta fields.
|
|
570
|
+
|
|
571
|
+
**Anti-corrosion (expiry + HEAD re-validation).** A stale lesson that no longer
|
|
572
|
+
matches HEAD silently degrades every future plan. `consume` SKIPS (never applies)
|
|
573
|
+
a claim that is time-expired, whose `revalidate_against_head` check no longer
|
|
574
|
+
matches the working tree, or whose precondition does not match — surfacing each
|
|
575
|
+
under `skipped[]` with a reason. The HEAD check is a DETERMINISTIC path-exists /
|
|
576
|
+
grep, never an LLM judgment.
|
|
577
|
+
|
|
578
|
+
**Bounded critic (anti-windup).** A lesson fires only behind a matching
|
|
579
|
+
precondition and a bounded scope, and consumption emits ONE delta per claim — one
|
|
580
|
+
incident fixes ITS task, it never ratchets a global always-on policy.
|
|
581
|
+
|
|
582
|
+
**Interop, not a 4th store; generalizes as data.** The claim ledger is a fold +
|
|
583
|
+
a per-record content file on the SAME `.aperant/produce/<run-id>/` substrate M1/M2
|
|
584
|
+
already use — no new DB, no schema, no migration, and it touches none of the 3
|
|
585
|
+
adjudication engines (verify-proof / oracle / review). Generalization past
|
|
586
|
+
`lesson` is a data-driven **profile registry** (`CLAIM_PROFILES`): adding a second
|
|
587
|
+
profile is one map entry, not a code fork. The outer loop is now
|
|
588
|
+
**feature-complete** (M1–M6).
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Notes for the orchestrator
|
|
593
|
+
|
|
594
|
+
- **After editing this SKILL** (or any shipped `apt-*/SKILL.md`), re-run
|
|
595
|
+
`apt-tools init . --<runtime>` (e.g. `apt-tools init . --solo --claude`, and
|
|
596
|
+
once per other installed runtime) — or `/apt:update` — so each runtime's
|
|
597
|
+
`apt-file-manifest.json` + `apt-skill-version` headers stay in sync.
|
|
598
|
+
|
|
599
|
+
- The event log is the authority; `roadmap.json` is a derived cache, always
|
|
600
|
+
regenerable by folding the log. A corrupt/stale cache is repaired by the next
|
|
601
|
+
`status`/`tick` re-fold — never trust it as the source of truth (ID-01).
|
|
602
|
+
- Concurrent `add-milestone` writers are crash-safe by construction: the
|
|
603
|
+
mutation is a pure O_APPEND to the shared log (atomic under PIPE_BUF), and the
|
|
604
|
+
cache is a fold-under-lock single-writer regenerate — no lost updates.
|
|
605
|
+
- M1 introduces no new secret material, no daemon, and no new per-mode
|
|
606
|
+
persistence: it is framework filesystem substrate, cross-mode by construction.
|
|
@@ -29,7 +29,7 @@ Execute a small task quickly without full pipeline overhead. For small fixes, do
|
|
|
29
29
|
- **Working directory:** The project root (where you were invoked) UNLESS an active task has a task-level worktree (see below).
|
|
30
30
|
- **Constitution:** Read `AGENTS.md` in the project root if it exists
|
|
31
31
|
- **State directory:** `.aperant/quick/{task-id}/`
|
|
32
|
-
- **Task-level worktree isolation:** Use the `worktree_path` the router passed in skill context (router path) OR that §1a parsed from `task
|
|
32
|
+
- **Task-level worktree isolation:** Use the `worktree_path` the router passed in skill context (router path) OR that §1a parsed from `task ensure`'s envelope (direct path) — this is the worktree `task ensure` literally just provisioned for this task. When present, run all editing Bash commands with `cd {worktree_path} &&` prefix so the fix lands on the task branch. `apt-tools` calls still take the project root as `<project-dir>` so they coordinate through the main repo's shared `.aperant/`. The quick task's `.aperant/quick/{task-id}/` directory lives in the main repo, not the worktree. (Last-resort fallback only: if neither source supplied a `worktree_path` but `.aperant/state.json` has an active task with one, you may use that.)
|
|
33
33
|
</your_environment>
|
|
34
34
|
|
|
35
35
|
<state_files>
|
|
@@ -54,35 +54,27 @@ Extract the task description from `$ARGUMENTS`.
|
|
|
54
54
|
|
|
55
55
|
### 1a. Resolve canonical task id (idempotent)
|
|
56
56
|
|
|
57
|
-
QUICK now produces a canonical state.active_tasks record so `/apt:ship` can find the task via the lite ship profile.
|
|
57
|
+
QUICK now produces a canonical state.active_tasks record so `/apt:ship` can find the task via the lite ship profile. Idempotency is owned by the deterministic allocator `apt-tools task ensure --intent create-new` (NOT raw `task create`) — re-running returns the SAME task + worktree (`reused: true`), so the old `task get` guard dance is gone.
|
|
58
58
|
|
|
59
59
|
Two invocation paths converge here:
|
|
60
60
|
|
|
61
|
-
- **Router path** (`/apt` → `/apt:quick`): the router has already
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
- **Router path** (`/apt` → `/apt:quick`): the router has already run `task ensure --intent create-new` and injected `task_id` (+ `worktree_path`) into your skill context. Re-affirm idempotently with the same id:
|
|
62
|
+
```bash
|
|
63
|
+
apt-tools task ensure . --description "$ARGUMENTS" --intent create-new --track QUICK --id {task_id}
|
|
64
|
+
```
|
|
65
|
+
The `--id {task_id}` makes ensure resolve to the EXACT record the router just provisioned (`reused: true`) — no second task, no second worktree.
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- Else (record missing OR wrong track) → call:
|
|
72
|
-
```bash
|
|
73
|
-
apt-tools task create . --description "$ARGUMENTS" --track QUICK --id {task_id}
|
|
74
|
-
```
|
|
75
|
-
Parse `task_id` from the returned envelope (it will match the id you passed).
|
|
67
|
+
- **Direct path** (`/apt:quick foo`): no `task_id` in context — allocate now:
|
|
68
|
+
```bash
|
|
69
|
+
apt-tools task ensure . --description "$ARGUMENTS" --intent create-new --track QUICK
|
|
70
|
+
```
|
|
71
|
+
ensure is keyed on the normalized description + scope, so a retry returns the SAME canonical `{slug}_YY-MM-DD` `task_id`.
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
apt-tools task create . --description "$ARGUMENTS" --track QUICK
|
|
80
|
-
```
|
|
81
|
-
Parse the generated `task_id` from the envelope — it will be the canonical `{slug}_YY-MM-DD` shape.
|
|
73
|
+
Parse `task_id` from the returned envelope.
|
|
82
74
|
|
|
83
75
|
The task id is now canonical (no more `quick-YYYYMMDD-*` invention). `QuickTaskSchema` accepts both the canonical `{slug}_YY-MM-DD` form and the legacy `quick-YYYYMMDD-{slug}` form for back-compat with already-shipped task records on disk.
|
|
84
76
|
|
|
85
|
-
**Worktree isolation (both paths).** `task create` provisions a worktree when `task_isolation.worktree_per_task` is enabled (track-agnostic — QUICK gets one too). Parse `worktree.worktree_path`, `worktree.branch`, and `worktree.base_branch` from the `task
|
|
77
|
+
**Worktree isolation (both paths).** `task ensure --intent create-new` provisions a worktree when `task_isolation.worktree_per_task` is enabled (track-agnostic — QUICK gets one too). Parse `worktree.worktree_path`, `worktree.branch`, and `worktree.base_branch` from the `task ensure` envelope (direct path); on the router path the orchestrator already passed `worktree_path` into your skill context — use that. When a `worktree` block is present, print the banner and run all subsequent editing Bash commands with `cd {worktree_path} &&`:
|
|
86
78
|
|
|
87
79
|
```
|
|
88
80
|
[APT] Working in isolated worktree: {worktree_path}
|