@event4u/agent-config 14.19.0 → 14.21.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +351 -156
- package/README.md +1 -1
- package/agents/templates/.ai-council.yml.example +10 -0
- package/dist/agent-src/commands/agent-handoff.md +42 -41
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/{reference-repo.md → repo.md} +247 -32
- package/dist/agent-src/commands/analyze/roadmap-repos.md +129 -0
- package/dist/agent-src/commands/analyze.md +12 -7
- package/dist/agent-src/commands/feature/plan.md +55 -16
- package/dist/agent-src/commands/feature/refactor.md +8 -3
- package/dist/agent-src/commands/humanize.md +48 -4
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +22 -1
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +11 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +35 -2
- package/dist/agent-src/contexts/execution/terminal-states.md +4 -1
- package/dist/agent-src/rules/evaluator-independence.md +4 -4
- package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
- package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
- package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +27 -11
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +2 -2
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
- package/dist/agent-src/skills/technical-specification/SKILL.md +4 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/features.md +5 -0
- package/dist/agent-src/templates/roadmaps.md +29 -1
- package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
- package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
- package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
- package/dist/cli/mcp/dispatch.js +10 -0
- package/dist/cli/mcp/stdio.js +33 -2
- package/dist/cli/mcp/telemetry.js +227 -0
- package/dist/cli-delegate/{chunk-KPBWFOPZ.js → chunk-2FTMENJL.js} +194 -37
- package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-2TAQ2K4V.js} +166 -1
- package/dist/cli-delegate/{chunk-GZTMRYCN.js → chunk-643Z7FIC.js} +79 -12
- package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
- package/dist/cli-delegate/{chunk-IDHUQIXP.js → chunk-J3RFNKG4.js} +41 -5
- package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
- package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
- package/dist/cli-delegate/cmd_conformance.js +88 -110
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +42 -12
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +59 -902
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +62 -31
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -6
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -5
- package/dist/hooks/dispatch.js +3801 -2803
- package/dist/install/install.mjs +396 -168
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +809 -180
- package/dist/scripts/ai_council/content_ceiling.js +63 -0
- package/dist/scripts/ai_council/seat_policy.js +106 -0
- package/dist/scripts/ai_council/transport_resolver.js +21 -0
- package/dist/scripts/mcp_server/telemetry.js +148 -0
- package/docs/guidelines/agent-infra/naming.md +1 -1
- package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
- package/docs/guidelines/redundancy-taxonomy.md +28 -0
- package/llms.txt +14 -14
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
- package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
- package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
- package/src/config/assurance-capability-registry.json +9 -0
- package/src/config/gate-coverage.yml +55 -0
- package/src/config/gate-violation-baselines.json +18 -6
- package/src/config/release-gate-locality.yml +4 -3
- package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
- package/src/scripts/_lib/audit_field_provenance.ts +44 -3
- package/src/scripts/_lib/blocked_by_marker.ts +189 -0
- package/src/scripts/_lib/host_capability.ts +76 -1
- package/src/scripts/_lib/install_reach_checks.ts +33 -1
- package/src/scripts/_lib/mcp_bridge.ts +222 -10
- package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
- package/src/scripts/_lib/orchestration_record.ts +23 -1
- package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
- package/src/scripts/_lib/release_highlights.ts +19 -211
- package/src/scripts/_lib/release_material.ts +27 -77
- package/src/scripts/_lib/release_position.ts +96 -0
- package/src/scripts/_lib/review_skipped_record.ts +17 -1
- package/src/scripts/_lib/security_lint.ts +179 -7
- package/src/scripts/_lib/self_repair.ts +141 -6
- package/src/scripts/_lib/self_repair_store.ts +273 -7
- package/src/scripts/_lib/structured_ask.ts +117 -0
- package/src/scripts/_lib/subagent_capsule.ts +155 -3
- package/src/scripts/_lib/tty_prompt.ts +76 -0
- package/src/scripts/ai_council/api_transport.ts +163 -0
- package/src/scripts/ai_council/clients.ts +58 -63
- package/src/scripts/ai_council/config.ts +13 -0
- package/src/scripts/ai_council/content_ceiling.ts +79 -0
- package/src/scripts/ai_council/jury_aggregate.ts +178 -0
- package/src/scripts/ai_council/seat_policy.ts +137 -0
- package/src/scripts/ai_council/status_surface.ts +79 -0
- package/src/scripts/ai_council/transport_resolver.ts +59 -1
- package/src/scripts/ai_tells_rules.ts +446 -5
- package/src/scripts/ask_block_census.ts +499 -0
- package/src/scripts/bench_humanizer_eval.ts +264 -40
- package/src/scripts/bench_prose_tells_fp.ts +198 -0
- package/src/scripts/build_rule_trigger_matrix.ts +5 -0
- package/src/scripts/check_branch_work_committed.ts +234 -0
- package/src/scripts/check_mcp_doc_drift.ts +217 -0
- package/src/scripts/check_pack_size.ts +321 -3
- package/src/scripts/check_release_highlights.ts +0 -157
- package/src/scripts/council_cli.ts +18 -27
- package/src/scripts/detect_ai_tells.ts +142 -20
- package/src/scripts/handoff_context_hook.ts +54 -7
- package/src/scripts/harvest_reference_tokens.ts +698 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +31 -1
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +45 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +191 -0
- package/src/scripts/hooks/session_eol_hook.ts +18 -7
- package/src/scripts/install-hooks.sh +52 -0
- package/src/scripts/install.ts +4 -4
- package/src/scripts/lint_agent_security.ts +316 -25
- package/src/scripts/lint_confusables.ts +42 -6
- package/src/scripts/lint_handoffs.ts +0 -132
- package/src/scripts/lint_hidden_unicode.ts +49 -7
- package/src/scripts/lint_instruction_smuggling.ts +42 -6
- package/src/scripts/lint_mcp_config_security.ts +42 -6
- package/src/scripts/lint_roadmap_blockers.ts +51 -1
- package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
- package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
- package/src/scripts/mcp_server/resources.ts +41 -0
- package/src/scripts/mcp_server/telemetry.ts +19 -4
- package/src/scripts/migrate_command_suggestions.ts +1 -1
- package/src/scripts/orchestration_record.ts +12 -1
- package/src/scripts/probe_unblocked_ask.ts +135 -2
- package/src/scripts/release.ts +50 -95
- package/src/scripts/release_drill.ts +6 -10
- package/src/scripts/release_env.ts +1 -0
- package/src/scripts/release_publication.ts +40 -31
- package/src/scripts/self_repair_cli.ts +31 -1
- package/src/scripts/self_review_gate.ts +409 -15
- package/src/scripts/skill_scout.ts +69 -0
- package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
- package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/event4u-app/agent-config/actions/workflows/smoke.yml) [](https://github.com/event4u-app/agent-config/actions/workflows/smoke-public-install.yml) [](https://www.npmjs.com/package/@event4u/agent-config) [](https://glama.ai/mcp/servers/event4u-app/agent-config) [](https://mcptoplist.com/server/glama%2Fevent4u-app%2Fagent-config)
|
|
6
6
|
|
|
7
|
-
[](dist/agent-src/skills/) [](dist/agent-src/rules/) [](dist/agent-src/skills/) [](dist/agent-src/rules/) [](dist/agent-src/commands/) [](docs/guidelines/) [](dist/agent-src/personas/) [](dist/agent-src/personas/advisors/) <!-- claim:published-artifact-counts -->
|
|
8
8
|
|
|
9
9
|
<sub>**How these are counted** — one canonical counter, `agent-config` → `update_counts --check`, re-derives all six from the tree and fails CI on a drift of one. Two bases are not what the linked directory shows, so they are stated here rather than left to be inferred: **Commands 202** counts every command file **recursively** (the linked directory holds 61 at its top level), and **Rules 120** counts the **source** rules while the linked projection holds 119 — one rule is dormant and is not projected. **Personas 29** excludes the directory README. Counts are of files and directories: none of them measures quality, activation, or adoption. <!-- claim:published-artifact-counts --></sub>
|
|
10
10
|
|
|
@@ -393,6 +393,16 @@ members:
|
|
|
393
393
|
|
|
394
394
|
gemini:
|
|
395
395
|
enabled: false
|
|
396
|
+
# HONEST NULL, not a probe result (road-to-admissible-council-seats 1.2).
|
|
397
|
+
# `council:status` prints this line, so the seat is no longer silently off.
|
|
398
|
+
disabled_reason: >-
|
|
399
|
+
honest null 2026-09-07 — the CLI headless contract could not be
|
|
400
|
+
established: the free tier on the probing machine fails with
|
|
401
|
+
IneligibleTierError before the run reaches the point where a piped stdin
|
|
402
|
+
alone would decide it, so whether the gemini CLI stays non-interactive
|
|
403
|
+
without -p/--prompt is UNKNOWN, not false. The api transport for this
|
|
404
|
+
provider became live in the same change; this seat stays off until the
|
|
405
|
+
contract is observed on a machine that can reach it.
|
|
396
406
|
# not-listed: gemini — the `gemini` CLI is installed here and its `--help` exposes only `-m, --model <string>` — no listing subcommand and no documented "latest" alias, so no sentinel could be substituted. An honest null for this provider, not a guess.
|
|
397
407
|
# The pin is therefore stamped as-of the drain date with NO refresh claimed;
|
|
398
408
|
# `verified_at` records when a human last looked, which is the only thing it
|
|
@@ -8,7 +8,7 @@ replaces: []
|
|
|
8
8
|
visibility: visible
|
|
9
9
|
skills: [agent-docs-writing]
|
|
10
10
|
description: Pick a recent session, generate a handoff from its transcript, and seed a fresh session with it — or summarize the live conversation for copy-paste.
|
|
11
|
-
argument-hint: "[--print |
|
|
11
|
+
argument-hint: "[--print | with tasks]"
|
|
12
12
|
suggestion:
|
|
13
13
|
eligible: true
|
|
14
14
|
trigger_description: "user asks for an agent handoff, to resume/continue a previous session in a fresh chat, or a context-summary to paste into a new chat"
|
|
@@ -114,10 +114,51 @@ Roadmap: {roadmap file if active, or "none"}
|
|
|
114
114
|
## Key decisions
|
|
115
115
|
- {important decisions made during this conversation}
|
|
116
116
|
|
|
117
|
+
## Least confident
|
|
118
|
+
- {the claim in this handoff you are least sure of} — verify: {command or
|
|
119
|
+
observable state that would confirm or kill it}
|
|
120
|
+
|
|
121
|
+
## Biggest thing missed
|
|
122
|
+
- {what a reviewer would most likely find that you did not} — verify: {command}
|
|
123
|
+
|
|
124
|
+
## Breaks in three months because
|
|
125
|
+
- {the assumption most likely to expire, and what expires it} — verify: {command}
|
|
126
|
+
|
|
127
|
+
## Not done
|
|
128
|
+
- {work inside the stated scope that did not land} — verify: {command}
|
|
129
|
+
|
|
117
130
|
## Relevant files
|
|
118
131
|
- {list of files that were edited or are important for context}
|
|
119
132
|
```
|
|
120
133
|
|
|
134
|
+
### The four self-critique sections — why every line carries a `verify:`
|
|
135
|
+
|
|
136
|
+
Every other section states what HAPPENED. None of them says what the outgoing
|
|
137
|
+
session is **least sure of**, which is the one thing the incoming session cannot
|
|
138
|
+
reconstruct and the one thing that decides where it should look first.
|
|
139
|
+
|
|
140
|
+
Each line in those four sections MUST name the command or observable state that
|
|
141
|
+
would confirm or kill it. An unverifiable line of self-doubt is filler: it reads
|
|
142
|
+
as diligence, costs the next session a read, and cannot be acted on. `none` is
|
|
143
|
+
accepted as the whole body of a section — an honest "nothing here" is an answer
|
|
144
|
+
— and blankness is not, exactly as `## Open questions` already treats the same
|
|
145
|
+
distinction. Nothing enforces either direction: the handoff artifact validator
|
|
146
|
+
that would have was retired with `HANDOFF.md`, so the contract is model-carried
|
|
147
|
+
here.
|
|
148
|
+
|
|
149
|
+
### Capture, do not chase
|
|
150
|
+
|
|
151
|
+
A finding surfaced **while writing the handoff** is written down, never fixed in
|
|
152
|
+
the handoff turn. The handoff exists because the session is ending, so a fix
|
|
153
|
+
started there is the least-verified change in the whole run — it lands after the
|
|
154
|
+
verification budget is spent, with no room to prove it.
|
|
155
|
+
|
|
156
|
+
The destination is a `model-noticed` self-repair record: `upsertFinding` in
|
|
157
|
+
`src/scripts/_lib/self_repair_store.ts`, carrying a `target` from the closed
|
|
158
|
+
`rule: | skill: | command: | hook:` vocabulary so the finding is joined to the
|
|
159
|
+
asset it is about. Put the same finding in `## Not done` with its `verify:`, so
|
|
160
|
+
the next session sees it without having to query the store.
|
|
161
|
+
|
|
121
162
|
The CLI generator emits the same section set (minus the live-only
|
|
122
163
|
*Repeatable workflow* / *Feedback history* refinements) — the template above
|
|
123
164
|
stays the single source of the section contract.
|
|
@@ -150,46 +191,6 @@ block (e.g. *"Copy this into a new chat:"*) and nothing after — no follow-up
|
|
|
150
191
|
questions, no numbered options. The picker in Step 2 is the one exception:
|
|
151
192
|
it is the flow's single question, asked BEFORE any handoff is generated.
|
|
152
193
|
|
|
153
|
-
## 2b. File-artifact mode — `HANDOFF.md` (optional, host-neutral)
|
|
154
|
-
|
|
155
|
-
On `/agent-handoff --file` (or when a workflow skill's phase boundary asks
|
|
156
|
-
for a standing handoff), ALSO write the contract to
|
|
157
|
-
`agents/runtime/state/HANDOFF.md` (gitignored runtime state — plain
|
|
158
|
-
Markdown, no host API). Required fields, in order:
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
# HANDOFF
|
|
162
|
-
## Mode
|
|
163
|
-
{current workflow mode/phase, e.g. Implement (TDD)}
|
|
164
|
-
## Contract received
|
|
165
|
-
{what the previous phase handed over}
|
|
166
|
-
## Contract owed
|
|
167
|
-
{what the current phase must produce before yielding}
|
|
168
|
-
## Decisions
|
|
169
|
-
- {decision taken, with one-line rationale} {optionally close the line with
|
|
170
|
-
`[reversible]` or `[irreversible]` — those two spellings exactly}
|
|
171
|
-
## Open questions
|
|
172
|
-
- {unresolved items the next session must not silently drop — each as a
|
|
173
|
-
question ending in `?`; write `none` when there genuinely are none}
|
|
174
|
-
## Next command
|
|
175
|
-
{the single command or step to run first on resume}
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
**Resume rule:** a workflow skill's step 0 checks for this file and resumes
|
|
179
|
-
from its contract (mode-inference table) instead of re-deriving state; a
|
|
180
|
-
long phase refreshes the file before yielding. Validated by
|
|
181
|
-
`lint_handoffs.ts` when present — a missing required field is red, and so is an
|
|
182
|
-
`## Open questions` section that answers neither way (blank, or a bare `TBD` /
|
|
183
|
-
`TODO` / `...`). A `?`-terminated question passes; so does an explicit `none` —
|
|
184
|
-
the check exists to stop a blank section reading as an all-clear, not to force a
|
|
185
|
-
question where there is none.
|
|
186
|
-
|
|
187
|
-
**Critical-planning-file safety protocol** (applies to HANDOFF.md and agent
|
|
188
|
-
roadmap edits): read the current file FIRST; take a timestamped backup copy
|
|
189
|
-
next to it (`HANDOFF.md.<ts>.bak`) before overwrite; duplicate-check before
|
|
190
|
-
appending (never double-append a section); preserve the section structure;
|
|
191
|
-
post-verify the write by re-reading the required fields.
|
|
192
|
-
|
|
193
194
|
## Detection — when natural-language triggers count as explicit
|
|
194
195
|
|
|
195
196
|
The user does not need to type `/agent-handoff` literally. Treat as
|
|
@@ -22,7 +22,7 @@ packs:
|
|
|
22
22
|
Turn a file someone dropped in `agents/tmp/` into either a roadmap this repo can
|
|
23
23
|
execute, or a written reason it was dropped.
|
|
24
24
|
|
|
25
|
-
The sibling [`/analyze:
|
|
25
|
+
The sibling [`/analyze:repo`](repo.md) does this for an
|
|
26
26
|
**external** repository. This does it for a **local artifact** — a review, a
|
|
27
27
|
prompt, a feature spec, a transcript, a persona, a competitor teardown — and the
|
|
28
28
|
difference matters: an inbox file is a **frozen snapshot of an opinion about a
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
model_tier: high
|
|
3
|
-
name: analyze-
|
|
3
|
+
name: analyze-repo
|
|
4
4
|
pack: analysis-workbench
|
|
5
5
|
visibility: internal
|
|
6
|
-
sub:
|
|
6
|
+
sub: repo
|
|
7
7
|
cluster: analyze
|
|
8
|
+
replaces: [analyze-reference-repo, analyze:reference-repo]
|
|
8
9
|
skills: [project-analyzer, learning-to-rule-or-skill]
|
|
9
10
|
description: Analyze an external reference repository (competitor, inspiration, peer) and produce a structured comparison + adoption plan for this project.
|
|
10
|
-
argument-hint: "<repo-url
|
|
11
|
+
argument-hint: "<repo-url|owner/repo|archive> [--mode=plan|execute] [--loops=N] [--focus=<area>] [--deep] [--refresh] [--no-roadmap]"
|
|
12
|
+
limits:
|
|
13
|
+
mode_default: plan
|
|
14
|
+
max_iterations: 3
|
|
15
|
+
hard_ceiling: 5
|
|
16
|
+
no_gain_stop: 2
|
|
17
|
+
target_metric: required
|
|
11
18
|
suggestion:
|
|
12
19
|
eligible: false
|
|
13
20
|
rationale: "Cluster sub-command — reached via its cluster head's routing or its explicit /cluster:sub name; not independently suggested (surface-consolidation)."
|
|
@@ -17,7 +24,7 @@ packs:
|
|
|
17
24
|
- meta
|
|
18
25
|
---
|
|
19
26
|
|
|
20
|
-
# analyze-
|
|
27
|
+
# analyze-repo
|
|
21
28
|
|
|
22
29
|
Analyze a **different** repository (a competitor, a reference implementation, or
|
|
23
30
|
a project the user admires) and produce a structured document that anchors on
|
|
@@ -35,26 +42,83 @@ The user provides a repository URL — a full GitHub URL
|
|
|
35
42
|
|
|
36
43
|
Optional arguments:
|
|
37
44
|
|
|
45
|
+
- `--mode=plan|execute` — `plan` is the **default** (§ Enforced limits).
|
|
46
|
+
- `--loops=N` — refinement-loop budget. **Default: 3**; hard ceiling 5.
|
|
38
47
|
- `--focus=<area>` — restrict analysis to one axis (e.g. `installer`,
|
|
39
48
|
`skills`, `mcp`, `governance`, `ci`). Default: full-surface.
|
|
49
|
+
- `--refresh` — re-resolve the reference's head revision (§ 2a). Without it a
|
|
50
|
+
re-run reads the revision already pinned in the local manifest.
|
|
40
51
|
- `--deep` — bounded deep-verification tier (§ 2b). Read-only clone at a pinned
|
|
41
52
|
SHA, never executed. Requires a non-empty anchor table.
|
|
42
53
|
- `--no-roadmap` — skip the roadmap-draft step.
|
|
43
54
|
|
|
55
|
+
## Enforced limits
|
|
56
|
+
|
|
57
|
+
The frontmatter `limits:` block is the machine-readable pin
|
|
58
|
+
(`tests/scripts/analyze_repo_limits.test.ts` fails when flow and pin drift);
|
|
59
|
+
the steps below are the enforcement — each limit is a step the run MUST
|
|
60
|
+
execute, not advice.
|
|
61
|
+
|
|
62
|
+
### Execution mode — plan-only default (`mode_default: plan`)
|
|
63
|
+
|
|
64
|
+
`--mode=plan` is the **default**: run §§ 1-6 — pin, fetch, extract, probe,
|
|
65
|
+
compare, classify, converge, write the local artifacts — then present the
|
|
66
|
+
result and STOP. No roadmap landing, no ledger rows, no tracked write of any
|
|
67
|
+
kind. `--mode=execute` must be **explicitly present in the invocation** to
|
|
68
|
+
reach §§ 7-8; treat its absence as plan mode even when conversation momentum
|
|
69
|
+
suggests otherwise. Execute mode does not remove the per-write confirmations in
|
|
70
|
+
§§ 7-8 — it only makes them reachable.
|
|
71
|
+
|
|
72
|
+
### Pre-registered target metric — required before loop 1 (`target_metric: required`)
|
|
73
|
+
|
|
74
|
+
Before loop 1 may run, the analysis document MUST carry a `Target metric` line
|
|
75
|
+
naming the metric of § 5c, its **measured baseline** taken from the seed pass,
|
|
76
|
+
and the predicted direction. No baseline → REFUSE to enter loop 1 with:
|
|
77
|
+
`target metric not pre-registered — record the seed-pass baseline first`. The
|
|
78
|
+
metric named before loop 1 is the metric every loop is scored against; loops
|
|
79
|
+
never move the goalposts.
|
|
80
|
+
|
|
81
|
+
### Loop budget (`max_iterations: 3`, `hard_ceiling: 5`)
|
|
82
|
+
|
|
83
|
+
`--loops=N` caps the refinement loops. **Default: 3** — one loop per lens
|
|
84
|
+
(§ 5b), which is what makes three the budget rather than a round number.
|
|
85
|
+
Hard ceiling: 5 — a larger `--loops` value is clamped to 5 with a warning.
|
|
86
|
+
|
|
87
|
+
**Halt-on-spin tripwire (`no_gain_stop: 2`), checked after every loop and
|
|
88
|
+
overriding the budget:**
|
|
89
|
+
|
|
90
|
+
- **Two consecutive zero-delta loops → STOP** before the next lens runs, and
|
|
91
|
+
say which two loops produced no delta and on which metric. Spinning without
|
|
92
|
+
gain is the failure the metric exists to catch.
|
|
93
|
+
- A verdict table still contested at the ceiling stops the run with a
|
|
94
|
+
maintainer question (§ 5b) — never silently.
|
|
95
|
+
- A single zero-delta loop **never** cancels the remaining lenses. It is a
|
|
96
|
+
signal about that lens, not a prediction about the next one.
|
|
97
|
+
|
|
98
|
+
### Read ceiling per loop
|
|
99
|
+
|
|
100
|
+
Loop *n* cannot read deeper than the seed pass without a local clone, so
|
|
101
|
+
`--deep` (§ 2b) becomes the **default whenever the loop runs**. The three-part
|
|
102
|
+
read ceiling of § 2b applies per loop, and the loop that hits it logs one
|
|
103
|
+
read-ceiling line naming the bound that fired.
|
|
104
|
+
|
|
44
105
|
## Steps
|
|
45
106
|
|
|
46
|
-
### 1.
|
|
107
|
+
### 1. Resolve scope from the invocation — do not ask
|
|
47
108
|
|
|
48
|
-
|
|
109
|
+
Scope comes from the arguments, never from a prompt. A bare repository argument
|
|
110
|
+
means **full scope**; `--focus=<area>` means focused. **Ask nothing before the
|
|
111
|
+
first fetch.** The four-option menu this step used to open with cost one prompt
|
|
112
|
+
per repository in a batch, which is a prompt the invocation had already
|
|
113
|
+
answered.
|
|
49
114
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
> 2. Focused — one axis (I'll ask which)
|
|
54
|
-
> 3. Quick scan — README + top-level layout only
|
|
55
|
-
> 4. Cancel
|
|
115
|
+
The one question that survives is an **unresolvable repository identity** — the
|
|
116
|
+
argument matches no repository, or matches more than one. That is a genuine
|
|
117
|
+
ambiguity the invocation did not settle, and it halts before any fetch.
|
|
56
118
|
|
|
57
|
-
|
|
119
|
+
Everything the menu's "Cancel" option protected is protected elsewhere: the
|
|
120
|
+
write-acts of §§ 7-8 keep their own confirmations, and plan mode (§ Enforced
|
|
121
|
+
limits) is the default, so a run that is never confirmed writes nothing tracked.
|
|
58
122
|
|
|
59
123
|
### 1b. Anchor table first
|
|
60
124
|
|
|
@@ -81,6 +145,26 @@ Use `web-fetch` for rendered files, GitHub REST (`/repos/{o}/{r}/contents/{p}`)
|
|
|
81
145
|
for listings. **Max 40 fetches** — if more is needed, ask which subtree to
|
|
82
146
|
expand.
|
|
83
147
|
|
|
148
|
+
### 2a. Pin the upstream revision — once, before any reasoning
|
|
149
|
+
|
|
150
|
+
The **seed pass** resolves the reference's head revision exactly once and
|
|
151
|
+
records it in the local manifest (§ 6). Every loop of § 5b reads **that same
|
|
152
|
+
revision**. Only `--refresh` re-resolves it.
|
|
153
|
+
|
|
154
|
+
Why once: a loop that re-resolves is comparing two different repositories and
|
|
155
|
+
calling the difference a finding. Convergence over a moving target is not
|
|
156
|
+
convergence, and a delta produced by an upstream commit that landed between
|
|
157
|
+
loop 1 and loop 2 is upstream's news, not this analysis's.
|
|
158
|
+
|
|
159
|
+
Record in the iteration record, once per pass: `revision: <sha>` — the **same**
|
|
160
|
+
value on every pass of a run. A pass whose recorded revision differs from the
|
|
161
|
+
seed pass's is a defect in the run, not a finding about the reference.
|
|
162
|
+
|
|
163
|
+
Because loop *n* cannot read deeper than the seed pass without a local clone,
|
|
164
|
+
`--deep` (§ 2b) is the default whenever the loop runs. Each loop that hits the
|
|
165
|
+
§ 2b three-part read ceiling logs **one** read-ceiling line naming the bound
|
|
166
|
+
that fired and the loop it fired in.
|
|
167
|
+
|
|
84
168
|
### 2b. Deep verification tier — `--deep`, opt-in
|
|
85
169
|
|
|
86
170
|
Forty top-level fetches cannot reach a fact buried in an implementation file, so
|
|
@@ -179,38 +263,111 @@ mentions a ledger word — a check that mostly fires wrongly gets waved through.
|
|
|
179
263
|
A **checklist obligation**, not a CI gate: `check_claims` guards the ledger's
|
|
180
264
|
integrity, never a proposal against it.
|
|
181
265
|
|
|
182
|
-
### 5b.
|
|
266
|
+
### 5b. Three loops, three different questions
|
|
267
|
+
|
|
268
|
+
One pass is a draft, not an analysis — but three passes asking the same
|
|
269
|
+
question are three rewordings, which costs three times the fetches and produces
|
|
270
|
+
prose churn. So the loops are **not** repetitions of one critique. Each has its
|
|
271
|
+
own lens, and the lens is what makes the loop worth its cost:
|
|
272
|
+
|
|
273
|
+
| Loop | Lens | The question it asks, and only it |
|
|
274
|
+
|---|---|---|
|
|
275
|
+
| 1 | **Coverage** | What was missed? What was wrongly marked absent? Which rows rest on a weak anchor — no `file:line`, or one that no longer resolves? |
|
|
276
|
+
| 2 | **Adversary** | Was the *form* copied instead of the principle? Is this only *different* rather than *better*? Does this package already solve it elsewhere? What does it cost in tokens, surface and maintenance? |
|
|
277
|
+
| 3 | **Convergence** | Resolve contradictions between the first two. Fold duplicates. Cut the speculative. Bind every remaining line to evidence on **both** sides. |
|
|
278
|
+
|
|
279
|
+
Each loop takes as input **both** the previous analysis **and** the previous
|
|
280
|
+
roadmap draft — a finding that changed the analysis but not the roadmap is a
|
|
281
|
+
finding the run has not finished acting on.
|
|
282
|
+
|
|
283
|
+
Each loop appends its own **delta block** to `## Iteration record`, naming its
|
|
284
|
+
lens, with one row per change and a reason per row:
|
|
285
|
+
|
|
286
|
+
```markdown
|
|
287
|
+
### Loop {n} — {Coverage | Adversary | Convergence} · revision: {sha}
|
|
288
|
+
|
|
289
|
+
| Change | Row | From → To | Reason |
|
|
290
|
+
|---|---|---|---|
|
|
291
|
+
| added / removed / flipped / folded | … | … | … |
|
|
292
|
+
```
|
|
183
293
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
294
|
+
**A loop whose delta block has no added, removed, flipped or folded entry is
|
|
295
|
+
recorded as a zero-delta loop, never omitted.** An omitted block is
|
|
296
|
+
indistinguishable from a loop that never ran, and the halt rule below counts
|
|
297
|
+
zero-delta loops — so omitting one silently disarms the tripwire.
|
|
298
|
+
|
|
299
|
+
A verdict table still contested at the ceiling is itself the finding — mark it
|
|
300
|
+
`contested — needs maintainer judgement` and stop with the question, never
|
|
190
301
|
silently.
|
|
191
302
|
|
|
303
|
+
### 5c. The target metric is a decision-quality measure
|
|
304
|
+
|
|
305
|
+
The metric is:
|
|
306
|
+
|
|
307
|
+
> the count of ADOPT/ADAPT rows carrying a concrete `file:line` on **both** the
|
|
308
|
+
> reference side and this package's side.
|
|
309
|
+
|
|
310
|
+
Not the number of rows, not the length of the document, not the count of
|
|
311
|
+
findings. An output-volume metric rewards a loop for saying more, which is
|
|
312
|
+
precisely the churn the three lenses exist to prevent; this metric only moves
|
|
313
|
+
when a verdict became *decidable* — someone can now go and look at both ends.
|
|
314
|
+
|
|
315
|
+
Its baseline is measured on the seed pass and pre-registered before loop 1
|
|
316
|
+
(§ Enforced limits). The halt rules that read it:
|
|
317
|
+
|
|
318
|
+
- **Two consecutive zero-delta loops → STOP** before the next lens runs, naming
|
|
319
|
+
the two loops and the metric. Spin, not convergence.
|
|
320
|
+
- **A single zero-delta loop never cancels the remaining lenses.** Loop 1
|
|
321
|
+
finding nothing to add on Coverage says nothing about whether the Adversary
|
|
322
|
+
lens will find something to remove — the lenses ask different questions, so
|
|
323
|
+
one lens's silence is not evidence about the next.
|
|
324
|
+
- A contested table stops the run with a maintainer question (§ 5b).
|
|
325
|
+
|
|
192
326
|
A contested table is a **published finding, not an adoption proposal**: the
|
|
193
327
|
reference surface holds elements this repo cannot mechanically classify, and no
|
|
194
328
|
automation converts that into an ADOPT decision. Convergence is an analyst
|
|
195
329
|
obligation with a recorded trail — **never an LLM-as-judge gate**, never a
|
|
196
330
|
script.
|
|
197
331
|
|
|
198
|
-
### 6. Write the analysis document
|
|
332
|
+
### 6. Write the analysis document — under the opaque id, in the local area
|
|
333
|
+
|
|
334
|
+
**Target: `agents/.harvest-local/repo/<opaque-id>/analysis.md`.** Every pass and
|
|
335
|
+
loop artifact of a run lives under that one directory, and the run writes
|
|
336
|
+
nothing under `agents/evidence/analysis/`.
|
|
337
|
+
|
|
338
|
+
The old target was `agents/evidence/analysis/compare-<slug>.md` with
|
|
339
|
+
`<slug>` = `<owner>-<repo>`, which put the reference's identity into a path.
|
|
340
|
+
`.gitignore` covers `compare-*.md` under the evidence directory but nothing
|
|
341
|
+
else there, so any other filename in that directory would have been unprotected
|
|
342
|
+
by construction — the protection was a glob, not a boundary.
|
|
343
|
+
`agents/.harvest-local/` is a whole gitignored directory, so the boundary is the
|
|
344
|
+
directory rather than a pattern one rename defeats.
|
|
345
|
+
|
|
346
|
+
**The opaque id.** Derived by
|
|
347
|
+
`./scripts-run src/scripts/harvest_reference_tokens` from the canonical
|
|
348
|
+
repository identity **and** the pinned revision of § 2a: `sha256(identity +
|
|
349
|
+
"@" + revision)`, first 16 hex characters. Two consequences that are the point
|
|
350
|
+
of including the revision: the id is **stable** across two runs at the same
|
|
351
|
+
revision, so a resumed or repeated run lands in the same directory; and it
|
|
352
|
+
**differs** across revisions, so one repository at two historical pins is two
|
|
353
|
+
pieces of evidence rather than one overwriting the other.
|
|
354
|
+
|
|
355
|
+
**The plaintext lives in exactly one place** — `identity` in the local
|
|
356
|
+
manifest, `agents/.harvest-local/manifest.jsonl`, inside the same gitignored
|
|
357
|
+
directory. Nothing else in the run resolves an opaque id back to a name.
|
|
199
358
|
|
|
200
|
-
|
|
201
|
-
missing, with `.gitkeep` — same convention as `project-analyzer`). Slug rule:
|
|
202
|
-
`<owner>-<repo>` lowercased, non-alphanumeric → `-`, collapse runs. Structure:
|
|
359
|
+
Structure:
|
|
203
360
|
|
|
204
361
|
```markdown
|
|
205
362
|
# Reference analysis: {owner}/{repo}
|
|
206
363
|
|
|
207
364
|
> One-sentence framing of why this reference matters.
|
|
208
365
|
|
|
209
|
-
- **Source:**
|
|
366
|
+
- **Source:** `opaque:{opaque-id}` — resolvable only via the local manifest
|
|
210
367
|
- **Fetched commit:** {sha} ({date})
|
|
211
368
|
- **Own-tree SHA:** {sha}
|
|
212
369
|
- **Focus:** {full | area} · **Depth:** {surface | deep}
|
|
213
|
-
- **Analyst:** agent via `/analyze-
|
|
370
|
+
- **Analyst:** agent via `/analyze-repo`
|
|
214
371
|
|
|
215
372
|
## Anchor table
|
|
216
373
|
|
|
@@ -231,9 +388,31 @@ missing, with `.gitkeep` — same convention as `project-analyzer`). Slug rule:
|
|
|
231
388
|
| Artifact | Our consumer (file:line) | Discovered? | Validates? | Exact failing axes or error |
|
|
232
389
|
|---|---|---|---|---|
|
|
233
390
|
|
|
391
|
+
## Target metric
|
|
392
|
+
|
|
393
|
+
- **Metric:** ADOPT/ADAPT rows with a `file:line` on both sides (§ 5c)
|
|
394
|
+
- **Seed-pass baseline:** {n} · **Predicted direction:** up
|
|
395
|
+
|
|
234
396
|
## Iteration record
|
|
235
397
|
|
|
236
|
-
|
|
398
|
+
`revision: {sha}` — the § 2a pin, identical on every pass below.
|
|
399
|
+
|
|
400
|
+
One delta block per loop, in order, each naming its lens. A zero-delta loop
|
|
401
|
+
keeps its block and records the zero (§ 5b).
|
|
402
|
+
|
|
403
|
+
### Loop 1 — Coverage · revision: {sha}
|
|
404
|
+
|
|
405
|
+
| Change | Row | From → To | Reason |
|
|
406
|
+
|---|---|---|---|
|
|
407
|
+
|
|
408
|
+
### Loop 2 — Adversary · revision: {sha}
|
|
409
|
+
|
|
410
|
+
| Change | Row | From → To | Reason |
|
|
411
|
+
|---|---|---|---|
|
|
412
|
+
|
|
413
|
+
### Loop 3 — Convergence · revision: {sha}
|
|
414
|
+
|
|
415
|
+
| Change | Row | From → To | Reason |
|
|
237
416
|
|---|---|---|---|
|
|
238
417
|
|
|
239
418
|
## Findings
|
|
@@ -270,6 +449,9 @@ omit the section entirely when every row extends something that exists.}
|
|
|
270
449
|
does not fit — a seed that skipped this line is not ready to hand over}
|
|
271
450
|
|
|
272
451
|
## Open questions for the maintainer
|
|
452
|
+
{Each line is a question to ask the maintainer directly, one at a time, when
|
|
453
|
+
this report is handed over — the section records what is owed, it does not
|
|
454
|
+
discharge it.}
|
|
273
455
|
```
|
|
274
456
|
|
|
275
457
|
The `## Seeds` section is the handoff shape
|
|
@@ -282,19 +464,52 @@ it makes the four-surface overlap scan that
|
|
|
282
464
|
requires visible at handoff time, when the analysis is still open, instead of
|
|
283
465
|
re-derived later by whoever picks the seed up.
|
|
284
466
|
|
|
285
|
-
### 7. Offer next steps
|
|
467
|
+
### 7. Offer next steps — execute mode only
|
|
286
468
|
|
|
287
|
-
|
|
469
|
+
**Plan mode stops here** (§ Enforced limits). `--mode=execute` makes this step
|
|
470
|
+
reachable; it does not make it automatic.
|
|
288
471
|
|
|
289
|
-
> Analysis written to `agents/
|
|
472
|
+
> Analysis written to `agents/.harvest-local/repo/{opaque-id}/analysis.md`.
|
|
290
473
|
>
|
|
291
|
-
> 1. Draft roadmap from ADOPT/ADAPT — `agents/roadmaps/
|
|
474
|
+
> 1. Draft roadmap from ADOPT/ADAPT — `agents/roadmaps/road-to-{defect}.md`
|
|
292
475
|
> 2. Merge findings into an existing roadmap — say which
|
|
293
476
|
> 3. Stop here
|
|
294
477
|
> 4. Deep-dive on one axis — say which
|
|
295
478
|
|
|
296
479
|
Never create the roadmap without explicit confirmation.
|
|
297
480
|
|
|
481
|
+
#### The landed roadmap is named after the defect, never after the source
|
|
482
|
+
|
|
483
|
+
A tracked filename is a published string. `adopt-{owner}-{repo}.md` publishes
|
|
484
|
+
the reference's identity in the one surface no `.gitignore` can retract, and it
|
|
485
|
+
also names the wrong thing: the roadmap exists because **this package has a
|
|
486
|
+
gap**, not because some other project exists.
|
|
487
|
+
|
|
488
|
+
- **Filename:** derived from the capability gap —
|
|
489
|
+
`agents/roadmaps/road-to-<the-thing-we-lack>.md`. It contains neither the
|
|
490
|
+
owner nor the repository name. If the only name you can think of is the
|
|
491
|
+
reference's, the finding is not yet understood well enough to land.
|
|
492
|
+
- **Header:** carries a provenance block with an **encrypted token**
|
|
493
|
+
(`ENC1:` via `src/scripts/_lib/link_crypto.ts`), never the plaintext URL —
|
|
494
|
+
the form
|
|
495
|
+
[`source-confidentiality`](../../../../rules/source-confidentiality.md)
|
|
496
|
+
requires of a tracked roadmap that cites a source. Sources are referenced as
|
|
497
|
+
*Source A / B / C* in the prose.
|
|
498
|
+
- **Verified by:** `./scripts-run src/scripts/check_no_external_sources`, which
|
|
499
|
+
is the deterministic backstop rather than the discipline itself.
|
|
500
|
+
|
|
501
|
+
#### Never hand a subagent a plaintext URL
|
|
502
|
+
|
|
503
|
+
Under the harvester (`/analyze:roadmap-repos`) the orchestrator passes the
|
|
504
|
+
subagent **the opaque id and nothing else**. The subagent reads the URL from the
|
|
505
|
+
local manifest itself, so the plaintext never appears in a dispatch argument.
|
|
506
|
+
|
|
507
|
+
The cost is one indirection, and it is taken **on precaution**: whether a given
|
|
508
|
+
host retains a subagent's arguments in a transcript or audit log is
|
|
509
|
+
host-dependent and was not verifiable from this tree. That is stated rather than
|
|
510
|
+
asserted away — the indirection is cheap enough not to need a proven threat, and
|
|
511
|
+
claiming a proven one would be a claim this package cannot support.
|
|
512
|
+
|
|
298
513
|
### 8. Close the loop — offer the ledger rows
|
|
299
514
|
|
|
300
515
|
**Only after a roadmap draft is accepted** (option 1 or 2 above). This step
|
|
@@ -313,7 +528,7 @@ One row per **anchored ADOPT or ADAPT** finding, and nothing else:
|
|
|
313
528
|
|---|---|
|
|
314
529
|
| `harvest_id` | a kebab-case slug for the mechanism |
|
|
315
530
|
| `stated_in` | the roadmap file the user just accepted |
|
|
316
|
-
| `source_ref` |
|
|
531
|
+
| `source_ref` | `opaque:<id>` or an `ENC1:` token — never the plaintext URL; the § 2a pin is inside the id |
|
|
317
532
|
| `evidence_locator` | the reference-side `file:line` from that row of the comparison matrix |
|
|
318
533
|
| `harvested_at` | today |
|
|
319
534
|
| `verdict` | `adopt` or `adapt` |
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
model_tier: medium
|
|
3
|
+
name: analyze-roadmap-repos
|
|
4
|
+
pack: analysis-workbench
|
|
5
|
+
visibility: internal
|
|
6
|
+
sub: roadmap-repos
|
|
7
|
+
cluster: analyze
|
|
8
|
+
type: orchestrator
|
|
9
|
+
replaces: []
|
|
10
|
+
skills: [subagent-orchestration]
|
|
11
|
+
description: Walk the roadmap estate's encrypted reference tokens and feed each unique repository through analyze-repo, one subagent at a time, without producing one roadmap per repository.
|
|
12
|
+
argument-hint: "[--limit=N] [--resume] [--refresh] [--mode=plan|execute]"
|
|
13
|
+
suggestion:
|
|
14
|
+
eligible: false
|
|
15
|
+
rationale: "Cluster sub-command — reached via its cluster head's routing or its explicit /cluster:sub name; not independently suggested (surface-consolidation)."
|
|
16
|
+
workspaces:
|
|
17
|
+
- agent-config-maintainer
|
|
18
|
+
packs:
|
|
19
|
+
- meta
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# analyze-roadmap-repos
|
|
23
|
+
|
|
24
|
+
The thin harvester in front of [`analyze-repo`](repo.md). It walks the roadmap
|
|
25
|
+
estate's encrypted reference tokens, resolves each to a repository identity, and
|
|
26
|
+
feeds the unique ones through the analysis command one at a time.
|
|
27
|
+
|
|
28
|
+
**This command contains no analysis instruction and never will.** It resolves,
|
|
29
|
+
dispatches, and folds. Every judgement about a reference — what to fetch, what
|
|
30
|
+
to compare, what to adopt, how to converge — belongs to `analyze-repo`, which
|
|
31
|
+
owns the loop contract and its limits. A second copy of that reasoning here
|
|
32
|
+
would be a second implementation to keep in step with the first, which is the
|
|
33
|
+
condition step 1.1 of its roadmap removed.
|
|
34
|
+
|
|
35
|
+
## Steps
|
|
36
|
+
|
|
37
|
+
### 1. Discovery — run the script, read the manifest
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
./scripts-run src/scripts/harvest_reference_tokens --dry-run # census only
|
|
41
|
+
./scripts-run src/scripts/harvest_reference_tokens --resume --limit=N # write the manifest
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The script is the only discovery mechanism: it extracts the `ENC1:` tokens
|
|
45
|
+
across the five estate levels, decrypts them, classifies each resolved URL,
|
|
46
|
+
canonicalizes the repositories, deduplicates on identity plus pinned revision,
|
|
47
|
+
and writes `agents/.harvest-local/manifest.jsonl`.
|
|
48
|
+
|
|
49
|
+
It **refuses without a link-encryption key** rather than reporting a short
|
|
50
|
+
census — a classification of zero repositories that actually means "nobody could
|
|
51
|
+
look" is the failure mode this whole pass exists to avoid.
|
|
52
|
+
|
|
53
|
+
Read the manifest. Do not re-derive any of it here.
|
|
54
|
+
|
|
55
|
+
### 2. Dispatch — one subagent per repository, sequential
|
|
56
|
+
|
|
57
|
+
For each manifest entry with status `pending`, in manifest order, up to the
|
|
58
|
+
batch limit:
|
|
59
|
+
|
|
60
|
+
- Spawn **one subagent** and have it run `/analyze:repo` for that entry.
|
|
61
|
+
- Pass the subagent **the opaque id only** — never a resolved URL. The subagent
|
|
62
|
+
reads the URL from `agents/.harvest-local/manifest.jsonl` itself. One
|
|
63
|
+
indirection, taken on precaution (`analyze-repo` § 7).
|
|
64
|
+
- **Sequential, never a fan-out.** Over a hundred identities at four passes each
|
|
65
|
+
cannot share one session, and every external fetch is spent deliberately. The
|
|
66
|
+
manifest is the only shared state between subagents.
|
|
67
|
+
- Write the entry's status back as the run progresses: `running`, then `done` or
|
|
68
|
+
`failed`. A batch interrupted mid-flight resumes from those statuses.
|
|
69
|
+
|
|
70
|
+
Default batch limit is **small**. A harvester that walks the whole estate in one
|
|
71
|
+
invocation spends a hundred repositories' worth of fetches on a decision nobody
|
|
72
|
+
took.
|
|
73
|
+
|
|
74
|
+
### 3. Ownership fold — one gap, one roadmap
|
|
75
|
+
|
|
76
|
+
After the batch, and never during it, run the fold pass of
|
|
77
|
+
[`analyze-repo`](repo.md) § 7 across the batch's findings as a set. Consult
|
|
78
|
+
`src/scripts/roadmap_context.ts` and the run's own candidate registry, then pick
|
|
79
|
+
exactly one disposition per repository:
|
|
80
|
+
|
|
81
|
+
| Disposition | When |
|
|
82
|
+
|---|---|
|
|
83
|
+
| no action | the finding is REJECT or ALREADY throughout |
|
|
84
|
+
| already planned | an active roadmap already owns the gap |
|
|
85
|
+
| extend an existing roadmap | the gap belongs to an owner that exists |
|
|
86
|
+
| create a follow-up | the gap belongs under an owner but is out of its scope |
|
|
87
|
+
| create new | no owner exists |
|
|
88
|
+
| contested | two owners claim it — stop and ask |
|
|
89
|
+
|
|
90
|
+
**Three repositories showing the same gap strengthen the evidence on one owning
|
|
91
|
+
roadmap. They never create three.** That is the whole reason this command exists
|
|
92
|
+
rather than a loop that invokes `analyze-repo` and keeps whatever it returns.
|
|
93
|
+
|
|
94
|
+
### 4. Landing — local-only
|
|
95
|
+
|
|
96
|
+
The batch's consolidated result is written to `agents/.harvest-local/` and
|
|
97
|
+
nowhere else. **No per-run consolidate roadmap takes an active top-level estate
|
|
98
|
+
slot** — decided 2026-09-06 under the maintainer's standing delegation, recorded
|
|
99
|
+
in `road-to-bounded-reference-harvest-loop` § Blockers. A recurring process that
|
|
100
|
+
takes a slot per run converts the estate ratchet's allowance into a standing
|
|
101
|
+
exemption, which removes the pressure the ratchet exists to apply.
|
|
102
|
+
|
|
103
|
+
Accepted consequence, stated rather than hidden: **no batch is visible in the
|
|
104
|
+
roadmap dashboard.** Any roadmap the fold pass does land is an ordinary estate
|
|
105
|
+
entry landed for a named capability gap, and is subject to the estate gate like
|
|
106
|
+
any other.
|
|
107
|
+
|
|
108
|
+
## Safety
|
|
109
|
+
|
|
110
|
+
- Read-only on every reference. The no-execute invariant of `analyze-repo`
|
|
111
|
+
§ Safety binds every subagent this command spawns.
|
|
112
|
+
- No plaintext repository URL is ever passed as a dispatch argument.
|
|
113
|
+
- Nothing tracked is written by this command itself.
|
|
114
|
+
- Hard-Floor actions stay this-turn gated. A batch authorizes fetches, never a
|
|
115
|
+
commit, a push or a merge.
|
|
116
|
+
|
|
117
|
+
## When **not** to use
|
|
118
|
+
|
|
119
|
+
- One known reference → [`analyze-repo`](repo.md) directly. The harvester's only
|
|
120
|
+
job is the estate walk.
|
|
121
|
+
- Analyzing this repository → `/project-analyze`.
|
|
122
|
+
- A dropped local artifact → [`/analyze:inbox`](inbox.md).
|
|
123
|
+
|
|
124
|
+
## Related
|
|
125
|
+
|
|
126
|
+
- Command: [`analyze-repo`](repo.md) — the analysis engine this dispatches to.
|
|
127
|
+
- Script: `src/scripts/harvest_reference_tokens.ts` — discovery, the only one.
|
|
128
|
+
- Rule: [`source-confidentiality`](../../../../rules/source-confidentiality.md)
|
|
129
|
+
— why the identities stay in the gitignored area.
|