froid-loop 0.11.1__py3-none-any.whl
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.
- froid_loop/__init__.py +11 -0
- froid_loop/__main__.py +12 -0
- froid_loop/adapters/__init__.py +3 -0
- froid_loop/adapters/base.py +254 -0
- froid_loop/adapters/entrypoints.py +63 -0
- froid_loop/adapters/env_fault.py +290 -0
- froid_loop/adapters/generic.py +2013 -0
- froid_loop/adapters/mock.py +49 -0
- froid_loop/adapters/multiplexer.py +914 -0
- froid_loop/adapters/opencode_http.py +1687 -0
- froid_loop/adapters/profile.py +650 -0
- froid_loop/adapters/psmux_backend.py +1428 -0
- froid_loop/adapters/registry.py +322 -0
- froid_loop/adapters/tmux_backend.py +35 -0
- froid_loop/adapters/tmux_base.py +630 -0
- froid_loop/checks.py +187 -0
- froid_loop/cli.py +5041 -0
- froid_loop/data/__init__.py +0 -0
- froid_loop/data/froid_loop_hook.py +228 -0
- froid_loop/data/froid_loop_probe_hook.py +88 -0
- froid_loop/data/plugins/example/plugin.toml +21 -0
- froid_loop/data/plugins/tea/plugin.toml +184 -0
- froid_loop/data/plugins/tea/tea_plugin.py +258 -0
- froid_loop/data/plugins/unity/plugin.toml +140 -0
- froid_loop/data/plugins/unity/unity_assets/FroidLoop.Unity.Editor.asmdef +16 -0
- froid_loop/data/plugins/unity/unity_assets/FroidLoop.Unity.Editor.asmdef.meta +7 -0
- froid_loop/data/plugins/unity/unity_assets/SceneAutoSaveGuard.cs +221 -0
- froid_loop/data/plugins/unity/unity_assets/SceneAutoSaveGuard.cs.meta +11 -0
- froid_loop/data/plugins/unity/unity_assets/_folders/Editor.meta +8 -0
- froid_loop/data/plugins/unity/unity_assets/_folders/FroidLoop.meta +8 -0
- froid_loop/data/plugins/unity/unity_cleanup.py +125 -0
- froid_loop/data/plugins/unity/unity_dialog_probe.py +239 -0
- froid_loop/data/plugins/unity/unity_facts.md +17 -0
- froid_loop/data/plugins/unity/unity_plugin.py +415 -0
- froid_loop/data/plugins/unity/unity_quiesce.py +234 -0
- froid_loop/data/plugins/unity/unity_ready.py +230 -0
- froid_loop/data/plugins/unity/unity_seed_assets.py +298 -0
- froid_loop/data/plugins/unity/unity_setup.py +551 -0
- froid_loop/data/plugins/unity/unity_teardown.py +362 -0
- froid_loop/data/profiles/antigravity.toml +52 -0
- froid_loop/data/profiles/claude.toml +85 -0
- froid_loop/data/profiles/codex.toml +22 -0
- froid_loop/data/profiles/copilot.toml +52 -0
- froid_loop/data/profiles/gemini.toml +26 -0
- froid_loop/data/profiles/opencode.toml +54 -0
- froid_loop/data/settings/core.toml +458 -0
- froid_loop/data/skills/README.md +93 -0
- froid_loop/data/skills/froid-loop-resolve/SKILL.md +288 -0
- froid_loop/data/skills/froid-loop-setup/SKILL.md +161 -0
- froid_loop/data/skills/froid-loop-setup/assets/module-help.csv +3 -0
- froid_loop/data/skills/froid-loop-setup/assets/module.yaml +19 -0
- froid_loop/data/skills/froid-loop-sweep/SKILL.md +100 -0
- froid_loop/data/skills/froid-loop-sweep/automation-mode.md +127 -0
- froid_loop/data/skills/froid-loop-sweep/deferred-work-format.md +302 -0
- froid_loop/data/skills/froid-loop-sweep/migration-mode.md +86 -0
- froid_loop/decisions.py +202 -0
- froid_loop/deferredwork.py +2282 -0
- froid_loop/devcontract.py +892 -0
- froid_loop/diagnostics.py +1104 -0
- froid_loop/documents.py +532 -0
- froid_loop/engine.py +7732 -0
- froid_loop/envvars.py +111 -0
- froid_loop/escalation.py +225 -0
- froid_loop/events.py +266 -0
- froid_loop/fences.py +103 -0
- froid_loop/froidconfig.py +226 -0
- froid_loop/frontmatter.py +526 -0
- froid_loop/gates.py +133 -0
- froid_loop/install.py +2936 -0
- froid_loop/journal.py +178 -0
- froid_loop/machine.py +148 -0
- froid_loop/model.py +898 -0
- froid_loop/operatoractions.py +474 -0
- froid_loop/platform_util.py +1490 -0
- froid_loop/plugins/__init__.py +64 -0
- froid_loop/plugins/bus.py +259 -0
- froid_loop/plugins/context.py +319 -0
- froid_loop/plugins/loader.py +145 -0
- froid_loop/plugins/manifest.py +279 -0
- froid_loop/plugins/model.py +296 -0
- froid_loop/plugins/registry.py +245 -0
- froid_loop/plugins/trust.py +75 -0
- froid_loop/policy.py +1569 -0
- froid_loop/probe.py +1044 -0
- froid_loop/process_host.py +408 -0
- froid_loop/recovery_flow.py +1561 -0
- froid_loop/resolve.py +283 -0
- froid_loop/runs.py +4715 -0
- froid_loop/runsetup.py +1293 -0
- froid_loop/sanitize.py +593 -0
- froid_loop/settings_schema.py +276 -0
- froid_loop/signals.py +160 -0
- froid_loop/sprintstatus.py +609 -0
- froid_loop/statemachine.py +57 -0
- froid_loop/stories.py +615 -0
- froid_loop/stories_engine.py +796 -0
- froid_loop/sweep.py +1892 -0
- froid_loop/tokens.py +196 -0
- froid_loop/tui/__init__.py +11 -0
- froid_loop/tui/app.py +1584 -0
- froid_loop/tui/data.py +840 -0
- froid_loop/tui/launch.py +1003 -0
- froid_loop/tui/screens/__init__.py +1 -0
- froid_loop/tui/screens/dashboard.py +1071 -0
- froid_loop/tui/screens/modals.py +943 -0
- froid_loop/tui/screens/settings_screen.py +477 -0
- froid_loop/tui/settings.py +135 -0
- froid_loop/tui/widgets.py +981 -0
- froid_loop/verify.py +4545 -0
- froid_loop/workspace.py +320 -0
- froid_loop/worktree_flow.py +2301 -0
- froid_loop-0.11.1.dist-info/METADATA +728 -0
- froid_loop-0.11.1.dist-info/RECORD +116 -0
- froid_loop-0.11.1.dist-info/WHEEL +4 -0
- froid_loop-0.11.1.dist-info/entry_points.txt +2 -0
- froid_loop-0.11.1.dist-info/licenses/LICENSE +30 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: froid-loop-resolve
|
|
3
|
+
description: 'Interactive escalation-resolution workflow for the froid-loop orchestrator. A froid-loop run paused on a CRITICAL escalation (a contradiction or gap a dev/review session could not safely resolve alone); you and the human disambiguate the frozen spec so the story can be re-driven. Invoked as /froid-loop-resolve <story-key>. Unlike the automated dev/review sessions this session is interactive — a human is present and you SHOULD ask.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# froid-loop Escalation Resolution
|
|
7
|
+
|
|
8
|
+
A `froid-loop` run drove a story through dev → review, a session raised a
|
|
9
|
+
**CRITICAL escalation** (work could not proceed safely — usually a contradiction
|
|
10
|
+
or an unanswered question in the _frozen spec_), and the orchestrator paused the
|
|
11
|
+
whole run for a human. The session that escalated is gone; you are a fresh
|
|
12
|
+
interactive session whose job is to **resolve the ambiguity with the human and
|
|
13
|
+
update the frozen spec**, so the orchestrator can re-arm the story and re-drive
|
|
14
|
+
it against a corrected spec.
|
|
15
|
+
|
|
16
|
+
This is **interactive**: a human IS present. Ask questions, present options,
|
|
17
|
+
recommend — but the human makes the call. (`$FROID_LOOP_MODE` is intentionally
|
|
18
|
+
unset for this session; the never-ask automation rules do NOT apply.)
|
|
19
|
+
|
|
20
|
+
## Identity & I/O contract
|
|
21
|
+
|
|
22
|
+
These environment variables are set:
|
|
23
|
+
|
|
24
|
+
- `$FROID_LOOP_RUN_DIR` — the paused run's directory.
|
|
25
|
+
- `$FROID_LOOP_STORY_KEY` — the escalated story key (also your invocation argument).
|
|
26
|
+
- `$FROID_LOOP_RESOLVE_CONTEXT` — path to a `context.json` written for you.
|
|
27
|
+
|
|
28
|
+
**Read `$FROID_LOOP_RESOLVE_CONTEXT` FIRST.** Its schema:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"story_key": "6-4-cli-list-command",
|
|
33
|
+
"run_id": "20260613-111429-6a14",
|
|
34
|
+
"spec_file": "/abs/path/to/_froid-output/implementation-artifacts/spec-<story>.md",
|
|
35
|
+
"spec_reaches_the_redrive": true,
|
|
36
|
+
"redrive_base_ref": "<branch the re-drive reads, or HEAD>",
|
|
37
|
+
"baseline_commit": "<sha>",
|
|
38
|
+
"paused_reason": "CRITICAL escalation from review session: ...",
|
|
39
|
+
"escalations": [
|
|
40
|
+
{
|
|
41
|
+
"type": "<kind>",
|
|
42
|
+
"severity": "CRITICAL",
|
|
43
|
+
"detail": "<what's ambiguous/contradictory>"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"resolution_path": "/abs/path/to/<run>/resolve/<story>/resolution.json"
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**`spec_reaches_the_redrive` says whether your edit has a future.** The re-drive
|
|
51
|
+
reads one tree; `spec_file` may name another. Under worktree isolation the run's mount
|
|
52
|
+
is discarded before the re-drive reads anything, so a spec inside that mount is
|
|
53
|
+
destroyed with it. When this field is `false`, every write to `spec_file` still
|
|
54
|
+
SUCCEEDS and is then thrown away — worse than not editing at all, because the session
|
|
55
|
+
looks resolved. `null` means the task has no spec on record: there is nothing to edit
|
|
56
|
+
and step 4 does not apply.
|
|
57
|
+
|
|
58
|
+
**`redrive_base_ref` tells you which of the two remedies applies.** Read it before you
|
|
59
|
+
tell the human anything: a branch name and `HEAD` mean opposite things.
|
|
60
|
+
|
|
61
|
+
Do not skip the edit when it is `false` — the corrected spec is what gets carried
|
|
62
|
+
over, and it is the clearest statement of what you and the human agreed. Do step 4 as
|
|
63
|
+
usual, then tell the human, in the same breath as the resolution, **where the
|
|
64
|
+
correction has to land to be read** — which the field decides: when `redrive_base_ref`
|
|
65
|
+
names a branch, committed on `redrive_base_ref`; when it is `HEAD`, re-applied in the
|
|
66
|
+
main checkout, uncommitted. The two paragraphs below carry each arm.
|
|
67
|
+
|
|
68
|
+
Be precise about this, because the two obvious moves both fail silently:
|
|
69
|
+
|
|
70
|
+
- Committing from the **main checkout** cannot include the file you edited — it lives
|
|
71
|
+
in a linked unit worktree, which is a separate working tree.
|
|
72
|
+
- Committing on the **unit's own branch** does not reach the re-drive either. The
|
|
73
|
+
replacement worktree is cut fresh from `redrive_base_ref`, not from the branch of
|
|
74
|
+
the mount that was discarded.
|
|
75
|
+
|
|
76
|
+
So the correction has to reach `redrive_base_ref` itself: make the same edit to that
|
|
77
|
+
tree's copy of the spec and commit it there. The orchestrator names the same ref when
|
|
78
|
+
it re-arms; say it here so they hear it before they close the session rather than
|
|
79
|
+
after.
|
|
80
|
+
|
|
81
|
+
**When `redrive_base_ref` is `HEAD`, do not tell them to commit anything.** That means
|
|
82
|
+
the re-drive runs in the **main checkout** and reads its WORKING TREE, so an edit there
|
|
83
|
+
is read as-is. `spec_reaches_the_redrive: false` beside a `HEAD` base is the opposite
|
|
84
|
+
problem from the one above: `spec_file` points into a worktree this run has STOPPED
|
|
85
|
+
using, because its isolation policy changed while the story sat escalated. The remedy
|
|
86
|
+
is to make the same edit to the main checkout's copy of the spec — no commit, no
|
|
87
|
+
branch. Telling them to commit here sends them to a tree the re-drive does not read,
|
|
88
|
+
which is the same lost work in the other direction.
|
|
89
|
+
|
|
90
|
+
In **stories mode** (folder+id dispatch) the context also carries a `stories`
|
|
91
|
+
block — the manifest intent for this story, so you can see WHAT it is meant to do
|
|
92
|
+
without hunting for it:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"stories": {
|
|
97
|
+
"spec_folder": "_froid-output/epic-1",
|
|
98
|
+
"story": {
|
|
99
|
+
"id": "6-4-cli-list-command",
|
|
100
|
+
"title": "CLI list command",
|
|
101
|
+
"description": "…",
|
|
102
|
+
"spec_checkpoint": false,
|
|
103
|
+
"done_checkpoint": false,
|
|
104
|
+
"invoke_dev_with": "…free-text planner→dev note, or ''…"
|
|
105
|
+
},
|
|
106
|
+
"sentinel": {
|
|
107
|
+
"kind": "unresolved",
|
|
108
|
+
"path": ".../stories/6-4-cli-list-command-unresolved.md",
|
|
109
|
+
"blocking_condition": "…the reason planning halted…"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The `sentinel` sub-block is present ONLY when the escalated story is a **sentinel**
|
|
116
|
+
(see the stories-mode section below); an ordinary escalation omits it.
|
|
117
|
+
|
|
118
|
+
Your **output marker** is the file at `resolution_path`. Writing it is the LAST
|
|
119
|
+
action of a successful resolution. Schema:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"story_key": "<key>",
|
|
124
|
+
"decision": "<one or two sentences: the rule you and the human chose>",
|
|
125
|
+
"spec_file": "<the spec you edited>",
|
|
126
|
+
"spec_updated": true,
|
|
127
|
+
"restore_patch": "<optional: path to a saved intent-gap patch to re-apply>"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`restore_patch` is **optional** and used only for the intent-gap patch-restore
|
|
132
|
+
case below — omit it entirely for an ordinary resolution.
|
|
133
|
+
|
|
134
|
+
## What you MUST do
|
|
135
|
+
|
|
136
|
+
1. **Read the context**, then read the **frozen spec** at `spec_file` in full —
|
|
137
|
+
especially its `<frozen-after-approval>` block (the intent the dev/review
|
|
138
|
+
sessions treat as authoritative). The escalation is almost always that this
|
|
139
|
+
block is silent on, or contradicts, a case the implementation hit.
|
|
140
|
+
2. **Present the escalation plainly** to the human: what is ambiguous or
|
|
141
|
+
contradictory, why it blocks safe implementation, and **2–4 concrete
|
|
142
|
+
resolution options** with a clear recommendation and its trade-offs. Keep it
|
|
143
|
+
tight — quote the relevant spec lines.
|
|
144
|
+
3. **Get the human's decision.** Ask follow-ups if the choice is unclear. Do not
|
|
145
|
+
invent requirements; if the human is unsure, help them reason, don't guess.
|
|
146
|
+
4. **Update the frozen spec** to encode the decision unambiguously: amend the
|
|
147
|
+
`<frozen-after-approval>` block and any affected acceptance criteria / test
|
|
148
|
+
matrix rows so a fresh dev session has exactly one correct reading. Make the
|
|
149
|
+
smallest change that removes the ambiguity. You MAY use the `froid-spec` or
|
|
150
|
+
`froid-correct-course` skills if a larger spec change is warranted. **If
|
|
151
|
+
`spec_reaches_the_redrive` is `false`, make the same edit and then say plainly
|
|
152
|
+
that this copy is not the one the re-drive reads, and name the remedy that
|
|
153
|
+
`redrive_base_ref` selects: on a branch, the correction must be
|
|
154
|
+
committed on `redrive_base_ref`; on `HEAD`, it must be re-applied in the main
|
|
155
|
+
checkout, uncommitted** — an unflagged edit here is lost work, and a commit in the
|
|
156
|
+
wrong tree or on the wrong branch is lost work that looks done.
|
|
157
|
+
5. **Write the resolution marker** at `resolution_path` (schema above), then tell
|
|
158
|
+
the human the resolution is recorded and they can exit this session — the
|
|
159
|
+
orchestrator will offer to **re-arm the story and resume the run** (a clean
|
|
160
|
+
rebuild against the corrected spec).
|
|
161
|
+
|
|
162
|
+
## Special case: a review-stage `intent gap` with a saved patch
|
|
163
|
+
|
|
164
|
+
When the escalation came from the **review step** halting on an `intent gap`, the
|
|
165
|
+
dev session first **saved its attempted change as a patch file** (in the
|
|
166
|
+
implementation-artifacts folder) before reverting the tree — the escalation
|
|
167
|
+
`detail` and the spec's `## Review Triage Log` reference the patch path. That
|
|
168
|
+
patch is concrete evidence: it shows exactly which reading of the intent the run
|
|
169
|
+
implemented.
|
|
170
|
+
|
|
171
|
+
**First check `restore_supported` in the context file.** When it is `false`
|
|
172
|
+
(worktree-isolation runs: the re-drive discards and re-mounts the unit's
|
|
173
|
+
worktree, so an in-place restore can never land; an escalation with no recorded
|
|
174
|
+
spec: a restored patch has no review to resume; a pre-planning sentinel wedge:
|
|
175
|
+
there is no attempted implementation to restore), **never offer the restore
|
|
176
|
+
option and never record `restore_patch`** — the orchestrator would reject the
|
|
177
|
+
resolution and this whole session's negotiation would be wasted. The patch is
|
|
178
|
+
still available as evidence.
|
|
179
|
+
|
|
180
|
+
Use the patch two ways:
|
|
181
|
+
|
|
182
|
+
- **As evidence.** Read the patch (and the diff it represents) to see what the
|
|
183
|
+
guessed reading produced — often clearer input for writing the clarification
|
|
184
|
+
than the questions alone.
|
|
185
|
+
- **When the attempted reading was actually correct.** Sometimes the run's guess
|
|
186
|
+
is the right one and only the _intent_ was silent. Present this as an explicit
|
|
187
|
+
option to the human: _"the implementation read it as X, which is in fact what we
|
|
188
|
+
want — amend the intent to say X, and resume **review** on the already-written
|
|
189
|
+
change instead of re-implementing it."_ If the human chooses this:
|
|
190
|
+
1. Still **amend the intent** in the spec so it unambiguously says X (step 4
|
|
191
|
+
above is unchanged — the frozen intent must match the restored code).
|
|
192
|
+
2. Add **`"restore_patch": "<the saved patch path>"`** to `resolution.json`
|
|
193
|
+
(copy the path verbatim from the escalation detail / triage log).
|
|
194
|
+
|
|
195
|
+
The orchestrator then re-arms the spec to `in-review`, re-applies the patch onto
|
|
196
|
+
the baseline, and re-dispatches — the session resumes at the review step on the
|
|
197
|
+
restored diff. **Do NOT `git apply` the patch yourself and do NOT set the spec
|
|
198
|
+
status** — the orchestrator does both deterministically at re-arm.
|
|
199
|
+
|
|
200
|
+
**The restore must not overlap resolution commits.** Re-arm advances the
|
|
201
|
+
re-drive's baseline to the branch's post-resolve HEAD, but the saved patch was
|
|
202
|
+
diffed from the ORIGINAL baseline — so if this session left commits that touch
|
|
203
|
+
the patch's own files, the restore's `git apply` fails and the story
|
|
204
|
+
re-escalates (loudly, by design: the orchestrator never silently merges the
|
|
205
|
+
resolution with the stale attempt). If the resolution work already includes or
|
|
206
|
+
supersedes the attempted change, **omit `restore_patch`** — the commits survive
|
|
207
|
+
re-arm as the re-drive's starting point, so a from-scratch re-drive builds
|
|
208
|
+
directly on them.
|
|
209
|
+
|
|
210
|
+
If the attempted reading was wrong (the common case), omit `restore_patch`
|
|
211
|
+
entirely: the orchestrator re-drives from scratch against the corrected intent.
|
|
212
|
+
|
|
213
|
+
## What you MUST NOT do
|
|
214
|
+
|
|
215
|
+
- **Do NOT** write the orchestrator's `result.json` — that is a dev/review
|
|
216
|
+
artifact; this is not one of those sessions.
|
|
217
|
+
- **Do NOT** change `sprint-status.yaml`, and **do NOT** set the spec's `status:`
|
|
218
|
+
field — the orchestrator deterministically re-arms the spec status on resume.
|
|
219
|
+
Edit spec **content** only.
|
|
220
|
+
- **Do NOT** implement the story, write feature code, run tests, or commit. Your
|
|
221
|
+
job ends at a corrected spec + the resolution marker. That holds when
|
|
222
|
+
`spec_reaches_the_redrive` is `false` too: landing the corrected spec where the
|
|
223
|
+
re-drive reads it is the HUMAN's step — committing it on `redrive_base_ref` when that
|
|
224
|
+
names a branch, re-applying it in the main checkout when it is `HEAD`. Tell them it
|
|
225
|
+
is required, and which one; do not do it yourself.
|
|
226
|
+
- **Do NOT** widen scope. Resolve exactly the escalated ambiguity; if you notice
|
|
227
|
+
unrelated problems, note them to the human but leave them alone.
|
|
228
|
+
|
|
229
|
+
## Stories mode: sentinels and the preserved copy
|
|
230
|
+
|
|
231
|
+
In stories mode a story that could not even be **planned** — the dev session hit
|
|
232
|
+
a contradiction or gap before it could write a real spec — leaves a fixed-slug
|
|
233
|
+
**sentinel** file instead of a frozen spec: `<id>-unresolved.md` (the intent was
|
|
234
|
+
too ambiguous to plan) or `<id>-ambiguous.md` (more than one story spec matched
|
|
235
|
+
the id). The context's `stories.sentinel` block names it and carries the
|
|
236
|
+
`blocking_condition` the session recorded.
|
|
237
|
+
|
|
238
|
+
A sentinel is **not a spec you edit** — there is no plan or `<frozen-after-approval>`
|
|
239
|
+
block inside it. So for a sentinel:
|
|
240
|
+
|
|
241
|
+
- **Do not try to amend a frozen spec** (step 4's "edit the frozen spec" does not
|
|
242
|
+
apply — there isn't one). Instead resolve the _upstream_ ambiguity so a fresh
|
|
243
|
+
planning pass can succeed: usually that means clarifying `SPEC.md` (the epic
|
|
244
|
+
spec) or this story's entry in `stories.yaml` — the `title` / `description` /
|
|
245
|
+
`invoke_dev_with` the planner reads — with the human.
|
|
246
|
+
- **`redrive_base_ref` decides where that upstream edit has to land, exactly as it
|
|
247
|
+
does for a spec.** `spec_reaches_the_redrive` does not answer this — it is about
|
|
248
|
+
`spec_file`, which for a sentinel is the file being deleted. The artifacts you
|
|
249
|
+
actually edit are `SPEC.md` / `stories.yaml`, and they face the same question: when
|
|
250
|
+
`redrive_base_ref` names a **branch**, the re-drive mounts a fresh worktree and
|
|
251
|
+
re-plans from that branch's COMMITTED tree, so an uncommitted edit is invisible and
|
|
252
|
+
the re-plan mints the same sentinel again — tell the human it has to be committed
|
|
253
|
+
there. When it is `HEAD`, the re-drive re-plans in the main checkout's working tree
|
|
254
|
+
and the edit is read as-is — do not tell them to commit. The orchestrator re-arms on
|
|
255
|
+
the same rule and will hold the resume until the branch carries it.
|
|
256
|
+
- On **re-arm** the orchestrator does NOT flip the sentinel to `ready-for-dev`
|
|
257
|
+
(there is no plan to route to). It **preserves a copy** of the sentinel under
|
|
258
|
+
`{run}/sentinels/<id>-<kind>.md` as a breadcrumb, **deletes** the sentinel, and
|
|
259
|
+
the next dispatch re-plans the story from scratch (leg 1 again for a
|
|
260
|
+
`spec_checkpoint` story). You do not touch the sentinel file yourself.
|
|
261
|
+
- Write the resolution marker as usual once the human has decided how to
|
|
262
|
+
disambiguate; set `spec_file` to whatever you edited (e.g. `SPEC.md`), or omit
|
|
263
|
+
it if the fix was entirely in `stories.yaml`.
|
|
264
|
+
|
|
265
|
+
### Not a sentinel: more than one file matches the id
|
|
266
|
+
|
|
267
|
+
Distinct from the single-file `<id>-ambiguous.md` sentinel above: when **more
|
|
268
|
+
than one** file in `stories/` matches `<id>-*.md` (say `3-login.md` AND
|
|
269
|
+
`3-signup.md`), the id itself is ambiguous _on disk_ and the orchestrator wedges
|
|
270
|
+
the story without picking either file. You can recognize this state by the
|
|
271
|
+
escalation reason (`ambiguous story file match: <names>`) and by what the
|
|
272
|
+
context does NOT have: no `stories.sentinel` block and no single spec path.
|
|
273
|
+
|
|
274
|
+
The auto-clear above does **not** apply — there is no sentinel to preserve and
|
|
275
|
+
delete, and re-arming alone just re-wedges on the same duplicates. The
|
|
276
|
+
resolution IS the cleanup: with the human, decide which file is the story's real
|
|
277
|
+
spec and remove or rename the other (merge content first if both carry real
|
|
278
|
+
work; renaming must move it out of the `<id>-*` pattern or to another id).
|
|
279
|
+
Exactly one match re-dispatches that spec; zero matches re-plans from scratch.
|
|
280
|
+
Then write the resolution marker as usual — re-arm + resume takes it from there.
|
|
281
|
+
|
|
282
|
+
## If you cannot resolve it
|
|
283
|
+
|
|
284
|
+
If the human defers, the information needed is genuinely unavailable, or the
|
|
285
|
+
right fix is out of scope for a spec edit (e.g. it needs a PRD/architecture
|
|
286
|
+
change), say so plainly and **do not** write the resolution marker. Exiting
|
|
287
|
+
without the marker leaves the story escalated and the run paused — the safe
|
|
288
|
+
default. The orchestrator will not re-arm a story with no recorded resolution.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'froid-loop-setup'
|
|
3
|
+
description: Sets up FROID Loop Skills module in a project. Use when the user requests to 'install froid-loop module', 'configure FROID Loop Skills', or 'setup FROID Loop Skills'.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Module Setup
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Installs, configures, **and upgrades** the froid-loop module in a project.
|
|
11
|
+
|
|
12
|
+
This module is unusual: alongside its automation skills it relies on the **froid-loop orchestrator tool** — the Python program that actually drives the loop — installed as the `froid-loop` package from its public Git repository. The skills do nothing on their own.
|
|
13
|
+
|
|
14
|
+
**The FROID installer owns `_froid/` registration; this skill does not.** When froid-loop is installed through the FROID installer (`npx froid-plane install`), the installer stages the skills under `_froid/froid-loop/`, writes that module's own config and help files, records it in `_froid/_config/` (manifest, skill manifest, files manifest), and rebuilds the `/froid-help` catalog. It regenerates the central `_froid/config.toml` on every run, so nothing outside the installer should write there.
|
|
15
|
+
|
|
16
|
+
So this skill's job is the part the installer structurally **cannot** do:
|
|
17
|
+
|
|
18
|
+
1. Install **or upgrade** the orchestrator tool (the installer copies skill directories only — it cannot carry a Python package).
|
|
19
|
+
2. Run `froid-loop init` to register the per-CLI hooks, lay down the bundled skills, and write `.froid-loop/policy.toml` + gitignore entries.
|
|
20
|
+
3. Preflight with `froid-loop validate` and point the user at per-role adapter config.
|
|
21
|
+
|
|
22
|
+
It also refreshes one file — `_froid/froid-loop/module-help.csv` — so the module's help entries are present even on a project that installed the tool directly rather than through the FROID installer. Nothing else under `_froid/` is written or deleted.
|
|
23
|
+
|
|
24
|
+
Module identity (name, code, version) comes from `./assets/module.yaml`.
|
|
25
|
+
|
|
26
|
+
`{project-root}` is a **literal token** in FROID config _values_ — never substitute it there. **This does not apply to the filesystem path _arguments_ in the commands below**: those are real paths, so resolve `{project-root}` to the actual project root before running.
|
|
27
|
+
|
|
28
|
+
## On Activation
|
|
29
|
+
|
|
30
|
+
1. Read `./assets/module.yaml` for module metadata (the `code` field is the module identifier).
|
|
31
|
+
2. Check whether `{project-root}/_froid/` exists. If it does not, this project has no FROID install — say so, and note that the automation skills expect one. Setup can still install the orchestrator tool.
|
|
32
|
+
3. Check whether `{project-root}/_froid/froid-loop/` exists. If it does, the module was installed by the FROID installer and is already registered. If it does not, tell the user the module is not registered with FROID, and that installing it via `npx froid-plane install` (selecting **froid-loop**) adds it to `/froid-help`. Do **not** gate setup on this — continue either way.
|
|
33
|
+
|
|
34
|
+
**Decide fresh-install vs upgrade.** This drives whether the tool is upgraded and whether the per-project skills are refreshed. Treat it as an **upgrade** when either holds:
|
|
35
|
+
|
|
36
|
+
- The user asked for one in their arguments — `upgrade`, `update`, `upgrade tool and skills`, or similar.
|
|
37
|
+
- The orchestrator tool is already installed under uv: run `uv tool list` and look for a `froid-loop` entry. (A bare `froid-loop --version` is **not** sufficient on its own — it can be satisfied by a source checkout or unrelated virtualenv; see step 1 below.)
|
|
38
|
+
|
|
39
|
+
Otherwise it is a **fresh install**. State the decision to the user before proceeding — e.g. "Detected an existing froid-loop install — running an upgrade: tool + skills" or "No existing install detected — running a fresh setup".
|
|
40
|
+
|
|
41
|
+
If the user provides arguments (e.g. `accept all defaults`, `--headless`, `upgrade`), use them and skip interactive prompting. Still display the full confirmation summary at the end.
|
|
42
|
+
|
|
43
|
+
## Register Help Entries
|
|
44
|
+
|
|
45
|
+
Refresh the module's help entries. This is the only file this skill writes under `_froid/`, and it is exactly what the FROID installer itself places there — so it is a no-op on an installer-installed project and idempotent on every re-run.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
mkdir -p "{project-root}/_froid/froid-loop"
|
|
49
|
+
cp ./assets/module-help.csv "{project-root}/_froid/froid-loop/module-help.csv"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`/froid-help` reads the assembled catalog at `_froid/_config/froid-help.csv`, which the FROID installer rebuilds from every `_froid/<module>/module-help.csv`. So on a project that never ran the FROID installer, these entries become visible the next time it runs — not immediately. Say that plainly in the Confirm step rather than claiming the help system was updated.
|
|
53
|
+
|
|
54
|
+
Skip this step entirely if `{project-root}/_froid/` does not exist.
|
|
55
|
+
|
|
56
|
+
## Install the Orchestrator Tool
|
|
57
|
+
|
|
58
|
+
The orchestrator is what spawns fresh coding CLI sessions through the selected adapter(s) to invoke `froid-build-auto` (the upstream dev primitive; `froid-dev-auto` on pre-rename releases) for the dev pass — then re-invokes it on the `done` spec for the follow-up review pass — and `froid-loop-sweep`, watches their hook signals, and verifies their artifacts. Installing it is therefore part of setup, not an optional extra.
|
|
59
|
+
|
|
60
|
+
> **Why from Git?** The FROID installer copies only skill directories into a project — it does not carry sibling files, so the tool can't ride along in the skill folder. The canonical source is <https://github.com/cordya-ai/froid-loop>. (The reverse holds, though: the tool's wheel **bundles** the skills, so `froid-loop init` lays them down into a project's skill trees on its own — see step 3.)
|
|
61
|
+
|
|
62
|
+
Unless the user explicitly asked to skip it (e.g. `skills only` / `--no-tool`), install **or upgrade** and bootstrap now. Resolve `{project-root}` to the real project path before running.
|
|
63
|
+
|
|
64
|
+
1. **Check what's already on PATH:** run `froid-loop --version`. A version printing here does **not** mean this project is set up — it only means _some_ `froid-loop` is importable in the current environment. Before trusting it, run `uv tool list` and look for `froid-loop`: if it's absent (the on-PATH copy comes from a source checkout or an unrelated virtualenv), warn the user that the active environment is shadowing a clean install and that the project would be relying on that checkout. Unless the user explicitly declines, install/upgrade from the canonical source below so the project doesn't depend on an incidental dev environment.
|
|
65
|
+
|
|
66
|
+
2. **Install or upgrade from the Git repository** (the `[tui]` extra pulls in the Textual dashboard so `froid-loop tui` works). `uv tool install` puts `froid-loop` in uv's own managed environment, so there's no PEP 668 externally-managed conflict and no need for `--user`, an activated virtualenv, or `--break-system-packages`.
|
|
67
|
+
|
|
68
|
+
- **Fresh install** (no uv-managed `froid-loop`):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv tool install "froid-loop[tui] @ git+https://github.com/cordya-ai/froid-loop.git"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Pin a release tag for reproducibility by appending `@v<X.Y.Z>` to the Git URL.
|
|
75
|
+
|
|
76
|
+
- **Upgrade** (uv already manages `froid-loop`):
|
|
77
|
+
|
|
78
|
+
1. Record the current version first so you can report the delta: `froid-loop --version`.
|
|
79
|
+
2. Default — follow `main` (or the currently pinned tag):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv tool upgrade froid-loop --reinstall
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The `--reinstall` is **required** for a Git source: a plain `uv tool upgrade` reuses the cached commit and won't pull new code. Then **offer to pin a release tag** for reproducibility — if the user wants a specific version, move to it with:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv tool install --force "froid-loop[tui] @ git+https://github.com/cordya-ai/froid-loop.git@v<X.Y.Z>"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
3. Re-run `froid-loop --version` and note the before → after for the confirmation step.
|
|
92
|
+
|
|
93
|
+
3. **Bootstrap the project** — install the coding-CLI hooks, the bundled `froid-loop-*` skills, the `.froid-loop/policy.toml` template, and the gitignore entry (idempotent).
|
|
94
|
+
|
|
95
|
+
First decide **which coding CLI(s)** the orchestrator should drive. The supported adapters are `claude` (default), `codex`, `gemini`, `copilot`, and `antigravity` (Google's `agy`). Hooks are registered per CLI, so the choice matters — register every CLI you intend to use for dev/review/triage. Ask the user (unless they already specified it in their setup args, e.g. `cli: claude, codex`, or accepted defaults — then default to `claude` only):
|
|
96
|
+
|
|
97
|
+
> "Which coding CLI(s) should the orchestrator drive — `claude`, `codex`, `gemini`, `copilot`, and/or `antigravity`? You can pick more than one. [claude]"
|
|
98
|
+
|
|
99
|
+
Build the command with one `--cli <name>` per selected CLI (the flag is repeatable). **On an upgrade, append `--force-skills`** so the per-project skill copies are actually refreshed — without it `init` skips every existing skill dir and the project keeps stale skills against the upgraded tool. On a fresh install, omit it.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# fresh install, claude only (default)
|
|
103
|
+
froid-loop init --project "{project-root}" --cli claude
|
|
104
|
+
|
|
105
|
+
# fresh install, multiple, e.g. claude + codex + gemini
|
|
106
|
+
froid-loop init --project "{project-root}" --cli claude --cli codex --cli gemini
|
|
107
|
+
|
|
108
|
+
# upgrade — refresh the bundled skills in place
|
|
109
|
+
froid-loop init --project "{project-root}" --cli claude --force-skills
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Names must be exactly `claude`, `codex`, `gemini`, `copilot`, or `antigravity` — `init` errors on an unknown profile and lists the valid ones. `init` prints any one-time first-run notes per CLI (e.g. start `claude` once in the project and accept the workspace-trust + hooks-approval dialogs before `froid-loop run` — spawned sessions can't answer first-run dialogs). Relay those notes to the user.
|
|
113
|
+
|
|
114
|
+
**Skills are installed automatically:** `init` lays the bundled `froid-loop-*` skills into the right tree for each selected CLI — `.claude/skills/` for `claude`, `.agents/skills/` for `codex`/`gemini`/`copilot`/`antigravity`. On a fresh install, existing skill dirs are left untouched; on an upgrade, `--force-skills` overwrites them with the bundled copies from the upgraded tool (use `--no-skills` to skip the step and manage skills yourself).
|
|
115
|
+
|
|
116
|
+
> **Note:** `--force-skills` also overwrites `froid-loop-setup` itself (it ships in the same bundle). That's expected and safe — the freshly laid-down setup skill takes effect on the **next** invocation, and your `_froid/custom/*.toml` overrides (keyed by skill directory name) are untouched.
|
|
117
|
+
|
|
118
|
+
4. **Preflight** — verify config, sprint-status, git, tmux, and the coding CLI:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
froid-loop validate --project "{project-root}"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`validate` exits non-zero when the project isn't fully ready (e.g. no `sprint-status.yaml` yet, or `froid-sprint-planning` hasn't run). On a fresh project that is **expected** — report its findings to the user as a readiness checklist, not as an install failure.
|
|
125
|
+
|
|
126
|
+
5. **Point the user at per-role adapter config.** `--cli` in step 3 only registers _hooks_ for each CLI. Which CLI actually **runs** each stage is governed by `{project-root}/.froid-loop/policy.toml`, written from a template by `init`. The `[adapter] name` (default `claude`) applies to every stage; optional `[adapter.dev]`, `[adapter.review]`, and `[adapter.triage]` tables override individual stages (each takes its own `name` and `extra_args`). So a mixed setup — e.g. `claude` for dev, `codex` for review — needs both the hooks registered (step 3) **and** the role pointed at that CLI in `policy.toml`:
|
|
127
|
+
|
|
128
|
+
```toml
|
|
129
|
+
[adapter]
|
|
130
|
+
name = "claude" # default for all stages
|
|
131
|
+
|
|
132
|
+
[adapter.review]
|
|
133
|
+
name = "codex" # review runs on codex instead
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Tell the user where the file is and that any CLI named in `policy.toml` must also have been registered with `--cli` in step 3 (re-run `froid-loop init --cli <name>` to add one later). Leave `policy.toml` untouched if they only use a single CLI — the default is correct.
|
|
137
|
+
|
|
138
|
+
## Confirm
|
|
139
|
+
|
|
140
|
+
Report:
|
|
141
|
+
|
|
142
|
+
- **Fresh install:** the installed `froid-loop --version`, that `froid-loop init` registered hooks, installed the `froid-loop-*` skills, and wrote policy/gitignore for the selected coding CLI(s) (name each one — e.g. "hooks + skills installed for claude, codex").
|
|
143
|
+
- **Upgrade:** the before → after `froid-loop --version` (e.g. "upgraded 0.3.1 → 0.3.2", or "already current at 0.3.2"), and that the `froid-loop-*` skills were **refreshed** (not skipped) with `--force-skills` in each CLI tree.
|
|
144
|
+
|
|
145
|
+
Also report:
|
|
146
|
+
|
|
147
|
+
- The `froid-loop validate` preflight result (pass, or the readiness checklist of what's still missing).
|
|
148
|
+
- That `_froid/froid-loop/module-help.csv` was refreshed. If `_froid/froid-loop/` did not exist before this run (i.e. the FROID installer never installed the module), say that the help entries will appear in `/froid-help` after the FROID installer next runs, and that installing the module via `npx froid-plane install` registers it properly.
|
|
149
|
+
- That this skill wrote nothing else under `_froid/` — module registration, `config.toml`, and the help catalog are owned by the FROID installer.
|
|
150
|
+
|
|
151
|
+
Then display the `module_greeting` from `./assets/module.yaml` to the user.
|
|
152
|
+
|
|
153
|
+
## Outcome
|
|
154
|
+
|
|
155
|
+
Use the user's configured name and language for the remainder of the session. Read them from FROID's central config via its own resolver (four-layer TOML merge; needs FROID v6.10+ and Python 3.11+):
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
uv run "{project-root}/_froid/scripts/resolve_config.py" --project-root "{project-root}" --key core
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Take `user_name` and `communication_language` from the `core` table. If the script is absent or exits non-zero, fall back to addressing the user neutrally in English — do not write or repair any config file.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
|
|
2
|
+
FROID Loop Skills,froid-loop-setup,Setup Loop Module,SA,Install or update FROID Loop module config and help entries.,configure,{-H: headless mode},anytime,,,false,{project-root}/_froid,config.yaml entries
|
|
3
|
+
FROID Loop Skills,froid-loop-sweep,Sweep Triage,ST,Read-only triage of the deferred-work ledger into a machine-readable partition. Automation-only; froid-loop sweep invokes it.,triage,{--feedback path},anytime,,,false,implementation_artifacts,result.json triage plan
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
code: froid-loop
|
|
2
|
+
name: FROID Loop Skills
|
|
3
|
+
description: "Automation-mode skills driven by the froid-loop orchestrator: interactive escalation resolution (froid-loop-resolve) and deferred-work sweep triage (froid-loop-sweep) — the inner dev primitive (which self-reviews and commits) is the upstream froid-build-auto skill (froid-dev-auto on pre-rename releases)"
|
|
4
|
+
module_version: 0.11.1
|
|
5
|
+
default_selected: false
|
|
6
|
+
module_greeting: >
|
|
7
|
+
FROID Loop installed — both the automation skills and the
|
|
8
|
+
froid-loop orchestrator tool (the Python program that drives the loop). Setup
|
|
9
|
+
installed the `froid-loop` package from its Git repository with
|
|
10
|
+
`uv tool install`, ran `froid-loop init` (skills + hooks + policy + gitignore),
|
|
11
|
+
and `froid-loop validate`
|
|
12
|
+
(preflight). The skills
|
|
13
|
+
are invoked by the orchestrator and must stay installed together — the
|
|
14
|
+
froid-loop-sweep skill normalizes and migrates the deferred-work ledger per its
|
|
15
|
+
own deferred-work-format.md. They require the Froid Plane (bmm) module:
|
|
16
|
+
_froid/bmm/config.yaml and a sprint-status.yaml from froid-sprint-planning. Run
|
|
17
|
+
`froid-loop run` to start, `froid-loop tui` for the dashboard. To upgrade later,
|
|
18
|
+
just re-run `/froid-loop-setup` (or `/froid-loop-setup upgrade`) — it upgrades the
|
|
19
|
+
orchestrator tool and refreshes the per-project skills for you.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: froid-loop-sweep
|
|
3
|
+
description: 'Triage the deferred-work ledger for the froid-loop orchestrator: verify every open entry against the actual codebase and return a machine-readable partition (bundles, already-resolved, blocked, skip, human decisions). Also migrates legacy pre-DW-format ledgers when invoked with --migrate. Automation-only — invoked by froid-loop sweep runs, not by humans.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deferred-Work Sweep Triage
|
|
7
|
+
|
|
8
|
+
**Goal:** Classify every open entry in `{implementation_artifacts}/deferred-work.md`
|
|
9
|
+
into a machine-readable triage plan the orchestrator can validate and execute.
|
|
10
|
+
|
|
11
|
+
This workflow is **read-only and automation-native**: it runs only inside a
|
|
12
|
+
`froid-loop` sweep session. You never edit the ledger, never edit code, never
|
|
13
|
+
ask questions. Your sole output is the result file. (The one exception is
|
|
14
|
+
migration mode, which edits exactly one file — the ledger.)
|
|
15
|
+
|
|
16
|
+
## On Activation
|
|
17
|
+
|
|
18
|
+
### Step 0: Automation Check & Mode Dispatch
|
|
19
|
+
|
|
20
|
+
Run: `echo "${FROID_LOOP_MODE:-}"`
|
|
21
|
+
|
|
22
|
+
If the output is not `1`, state that this skill only runs inside a froid-loop
|
|
23
|
+
sweep and end your turn. Otherwise read `./automation-mode.md` fully — its
|
|
24
|
+
rules and result schema govern this entire run.
|
|
25
|
+
|
|
26
|
+
If the invocation carries `--migrate <manifest-path>`, this is a **migration
|
|
27
|
+
session**, not triage: read `./migration-mode.md` and follow it instead of
|
|
28
|
+
Steps 1–4 below.
|
|
29
|
+
|
|
30
|
+
### Step 1: Locate the ledger
|
|
31
|
+
|
|
32
|
+
Read `{project-root}/_froid/bmm/config.yaml` to resolve `implementation_artifacts`,
|
|
33
|
+
then read `{implementation_artifacts}/deferred-work.md` in full. Open entries
|
|
34
|
+
are `### DW-<n>:` blocks whose `status:` line is `open`. If the ledger is
|
|
35
|
+
missing or unreadable, escalate `CRITICAL` (`type: missing-ledger`) per
|
|
36
|
+
automation-mode.md and end your turn.
|
|
37
|
+
|
|
38
|
+
An entry carrying an `archived:` line keeps only a stub here — its full body
|
|
39
|
+
lives in the sibling `deferred-work-archive.md`, keyed by the same DW- id; read
|
|
40
|
+
it there before classifying that entry. An `archived-body:` line says the same
|
|
41
|
+
of an entry that was archived and later reopened: it is live work again, but the
|
|
42
|
+
body it carried before that close is still in the archive file, in the block
|
|
43
|
+
stamped with the date the line carries.
|
|
44
|
+
|
|
45
|
+
If the invocation carries `--feedback <path>`, read that file FIRST — it lists
|
|
46
|
+
the deterministic validation errors your previous attempt's result.json failed
|
|
47
|
+
on. Fix exactly those defects in this attempt's output.
|
|
48
|
+
|
|
49
|
+
### Step 2: Verify every open entry against the code
|
|
50
|
+
|
|
51
|
+
Ledger statuses are known-unreliable: entries are often resolved by later work
|
|
52
|
+
but never marked done. For EACH open entry:
|
|
53
|
+
|
|
54
|
+
1. Read its `location:` (file/component) in the current tree.
|
|
55
|
+
2. Check whether the described issue still exists — read the code, grep for
|
|
56
|
+
the symptom, check `git log` for commits that touched the area since the
|
|
57
|
+
entry's `origin:` date.
|
|
58
|
+
3. Record concrete evidence either way. "Probably fixed" is not evidence;
|
|
59
|
+
a file:line or commit hash is.
|
|
60
|
+
|
|
61
|
+
Use sub-agents for parallel verification when available; never ask permission.
|
|
62
|
+
|
|
63
|
+
### Step 3: Partition
|
|
64
|
+
|
|
65
|
+
Classify each open entry into exactly ONE category:
|
|
66
|
+
|
|
67
|
+
- **already_resolved** — the issue no longer exists in the code. Requires
|
|
68
|
+
concrete `evidence` (file:line that now handles it, or the commit that fixed
|
|
69
|
+
it). The orchestrator closes the ledger entry deterministically.
|
|
70
|
+
- **bundles** — buildable now: every file the fix needs already exists and no
|
|
71
|
+
future story has to land first. Group entries that share a touchpoint (same
|
|
72
|
+
file, same subsystem, same validator pattern) into cohesive single-goal
|
|
73
|
+
bundles sized for one dev session; an entry that stands alone is a
|
|
74
|
+
one-entry bundle. `name` matches `^[a-z0-9][a-z0-9-]{1,39}\Z` (kebab-case,
|
|
75
|
+
at most 40 characters; e.g. `unicode-string-hardening`), and `intent` is
|
|
76
|
+
2–6 sentences describing the one cohesive goal.
|
|
77
|
+
- **blocked** — the fix is only meaningful (or meaningfully easier) after a
|
|
78
|
+
named future story/epic lands. Name the blocker verbatim.
|
|
79
|
+
- **skip** — superseded, moot, or tied to a scenario the project explicitly
|
|
80
|
+
excludes. Give the reason.
|
|
81
|
+
- **decisions** — a human must choose. ALWAYS a decision, never a bundle:
|
|
82
|
+
renegotiating anything inside a spec's `<frozen-after-approval>` block,
|
|
83
|
+
reversing a deliberate human-approved scope decision, API-shape changes that
|
|
84
|
+
ripple to unbuilt consumers, and entries deferred with reason
|
|
85
|
+
"auto-mode: needs human decision". Each decision gets 2–4 concrete options
|
|
86
|
+
(each with an `effect`: `build` + an implementation intent, `close` +
|
|
87
|
+
optional resolution, or `keep-open`) and your `recommendation`. The only
|
|
88
|
+
exception: a frozen-block renegotiation that is clearly net-positive,
|
|
89
|
+
non-destructive, and behavior-tightening may be bundled — when in doubt,
|
|
90
|
+
make it a decision.
|
|
91
|
+
|
|
92
|
+
Every open entry appears in exactly one category. The orchestrator validates
|
|
93
|
+
this deterministically; a missed or double-counted entry fails the whole
|
|
94
|
+
result and burns a retry.
|
|
95
|
+
|
|
96
|
+
### Step 4: Write the result and end your turn
|
|
97
|
+
|
|
98
|
+
Write the result.json per `./automation-mode.md` and state in one line how
|
|
99
|
+
many entries went to each category. End your turn. Do not edit any file other
|
|
100
|
+
than the result file.
|