@aperant/framework 0.8.4 → 0.8.6
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 +156 -0
- package/agents/apt-planner.md +34 -3
- package/dist/cli/commands/coverage-check.d.mts.map +1 -1
- package/dist/cli/commands/coverage-check.mjs +74 -7
- package/dist/cli/commands/coverage-check.mjs.map +1 -1
- package/dist/cli/commands/detect-runtime.d.mts.map +1 -1
- package/dist/cli/commands/detect-runtime.mjs +18 -12
- package/dist/cli/commands/detect-runtime.mjs.map +1 -1
- package/dist/cli/coverage-check/user-outcomes.d.mts +84 -0
- package/dist/cli/coverage-check/user-outcomes.d.mts.map +1 -0
- package/dist/cli/coverage-check/user-outcomes.mjs +265 -0
- package/dist/cli/coverage-check/user-outcomes.mjs.map +1 -0
- package/dist/cli/host/detect.mjs +1 -1
- package/dist/cli/host/detect.mjs.map +1 -1
- package/dist/cli/install/install-from-source.mjs +3 -3
- 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/verify-proof/idl/index.d.mts +1 -1
- package/dist/cli/verify-proof/idl/index.mjs +7 -8
- package/dist/cli/verify-proof/idl/index.mjs.map +1 -1
- package/dist/cli/verify-proof/idl/types.d.ts +5 -4
- package/dist/cli/verify-proof/idl/types.d.ts.map +1 -1
- package/dist/cli/verify-proof/idl/types.js +4 -3
- package/dist/cli/verify-proof/idl/types.js.map +1 -1
- package/dist/cli/verify-proof/resolver.d.mts +63 -1
- package/dist/cli/verify-proof/resolver.d.mts.map +1 -1
- package/dist/cli/verify-proof/resolver.mjs +164 -4
- package/dist/cli/verify-proof/resolver.mjs.map +1 -1
- package/dist/cli/verify-proof/runtime-detect.d.mts +6 -3
- package/dist/cli/verify-proof/runtime-detect.d.mts.map +1 -1
- package/dist/cli/verify-proof/runtime-detect.mjs +104 -11
- package/dist/cli/verify-proof/runtime-detect.mjs.map +1 -1
- package/dist/cli/verify-proof/trust.d.mts +1 -1
- package/dist/cli/verify-proof/trust.d.mts.map +1 -1
- package/dist/cli/verify-proof/trust.mjs +1 -1
- package/dist/driver-sdk/conformance.d.ts +41 -0
- package/dist/driver-sdk/conformance.d.ts.map +1 -0
- package/dist/driver-sdk/conformance.js +123 -0
- package/dist/driver-sdk/conformance.js.map +1 -0
- package/dist/driver-sdk/errors.d.ts +75 -0
- package/dist/driver-sdk/errors.d.ts.map +1 -0
- package/dist/driver-sdk/errors.js +80 -0
- package/dist/driver-sdk/errors.js.map +1 -0
- package/dist/driver-sdk/idl.d.ts +221 -0
- package/dist/driver-sdk/idl.d.ts.map +1 -0
- package/dist/driver-sdk/idl.js +140 -0
- package/dist/driver-sdk/idl.js.map +1 -0
- package/dist/driver-sdk/index.d.ts +28 -0
- package/dist/driver-sdk/index.d.ts.map +1 -0
- package/dist/driver-sdk/index.js +28 -0
- package/dist/driver-sdk/index.js.map +1 -0
- package/dist/driver-sdk/manifest.d.ts +93 -0
- package/dist/driver-sdk/manifest.d.ts.map +1 -0
- package/dist/driver-sdk/manifest.js +12 -0
- package/dist/driver-sdk/manifest.js.map +1 -0
- package/dist/driver-sdk/retry.d.ts +33 -0
- package/dist/driver-sdk/retry.d.ts.map +1 -0
- package/dist/driver-sdk/retry.js +50 -0
- package/dist/driver-sdk/retry.js.map +1 -0
- package/dist/plugin/.claude-plugin/plugin.json +2 -1
- package/dist/plugin/agents/apt-planner.md +34 -3
- package/dist/plugin/skills/apt-plan/SKILL.md +50 -0
- package/dist/plugin/skills/apt-pr-review/SKILL.md +1 -1
- package/dist/plugin/skills/apt-research/SKILL.md +526 -0
- package/dist/plugin/skills/apt-research/appendices/budget-loop.md +397 -0
- package/dist/plugin/skills/apt-research/appendices/claim-graph-schema.md +206 -0
- package/dist/plugin/skills/apt-research/appendices/domain-tools.md +236 -0
- package/dist/plugin/skills/apt-spar/SKILL.md +19 -7
- package/dist/plugin/skills/apt-verify-proof/SKILL.md +41 -2
- package/dist/schemas/quick-task.d.ts +17 -17
- package/drivers/.gitkeep +0 -0
- package/drivers/api/README.md +40 -0
- package/drivers/api/driver.mjs +59 -0
- package/drivers/api/manifest.json +26 -0
- package/drivers/browser/README.md +105 -0
- package/drivers/browser/driver.mjs +134 -0
- package/drivers/browser/manifest.json +35 -0
- package/drivers/cli/README.md +44 -0
- package/drivers/cli/driver.mjs +62 -0
- package/drivers/cli/manifest.json +28 -0
- package/drivers/electron/README.md +64 -0
- package/drivers/electron/driver.mjs +87 -0
- package/drivers/electron/manifest.json +37 -0
- package/package.json +7 -3
- package/skills/apt-plan/SKILL.md +50 -0
- package/skills/apt-planner.md +16 -0
- package/skills/apt-pr-review/SKILL.md +1 -1
- package/skills/apt-research/SKILL.md +526 -0
- package/skills/apt-research/appendices/budget-loop.md +397 -0
- package/skills/apt-research/appendices/claim-graph-schema.md +206 -0
- package/skills/apt-research/appendices/domain-tools.md +236 -0
- package/skills/apt-spar/SKILL.md +19 -7
- package/skills/apt-verify-proof/SKILL.md +41 -2
- package/src/cli/commands/coverage-check.mjs +126 -44
- package/src/cli/commands/detect-runtime.mjs +23 -14
- package/src/cli/coverage-check/user-outcomes.mjs +273 -0
- package/src/cli/host/detect.mjs +1 -1
- package/src/cli/install/install-from-source.mjs +3 -3
- package/src/cli/install/legacy-paths.mjs +2 -0
- package/src/cli/verify-proof/idl/index.mjs +7 -8
- package/src/cli/verify-proof/idl/types.ts +5 -4
- package/src/cli/verify-proof/manifest-schema.json +2 -1
- package/src/cli/verify-proof/resolver.mjs +171 -4
- package/src/cli/verify-proof/runtime-detect.mjs +99 -10
- package/src/cli/verify-proof/trust.mjs +1 -1
- package/templates/proof-verification.md +32 -3
- package/workflows/verify-proof.md +78 -9
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# Time-Budgeted Background Loop
|
|
2
|
+
|
|
3
|
+
> Per-iteration loop spec for `/apt:research --budget <duration>`. Load
|
|
4
|
+
> when any budget is set (explicit flag, named alias, or prose-detected)
|
|
5
|
+
> OR when running a single session that needs the 4-role discipline.
|
|
6
|
+
|
|
7
|
+
## Why this exists
|
|
8
|
+
|
|
9
|
+
A naive "keep researching" loop manufactures false confidence over time —
|
|
10
|
+
the agent finds more weak sources that confirm its initial position, prunes
|
|
11
|
+
counter-evidence as noise, and arrives at the budget cap with a polished
|
|
12
|
+
wrong answer. This appendix encodes the disciplines that prevent that:
|
|
13
|
+
|
|
14
|
+
- **4-role specialization** so a single agent can't self-rationalize
|
|
15
|
+
- **Priority by impact × centrality × uncertainty** so load-bearing claims
|
|
16
|
+
get attacked early, not last
|
|
17
|
+
- **Trigger-gated spar** so cross-LLM challenges fire on real conflict, not
|
|
18
|
+
on a clock
|
|
19
|
+
- **Citation audit** so fabricated DOIs get quarantined, not amplified
|
|
20
|
+
- **Dual stop states (CONVERGED vs STALLED)** so the skill never confuses
|
|
21
|
+
stuckness with done-ness
|
|
22
|
+
- **Early termination** so a budget is a CAP not a target — converging at
|
|
23
|
+
hour 3 of an 8h budget stops the loop, doesn't burn the remaining 5h
|
|
24
|
+
|
|
25
|
+
## Budget as the primitive
|
|
26
|
+
|
|
27
|
+
The skill accepts one canonical flag plus three named aliases:
|
|
28
|
+
|
|
29
|
+
| Flag | Resolves to | Typical use |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `--budget <duration>` | Explicit cap; ISO-style `30m`, `4h`, `10h`, `2d` (1m – 72h range) | Any custom horizon |
|
|
32
|
+
| `--overnight` | `--budget 8h` | While you sleep |
|
|
33
|
+
| `--weekend` | `--budget 48h` | Long horizon, Friday → Monday |
|
|
34
|
+
| `--background` | `--budget 4h` | During work day |
|
|
35
|
+
|
|
36
|
+
Auto-detection from prose (Step 2 of SKILL.md) maps natural-language signals
|
|
37
|
+
into a budget value:
|
|
38
|
+
|
|
39
|
+
| Prose signal | Inferred budget |
|
|
40
|
+
|---|---|
|
|
41
|
+
| "overnight", "while I sleep" | 8h |
|
|
42
|
+
| "weekend", "over the weekend", "by Monday" | 48h |
|
|
43
|
+
| "for X hours/days/minutes" | X |
|
|
44
|
+
| "while I'm at work" | 8h |
|
|
45
|
+
| "in the background" | 4h |
|
|
46
|
+
| "really thoroughly", "deep dive", "question my beliefs" | 4h |
|
|
47
|
+
| Decomposition produces ≥8 sub-questions OR ≥3 contested perspectives | 4h |
|
|
48
|
+
| (no signal AND no flag) | none — single-session pipeline runs |
|
|
49
|
+
|
|
50
|
+
The auto-detection announcement (Step 2 closing line) MUST surface BOTH the
|
|
51
|
+
budget value AND the signal that triggered it:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
[apt:research] {Mode} / {Domain} — auto-budget 8h from signal "overnight".
|
|
55
|
+
Pass --budget <duration> to override or --no-budget to disable.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The user can pass `--no-budget` to force the single-session pipeline even
|
|
59
|
+
when prose signals would otherwise trigger budget mode. Explicit user
|
|
60
|
+
intent always wins.
|
|
61
|
+
|
|
62
|
+
## Single-session pipeline (no budget set)
|
|
63
|
+
|
|
64
|
+
If no budget is set AND no prose signal fires:
|
|
65
|
+
- Run Step 5 (the 4-role iteration) up to 5 times
|
|
66
|
+
- After 5 iterations without terminal state, force `STALLED` with
|
|
67
|
+
`## Cannot resolve in single-session mode — re-run with --budget 4h or higher`
|
|
68
|
+
- This is the cap that prevents the lighter single-session mode from
|
|
69
|
+
silently growing into something that should have been a budgeted run
|
|
70
|
+
|
|
71
|
+
## Agent roles
|
|
72
|
+
|
|
73
|
+
Per iteration, FOUR `apt-researcher` agents are spawned in a single
|
|
74
|
+
parallel message. Each has an isolated context (no shared scratch state)
|
|
75
|
+
and a distinct objective.
|
|
76
|
+
|
|
77
|
+
### Builder
|
|
78
|
+
|
|
79
|
+
> System prompt seed: "You are a synthesizer. Read the current claim graph
|
|
80
|
+
> and the spec. Advance the synthesis on the chosen attack claim. Propose
|
|
81
|
+
> what we should now believe, given the evidence, and why. You may NOT
|
|
82
|
+
> falsify — that is the Skeptic's job. You may propose new claims if they
|
|
83
|
+
> follow from existing evidence."
|
|
84
|
+
|
|
85
|
+
Tool surface: full read (Read/Grep/Glob), WebSearch, WebFetch, Context7
|
|
86
|
+
MCP, plus the domain-specific tools from `domain-tools.md`.
|
|
87
|
+
|
|
88
|
+
Output shape: a structured block written to the Task return:
|
|
89
|
+
```
|
|
90
|
+
## Builder
|
|
91
|
+
### Position
|
|
92
|
+
{one paragraph synthesis}
|
|
93
|
+
### Supporting evidence (existing)
|
|
94
|
+
- {source_id}: {claim_id} — {one-line why it supports}
|
|
95
|
+
### New claims proposed (if any)
|
|
96
|
+
- {statement} — {evidence_for source_ids} — {depends_on claim_ids}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Skeptic
|
|
100
|
+
|
|
101
|
+
> System prompt seed: "You are an adversary. Read the chosen attack claim.
|
|
102
|
+
> Your only job is to find concrete counter-evidence or a logical/empirical
|
|
103
|
+
> falsification. Confirming the claim or hedging is failure. Produce at
|
|
104
|
+
> least one specific challenge with a citation OR explicit reasoning."
|
|
105
|
+
|
|
106
|
+
Tool surface: same as Builder.
|
|
107
|
+
|
|
108
|
+
Output shape:
|
|
109
|
+
```
|
|
110
|
+
## Skeptic
|
|
111
|
+
### Falsification target
|
|
112
|
+
{claim_id}: {statement}
|
|
113
|
+
### Counter-evidence
|
|
114
|
+
- {source_id or new source}: {quote} — {why it falsifies}
|
|
115
|
+
### Failure mode of the claim
|
|
116
|
+
{one paragraph — when does this claim break? What context invalidates it?}
|
|
117
|
+
### Verdict
|
|
118
|
+
{retract | downgrade | contest | no-falsification-found}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
If `no-falsification-found` AND the claim was at `confidence: high`,
|
|
122
|
+
the Skeptic must explicitly state: "I attempted falsification via [search
|
|
123
|
+
queries / reasoning paths] and found no counter-evidence. The claim
|
|
124
|
+
survives this attack."
|
|
125
|
+
|
|
126
|
+
### Retriever
|
|
127
|
+
|
|
128
|
+
> System prompt seed: "You are an evidence finder. Read the spec, the
|
|
129
|
+
> claim graph, and the list of sources already in sources.json. Your
|
|
130
|
+
> ONLY job is to find NEW sources (not already in sources.json) that
|
|
131
|
+
> bear on any open or contested claim. Do NOT synthesize. Do NOT take
|
|
132
|
+
> sides. Return URLs + extracted quotes + source-type classification."
|
|
133
|
+
|
|
134
|
+
Tool surface: WebSearch, WebFetch, Context7, plus domain-specific
|
|
135
|
+
search tools (PubMed for empirical, GitHub Code Search for code, arxiv
|
|
136
|
+
for mechanistic).
|
|
137
|
+
|
|
138
|
+
Output shape:
|
|
139
|
+
```
|
|
140
|
+
## Retriever
|
|
141
|
+
### New sources found
|
|
142
|
+
- {url}: tier={tier}, type={type}, derivation_chain={[urls cited]},
|
|
143
|
+
quote_anchor={"..."}
|
|
144
|
+
### Search trail
|
|
145
|
+
- query: "{q}" — engine: {WebSearch|PubMed|GitHub|...} — useful_hits: {N}
|
|
146
|
+
### Frontier status
|
|
147
|
+
{exhausted | active | promising} — {one-line why}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The `frontier status: exhausted` signal is load-bearing for the STALLED
|
|
151
|
+
stop state. Retriever must report it honestly — if every new search
|
|
152
|
+
returns sources already in `sources.json` (modulo near-duplicates),
|
|
153
|
+
the frontier IS exhausted for this iteration's queries. Judge uses this
|
|
154
|
+
to decide stop state.
|
|
155
|
+
|
|
156
|
+
### Judge
|
|
157
|
+
|
|
158
|
+
> System prompt seed: "You are the arbiter. Read the Builder, Skeptic, and
|
|
159
|
+
> Retriever outputs plus the current claim graph. Update claim statuses
|
|
160
|
+
> with explicit evidence deltas. You may NOT propose new claims of your
|
|
161
|
+
> own; you may accept or reject claims proposed by Builder. Apply domain
|
|
162
|
+
> gates: demote first-principles output to `hypothesis` in non-mechanistic
|
|
163
|
+
> domains; require Crossref/PubMed-verified citations in empirical
|
|
164
|
+
> domains."
|
|
165
|
+
|
|
166
|
+
Tool surface: read-only access to `claims.json`, `sources.json`, the three
|
|
167
|
+
role outputs, and `research-spec.md`. NO web tools (no temptation to
|
|
168
|
+
re-research).
|
|
169
|
+
|
|
170
|
+
Output shape (mandatory JSON, parsed and merged into the graph):
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"iteration": N,
|
|
174
|
+
"attacked_claim": "C-007",
|
|
175
|
+
"claim_deltas": [
|
|
176
|
+
{
|
|
177
|
+
"claim_id": "C-007",
|
|
178
|
+
"old_status": "live",
|
|
179
|
+
"new_status": "contested",
|
|
180
|
+
"old_confidence": "medium",
|
|
181
|
+
"new_confidence": "low",
|
|
182
|
+
"reason": "Skeptic surfaced S-019 (peer-reviewed) contradicting; downgrade per source-tier weighting."
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
"new_claims": [
|
|
186
|
+
{
|
|
187
|
+
"id": "C-021",
|
|
188
|
+
"statement": "...",
|
|
189
|
+
"source_tier": "...",
|
|
190
|
+
"evidence_for": ["S-019"],
|
|
191
|
+
"depends_on": [],
|
|
192
|
+
"contradicts": ["C-007"],
|
|
193
|
+
"impact": "medium"
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
"new_sources_accepted": ["S-019", "S-020"],
|
|
197
|
+
"new_sources_quarantined": ["S-021"],
|
|
198
|
+
"frontier_exhausted_this_iter": false,
|
|
199
|
+
"tier1_conflict_introduced": true
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Priority formula
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
priority(C) = impact(C) × centrality(C) × uncertainty(C)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
- `impact(C)`: `high=1.0, medium=0.6, low=0.3` — sourced from
|
|
210
|
+
`research-spec.md ## Critical claims`, may be bumped by Judge when
|
|
211
|
+
graph topology changes.
|
|
212
|
+
- `centrality(C)`: 0-1, computed by Judge each iteration (see
|
|
213
|
+
`claim-graph-schema.md`).
|
|
214
|
+
- `uncertainty(C)`: 0-1, computed by Judge each iteration.
|
|
215
|
+
|
|
216
|
+
The next claim to attack is `argmax(priority)` over claims with
|
|
217
|
+
`status ∈ {open, contested, live}`. Tie-break by: oldest
|
|
218
|
+
`last_attacked_iter`, then by `impact`, then alphabetical claim ID.
|
|
219
|
+
|
|
220
|
+
**Why this beats "lowest confidence first":**
|
|
221
|
+
|
|
222
|
+
A high-confidence claim that everything else depends on (high `impact`,
|
|
223
|
+
high `centrality`) MUST be attacked early. If it survives, the rest of
|
|
224
|
+
the graph rests on firmer ground. If it falls, the cascade reveals which
|
|
225
|
+
descendants were also wrong before more time is spent building on them.
|
|
226
|
+
|
|
227
|
+
"Lowest confidence first" chases the noisiest claims and leaves the
|
|
228
|
+
load-bearing assumptions untested until late, when their failure is
|
|
229
|
+
maximally expensive.
|
|
230
|
+
|
|
231
|
+
## Spar triggers (NOT every-N-iterations)
|
|
232
|
+
|
|
233
|
+
`/apt:spar` fires from Step 8a when ANY of these conditions hold after
|
|
234
|
+
Judge has updated the graph:
|
|
235
|
+
|
|
236
|
+
| Trigger | Detection |
|
|
237
|
+
|---|---|
|
|
238
|
+
| **Tier-1 conflict** | Two claims with `confidence ≥ medium` and a `contradicts` edge between them |
|
|
239
|
+
| **Critical-claim stall** | A claim flagged in `## Critical claims` has had `status ∈ {contested, open}` for ≥ 2 consecutive iterations with no confidence change |
|
|
240
|
+
| **Vendor-only evidence** | A claim's `evidence_for[]` contains ONLY sources with `tier: vendor-doc` AND `impact ≥ medium` |
|
|
241
|
+
|
|
242
|
+
Spar prompt MUST include:
|
|
243
|
+
1. The current synthesis position (1 paragraph)
|
|
244
|
+
2. The specific claim under challenge (statement + current evidence)
|
|
245
|
+
3. Explicit instruction: "Produce a concrete claim status delta with citation diff. Reject debate summaries with no actionable delta."
|
|
246
|
+
4. The current `claims.json` excerpt for the challenged claim + neighbors
|
|
247
|
+
|
|
248
|
+
Spar return is parsed for a Judge-shaped delta. If the return does NOT
|
|
249
|
+
include `claim_deltas[]`, mark the spar `## status: theater` in
|
|
250
|
+
`spar/{round-slug}.md` and DO NOT update the graph. This prevents
|
|
251
|
+
"both LLMs trained on the same corpus rephrased each other" from
|
|
252
|
+
corrupting the synthesis.
|
|
253
|
+
|
|
254
|
+
## Stop states + early termination
|
|
255
|
+
|
|
256
|
+
Two terminal states. The skill MUST distinguish them in `RESEARCH.md`
|
|
257
|
+
status header and in the final report. **A budget is a CAP, not a target.**
|
|
258
|
+
The loop stops the instant a terminal state fires — remaining budget is
|
|
259
|
+
not consumed.
|
|
260
|
+
|
|
261
|
+
### CONVERGED
|
|
262
|
+
|
|
263
|
+
All of:
|
|
264
|
+
- Every claim in `## Critical claims` is at `confidence: high`
|
|
265
|
+
- Zero unresolved tier-1 conflicts (every contradicts-edge with both ends
|
|
266
|
+
`confidence ≥ medium` has been resolved by retracting one side)
|
|
267
|
+
- Retriever reported `frontier_exhausted_this_iter: true` for the last 2
|
|
268
|
+
iterations (no new sources to be found)
|
|
269
|
+
- Citation audit ran in one of the last 4 iterations with zero new
|
|
270
|
+
quarantines
|
|
271
|
+
|
|
272
|
+
Output: full synthesis with confidence statements. Budget remaining is
|
|
273
|
+
reported in the final report (e.g. "CONVERGED at iter 12 of estimated 24,
|
|
274
|
+
budget used: 3h 14m of 8h").
|
|
275
|
+
|
|
276
|
+
### STALLED
|
|
277
|
+
|
|
278
|
+
Retriever frontier exhausted (no new sources for 2 iterations) but
|
|
279
|
+
critical claims remain at `contested` or `confidence < high`. Output
|
|
280
|
+
MUST include a `## Cannot resolve without` section listing what new
|
|
281
|
+
evidence would be required:
|
|
282
|
+
|
|
283
|
+
- Real-world experiment (specify the experiment)
|
|
284
|
+
- Paywalled paper access (specify the citation)
|
|
285
|
+
- Vendor disclosure (specify what disclosure)
|
|
286
|
+
- Domain expert interview (specify the question)
|
|
287
|
+
- Code execution / falsification harness (specify the test)
|
|
288
|
+
- Telemetry / instrumented data (specify the measurement)
|
|
289
|
+
|
|
290
|
+
STALLED is NOT a failure — it is the honest answer when evidence
|
|
291
|
+
genuinely runs out. Confident-sounding synthesis on a stalled question
|
|
292
|
+
is the worst outcome the skill can produce; STALLED prevents it.
|
|
293
|
+
|
|
294
|
+
### Budget-cap exhaustion
|
|
295
|
+
|
|
296
|
+
When `elapsed ≥ budget`, force `STALLED` with `## Stopped at budget cap`
|
|
297
|
+
regardless of mid-iter state. Honest, even if mid-attack. The reason
|
|
298
|
+
this is STALLED and not its own state: hitting the cap means evidence
|
|
299
|
+
acquisition was not yet complete, which IS the STALLED condition. The
|
|
300
|
+
`## Stopped at budget cap` note distinguishes it from a frontier-exhausted
|
|
301
|
+
STALLED for the reader.
|
|
302
|
+
|
|
303
|
+
### Early-termination rule
|
|
304
|
+
|
|
305
|
+
Whichever terminal state fires first wins. The skill body MUST check
|
|
306
|
+
terminal-state criteria at the END of every iteration before scheduling
|
|
307
|
+
the next wake. A 3-hour CONVERGED at hour 3 of an 8-hour budget exits
|
|
308
|
+
cleanly; the saved compute is reported in the final summary, NOT spent
|
|
309
|
+
on extra iterations "just in case."
|
|
310
|
+
|
|
311
|
+
## Progress checkpoints (tail-able)
|
|
312
|
+
|
|
313
|
+
Long-running loops need observable progress without interrupting the
|
|
314
|
+
loop. At the START of every iteration, the skill body appends ONE line
|
|
315
|
+
to `.aperant/research/{task-id}/progress.log`:
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
{ISO timestamp} iter={N}/{est_max} budget={used}/{cap} next_attack={C-id} priority={value} status={INVESTIGATING|SYNTHESIZING|...}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Example:
|
|
322
|
+
```
|
|
323
|
+
2026-05-24T10:14:22Z iter=4/24 budget=42m/8h next_attack=C-007 priority=0.84 status=INVESTIGATING
|
|
324
|
+
2026-05-24T10:34:15Z iter=5/24 budget=1h12m/8h next_attack=C-012 priority=0.71 status=INVESTIGATING
|
|
325
|
+
2026-05-24T10:55:08Z iter=6/24 budget=1h33m/8h next_attack=C-007 priority=0.69 status=INVESTIGATING
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Users can `tail -f .aperant/research/{task-id}/progress.log` to watch the
|
|
329
|
+
loop without blocking it. The line is intentionally one-per-iteration
|
|
330
|
+
(not one-per-agent-return) to keep the log scannable. The richer
|
|
331
|
+
per-iteration trace lives in `iteration-log.md`.
|
|
332
|
+
|
|
333
|
+
At terminal state, the final line includes the verdict:
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
2026-05-24T13:28:51Z iter=12/24 budget=3h14m/8h verdict=CONVERGED critical_claims_high=5/5 unresolved_conflicts=0
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`est_max` is recomputed each iteration based on average iteration
|
|
340
|
+
duration so far × remaining budget. It is a hint, not a guarantee.
|
|
341
|
+
|
|
342
|
+
## Wake-loop continuation
|
|
343
|
+
|
|
344
|
+
End of each iteration (when status = CONTINUE), the skill calls
|
|
345
|
+
`ScheduleWakeup`:
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
ScheduleWakeup({
|
|
349
|
+
delaySeconds: 1200, // 20 min — past cache TTL
|
|
350
|
+
prompt: "/apt:research --resume {task-id} --budget {remaining}",
|
|
351
|
+
reason: "apt:research budget loop iter {N+1}, next attack: {claim_id}, budget remaining: {remaining}"
|
|
352
|
+
})
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The `--budget {remaining}` arg keeps the budget value monotonically
|
|
356
|
+
decreasing across wakes so a crash + manual restart preserves the cap.
|
|
357
|
+
|
|
358
|
+
Then exits cleanly. The host CLI delivers the wake event when ready and
|
|
359
|
+
the skill resumes from `RESEARCH.md` status (which was set to
|
|
360
|
+
`INVESTIGATING` before the spawn).
|
|
361
|
+
|
|
362
|
+
This is the same primitive `/apt:watch-ci` uses. No daemons, no
|
|
363
|
+
cross-CLI re-exec, no external scheduler.
|
|
364
|
+
|
|
365
|
+
If `ScheduleWakeup` is unavailable in the current host CLI environment,
|
|
366
|
+
the skill MUST refuse `--budget` with an explicit error pointing the
|
|
367
|
+
user at the manual `--resume` workflow.
|
|
368
|
+
|
|
369
|
+
## Resume semantics
|
|
370
|
+
|
|
371
|
+
`--resume <task-id>` re-enters at the iteration boundary:
|
|
372
|
+
1. Read `research-spec.md` (immutable, locked at Step 3)
|
|
373
|
+
2. Read `claims.json`, `sources.json`, `RESEARCH.md` status
|
|
374
|
+
3. Read `## Next attack` from `RESEARCH.md` (written by previous iteration)
|
|
375
|
+
4. Compute remaining budget = `original_budget - elapsed_at_start_of_iter`
|
|
376
|
+
(Step 9 of SKILL.md records elapsed in the iteration log before
|
|
377
|
+
scheduling the wake)
|
|
378
|
+
5. Go to Step 5 with that claim as the attack target
|
|
379
|
+
|
|
380
|
+
If the previous run was killed mid-iteration (incomplete Judge output in
|
|
381
|
+
`iteration-log.md`), discard the partial iteration entry and re-run from
|
|
382
|
+
the last fully-recorded iteration. The graph state on disk is canonical;
|
|
383
|
+
the partial log entry is lost work, not corrupted state.
|
|
384
|
+
|
|
385
|
+
## Budget override precedence
|
|
386
|
+
|
|
387
|
+
| Source of budget value | Precedence |
|
|
388
|
+
|---|---|
|
|
389
|
+
| Explicit `--budget <duration>` flag | wins all |
|
|
390
|
+
| Explicit `--no-budget` flag | wins all (forces single-session mode) |
|
|
391
|
+
| Named alias (`--overnight`, `--weekend`, `--background`) | beats prose detection |
|
|
392
|
+
| Prose detection (from Step 2 of SKILL.md) | beats default |
|
|
393
|
+
| Default | single-session mode (no budget loop) |
|
|
394
|
+
|
|
395
|
+
Bounds: `1m ≤ budget ≤ 72h`. Outside-range values are rejected with an
|
|
396
|
+
explicit error. The 72h ceiling is intentional — longer than that and
|
|
397
|
+
the wall-clock predictability of the artifact starts to suffer.
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Claim Graph Schema
|
|
2
|
+
|
|
3
|
+
> JSON schema for `claims.json` and `sources.json`. Replaces the flat
|
|
4
|
+
> `findings.tsv` ledger. Load when reasoning about claim state, source
|
|
5
|
+
> tiers, dependencies, or status transitions.
|
|
6
|
+
|
|
7
|
+
## Why a graph, not a list
|
|
8
|
+
|
|
9
|
+
A flat ledger answers "what did we find?" but not "what does each finding
|
|
10
|
+
depend on?" or "if we retract this claim, what else collapses?" The graph
|
|
11
|
+
makes the dependency structure explicit so:
|
|
12
|
+
|
|
13
|
+
- Priority can rank by `centrality` (how many other claims depend on this one)
|
|
14
|
+
- Skeptic can target the most load-bearing claim, not the weakest one
|
|
15
|
+
- Retraction propagates (downgrading a root claim downgrades its descendants)
|
|
16
|
+
- Contradictions surface as edges, not as silently-averaged confidence
|
|
17
|
+
|
|
18
|
+
## `claims.json` — one entry per discovered claim
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"version": 1,
|
|
23
|
+
"claims": {
|
|
24
|
+
"C-001": {
|
|
25
|
+
"statement": "Softer rear axle increases lateral grip on no-diff karts.",
|
|
26
|
+
"source_tier": "community-lore",
|
|
27
|
+
"conditions": {
|
|
28
|
+
"kart_class": "OK1",
|
|
29
|
+
"track_temp": "any",
|
|
30
|
+
"tire_compound": "any"
|
|
31
|
+
},
|
|
32
|
+
"evidence_for": ["S-003", "S-007", "S-012"],
|
|
33
|
+
"evidence_against": ["S-005"],
|
|
34
|
+
"depends_on": ["C-002"],
|
|
35
|
+
"supports": ["C-009"],
|
|
36
|
+
"contradicts": [],
|
|
37
|
+
"impact": "high",
|
|
38
|
+
"centrality": 0.83,
|
|
39
|
+
"uncertainty": 0.62,
|
|
40
|
+
"confidence": "medium",
|
|
41
|
+
"status": "contested",
|
|
42
|
+
"last_attacked_iter": 4,
|
|
43
|
+
"history": [
|
|
44
|
+
{
|
|
45
|
+
"iter": 1,
|
|
46
|
+
"status": "open",
|
|
47
|
+
"confidence": "low",
|
|
48
|
+
"note": "Seeded from spec sub-question Q3."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"iter": 4,
|
|
52
|
+
"status": "contested",
|
|
53
|
+
"confidence": "medium",
|
|
54
|
+
"note": "Skeptic surfaced S-005 (SAE paper) contradicting forum consensus. Judge moved to contested."
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Field rules
|
|
63
|
+
|
|
64
|
+
| Field | Required | Notes |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `statement` | yes | One sentence, falsifiable form |
|
|
67
|
+
| `source_tier` | yes | `peer-reviewed \| independent-test \| primary-doc \| vendor-doc \| community-lore \| derived-theory \| hypothesis` |
|
|
68
|
+
| `conditions` | yes | Object of context dimensions; `{}` if unconditional |
|
|
69
|
+
| `evidence_for` / `evidence_against` | yes | Arrays of source IDs (`S-NNN`) |
|
|
70
|
+
| `depends_on` | yes | Claim IDs this claim derives from; empty if root |
|
|
71
|
+
| `supports` / `contradicts` | yes | Claim IDs this claim affects |
|
|
72
|
+
| `impact` | yes | `high \| medium \| low` — from spec `## Critical claims` |
|
|
73
|
+
| `centrality` | computed | 0-1; out-degree on `supports`+`contradicts` normalized by graph size |
|
|
74
|
+
| `uncertainty` | computed | 0-1; function of evidence-for/against ratio + source tiers |
|
|
75
|
+
| `confidence` | yes | `high \| medium \| low \| contested` |
|
|
76
|
+
| `status` | yes | `open \| live \| dead \| contested \| retracted \| hypothesis \| converged` |
|
|
77
|
+
| `last_attacked_iter` | yes | Integer; iter number when last picked by priority |
|
|
78
|
+
| `history[]` | yes | Append-only; every Judge ruling adds an entry |
|
|
79
|
+
|
|
80
|
+
### Status transitions
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
open ─────┬──> live ──┬──> converged
|
|
84
|
+
│ │
|
|
85
|
+
├──> contested
|
|
86
|
+
│ │
|
|
87
|
+
├──> hypothesis (domain ≠ mechanistic + first-principles output)
|
|
88
|
+
│
|
|
89
|
+
└──> retracted (citation audit failed, no other support)
|
|
90
|
+
|
|
91
|
+
dead = candidate approach with documented prior failure (SOLVE mode)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## `sources.json` — one entry per discovered source
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"version": 1,
|
|
99
|
+
"sources": {
|
|
100
|
+
"S-003": {
|
|
101
|
+
"url": "https://www.kartpulse.com/threads/axle-stiffness-explained.1234",
|
|
102
|
+
"tier": "community-lore",
|
|
103
|
+
"type": "forum-post",
|
|
104
|
+
"fetched_at": "2026-05-24T10:14:22Z",
|
|
105
|
+
"verified_at": "2026-05-24T11:42:08Z",
|
|
106
|
+
"derivation_chain": [],
|
|
107
|
+
"quality": {
|
|
108
|
+
"author_credentials": "unknown",
|
|
109
|
+
"replicated": false,
|
|
110
|
+
"peer_reviewed": false
|
|
111
|
+
},
|
|
112
|
+
"quote_anchor": "softer axles flex more under load and..."
|
|
113
|
+
},
|
|
114
|
+
"S-005": {
|
|
115
|
+
"url": "https://saemobilus.sae.org/papers/...",
|
|
116
|
+
"tier": "peer-reviewed",
|
|
117
|
+
"type": "paper",
|
|
118
|
+
"fetched_at": "2026-05-24T10:22:09Z",
|
|
119
|
+
"verified_at": "2026-05-24T10:22:31Z",
|
|
120
|
+
"derivation_chain": [],
|
|
121
|
+
"doi": "10.4271/2019-01-1234",
|
|
122
|
+
"doi_verified_via": "crossref",
|
|
123
|
+
"quality": {
|
|
124
|
+
"n": null,
|
|
125
|
+
"design": "analytic",
|
|
126
|
+
"peer_reviewed": true,
|
|
127
|
+
"replicated": null
|
|
128
|
+
},
|
|
129
|
+
"quote_anchor": "torsional stiffness coupling to inside-rear lift..."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Field rules
|
|
136
|
+
|
|
137
|
+
| Field | Required | Notes |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `url` | yes | Canonical URL or DOI URL |
|
|
140
|
+
| `tier` | yes | Matches the claim `source_tier` taxonomy |
|
|
141
|
+
| `type` | yes | `paper \| RCT \| meta-analysis \| primary-doc \| vendor-doc \| forum-post \| blog \| book \| video \| code` |
|
|
142
|
+
| `fetched_at` | yes | ISO-8601 timestamp at first fetch |
|
|
143
|
+
| `verified_at` | nullable | ISO-8601 timestamp at last citation-audit pass; `null` until verified |
|
|
144
|
+
| `derivation_chain` | yes | Array of source IDs this source cites; **load-bearing for independence checks** |
|
|
145
|
+
| `quality` | yes | Object; fields depend on `type` — `{n, design, peer_reviewed, replicated}` for empirical |
|
|
146
|
+
| `quote_anchor` | yes | The exact substring the claim relies on; citation audit re-fetches and checks ≥80% match |
|
|
147
|
+
|
|
148
|
+
### Derivation chain (the independence check)
|
|
149
|
+
|
|
150
|
+
Three sources that all cite the same primary source = **one** source for the
|
|
151
|
+
purpose of triangulation. When computing `centrality` and `uncertainty`, the
|
|
152
|
+
Judge must walk `derivation_chain` to deduplicate effective sources. The
|
|
153
|
+
schema captures this explicitly so future iterations don't double-count.
|
|
154
|
+
|
|
155
|
+
## Computed fields
|
|
156
|
+
|
|
157
|
+
`centrality` and `uncertainty` are recomputed by the Judge at the end of every
|
|
158
|
+
iteration, NEVER written by Builder/Skeptic/Retriever. Formula reference:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
centrality(C) =
|
|
162
|
+
( |descendants_in_supports(C)| + |descendants_in_contradicts(C)| )
|
|
163
|
+
/ max(1, |total_claims|)
|
|
164
|
+
|
|
165
|
+
uncertainty(C) =
|
|
166
|
+
1 - weighted_evidence_for(C) / (weighted_evidence_for(C) + weighted_evidence_against(C))
|
|
167
|
+
|
|
168
|
+
where weight(S) =
|
|
169
|
+
{ peer-reviewed: 1.0,
|
|
170
|
+
independent-test: 0.85,
|
|
171
|
+
primary-doc: 0.7,
|
|
172
|
+
vendor-doc: 0.5,
|
|
173
|
+
community-lore: 0.25,
|
|
174
|
+
derived-theory: domain == mechanistic ? 0.6 : 0.2,
|
|
175
|
+
hypothesis: 0.1 }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`impact` is NOT computed — it comes from the spec's `## Critical claims`
|
|
179
|
+
section, optionally adjusted by the Judge when graph structure changes
|
|
180
|
+
(a claim acquiring many descendants gets impact bumped).
|
|
181
|
+
|
|
182
|
+
`priority(C) = impact(C) × centrality(C) × uncertainty(C)` — the next claim
|
|
183
|
+
to attack is `argmax(priority)` over claims with `status ∈ {open, contested,
|
|
184
|
+
live}`.
|
|
185
|
+
|
|
186
|
+
## Round-trip render to `RESEARCH.md`
|
|
187
|
+
|
|
188
|
+
The Judge renders a compact human-readable view into `RESEARCH.md`'s
|
|
189
|
+
`## Claim graph summary` section at synthesis time. The graph itself
|
|
190
|
+
(`claims.json` + `sources.json`) is the canonical store; the markdown is a
|
|
191
|
+
projection. Renderer guidance:
|
|
192
|
+
|
|
193
|
+
- Top 5 by `impact × centrality`
|
|
194
|
+
- Format: `**[{status}]** {statement} _(confidence: {confidence}, tier: {source_tier}, conditions: {summary})_`
|
|
195
|
+
- For each contested claim, render both positions and their strongest evidence
|
|
196
|
+
side-by-side. Do NOT collapse them.
|
|
197
|
+
|
|
198
|
+
## Migration from `findings.tsv` (if encountered on resume)
|
|
199
|
+
|
|
200
|
+
If `--resume` finds a legacy `findings.tsv` (from a pre-v1 session), the skill
|
|
201
|
+
must:
|
|
202
|
+
1. Stop. Print: "Legacy findings.tsv detected. Migrate with `apt-tools research migrate-graph {task-id}`."
|
|
203
|
+
2. Refuse to continue until migration runs.
|
|
204
|
+
|
|
205
|
+
This is intentional — there is no automatic mapping from flat ledger to graph
|
|
206
|
+
because the dependency edges aren't recoverable from the old format.
|