@terreno/agent-plugin-loop 0.0.0-stage → 57.22.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/.claude-plugin/plugin.json +28 -0
- package/CHANGELOG.md +2155 -0
- package/LICENSE +21 -0
- package/README.md +59 -2
- package/package.json +31 -4
- package/references/finding.schema.json +39 -0
- package/references/goal-tracking.md +71 -0
- package/references/heartbeat.md +91 -0
- package/references/mapreduce.md +90 -0
- package/references/pr-routing.md +77 -0
- package/references/scan-contract.md +195 -0
- package/references/scan-result.schema.json +121 -0
- package/references/scan-state.schema.json +199 -0
- package/skills/1-aim/SKILL.md +114 -0
- package/skills/1-aim/references/charter.md +96 -0
- package/skills/2-sweep/SKILL.md +92 -0
- package/skills/2-sweep/references/worker-briefing.md +70 -0
- package/skills/3-sift/SKILL.md +93 -0
- package/skills/4-plot/SKILL.md +124 -0
- package/skills/5-track/SKILL.md +112 -0
- package/skills/campaign/SKILL.md +185 -0
- package/skills/run/SKILL.md +165 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Scan contract
|
|
2
|
+
|
|
3
|
+
Aim, Sweep, Sift, Plot, and Track are **transitions**, not the orchestration loop.
|
|
4
|
+
`terreno-loop-campaign` is the invocable outer loop; it must never be recorded as a
|
|
5
|
+
`stage` value.
|
|
6
|
+
|
|
7
|
+
A scan is not a code change. Scan stages discover, prioritize, and shape work; the
|
|
8
|
+
Terreno lifecycle (`terreno-1-grow`, `terreno-2-pick`, `terreno-3-roast`,
|
|
9
|
+
`terreno-4-brew`, `terreno-5-taste`) implements and ships it. No scan stage edits
|
|
10
|
+
product code, commits, pushes, or opens a PR.
|
|
11
|
+
|
|
12
|
+
Two outer loops drive the stages. `terreno-loop-campaign` runs bounded rounds and stops
|
|
13
|
+
at each gate. `terreno-loop-run` stays resident: it keeps the campaign moving, routes
|
|
14
|
+
every PR to a named human per [`pr-routing.md`](pr-routing.md), and heartbeats over open
|
|
15
|
+
PRs per [`heartbeat.md`](heartbeat.md) so review comments, red CI, and merges are handled
|
|
16
|
+
without a person restarting anything.
|
|
17
|
+
|
|
18
|
+
| Owner | Responsibility |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| Campaign loop | when to invoke, which agent, persistence, retry, stop, escalation, lifecycle handoff |
|
|
21
|
+
| Resident loop | the same, plus PR routing, the heartbeat over open PRs, and scheduling |
|
|
22
|
+
| Scan stage | one bounded transition plus its evidence |
|
|
23
|
+
| Lifecycle stages | implementing, proving, submitting, and landing one plotted slice |
|
|
24
|
+
| Repository skills | repository commands, architecture, safety rules, and domain conventions |
|
|
25
|
+
| Campaign state | what a fresh invocation needs from previous rounds |
|
|
26
|
+
|
|
27
|
+
Every stage reads durable inputs, performs one bounded transition, writes campaign
|
|
28
|
+
state, emits one result document, and exits. Never rely on conversational memory.
|
|
29
|
+
|
|
30
|
+
## Stages
|
|
31
|
+
|
|
32
|
+
| Stage | Transition | PASS next |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `aim` | Goal, metric, baseline, detection rules, exclusions, validity rule, severity rubric, slice policy; human approval | `sweep` |
|
|
35
|
+
| `sweep` | Shard the rule hits and map parallel workers over the shards into candidate findings | `sift` |
|
|
36
|
+
| `sift` | Reduce: dedupe, verify, drop unfounded, rank, write the findings report | `plot`, or `track` when the round is dry |
|
|
37
|
+
| `plot` | Turn ranked findings into PR-sized slices and hand the top slice to the lifecycle | `track` with `handoff: grow` |
|
|
38
|
+
| `track` | Re-measure the goal metric, close or reopen findings, record the round, choose the next move | `plot`, `sweep`, or `null` |
|
|
39
|
+
|
|
40
|
+
## Goal before findings
|
|
41
|
+
|
|
42
|
+
A campaign exists to move one measurable goal, not to collect observations. Aim must
|
|
43
|
+
produce a metric with a command that prints it, a baseline captured by running that
|
|
44
|
+
command, and a target. Every later stage justifies its output by that metric:
|
|
45
|
+
|
|
46
|
+
- A detection rule that cannot plausibly move the metric does not belong in the charter.
|
|
47
|
+
- A finding that cannot be tied to the metric is dismissed in Sift, not deferred.
|
|
48
|
+
- A slice that lands without a metric re-measurement in Track is unproven work.
|
|
49
|
+
|
|
50
|
+
See [`goal-tracking.md`](goal-tracking.md).
|
|
51
|
+
|
|
52
|
+
## Evidence
|
|
53
|
+
|
|
54
|
+
Every candidate and every finding carries reproducible evidence: a `path:line`
|
|
55
|
+
anchor plus the command, query, probe output, or artifact that produced it. Findings
|
|
56
|
+
without evidence are dropped in Sift, never carried forward with a caveat. Never persist
|
|
57
|
+
chain-of-thought, worker transcripts, or speculative narration.
|
|
58
|
+
|
|
59
|
+
## Discover supporting skills
|
|
60
|
+
|
|
61
|
+
At the start of every stage:
|
|
62
|
+
|
|
63
|
+
1. Inspect skills exposed by the harness and repository.
|
|
64
|
+
2. Match their descriptions to **this round's rules, files, and findings**, not the
|
|
65
|
+
whole catalog.
|
|
66
|
+
3. Load applicable `SKILL.md` files before acting and record their names in `skills`.
|
|
67
|
+
4. If repository instructions require a capability and it is unavailable, return
|
|
68
|
+
`BLOCKED`; never silently skip it.
|
|
69
|
+
5. If no skill applies, infer conventions from repository instructions, existing code,
|
|
70
|
+
tests, package scripts, and recent analogous changes.
|
|
71
|
+
|
|
72
|
+
The lifecycle plugin's stages perform their own discovery once a slice is handed off.
|
|
73
|
+
Scan stages do not pre-resolve implementation skills for them.
|
|
74
|
+
|
|
75
|
+
## Map workers
|
|
76
|
+
|
|
77
|
+
Sweep spawns fresh workers with no parent memory. Each worker receives a
|
|
78
|
+
**shard briefing** and returns schema-valid findings only. Workers never reconstruct the
|
|
79
|
+
repository, never run a full-branch diff, never spawn nested workers, and never edit
|
|
80
|
+
files. See [`mapreduce.md`](mapreduce.md).
|
|
81
|
+
|
|
82
|
+
## Documentation
|
|
83
|
+
|
|
84
|
+
Scan stages write scan artifacts (charter, findings report, round records). They do not
|
|
85
|
+
write product architecture docs. The plotted slices carry documentation work: every task
|
|
86
|
+
Plot writes names the docs to create or update, and the lifecycle's documentation
|
|
87
|
+
contract applies when that slice runs.
|
|
88
|
+
|
|
89
|
+
## Stage result
|
|
90
|
+
|
|
91
|
+
The machine-readable result is for the next skill and the campaign loop. It is **not**
|
|
92
|
+
the human-facing answer.
|
|
93
|
+
|
|
94
|
+
Lead the chat with `status`, `next`, and `action` in one or two lines, plus the current
|
|
95
|
+
metric when the stage measured one. Put the YAML only in a collapsed details block.
|
|
96
|
+
|
|
97
|
+
The schema is [`scan-result.schema.json`](scan-result.schema.json) (`v: 2`). Required
|
|
98
|
+
keys are `v`, `stage`, `status`, `next`, and `action`. Omit nulls and empty arrays.
|
|
99
|
+
Status values are exactly `PASS`, `FAIL`, `BLOCKED`, or `PENDING`.
|
|
100
|
+
|
|
101
|
+
Wrap the YAML:
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<details>
|
|
105
|
+
<summary>Scan result</summary>
|
|
106
|
+
</details>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Example payload:
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
v: 2
|
|
113
|
+
stage: sift
|
|
114
|
+
status: PASS
|
|
115
|
+
goal: reduce-cold-build-time
|
|
116
|
+
round: 2
|
|
117
|
+
found: 31
|
|
118
|
+
kept: 12
|
|
119
|
+
metric:
|
|
120
|
+
value: 48.2
|
|
121
|
+
unit: s
|
|
122
|
+
ev: "bun run compile (cold): 48.2s"
|
|
123
|
+
artifacts:
|
|
124
|
+
- docs/scans/reduce-cold-build-time/round-2-findings.md
|
|
125
|
+
next: plot
|
|
126
|
+
action: Slice the four high-severity findings into the first PR-sized unit of work
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
| Key | Meaning |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| `goal` | campaign goal slug |
|
|
132
|
+
| `round` | current sweep round |
|
|
133
|
+
| `metric` | measured metric value, unit, delta, and the command that produced it |
|
|
134
|
+
| `found` / `kept` / `closed` | candidate, surviving, and resolved finding counts |
|
|
135
|
+
| `skills` | supporting skills loaded |
|
|
136
|
+
| `artifacts` | charter, candidate file, findings report, slice briefs |
|
|
137
|
+
| `handoff` | lifecycle stage the campaign must invoke next (`grow` or `pick`) |
|
|
138
|
+
| `fail` | `need` / `want` / `got` / `ev` |
|
|
139
|
+
| `block` | `kind` / `why` / optional `ev` |
|
|
140
|
+
| `ask` | human questions: `q` / `rec` / optional `opts` |
|
|
141
|
+
| `next` | recommended next scan stage or `null` |
|
|
142
|
+
| `action` | concrete next action |
|
|
143
|
+
| `wait` | seconds until the campaign should check a handed-off slice again |
|
|
144
|
+
|
|
145
|
+
## Campaign state
|
|
146
|
+
|
|
147
|
+
The charter and the findings report remain authoritative for scope and evidence.
|
|
148
|
+
Campaign state is a small loop-owned handoff, not a third plan.
|
|
149
|
+
|
|
150
|
+
Use an existing repository convention when present. Otherwise use
|
|
151
|
+
`.terreno/scan/<goal-slug>.json`, conforming to
|
|
152
|
+
[`scan-state.schema.json`](scan-state.schema.json). The campaign loop must preserve or
|
|
153
|
+
transport this file between fresh invocations. Do not commit it unless the repository
|
|
154
|
+
explicitly tracks scan state; lifecycle Brew must exclude loop-owned state from PR
|
|
155
|
+
commits.
|
|
156
|
+
|
|
157
|
+
Each invocation:
|
|
158
|
+
|
|
159
|
+
1. Read state and verify its goal, round, branch, and findings against reality.
|
|
160
|
+
2. Increment `attempt` for the invoked stage.
|
|
161
|
+
3. Consume `last` and prior `tried` approaches; do not repeat a failed approach without
|
|
162
|
+
new evidence.
|
|
163
|
+
4. Perform the stage.
|
|
164
|
+
5. Replace `last`, merge artifact references, and set `next`.
|
|
165
|
+
6. Emit the same result to the caller so the loop can persist it elsewhere.
|
|
166
|
+
|
|
167
|
+
These six operations are mandatory whenever a stage says "update campaign state." Every
|
|
168
|
+
result also includes a concrete `action`, even when `next` is `null`.
|
|
169
|
+
|
|
170
|
+
If no writable artifact exists, still emit the result. If the campaign loop cannot
|
|
171
|
+
preserve that result for the next fresh invocation, return `BLOCKED` and name the
|
|
172
|
+
missing state transport.
|
|
173
|
+
|
|
174
|
+
## Failures, blockers, and pending
|
|
175
|
+
|
|
176
|
+
- `FAIL`: objective failure of this stage — an unproven detection rule, a malformed
|
|
177
|
+
candidate set, a findings report that contradicts its evidence. Preserve exact
|
|
178
|
+
evidence and recommend the smallest retry.
|
|
179
|
+
- `BLOCKED`: no safe action exists now. Classify `human`, `environment`, `access`, or
|
|
180
|
+
`external`; include the exact action or decision required.
|
|
181
|
+
- `PENDING`: a handed-off slice is still moving through the lifecycle, a PR is waiting on
|
|
182
|
+
review or CI, or a long measurement has not finished. Include `wait`; the **campaign or
|
|
183
|
+
resident loop** waits and invokes again. Prefer the harness's native completion hook or the provider's watch hook over
|
|
184
|
+
sleep polling; use a timer only when no hook applies.
|
|
185
|
+
- `PASS`: this stage's success conditions are proven for the recorded round.
|
|
186
|
+
|
|
187
|
+
Human gates include the goal statement and target, destructive or irreversible
|
|
188
|
+
remediation, public API or data-format changes surfaced by findings, scope growth beyond
|
|
189
|
+
the approved charter, and policy-required approval. Include options, tradeoffs,
|
|
190
|
+
evidence, and a recommended default.
|
|
191
|
+
|
|
192
|
+
A campaign requesting human input must first summarize goal state, metric movement,
|
|
193
|
+
completed rounds, decisive evidence, options and impact, and a recommended default. It
|
|
194
|
+
ends with one exact question, then the Demo section when a handed-off PR has deployment
|
|
195
|
+
URLs. Objective failures are not human gates while a concrete safe action remains.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://terreno.dev/schemas/scan-result.schema.json",
|
|
4
|
+
"title": "Terreno scan stage result",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["v", "stage", "status", "next", "action"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"v": {"const": 2},
|
|
10
|
+
"stage": {"enum": ["aim", "sweep", "sift", "plot", "track"]},
|
|
11
|
+
"status": {"enum": ["PASS", "FAIL", "BLOCKED", "PENDING"]},
|
|
12
|
+
"goal": {"type": "string"},
|
|
13
|
+
"round": {"type": "integer", "minimum": 1},
|
|
14
|
+
"attempt": {"type": "integer", "minimum": 1},
|
|
15
|
+
"branch": {"type": "string"},
|
|
16
|
+
"sha": {"type": "string"},
|
|
17
|
+
"pr": {"type": "string"},
|
|
18
|
+
"skills": {"type": "array", "items": {"type": "string"}},
|
|
19
|
+
"rules": {"type": "array", "items": {"type": "string"}},
|
|
20
|
+
"shards": {"type": "integer", "minimum": 0},
|
|
21
|
+
"found": {"type": "integer", "minimum": 0},
|
|
22
|
+
"kept": {"type": "integer", "minimum": 0},
|
|
23
|
+
"closed": {"type": "integer", "minimum": 0},
|
|
24
|
+
"metric": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"required": ["value", "ev"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"value": {"type": "number"},
|
|
30
|
+
"unit": {"type": "string"},
|
|
31
|
+
"delta": {"type": "number"},
|
|
32
|
+
"ev": {"type": "string"}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"done": {"type": "array", "items": {"type": "string"}},
|
|
36
|
+
"artifacts": {"type": "array", "items": {"type": "string"}},
|
|
37
|
+
"slices": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"required": ["slug", "findings", "status"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"slug": {"type": "string"},
|
|
45
|
+
"ip": {"type": "string"},
|
|
46
|
+
"tasks": {"type": "string"},
|
|
47
|
+
"findings": {"type": "array", "items": {"type": "string"}},
|
|
48
|
+
"status": {"enum": ["planned", "running", "merged", "abandoned"]},
|
|
49
|
+
"pr": {"type": "string"}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"prs": {
|
|
54
|
+
"type": "array",
|
|
55
|
+
"items": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": ["pr", "bucket"],
|
|
59
|
+
"properties": {
|
|
60
|
+
"pr": {"type": "string"},
|
|
61
|
+
"bucket": {
|
|
62
|
+
"enum": ["unrouted", "answered", "broken", "bot-pending", "merged", "closed", "waiting"]
|
|
63
|
+
},
|
|
64
|
+
"who": {"type": "string"},
|
|
65
|
+
"slice": {"type": "string"}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"fail": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"items": {
|
|
72
|
+
"type": "object",
|
|
73
|
+
"additionalProperties": false,
|
|
74
|
+
"required": ["need", "want", "got", "ev"],
|
|
75
|
+
"properties": {
|
|
76
|
+
"need": {"type": "string"},
|
|
77
|
+
"sev": {"enum": ["blocking", "non_blocking"]},
|
|
78
|
+
"want": {"type": "string"},
|
|
79
|
+
"got": {"type": "string"},
|
|
80
|
+
"ev": {"type": "string"}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"block": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"additionalProperties": false,
|
|
89
|
+
"required": ["kind", "why"],
|
|
90
|
+
"properties": {
|
|
91
|
+
"kind": {"enum": ["human", "environment", "access", "external"]},
|
|
92
|
+
"why": {"type": "string"},
|
|
93
|
+
"ev": {"type": "string"}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"ask": {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"additionalProperties": false,
|
|
102
|
+
"required": ["q", "rec"],
|
|
103
|
+
"properties": {
|
|
104
|
+
"q": {"type": "string"},
|
|
105
|
+
"opts": {"type": "array", "items": {"type": "string"}},
|
|
106
|
+
"rec": {"type": "string"}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"handoff": {
|
|
111
|
+
"type": ["string", "null"],
|
|
112
|
+
"enum": ["grow", "pick", null]
|
|
113
|
+
},
|
|
114
|
+
"next": {
|
|
115
|
+
"type": ["string", "null"],
|
|
116
|
+
"enum": ["aim", "sweep", "sift", "plot", "track", null]
|
|
117
|
+
},
|
|
118
|
+
"action": {"type": "string"},
|
|
119
|
+
"wait": {"type": "integer", "minimum": 1}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://terreno.dev/schemas/scan-state.schema.json",
|
|
4
|
+
"title": "Terreno scan campaign state",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["v", "goal", "stage", "round", "attempt", "next"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"v": {"const": 2},
|
|
10
|
+
"goal": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"required": ["slug", "statement", "metric", "baseline", "target"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"slug": {"type": "string"},
|
|
16
|
+
"statement": {"type": "string"},
|
|
17
|
+
"charter": {"type": "string"},
|
|
18
|
+
"metric": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": ["name", "command", "unit", "direction"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"name": {"type": "string"},
|
|
24
|
+
"command": {"type": "string"},
|
|
25
|
+
"unit": {"type": "string"},
|
|
26
|
+
"direction": {"enum": ["up", "down"]},
|
|
27
|
+
"protocol": {"type": "string"}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"baseline": {"type": "number"},
|
|
31
|
+
"target": {"type": "number"},
|
|
32
|
+
"current": {"type": "number"},
|
|
33
|
+
"horizon": {"type": "string"},
|
|
34
|
+
"review": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"required": ["mode"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"mode": {"enum": ["fixed", "codeowners", "blame", "round-robin", "none"]},
|
|
40
|
+
"reviewers": {"type": "array", "items": {"type": "string"}},
|
|
41
|
+
"assignees": {"type": "array", "items": {"type": "string"}},
|
|
42
|
+
"teams": {"type": "array", "items": {"type": "string"}},
|
|
43
|
+
"draft": {"type": "boolean"},
|
|
44
|
+
"labels": {"type": "array", "items": {"type": "string"}},
|
|
45
|
+
"wipLimit": {"type": "integer", "minimum": 1},
|
|
46
|
+
"mergePolicy": {"enum": ["human", "agent-after-approval"]},
|
|
47
|
+
"notify": {"type": "string"},
|
|
48
|
+
"rotation": {"type": "integer", "minimum": 0}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"budget": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": false,
|
|
54
|
+
"properties": {
|
|
55
|
+
"rounds": {"type": "integer", "minimum": 1},
|
|
56
|
+
"slicesPerRound": {"type": "integer", "minimum": 1},
|
|
57
|
+
"openPrs": {"type": "integer", "minimum": 1},
|
|
58
|
+
"minStep": {"type": "number"}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"stage": {"enum": ["aim", "sweep", "sift", "plot", "track"]},
|
|
64
|
+
"round": {"type": "integer", "minimum": 1},
|
|
65
|
+
"attempt": {"type": "integer", "minimum": 1},
|
|
66
|
+
"branch": {"type": "string"},
|
|
67
|
+
"skills": {"type": "array", "items": {"type": "string"}},
|
|
68
|
+
"rules": {
|
|
69
|
+
"type": "array",
|
|
70
|
+
"items": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"additionalProperties": false,
|
|
73
|
+
"required": ["name", "query", "matches", "why"],
|
|
74
|
+
"properties": {
|
|
75
|
+
"name": {"type": "string"},
|
|
76
|
+
"query": {"type": "string"},
|
|
77
|
+
"matches": {"type": "string"},
|
|
78
|
+
"why": {"type": "string"},
|
|
79
|
+
"exclude": {"type": "array", "items": {"type": "string"}},
|
|
80
|
+
"hits": {"type": "integer", "minimum": 0}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"exclude": {"type": "array", "items": {"type": "string"}},
|
|
85
|
+
"findings": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"items": {"$ref": "finding.schema.json"}
|
|
88
|
+
},
|
|
89
|
+
"slices": {
|
|
90
|
+
"type": "array",
|
|
91
|
+
"items": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"additionalProperties": false,
|
|
94
|
+
"required": ["slug", "findings", "status"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"slug": {"type": "string"},
|
|
97
|
+
"ip": {"type": "string"},
|
|
98
|
+
"tasks": {"type": "string"},
|
|
99
|
+
"findings": {"type": "array", "items": {"type": "string"}},
|
|
100
|
+
"status": {"enum": ["planned", "running", "merged", "abandoned"]},
|
|
101
|
+
"branch": {"type": "string"},
|
|
102
|
+
"pr": {"type": "string"},
|
|
103
|
+
"reviewer": {"type": "string"},
|
|
104
|
+
"assignee": {"type": "string"},
|
|
105
|
+
"routedBy": {"enum": ["fixed", "codeowners", "blame", "round-robin", "none"]},
|
|
106
|
+
"bucket": {
|
|
107
|
+
"enum": ["unrouted", "answered", "broken", "bot-pending", "merged", "closed", "waiting"]
|
|
108
|
+
},
|
|
109
|
+
"answered": {"type": "array", "items": {"type": "string"}},
|
|
110
|
+
"closedReason": {"type": "string"},
|
|
111
|
+
"round": {"type": "integer", "minimum": 1}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"rounds": {
|
|
116
|
+
"type": "array",
|
|
117
|
+
"items": {
|
|
118
|
+
"type": "object",
|
|
119
|
+
"additionalProperties": false,
|
|
120
|
+
"required": ["round", "metricStart", "ev"],
|
|
121
|
+
"properties": {
|
|
122
|
+
"round": {"type": "integer", "minimum": 1},
|
|
123
|
+
"metricStart": {"type": "number"},
|
|
124
|
+
"metricEnd": {"type": "number"},
|
|
125
|
+
"found": {"type": "integer", "minimum": 0},
|
|
126
|
+
"kept": {"type": "integer", "minimum": 0},
|
|
127
|
+
"planned": {"type": "integer", "minimum": 0},
|
|
128
|
+
"fixed": {"type": "integer", "minimum": 0},
|
|
129
|
+
"dismissed": {"type": "integer", "minimum": 0},
|
|
130
|
+
"reopened": {"type": "integer", "minimum": 0},
|
|
131
|
+
"slices": {"type": "array", "items": {"type": "string"}},
|
|
132
|
+
"risks": {"type": "array", "items": {"type": "string"}},
|
|
133
|
+
"ev": {"type": "string"}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"artifacts": {"type": "array", "items": {"type": "string"}},
|
|
138
|
+
"heartbeat": {
|
|
139
|
+
"type": "object",
|
|
140
|
+
"additionalProperties": false,
|
|
141
|
+
"properties": {
|
|
142
|
+
"lastTick": {"type": "string"},
|
|
143
|
+
"interval": {"type": "integer", "minimum": 1},
|
|
144
|
+
"ticks": {"type": "integer", "minimum": 0},
|
|
145
|
+
"hostFailures": {"type": "integer", "minimum": 0},
|
|
146
|
+
"overrides": {
|
|
147
|
+
"type": "object",
|
|
148
|
+
"additionalProperties": false,
|
|
149
|
+
"properties": {
|
|
150
|
+
"reviewers": {"type": "array", "items": {"type": "string"}},
|
|
151
|
+
"assignee": {"type": "string"},
|
|
152
|
+
"wipLimit": {"type": "integer", "minimum": 1},
|
|
153
|
+
"rounds": {"type": "integer", "minimum": 1},
|
|
154
|
+
"until": {"type": "string"},
|
|
155
|
+
"tick": {"type": "integer", "minimum": 1}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"last": {
|
|
161
|
+
"anyOf": [
|
|
162
|
+
{"type": "null"},
|
|
163
|
+
{"$ref": "scan-result.schema.json"}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
"tried": {
|
|
167
|
+
"type": "array",
|
|
168
|
+
"items": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"additionalProperties": false,
|
|
171
|
+
"required": ["stage", "attempt", "why", "status", "ev"],
|
|
172
|
+
"properties": {
|
|
173
|
+
"stage": {"enum": ["aim", "sweep", "sift", "plot", "track"]},
|
|
174
|
+
"attempt": {"type": "integer", "minimum": 1},
|
|
175
|
+
"why": {"type": "string"},
|
|
176
|
+
"status": {"enum": ["PASS", "FAIL", "BLOCKED", "PENDING"]},
|
|
177
|
+
"ev": {"type": "string"}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"next": {
|
|
182
|
+
"type": "object",
|
|
183
|
+
"additionalProperties": false,
|
|
184
|
+
"required": ["stage", "why", "human"],
|
|
185
|
+
"properties": {
|
|
186
|
+
"stage": {
|
|
187
|
+
"type": ["string", "null"],
|
|
188
|
+
"enum": ["aim", "sweep", "sift", "plot", "track", null]
|
|
189
|
+
},
|
|
190
|
+
"handoff": {
|
|
191
|
+
"type": ["string", "null"],
|
|
192
|
+
"enum": ["grow", "pick", null]
|
|
193
|
+
},
|
|
194
|
+
"why": {"type": "string"},
|
|
195
|
+
"human": {"type": "boolean"}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 1-aim
|
|
3
|
+
description: Turn a long-term codebase goal into an approved scan charter — measurable metric, captured baseline, dry-run detection rules, exclusions, validity rule, severity rubric, and slice policy. Use when asked to scan a codebase for an outcome ("improve build time", "find N+1 queries", "reduce maintenance overhead", "make us WCAG-compliant"), to set a long-term engineering goal, or to start or reshape a scan campaign; not for implementation, PR operations, or one-off searches.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Aim — charter the goal
|
|
7
|
+
|
|
8
|
+
Turn "make the codebase better at X" into a charter a fresh Sweep agent can execute
|
|
9
|
+
without conversation history, and a metric that proves whether the campaign worked.
|
|
10
|
+
|
|
11
|
+
Read the shared [`scan contract`](../../references/scan-contract.md),
|
|
12
|
+
[`agentic map-reduce`](../../references/mapreduce.md),
|
|
13
|
+
[`goal tracking`](../../references/goal-tracking.md),
|
|
14
|
+
[`PR routing`](../../references/pr-routing.md), and the
|
|
15
|
+
[`charter template`](references/charter.md) before acting.
|
|
16
|
+
|
|
17
|
+
## Preconditions
|
|
18
|
+
|
|
19
|
+
- A goal, outcome, or complaint plus a repository are available.
|
|
20
|
+
- This invocation owns charter shaping only. It never edits product code. After
|
|
21
|
+
`PASS`, Sweep runs the scan.
|
|
22
|
+
|
|
23
|
+
## Inputs
|
|
24
|
+
|
|
25
|
+
- The requested outcome and any linked context
|
|
26
|
+
- Existing charter, campaign state, and prior findings when the goal already exists
|
|
27
|
+
- Repository instructions, code, tests, build scripts, CI config, and available skills
|
|
28
|
+
|
|
29
|
+
## Procedure
|
|
30
|
+
|
|
31
|
+
1. **Reconstruct.** Resolve the repository's scan conventions from its instructions and
|
|
32
|
+
nearby artifacts. If none exists, use `docs/scans/<goal-slug>/charter.md` for the
|
|
33
|
+
charter and `.terreno/scan/<goal-slug>.json` for campaign state, and record the new
|
|
34
|
+
convention. Read prior state and verify it against repository reality.
|
|
35
|
+
2. **Read architecture docs.** Load the architecture, domain, and operator docs for the
|
|
36
|
+
areas the goal touches. They define what "correct" means before any rule is written.
|
|
37
|
+
3. **Discover supporting skills.** Load repository/project skills matching the goal's
|
|
38
|
+
domains. Record them for downstream stages.
|
|
39
|
+
4. **Make the goal measurable.** Derive the metric, its command, unit, direction,
|
|
40
|
+
target, horizon, and budget per `goal-tracking.md`. Run the metric command now and
|
|
41
|
+
quote its output as the baseline. If nothing measurable exists, grill for a proxy or
|
|
42
|
+
return `BLOCKED` naming the missing instrumentation — never a judgment-only metric.
|
|
43
|
+
5. **Grill the human frontier.** Work one decision frontier at a time using selectable
|
|
44
|
+
options with a recommended default and the harness's structured question tool when it
|
|
45
|
+
has one. Settle: the outcome statement, the target and horizon, what is explicitly out
|
|
46
|
+
of scope, which trade-offs are unacceptable (for example "no public API breaks"), and
|
|
47
|
+
the budget. Vague or conflicting answers stay on the frontier.
|
|
48
|
+
6. **Settle review routing.** Ask who reviews the campaign's PRs and record the `review`
|
|
49
|
+
block from `pr-routing.md`: mode, reviewer and assignee handles, teams, draft policy,
|
|
50
|
+
labels, the open-PR limit, the merge policy, and how to notify. Verify every handle is
|
|
51
|
+
requestable before writing it. "Whoever is free" is not an answer — resolve it to a
|
|
52
|
+
mode and a list, or to an explicit `mode: none`. This is the decision that makes an
|
|
53
|
+
unattended run safe to leave running.
|
|
54
|
+
7. **Write detection rules.** For each rule record `name`, `query`, `matches`, `why`
|
|
55
|
+
(its link to the metric), and `exclude`. Dry-run every rule, record its hit count, and
|
|
56
|
+
remove or narrow rules that return nothing or flood. A rule that cannot plausibly move
|
|
57
|
+
the metric does not ship.
|
|
58
|
+
8. **Define validity and severity.** State in one sentence what makes a finding valid,
|
|
59
|
+
and give the severity rubric concrete thresholds (`high` / `medium` / `low`) plus the
|
|
60
|
+
effort scale (`S` / `M` / `L`). Workers and Sift use these words verbatim.
|
|
61
|
+
9. **Set the slice policy.** How findings become PR-sized units: maximum files and
|
|
62
|
+
findings per slice, what must never be mixed in one slice, and which findings require
|
|
63
|
+
their own slice because they are risky or reviewer-heavy.
|
|
64
|
+
10. **Write and approve.** Produce the charter from the template, capture the baseline in
|
|
65
|
+
campaign state, and post the standalone approval brief: where the repository is today,
|
|
66
|
+
the goal and metric, the rules with their hit counts, the exclusions, the severity
|
|
67
|
+
rubric, the slice policy, and the decisions table pairing each settled decision with
|
|
68
|
+
the question that prompted it. Mark the charter approved only after human
|
|
69
|
+
confirmation. Update campaign state and emit the result collapsed per the scan
|
|
70
|
+
contract.
|
|
71
|
+
|
|
72
|
+
## Supporting skills
|
|
73
|
+
|
|
74
|
+
Follow the shared discovery procedure. Useful skills typically cover build/test tooling,
|
|
75
|
+
static analysis, performance measurement, accessibility, data access, or security,
|
|
76
|
+
depending on the goal. Names are repository-defined; none is universally required.
|
|
77
|
+
|
|
78
|
+
## Evidence produced
|
|
79
|
+
|
|
80
|
+
- Charter path and campaign-state path
|
|
81
|
+
- Metric definition plus the baseline command output, quoted
|
|
82
|
+
- Detection rules with dry-run hit counts
|
|
83
|
+
- Exclusions, validity rule, severity rubric, effort scale, slice policy
|
|
84
|
+
- Review block: mode, verified reviewer/assignee handles, draft and label policy,
|
|
85
|
+
open-PR limit, merge policy
|
|
86
|
+
- Decisions table with the question that prompted each decision
|
|
87
|
+
- Selected supporting skills and the approved `PASS` result
|
|
88
|
+
|
|
89
|
+
## Success conditions
|
|
90
|
+
|
|
91
|
+
- The metric has a command that prints a number, and the baseline was measured here.
|
|
92
|
+
- Every rule is dry-run-proven with a recorded hit count and a stated link to the metric.
|
|
93
|
+
- A fresh Sweep invocation can shard and brief workers from the charter alone.
|
|
94
|
+
- Every campaign PR has a named, verified destination, or the charter states `mode: none`.
|
|
95
|
+
- A reviewer with no prior context can approve or push back from the brief alone.
|
|
96
|
+
- Emit `PASS` with `next: sweep`.
|
|
97
|
+
|
|
98
|
+
## Failure conditions
|
|
99
|
+
|
|
100
|
+
An unmeasured baseline, an unproven rule, a missing validity rule, or a charter that
|
|
101
|
+
contradicts itself emits `FAIL` with exact defects, `next: aim`, and a focused retry.
|
|
102
|
+
Do not pass an unproven charter to Sweep.
|
|
103
|
+
|
|
104
|
+
## Blocked conditions
|
|
105
|
+
|
|
106
|
+
Unresolved goal or target decisions, a metric the repository cannot produce, a reviewer
|
|
107
|
+
handle that cannot be verified, or missing access to build/measurement tooling emit
|
|
108
|
+
`BLOCKED` with `next: null`, options, tradeoffs, and a recommended default.
|
|
109
|
+
|
|
110
|
+
## Recommended next stage
|
|
111
|
+
|
|
112
|
+
- `PASS` → Sweep
|
|
113
|
+
- `FAIL` → Aim with defect evidence
|
|
114
|
+
- `BLOCKED` → campaign loop routes the named human/external gate
|