session-orchestrator 3.17.0 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/030-wave-execution.mdc +17 -1
- package/CHANGELOG.md +105 -412
- package/README.md +12 -9
- package/SECURITY.md +190 -27
- package/agents/AGENTS.md +20 -3
- package/agents/code-implementer.md +6 -6
- package/agents/db-specialist.md +1 -1
- package/agents/qa-strategist.md +31 -6
- package/agents/schemas/qa-strategist.schema.json +27 -0
- package/agents/schemas/test-writer.schema.json +60 -2
- package/agents/security-reviewer.md +1 -1
- package/agents/session-reviewer.md +1 -1
- package/agents/test-writer.md +29 -10
- package/agents/ui-developer.md +1 -1
- package/commands/contract-version-bump.md +28 -0
- package/commands/portfolio.md +1 -1
- package/docs/USER-GUIDE.md +8 -3
- package/docs/ci-setup.md +121 -7
- package/docs/codex-setup.md +1 -1
- package/docs/components.md +6 -6
- package/docs/cursor-setup.md +22 -9
- package/docs/events-schema.md +5 -1
- package/docs/instruction-delivery.md +444 -0
- package/docs/rule-authoring.md +58 -9
- package/docs/session-config-reference.md +244 -9
- package/docs/session-config-template.md +39 -3
- package/hooks/_lib/guard-source-loader.mjs +467 -0
- package/hooks/_lib/lock-bootstrap.mjs +21 -0
- package/hooks/_lib/vcs-create-matcher.mjs +119 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/enforce-commands.mjs +10 -2
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +11 -2
- package/hooks/hooks-pi.json +10 -0
- package/hooks/hooks.json +21 -1
- package/hooks/on-session-end.mjs +178 -18
- package/hooks/on-session-start.mjs +23 -0
- package/hooks/post-bash-write-verify.mjs +977 -0
- package/hooks/post-subagent-discovery-validator.mjs +256 -41
- package/hooks/pre-bash-destructive-guard.mjs +525 -160
- package/hooks/pre-bash-issue-budget.mjs +167 -0
- package/hooks/pre-bash-sessions-ledger-guard.mjs +627 -0
- package/hooks/pre-bash-templates-first.mjs +96 -63
- package/hooks/subagent-telemetry.mjs +527 -37
- package/package.json +5 -2
- package/pi/prompts/contract-version-bump.md +12 -0
- package/rules/README.md +32 -0
- package/scripts/archive-closed-prds.mjs +12 -22
- package/scripts/autopilot-multi.mjs +103 -20
- package/scripts/backfill-abandoned-sessions.mjs +160 -4
- package/scripts/check-doc-consistency.sh +17 -1
- package/scripts/eval-session.mjs +50 -9
- package/scripts/fleet-instruction-scan.mjs +141 -0
- package/scripts/lib/autopilot/mr-draft.mjs +31 -1
- package/scripts/lib/autopilot/worktree-pipeline.mjs +113 -5
- package/scripts/lib/backlog-scan.mjs +39 -6
- package/scripts/lib/blocked-commands-policy.mjs +340 -0
- package/scripts/lib/ci-status-banner.mjs +75 -12
- package/scripts/lib/claude-md-budget-lint.mjs +283 -34
- package/scripts/lib/command-blocker.mjs +1013 -58
- package/scripts/lib/config/config-protection.mjs +2 -1
- package/scripts/lib/config/drift-check.mjs +9 -1
- package/scripts/lib/config/gitlab-portfolio.mjs +1 -1
- package/scripts/lib/config/issue-budget.mjs +123 -0
- package/scripts/lib/config/reconcile.mjs +21 -0
- package/scripts/lib/config/section-extractor.mjs +121 -1
- package/scripts/lib/config-schema.mjs +23 -3
- package/scripts/lib/config.mjs +17 -0
- package/scripts/lib/convergence-monitor.mjs +49 -3
- package/scripts/lib/description-surface.mjs +535 -0
- package/scripts/lib/dispatcher/enumerate.mjs +26 -40
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +26 -24
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +1 -1
- package/scripts/lib/eval/engine.mjs +47 -5
- package/scripts/lib/events.mjs +59 -7
- package/scripts/lib/gates/gate-full.mjs +15 -3
- package/scripts/lib/gates/gate-helpers.mjs +132 -6
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +28 -8
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +8 -2
- package/scripts/lib/gitlab-portfolio/cli.mjs +1 -1
- package/scripts/lib/handover-gate.mjs +7 -3
- package/scripts/lib/harness-audit/categories/category4.mjs +9 -3
- package/scripts/lib/instruction-budget-guard.mjs +402 -51
- package/scripts/lib/io.mjs +345 -10
- package/scripts/lib/issue-budget.mjs +269 -0
- package/scripts/lib/issue-close-strip-labels.mjs +39 -9
- package/scripts/lib/label-scope.mjs +47 -0
- package/scripts/lib/learnings/schema.mjs +43 -3
- package/scripts/lib/lock-reaper.mjs +1 -2
- package/scripts/lib/memory-proposals/schema.mjs +36 -1
- package/scripts/lib/peer-discovery.mjs +645 -0
- package/scripts/lib/pi-hook-bridge.mjs +146 -17
- package/scripts/lib/product-repo-detect.mjs +9 -8
- package/scripts/lib/project-hygiene.mjs +432 -0
- package/scripts/lib/quality-gate.mjs +167 -0
- package/scripts/lib/recommendations-v0.mjs +1 -1
- package/scripts/lib/reconcile/eligibility.mjs +1 -1
- package/scripts/lib/reconcile/emitter.mjs +23 -4
- package/scripts/lib/reconcile/engine.mjs +147 -39
- package/scripts/lib/reconcile/idempotency.mjs +114 -14
- package/scripts/lib/reconcile-nudge-banner.mjs +65 -9
- package/scripts/lib/resource-probe/evaluate.mjs +70 -4
- package/scripts/lib/resource-probe.mjs +19 -0
- package/scripts/lib/rule-loader.mjs +6 -0
- package/scripts/lib/scope-baseline.mjs +564 -0
- package/scripts/lib/scope-gate.mjs +399 -98
- package/scripts/lib/session-close-backfill.mjs +61 -6
- package/scripts/lib/session-end/phase-skip.mjs +1 -0
- package/scripts/lib/session-id.mjs +221 -41
- package/scripts/lib/session-lock.mjs +304 -6
- package/scripts/lib/session-schema/constants.mjs +22 -3
- package/scripts/lib/session-schema/validator.mjs +16 -0
- package/scripts/lib/sessions-integrity-banner.mjs +294 -0
- package/scripts/lib/sessions-staleness-banner.mjs +121 -12
- package/scripts/lib/skill-evolution/idempotency.mjs +135 -16
- package/scripts/lib/skill-evolution/mr-opener.mjs +9 -1
- package/scripts/lib/spiral-carryover.mjs +142 -30
- package/scripts/lib/state-md/mission-status.mjs +53 -3
- package/scripts/lib/subagents-schema.mjs +43 -9
- package/scripts/lib/test-runner/issue-reconcile.mjs +53 -13
- package/scripts/lib/tests-src-ratio.mjs +484 -0
- package/scripts/lib/validate/check-agents.mjs +56 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +244 -10
- package/scripts/lib/validate/check-rules.mjs +217 -35
- package/scripts/lib/validate/check-test-value-bans.mjs +782 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
- package/scripts/lib/validate-vendored-rules.mjs +10 -2
- package/scripts/lib/vault-archive.mjs +17 -2
- package/scripts/lib/vault-backfill/glab.mjs +8 -0
- package/scripts/lib/vault-mirror/process.mjs +30 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +293 -36
- package/scripts/lib/vcs-repo-spec.mjs +362 -0
- package/scripts/lib/wave-resource-gate.mjs +115 -11
- package/scripts/lib/worktree/listing.mjs +44 -7
- package/scripts/mcp-server.sh +17 -3
- package/scripts/measure-context-overhead.sh +151 -0
- package/scripts/memory-propose.mjs +72 -9
- package/scripts/print-applicable-rules.mjs +51 -12
- package/scripts/release.mjs +534 -0
- package/scripts/run-quality-gate.mjs +123 -5
- package/scripts/validate-wave-scope.mjs +182 -17
- package/scripts/vault-integration-watcher.mjs +32 -10
- package/skills/_shared/config-reading.md +2 -2
- package/skills/bootstrap/fast-template.md +1 -1
- package/skills/claude-md-drift-check/checker.mjs +145 -28
- package/skills/contract-version-bump/SKILL.md +219 -0
- package/skills/discovery/SKILL.md +4 -4
- package/skills/discovery/issue-templates.md +11 -11
- package/skills/discovery/probes-audit.md +1 -1
- package/skills/discovery/probes-feature.md +1 -1
- package/skills/discovery/probes-session.md +26 -5
- package/skills/ecosystem-health/SKILL.md +1 -1
- package/skills/ecosystem-health/wizard.md +4 -4
- package/skills/evolve/SKILL.md +1 -0
- package/skills/gitlab-ops/SKILL.md +20 -12
- package/skills/gitlab-portfolio/SKILL.md +2 -2
- package/skills/hook-development/SKILL.md +1 -1
- package/skills/mode-selector/SKILL.md +1 -1
- package/skills/npm-publish/SKILL.md +17 -1
- package/skills/plan/SKILL.md +5 -5
- package/skills/plan/mode-feature.md +4 -4
- package/skills/plan/mode-new.md +10 -10
- package/skills/plan/mode-retro.md +1 -1
- package/skills/quality-gates/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +21 -4
- package/skills/session-end/SKILL.md +34 -13
- package/skills/session-end/discovery-scan.md +4 -2
- package/skills/session-end/drift-operations.md +4 -4
- package/skills/session-end/metrics-collection.md +13 -0
- package/skills/session-end/phase-3-2-docs-verification.md +1 -1
- package/skills/session-end/phase-3-6-tail.md +2 -1
- package/skills/session-end/plan-verification.md +5 -2
- package/skills/session-end/vault-operations.md +1 -1
- package/skills/session-end/verification-checklist.md +1 -1
- package/skills/session-plan/SKILL.md +6 -2
- package/skills/session-plan/wave-template.md +2 -0
- package/skills/session-start/SKILL.md +73 -7
- package/skills/session-start/phase-4-5-resource-health.md +15 -2
- package/skills/test-runner/SKILL.md +2 -2
- package/skills/vault-sync/validator.mjs +108 -7
- package/skills/wave-executor/SKILL.md +5 -2
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/wave-loop.md +163 -10
- package/templates/_shared/loop.md +4 -4
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Session Orchestrator
|
|
2
2
|
|
|
3
3
|
[](LICENSE)
|
|
4
|
-
[](CHANGELOG.md)
|
|
5
5
|
[](https://www.npmjs.com/package/session-orchestrator)
|
|
6
|
-
[](docs/telemetry/telemetry-claims.md)
|
|
7
7
|
|
|
8
8
|
Loop engineering for AI coding agents — turn ad-hoc sessions into a repeatable research → plan → wave-execute → close loop with verification gates. Runs on **Claude Code, Codex CLI, Cursor, and [Pi](docs/pi-setup.md)**.
|
|
9
9
|
|
|
@@ -127,16 +127,17 @@ The system is markdown-driven config plus a thin Node runtime — skills, comman
|
|
|
127
127
|
- **Cross-session learning is opt-in and inspectable.** Every session writes a record; after 5+ sessions `/evolve analyze` extracts confidence-scored patterns you can read and prune. Nothing is hidden.
|
|
128
128
|
- **VCS dual support, no lock-in.** Auto-detects GitLab or GitHub from your remote and drives the full lifecycle for both.
|
|
129
129
|
|
|
130
|
-
## Recent highlights (v3.
|
|
130
|
+
## Recent highlights (v3.19.0)
|
|
131
131
|
|
|
132
|
-
Every release is additive and backward-compatible. Highlights of the v3.
|
|
132
|
+
Every release is additive and backward-compatible. Highlights of the v3.19.0 line:
|
|
133
133
|
|
|
134
|
-
- **
|
|
135
|
-
- **
|
|
136
|
-
- **
|
|
137
|
-
- **
|
|
134
|
+
- **Destructive-command guard, hardened in depth** — wrapper unwrapping (`sudo`/`doas`/`env`/`nohup`/`timeout`/`nice`/`stdbuf`, with depth-capped `-c` payload recursion) closes six measured bypasses (#982); the blocked-commands policy becomes a floor ∪ overlay model that can only escalate, never weaken (#972); shell redirects gain a target denylist — an `&>` redirect into a protected instruction file was a silent allow-with-truncation before (#983); and the denylist now resolves absolute paths, not just repo-relative ones.
|
|
135
|
+
- **Session identity with proof** — the session lock persists an owner proof at genesis, so an ending session can no longer release a living foreign lock, and the abandoned-session backfiller no longer deletes the very alarm it exists to raise (#987, #926, #914).
|
|
136
|
+
- **Supply chain** — two high-severity transitive vulnerabilities that `npm audit fix` could not reach are closed via package overrides.
|
|
137
|
+
- **Release as one dispatch** — `scripts/release.mjs` (#978, local half): a single surfaces table drives version rewrite and preflight (12 version literals across 10 files, CHANGELOG gate, tag/registry collision, drift sweep over all tracked files, CI-green-on-HEAD, leakage gate), and the git tag is created only AFTER a verified npm publish. Found two real gaps on its first run: v3.18.0 had been tagged but never published to npm, and the hidden `.codex-plugin` manifest was invisible to a plain ripgrep census.
|
|
138
|
+
- **session-orchestrator.com redesigned** — terminal hero, wave pipeline, leaderboard shell.
|
|
138
139
|
|
|
139
|
-
Previous line (v3.
|
|
140
|
+
Previous line (v3.18.0): panel-follow-ups and consolidation — bash-write-verify self-silencing vectors closed (#938), credential stripping at the source (#907), instruction-corpus diet 471→~440 directives, mutation-sweep-backed test consolidation.
|
|
140
141
|
|
|
141
142
|
Full version history: [CHANGELOG.md](CHANGELOG.md).
|
|
142
143
|
|
|
@@ -196,6 +197,8 @@ npm run typecheck # node --check on every .mjs file
|
|
|
196
197
|
|
|
197
198
|
`.npmrc` ships with `ignore-scripts=true` (supply-chain defence), so Husky git hooks don't auto-wire on install — run `npx husky` once after cloning. `git commit` then runs gitleaks → owner-privacy scan → lint-staged → commitlint. CI re-runs everything, plus more.
|
|
198
199
|
|
|
200
|
+
Two directories share the name *rules* and play opposite roles: [`rules/`](rules/README.md) is the **deliverable rule library** shipped *out* to consumer repos via `/bootstrap --sync-rules`, while [`.claude/rules/`](.claude/rules/) is this repo's own always-on rule set.
|
|
201
|
+
|
|
199
202
|
Contributor docs: [Plugin Architecture (v3)](docs/plugin-architecture-v3.md) · [CONTRIBUTING.md](CONTRIBUTING.md) · [agent authoring spec](agents/AGENTS.md).
|
|
200
203
|
|
|
201
204
|
## Support & scope
|
package/SECURITY.md
CHANGED
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
| Version | Supported |
|
|
6
6
|
|---------|-----------|
|
|
7
|
-
|
|
|
8
|
-
|
|
|
7
|
+
| 3.x | Yes |
|
|
8
|
+
| 2.x and earlier | No |
|
|
9
|
+
|
|
10
|
+
Only the latest 3.x minor receives fixes. See [CHANGELOG.md](CHANGELOG.md) for the
|
|
11
|
+
current release.
|
|
9
12
|
|
|
10
13
|
## Reporting a Vulnerability
|
|
11
14
|
|
|
@@ -23,15 +26,41 @@ Please include:
|
|
|
23
26
|
|
|
24
27
|
## Scope
|
|
25
28
|
|
|
26
|
-
Session Orchestrator is a
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
Session Orchestrator is a plugin for AI coding agents (Claude Code, Codex CLI,
|
|
30
|
+
Cursor, Pi), composed of Markdown instructions plus a Node ESM runtime under
|
|
31
|
+
`scripts/` and `hooks/`. It requires Node 24+.
|
|
32
|
+
|
|
33
|
+
What it **does** touch:
|
|
34
|
+
|
|
35
|
+
- **Local filesystem** — reads/writes repo files, `.orchestrator/` runtime state,
|
|
36
|
+
and (when vault integration is enabled) a host-local vault directory under `$HOME`.
|
|
37
|
+
- **Your VCS CLI** — spawns `glab` / `gh` using your existing authentication.
|
|
38
|
+
- **Credentials via environment** — reads `GITLAB_TOKEN` (baseline fetch),
|
|
39
|
+
`CLANK_EVENT_SECRET` (event-bus bearer token), and `NPM_TOKEN` from a gitignored
|
|
40
|
+
`.env.local` (publish flow only). It never persists them; `CLANK_EVENT_SECRET` is
|
|
41
|
+
transmitted as a bearer token when the event bus is configured. See
|
|
42
|
+
[.env.example](.env.example).
|
|
43
|
+
- **Outbound network, all opt-in and off by default** — event-bus webhook POSTs
|
|
44
|
+
(only when `CLANK_EVENT_URL` *and* `CLANK_EVENT_SECRET` are set), GitLab API
|
|
45
|
+
baseline fetches (only with `GITLAB_TOKEN`), and anonymous usage telemetry
|
|
46
|
+
(strictly opt-in, one-time consent, whitelist-projected — see
|
|
47
|
+
[docs/telemetry.md](docs/telemetry.md)).
|
|
48
|
+
- **An optional self-hosted ingest server** — `server/ingest/` is a small HTTP
|
|
49
|
+
service (with `Dockerfile`, rate limiting, SQLite persistence, retention) that an
|
|
50
|
+
operator may deploy to *receive* telemetry. It is not run by the plugin and is not
|
|
51
|
+
required to use it.
|
|
52
|
+
|
|
53
|
+
What it does **not** do:
|
|
29
54
|
- Execute user-provided code directly
|
|
55
|
+
- Store or forward credentials to any third party
|
|
56
|
+
- Send anything over the network without an explicit opt-in
|
|
30
57
|
|
|
31
58
|
Security concerns are most likely to involve:
|
|
32
|
-
- **Hook scripts** (`hooks
|
|
59
|
+
- **Hook scripts** (`hooks/*.mjs`) — command injection via crafted file paths or tool input
|
|
33
60
|
- **Skill instructions** — prompt injection that could bypass scope enforcement or safety constraints
|
|
34
61
|
- **Agent dispatch** — unintended tool access or scope escalation during wave execution
|
|
62
|
+
- **Session Config** — the `*-command` keys are executed via a shell; see
|
|
63
|
+
[Session Config Command Trust](#session-config-command-trust) below
|
|
35
64
|
|
|
36
65
|
## Disclosure
|
|
37
66
|
|
|
@@ -39,52 +68,186 @@ We follow [responsible disclosure](https://en.wikipedia.org/wiki/Responsible_dis
|
|
|
39
68
|
|
|
40
69
|
## Enforcement Architecture
|
|
41
70
|
|
|
42
|
-
|
|
71
|
+
Enforcement is a set of `PreToolUse` / `PreToolUse`-adjacent hooks registered via
|
|
72
|
+
`hooks/hooks.json` (with per-platform variants for Codex, Cursor, and Pi). All are
|
|
73
|
+
Node ESM; the former Bash implementations were removed in the v3.0.0 native
|
|
74
|
+
migration (#137/#138).
|
|
75
|
+
|
|
76
|
+
### Wave-scoped enforcement
|
|
43
77
|
|
|
44
|
-
|
|
78
|
+
Both wave guards read a `wave-scope.json` that the wave-executor writes before
|
|
79
|
+
dispatching each wave. Its location is **platform-resolved** by
|
|
80
|
+
`scripts/lib/scope-gate.mjs` — `.claude/`, `.codex/`, `.cursor/`, or `.pi/` under
|
|
81
|
+
the project root, depending on the host agent.
|
|
45
82
|
|
|
46
|
-
|
|
83
|
+
**File scope (`hooks/enforce-scope.mjs`)** intercepts `Edit`, `Write`, and
|
|
84
|
+
`MultiEdit`. It resolves the target through `realpath` (symlink-bypass defense) and
|
|
85
|
+
matches the result against `allowedPaths` — prefix, glob, or exact literal. An
|
|
86
|
+
explicit *absolute* allowlist entry is honoured before the project-root containment
|
|
87
|
+
check (#792), so a deliberate out-of-repo grant is reachable; every other
|
|
88
|
+
out-of-repo path is denied.
|
|
47
89
|
|
|
48
|
-
|
|
90
|
+
**Command scope (`hooks/enforce-commands.mjs`)** intercepts `Bash` and matches the
|
|
91
|
+
command against `blockedCommands[]` using word-boundary matching (so `rm` does not
|
|
92
|
+
match `format`). When `blockedCommands` is empty or absent, a hardcoded fallback
|
|
93
|
+
list applies (`rm -rf`, `git push --force` / `-f`, `git reset --hard`,
|
|
94
|
+
`drop table`, `git checkout -- .`).
|
|
49
95
|
|
|
50
|
-
|
|
96
|
+
Both wave guards **fail closed**: any unhandled internal error emits a deny,
|
|
97
|
+
never a silent allow. (The session-level destructive-command guard makes the
|
|
98
|
+
opposite, documented choice — see
|
|
99
|
+
[Policy floor (blocked-commands)](#policy-floor-blocked-commands).)
|
|
51
100
|
|
|
52
101
|
### Enforcement levels
|
|
53
102
|
|
|
54
|
-
Both
|
|
103
|
+
Both wave guards read the `enforcement` field from `wave-scope.json`:
|
|
55
104
|
|
|
56
105
|
| Level | Behavior | Exit code |
|
|
57
106
|
|-------|----------|-----------|
|
|
58
|
-
| `strict` | Deny the operation
|
|
107
|
+
| `strict` | Deny the operation via `hookSpecificOutput.permissionDecision: deny` on stdout | 0 |
|
|
59
108
|
| `warn` | Allow the operation, emit stderr warning | 0 |
|
|
60
109
|
| `off` | Skip all checks | 0 |
|
|
61
110
|
|
|
62
|
-
**
|
|
111
|
+
A deny exits **0**, not 2 (#906). Per the Claude Code hook contract a hook signals
|
|
112
|
+
either by exit code alone or by exit 0 plus structured JSON — never both; under
|
|
113
|
+
`exit 2` stdout JSON is discarded, which previously swallowed every deny reason.
|
|
114
|
+
The emitter is `scripts/lib/io.mjs#emitDeny`; see its JSDoc for the full payload.
|
|
63
115
|
|
|
64
|
-
|
|
116
|
+
**Default is `strict`** (fail-closed) when the `enforcement` field is missing.
|
|
117
|
+
|
|
118
|
+
### Policy floor (blocked-commands)
|
|
119
|
+
|
|
120
|
+
Since #972 the destructive-command guard (`pre-bash-destructive-guard.mjs`) no
|
|
121
|
+
longer reads a single policy file first-hit-wins — it merges two policy roles
|
|
122
|
+
via `scripts/lib/blocked-commands-policy.mjs` (`loadEffectivePolicy`):
|
|
123
|
+
|
|
124
|
+
| Role | Source | Semantics |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| **Floor** | `$CLAUDE_PLUGIN_ROOT/.orchestrator/policy/blocked-commands.json` | The plugin's own blocklist — immutable baseline. |
|
|
127
|
+
| **Overlay** | First existing of `<cwd>`, `$CLAUDE_PROJECT_DIR` (`.orchestrator/policy/blocked-commands.json`) | The consumer repo's policy — strictly additive. |
|
|
128
|
+
|
|
129
|
+
Roles are resolved purely by path — there is no marker field in the file.
|
|
130
|
+
Precedence: `cwd` → `CLAUDE_PROJECT_DIR` for the overlay; the plugin root
|
|
131
|
+
always supplies the floor. When both roles resolve to the same file (e.g.
|
|
132
|
+
inside the plugin repo itself), that one file *is* the policy.
|
|
65
133
|
|
|
66
|
-
|
|
134
|
+
**Merge contract** — union by rule `id`, floor rules first, escalate-only:
|
|
67
135
|
|
|
68
|
-
-
|
|
69
|
-
-
|
|
136
|
+
- An overlay-only `id` is appended (additive).
|
|
137
|
+
- On an `id` collision with a floor rule of severity `block`, the **whole floor
|
|
138
|
+
rule wins** — no field merge (an overlay-supplied `pattern` or
|
|
139
|
+
`path-allowlist` would be a bypass); the overlay definition is dropped with a
|
|
140
|
+
stderr warning.
|
|
141
|
+
- A floor rule of severity `warn` escalates monotonically:
|
|
142
|
+
`max(floor, overlay)` with `warn < block`; unknown overlay severity → floor
|
|
143
|
+
kept + warning.
|
|
144
|
+
|
|
145
|
+
**Failure semantics** — the authoritative contract for this hook. Unlike the
|
|
146
|
+
wave guards above, it is deliberately *not* fail-closed on internal error:
|
|
147
|
+
|
|
148
|
+
| Condition | Effective policy |
|
|
149
|
+
|---|---|
|
|
150
|
+
| Overlay malformed / missing `.rules` / empty `rules: []` | **Fail-to-floor**: floor alone + stderr warning (an empty overlay cannot disarm the floor) |
|
|
151
|
+
| Floor unresolvable (no plugin root, or file missing) | Overlay alone + warning |
|
|
152
|
+
| Both missing | Fail-open (guard skipped) + warning — unchanged pre-#972 behavior |
|
|
153
|
+
| Internal error in the hook | `exit 0` fail-open — a documented decision; the merge module's functions are total (never throw) precisely so policy input can never reach this path |
|
|
154
|
+
|
|
155
|
+
**Trust note:** whoever controls `CLAUDE_PLUGIN_ROOT` controls the floor. That
|
|
156
|
+
is harness trust — the same party already controls the hook code itself — not a
|
|
157
|
+
new attack surface.
|
|
158
|
+
|
|
159
|
+
### Dynamic per-wave scoping
|
|
160
|
+
|
|
161
|
+
Scope constraints change between waves:
|
|
162
|
+
|
|
163
|
+
- **Discovery waves** use empty `allowedPaths` (deny-all writes) combined with
|
|
164
|
+
explicit read-only agent instructions (dual enforcement — hook-level + prompt-level).
|
|
165
|
+
- **Quality waves** use two-phase scope: production file patterns for simplification
|
|
166
|
+
passes, then test-only patterns (`**/*.test.*`, `**/*.spec.*`) for test/review passes.
|
|
167
|
+
|
|
168
|
+
### Session-level guards (active outside waves)
|
|
169
|
+
|
|
170
|
+
| Hook | Protects against |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `pre-bash-destructive-guard.mjs` | Destructive shell commands in the **main** session, per the effective `blocked-commands.json` policy — at least the 14 floor rules from the plugin's policy, plus any additive overlay rules from the repo's policy (`block` or `warn` severity, each citing its source rule; see [Policy floor (blocked-commands)](#policy-floor-blocked-commands)). Bypass requires `allow-destructive-ops: true` in Session Config. |
|
|
173
|
+
| `config-protection.mjs` | Edits that *loosen* a quality gate — lowered thresholds, added `eslint-disable`/`@ts-ignore`, rules flipped to `off`, widened `.gitleaks.toml` allowlists, relaxed tsconfig strictness. Warn-by-default, fail-open on internal error. |
|
|
174
|
+
| `pre-bash-staging-fence.mjs` + `wave-scope-commit-guard.mjs` | Concurrent `git add` races between parallel wave-agents, and lint-staged sweeps that re-stage files outside wave scope. Rejects the commit rather than the edit. |
|
|
175
|
+
|
|
176
|
+
The behavioural rules these guards mechanise are documented in
|
|
177
|
+
[`.claude/rules/parallel-sessions.md`](.claude/rules/parallel-sessions.md) (PSA-003,
|
|
178
|
+
PSA-004, PSA-007).
|
|
179
|
+
|
|
180
|
+
## Supply Chain
|
|
181
|
+
|
|
182
|
+
- `.npmrc` sets `ignore-scripts=true` — no dependency may run install/postinstall
|
|
183
|
+
scripts. This is the primary defense against postinstall-style attacks (SEC-020).
|
|
184
|
+
- CI enforces `npm audit --omit=dev --audit-level=high`.
|
|
185
|
+
- **gitleaks** (37 rules) and an **owner-leakage scanner**
|
|
186
|
+
(`scripts/lib/validate/check-owner-leakage.mjs`) both run in CI and as `.husky/`
|
|
187
|
+
pre-commit stages, so a secret or private-path leak is normally blocked before it
|
|
188
|
+
reaches a public branch. Note the asymmetry: the owner-leakage stage is
|
|
189
|
+
unconditional, whereas the local gitleaks stage is **skipped silently when gitleaks
|
|
190
|
+
is not installed** — CI remains the backstop for that one, and `--no-verify`
|
|
191
|
+
bypasses both.
|
|
192
|
+
- This repo is **npm-canonical**: `package-lock.json` is the committed lockfile and
|
|
193
|
+
`scripts/check-package-manager.mjs` guards against a foreign lockfile appearing.
|
|
194
|
+
|
|
195
|
+
## Session Config Command Trust
|
|
196
|
+
|
|
197
|
+
The Session Config keys `test-command`, `typecheck-command`, `lint-command`, and
|
|
198
|
+
`custom-phases[].command` are executed via a shell. A malicious commit to
|
|
199
|
+
`CLAUDE.md` could therefore inject commands — which is **RCE-equivalent within the
|
|
200
|
+
repo's existing trust model**, not a new attack surface: anyone able to commit can
|
|
201
|
+
already achieve the same through `package.json` scripts, `.husky/` hooks, or a test
|
|
202
|
+
file.
|
|
203
|
+
|
|
204
|
+
The mitigation is review, not sandboxing: treat Session Config like code. Any diff
|
|
205
|
+
touching a command-bearing key must show before/after. `custom-phases` additionally
|
|
206
|
+
rejects shell metacharacters as defense-in-depth. Full trust model in
|
|
207
|
+
[`.claude/rules/security.md`](.claude/rules/security.md).
|
|
70
208
|
|
|
71
209
|
## Prerequisites
|
|
72
210
|
|
|
73
|
-
-
|
|
74
|
-
|
|
211
|
+
- **Node.js 24+.** v3.x is Node ESM throughout; there is no Bash runtime dependency
|
|
212
|
+
for the hooks (`jq` is used only by a few `scripts/` validators, never by
|
|
213
|
+
`hooks/*.mjs`).
|
|
214
|
+
- Hooks run inside the host agent's harness as tool-use interceptors, not as
|
|
215
|
+
standalone scripts.
|
|
75
216
|
|
|
76
217
|
## Known Limitations
|
|
77
218
|
|
|
78
|
-
1. **No enforcement outside active waves** — when no `wave-scope.json` exists
|
|
219
|
+
1. **No wave enforcement outside active waves** — when no `wave-scope.json` exists
|
|
220
|
+
(between sessions, before the first wave, after cleanup), the two wave guards exit 0.
|
|
221
|
+
The session-level guards in the table above remain active.
|
|
222
|
+
|
|
223
|
+
2. **Prompt injection via VCS content** — issue titles and descriptions fetched via
|
|
224
|
+
`glab`/`gh` are consumed in agent prompts without sanitization. A malicious issue
|
|
225
|
+
body could inject instructions into an agent's context. Mitigated by: issues are
|
|
226
|
+
typically user-created in controlled workflows, and wave scope enforcement limits
|
|
227
|
+
the blast radius of any injected instructions.
|
|
79
228
|
|
|
80
|
-
|
|
229
|
+
3. **Plugin relies on the host harness** — tool-level enforcement is provided by the
|
|
230
|
+
agent's hook system. The plugin cannot enforce restrictions if hooks are bypassed
|
|
231
|
+
at the harness level (`disableAllHooks`, `--no-verify`, etc.).
|
|
81
232
|
|
|
82
|
-
|
|
233
|
+
4. **Session Config values are only partially validated** — `health-endpoints`,
|
|
234
|
+
`plan-baseline-path`, and `cross-repos` accept arbitrary strings. Do not embed
|
|
235
|
+
credentials in these fields (see Credential Safety below).
|
|
83
236
|
|
|
84
|
-
|
|
237
|
+
5. **Guards are heuristics, not proofs** — `config-protection.mjs` is a
|
|
238
|
+
low-false-positive line/regex heuristic, not an exhaustive AST gate, and fails
|
|
239
|
+
open by design so a guard bug never blocks legitimate work.
|
|
85
240
|
|
|
86
241
|
## Credential Safety
|
|
87
242
|
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
-
|
|
243
|
+
- Secrets are read from the environment or a gitignored `.env.local`, never written
|
|
244
|
+
into repo files by the plugin.
|
|
245
|
+
- VCS CLI tools (`glab`, `gh`) use your existing authentication; their credential
|
|
246
|
+
security is your responsibility.
|
|
247
|
+
- **Do not embed API keys, passwords, or auth tokens** in Session Config fields
|
|
248
|
+
(especially `health-endpoints` URLs). Session Config lives in `CLAUDE.md`, which is
|
|
249
|
+
normally committed.
|
|
250
|
+
- **Do not paste tokens into permission allowlists** in `.claude/settings.json` or
|
|
251
|
+
`.claude/settings.local.json` (SEC-021). `settings.local.json` is conventionally
|
|
252
|
+
untracked, so the pre-commit leakage scanner — which enumerates tracked files —
|
|
253
|
+
structurally cannot see a token pasted there.
|
package/agents/AGENTS.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agents-authoring-spec
|
|
3
|
+
description: NOT A DISPATCHABLE AGENT — never select this. It is the authoring specification that the agent definitions in this directory must follow, loaded as a nested instruction file. Claude Code's plugin loader registers every agents/*.md as an agent by directory convention, and the manifest's `agents` key is additive-only, so it cannot exclude a path. Without this frontmatter the file registered as an unnamed agent with FULL tool access; the minimal `tools` line below is what bounds that. If you need agent-authoring rules, read this file — do not dispatch it.
|
|
4
|
+
tools: Read
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# `agents/` — Sub-Agent Authoring Conventions
|
|
2
8
|
|
|
3
9
|
> Nested instruction file for the `agents/` subtree. Claude Code / Cursor IDE
|
|
@@ -9,7 +15,18 @@
|
|
|
9
15
|
> This is **not** an agent definition — it is the authoring spec the agent
|
|
10
16
|
> `*.md` definitions in this directory must follow. The plugin validator
|
|
11
17
|
> (`scripts/lib/validate/check-agents.mjs`) excludes `AGENTS.md` / `CLAUDE.md`
|
|
12
|
-
> from agent-frontmatter validation by name
|
|
18
|
+
> from agent-frontmatter validation by name, and `measureDescriptionSurface`
|
|
19
|
+
> excludes them from its walked corpus (#878).
|
|
20
|
+
>
|
|
21
|
+
> **Claude Code's plugin loader makes no such exception.** It registers every
|
|
22
|
+
> `agents/*.md` as a dispatchable agent by directory convention, and the
|
|
23
|
+
> manifest's `agents` key is documented as *additive* ("in addition to those in
|
|
24
|
+
> the `agents/` directory"), so it cannot exclude a path. With no frontmatter
|
|
25
|
+
> this file therefore registered as an agent named `AGENTS` with **full tool
|
|
26
|
+
> access**. The frontmatter above is the containment: it names the file for what
|
|
27
|
+
> it is, states in the `description` that it must never be dispatched, and caps
|
|
28
|
+
> `tools` at `Read`. Do not remove it — and if you add another non-agent doc to
|
|
29
|
+
> this directory, give it the same treatment.
|
|
13
30
|
>
|
|
14
31
|
> Sibling spec: for `.claude/rules/*.md` frontmatter (conditional loading via
|
|
15
32
|
> globs/mode/host-class/expiry, plus the never-always-on invariant for
|
|
@@ -63,8 +80,8 @@ tools: Read, Grep, Glob, Bash # comma-separated string OR JSON array (bo
|
|
|
63
80
|
`model:` is not just a compatibility field — it is a cost/quality dial per agent. Pick deliberately, don't default to `sonnet` everywhere.
|
|
64
81
|
|
|
65
82
|
- **`haiku`** — cheap, fast, advisory/judge roles where the task is narrow classification or a single yes/no verdict, not open-ended reasoning. Precedent: `dialectic-deriver`, `skill-applied-judge`. Pin `haiku` when the agent's whole job is "read a short input, emit a structured verdict."
|
|
66
|
-
- **`sonnet`** —
|
|
67
|
-
- **`inherit`** —
|
|
83
|
+
- **`sonnet`** — an explicit cost cap, NOT a default. Pin it only when an agent must stay on the workhorse tier even in an Opus session, and state the reason inline. A bare `sonnet` on a working agent silently overrides the operator's session model — the failure mode that moved the implementation and review catalog to `inherit`.
|
|
84
|
+
- **`inherit`** — **the default for the working catalog.** Lets the coordinator/session's active model tier flow through, so the agent runs at whatever tier the operator picked (an Opus session gives its implementers AND its reviewers Opus-quality judgment). Use it for implementation, test-writing, and review agents alike — `code-implementer`, `test-writer`, `security-reviewer`, `session-reviewer`, `db-specialist`, `ui-developer`, and the read-only analysis agents. Diverge only for a named cost/quality reason.
|
|
68
85
|
- **`opus`** — reserve for agents whose task genuinely needs the strongest available reasoning (e.g. `ux-evaluator`) and where the cost is justified because the agent runs rarely (dispatched solo, not fanned out across a wave).
|
|
69
86
|
- **Full model-ID pinning** (`claude-opus-4-7`, `claude-sonnet-5`, `claude-fable-5-20260101`, …) — only when the agent has a demonstrated dependency on a SPECIFIC model version, e.g. a reproducibility requirement that needs a dated snapshot, or a known behavioral regression on newer models for this agent's exact prompt. Pinning trades away automatic model-family upgrades — document the reason inline as a frontmatter comment when you do this.
|
|
70
87
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: code-implementer
|
|
3
3
|
description: Use this agent for feature implementation, API development, refactoring, and general code changes. Handles backend logic, API routes, service layers, and cross-cutting concerns. <example>Context: Wave plan assigns a new API endpoint implementation. user: "Implement CRUD API for invoices" assistant: "I'll dispatch the code-implementer agent to build the invoice API endpoints." <commentary>Feature implementation with multiple files is the code-implementer's core strength.</commentary></example> <example>Context: Refactoring task in an implementation wave. user: "Extract shared validation logic into a utility module" assistant: "I'll use the code-implementer to extract and refactor the validation logic." <commentary>Cross-file refactoring requires systematic reading, extraction, and verification.</commentary></example>
|
|
4
|
-
model:
|
|
4
|
+
model: inherit
|
|
5
5
|
color: green
|
|
6
6
|
tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
|
|
7
7
|
sandbox-tier: repo-write
|
|
@@ -24,17 +24,17 @@ You are a focused implementation agent. You write production code, refactor exis
|
|
|
24
24
|
2. **Confirm scope**: The wave plan task definition is your contract. If the task is ambiguous (e.g., "add validation" without specifying where), pause and report rather than guess.
|
|
25
25
|
3. **Match conventions**: Match existing style for naming (camelCase vs snake_case), error patterns (typed errors vs result objects), and module structure (default vs named exports).
|
|
26
26
|
4. **Implement minimally**: Touch only files in the assigned file scope. Do not refactor adjacent code that "could be cleaner" — that is out of scope unless the task explicitly says so.
|
|
27
|
-
5. **Run a fast feedback loop**: After substantive edits, run the project's typecheck (`tsgo --noEmit`, `tsc --noEmit`, or the configured command) to catch type errors early. Do not run the full test suite — that is the Quality wave's responsibility.
|
|
27
|
+
5. **Run a fast feedback loop**: After substantive edits, run the project's typecheck (`tsgo --noEmit`, `tsc --noEmit`, or the configured command) to catch type errors early. Do not run the full test suite as a routine loop — that is the Quality wave's responsibility. You MAY still run the typecheck/lint command or targeted tests to gather evidence for a `Status: done` claim (Verification gate below) — the bar is on the *routine full-suite run*, not on verifying your own scope.
|
|
28
28
|
6. **Self-review the diff**: Before reporting completion, mentally walk the diff and verify each change serves the task. Delete dead branches, debug logging, and TODO stubs.
|
|
29
29
|
7. **Report**: Output a structured summary (see Output Format).
|
|
30
|
-
- **Bite-sized plan**: If a bite-sized executable plan path is provided in your prompt (`docs/plans/<feature>.md`, see `skills/write-executable-plan/SKILL.md`),
|
|
30
|
+
- **Bite-sized plan**: If a bite-sized executable plan path is provided in your prompt (`docs/plans/<feature>.md`, see `skills/write-executable-plan/SKILL.md`), you own the **implement** and **verify-pass** steps of each Task's 5-step structure: write the production code, then run the Task's exact verification command. The **test-first** and **confirm-fail** steps belong to the test-writer and the **commit-stop** step to the coordinator — in this bite-sized structure the test is authored ahead of you, and you never run git-write operations (see Rules below), so do not attempt those three steps yourself. (Outside a bite-sized plan, a need-gated regression test for a bug you fix IS yours — see Rules.)
|
|
31
31
|
- **Bugfix prerequisite**: For bugfix-classified tasks: reference an existing `.orchestrator/debug/<session>-<n>.md` Phase-1 artifact (per `skills/debug/SKILL.md` Iron Law). If no artifact exists, invoke `/debug` first.
|
|
32
32
|
|
|
33
33
|
## Rules
|
|
34
34
|
|
|
35
|
-
- Do NOT write
|
|
36
|
-
- Do NOT modify test files
|
|
37
|
-
- Do NOT add documentation
|
|
35
|
+
- Tests are **need-gated, not banned**: when you fix a bug, author exactly ONE test that names the bug and fails without your fix (the fake-regression proof the wave-executor's per-agent testing expectation requires — `skills/wave-executor/SKILL.md` § Agent Prompt Best Practices, point 5). Do NOT write speculative test volume, and do NOT own test consolidation or coverage sweeps — those belong to the **test-writer**. (In a bite-sized plan's 5-step structure, the `test-first`/`confirm-fail` steps are the test-writer's — see Bite-sized plan above.)
|
|
36
|
+
- Do NOT modify test files beyond the one need-gated test your task's bug requires.
|
|
37
|
+
- Do NOT add standalone or narrative documentation (README, CLAUDE.md, guides), and never write docs for code that does not exist yet — those surfaces are owned by docs-writer. Inline code-surface docs ARE yours: comments where logic is non-obvious, plus JSDoc/TSDoc on public functions you author (per `.claude/rules/development.md` § Documentation).
|
|
38
38
|
- Do NOT introduce new runtime dependencies without explicit instruction. If a new dependency seems necessary, pause and report rather than installing.
|
|
39
39
|
- Do NOT run ANY git write operation (`git add`, `git commit`, `git stash`, `git mv`, `git rm`, `git push`, `git reset`) — the git index and stash are shared session resources (PSA-007); the coordinator handles ALL VCS operations.
|
|
40
40
|
- Do NOT touch unrelated files in the same directory just because they share a folder.
|
package/agents/db-specialist.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: db-specialist
|
|
3
3
|
description: Use this agent for database work — schema design, migrations, queries, indexes, and database functions. Handles SQL, ORMs, and database architecture decisions. <example>Context: New feature requires database schema changes. user: "Create the migration for the invoice tables with proper indexes" assistant: "I'll dispatch the db-specialist agent to design the schema and create the migration." <commentary>Schema design requires understanding normalization, indexing, and the existing data model.</commentary></example> <example>Context: Performance issue with database queries. user: "Optimize the slow invoice listing query" assistant: "I'll use the db-specialist to analyze and optimize the query with proper indexing." <commentary>Query optimization requires understanding execution plans, indexes, and data access patterns.</commentary></example>
|
|
4
|
-
model:
|
|
4
|
+
model: inherit
|
|
5
5
|
color: purple
|
|
6
6
|
tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
|
|
7
7
|
sandbox-tier: repo-write
|
package/agents/qa-strategist.md
CHANGED
|
@@ -10,10 +10,14 @@ output-schema: schemas/qa-strategist.schema.json
|
|
|
10
10
|
|
|
11
11
|
# QA Strategist Agent
|
|
12
12
|
|
|
13
|
-
You are a senior QA engineer conducting a read-only test-
|
|
13
|
+
You are a senior QA engineer conducting a read-only test-suite analysis between waves. You identify **both** failure modes of a suite: what is NOT tested (boundary conditions, error paths, integration contracts, silent failures) **and what is OVER-tested** (redundant, tautological, prose-pinning, and framework-verifying tests). You do NOT write tests or fix code. You produce a prioritised report.
|
|
14
|
+
|
|
15
|
+
Under-testing and over-testing are symmetric defects, not one real problem and one nitpick. A suite of 400 tests where 120 assert nothing costs real CI minutes, blocks refactors it should permit, and manufactures false confidence — that is a genuine finding, and the correct recommendation is deletion or consolidation, never "add more tests". Report a suite that needs shrinking as clearly as one that needs growing.
|
|
14
16
|
|
|
15
17
|
## Core Responsibilities
|
|
16
18
|
|
|
19
|
+
### A. Under-testing (gaps)
|
|
20
|
+
|
|
17
21
|
1. **Happy-path-only suites**: Identify test files that only test the success path and lack any negative or edge-case coverage
|
|
18
22
|
2. **Boundary conditions**: Flag missing tests for limit values (empty inputs, max-length strings, zero, negative numbers, null/undefined)
|
|
19
23
|
3. **Error-path coverage**: Detect unhandled or silently-swallowed errors (catch blocks with no assertion, error callbacks never invoked in tests)
|
|
@@ -21,6 +25,13 @@ You are a senior QA engineer conducting a read-only test-coverage gap analysis b
|
|
|
21
25
|
5. **Integration gaps**: Identify points where unit tests exist but no integration or contract test verifies the full call chain
|
|
22
26
|
6. **Flaky-prone patterns**: Flag time-dependent tests, tests that rely on ordering, or tests with hardcoded dates/ports
|
|
23
27
|
|
|
28
|
+
### B. Over-testing (redundancy)
|
|
29
|
+
|
|
30
|
+
7. **Duplicate tests**: Two or more tests that exercise the same branch with equivalent inputs — deleting all but one loses no catch-power. Count in `redundancy_counts.duplicate`.
|
|
31
|
+
8. **Worthless tests**: Tests that survive the falsification check trivially — they still pass when the function body is replaced with `throw new Error()`. Includes tautological computations (`expect(calcTax(p, r)).toBe(p * r)`), assert-nothing bodies, and overly-generous assertions (`toBeTruthy()` on an object). Count in `redundancy_counts.worthless`.
|
|
32
|
+
9. **Framework-only / prose-pinning tests**: Tests that verify the language, the framework, or the presence of a string in a document rather than this repo's behaviour — `expect(typeof fn).toBe('function')`, property-assignment round-trips, "the README contains heading X", enum-case counts. Count in `redundancy_counts.framework_only`.
|
|
33
|
+
10. **Test-to-source ratio**: Compute `test_to_src_ratio` = test LOC ÷ source LOC over the reviewed scope. It is a signal, not a verdict: a high ratio over logic-dense code is healthy; a high ratio driven by categories 7–9 is bloat. Always interpret it against those counts, never on its own.
|
|
34
|
+
|
|
24
35
|
## Workflow
|
|
25
36
|
|
|
26
37
|
1. **Read changed source files** from the wave scope. Understand what each module does: what inputs it accepts, what errors it can throw or return, what external calls it makes.
|
|
@@ -43,6 +54,8 @@ You are a senior QA engineer conducting a read-only test-coverage gap analysis b
|
|
|
43
54
|
- HIGH gaps: N
|
|
44
55
|
- MEDIUM gaps: N
|
|
45
56
|
- LOW gaps: N
|
|
57
|
+
- Redundant tests: N duplicate / N worthless / N framework-only
|
|
58
|
+
- Test-to-source ratio: N.N (test LOC ÷ source LOC over the reviewed scope)
|
|
46
59
|
|
|
47
60
|
## Coverage Gaps
|
|
48
61
|
|
|
@@ -53,15 +66,24 @@ You are a senior QA engineer conducting a read-only test-coverage gap analysis b
|
|
|
53
66
|
- **Missing scenario**: Describe the specific input/state/sequence not covered
|
|
54
67
|
- **Risk**: What breaks in production if this path is never exercised
|
|
55
68
|
|
|
69
|
+
## Redundancy Findings
|
|
70
|
+
|
|
71
|
+
### [HIGH|MEDIUM|LOW] <title>
|
|
72
|
+
- **Test file**: path/to/source.test.ts:line
|
|
73
|
+
- **Category**: duplicate | worthless | framework-only
|
|
74
|
+
- **Evidence**: Quote the assertion(s). For `worthless`, state the falsification result — "still passes when the body is replaced with `throw new Error()`".
|
|
75
|
+
- **Recommendation**: delete | merge into <test name> | parameterise <N> cases into one
|
|
76
|
+
- **Payoff**: What the suite gains — CI time, refactor freedom, removal of false confidence
|
|
77
|
+
|
|
56
78
|
## Well-covered areas
|
|
57
79
|
<list source files or functions with adequate test coverage>
|
|
58
80
|
```
|
|
59
81
|
|
|
60
82
|
## Severity Calibration
|
|
61
83
|
|
|
62
|
-
- **HIGH**: Untested error path that hides data corruption, auth bypass, or data loss; production silent failure
|
|
63
|
-
- **MEDIUM**: Missing boundary test for a public API; mocked integration with no assertion
|
|
64
|
-
- **LOW**: Missing a convenience edge case, cosmetic gap, or low-impact optional behaviour
|
|
84
|
+
- **HIGH**: Untested error path that hides data corruption, auth bypass, or data loss; production silent failure. On the redundancy side: a worthless test that is the ONLY test for a behaviour — it reads as covered but catches nothing, which is worse than a visible gap.
|
|
85
|
+
- **MEDIUM**: Missing boundary test for a public API; mocked integration with no assertion. On the redundancy side: a cluster of duplicates or framework-only tests large enough to slow CI or block a legitimate refactor.
|
|
86
|
+
- **LOW**: Missing a convenience edge case, cosmetic gap, or low-impact optional behaviour; one-off redundant test with negligible cost.
|
|
65
87
|
|
|
66
88
|
## Refusal Rule
|
|
67
89
|
|
|
@@ -76,18 +98,21 @@ After the human-readable gap report, append a fenced ```json block matching `age
|
|
|
76
98
|
"verdict": "PROCEED|PROCEED_WITH_FOLLOWUPS|FIX_REQUIRED|BLOCKED",
|
|
77
99
|
"report_path": ".orchestrator/audits/wave-reviewer-N-qa-strategist.md",
|
|
78
100
|
"gap_counts": {"high": 0, "med": 0, "low": 0},
|
|
101
|
+
"redundancy_counts": {"duplicate": 0, "worthless": 0, "framework_only": 0},
|
|
102
|
+
"test_to_src_ratio": 1.4,
|
|
79
103
|
"source_files_reviewed": 0,
|
|
80
104
|
"test_files_reviewed": 0,
|
|
81
105
|
"blockers": []
|
|
82
106
|
}
|
|
83
107
|
```
|
|
84
108
|
|
|
85
|
-
Required: `verdict` (enum PROCEED|PROCEED_WITH_FOLLOWUPS|FIX_REQUIRED|BLOCKED), `report_path`, `gap_counts`, `source_files_reviewed`, `test_files_reviewed`. Optional: `blockers`. The coordinator's `validateAgentOutput()` parses the LAST fenced ```json block; place it at the end of your response.
|
|
109
|
+
Required: `verdict` (enum PROCEED|PROCEED_WITH_FOLLOWUPS|FIX_REQUIRED|BLOCKED), `report_path`, `gap_counts`, `source_files_reviewed`, `test_files_reviewed`. Optional: `redundancy_counts`, `test_to_src_ratio`, `blockers`. Emit `redundancy_counts` and `test_to_src_ratio` on every run — omitting them reads as "no redundancy analysis performed", not as "zero redundancy found". The coordinator's `validateAgentOutput()` parses the LAST fenced ```json block; place it at the end of your response.
|
|
86
110
|
|
|
87
111
|
Verdict variants (concrete examples per scenario):
|
|
88
|
-
- Coverage strong, no gaps → `{"verdict": "PROCEED", "gap_counts": {"high": 0, "med": 0, "low": 0}}`
|
|
112
|
+
- Coverage strong, no gaps, no bloat → `{"verdict": "PROCEED", "gap_counts": {"high": 0, "med": 0, "low": 0}, "redundancy_counts": {"duplicate": 0, "worthless": 0, "framework_only": 0}}`
|
|
89
113
|
- Coverage adequate, advisory gaps only → `{"verdict": "PROCEED_WITH_FOLLOWUPS", "gap_counts": {"high": 0, "med": 3, "low": 4}}`
|
|
90
114
|
- HIGH-risk gap that would let real bug ship → `{"verdict": "FIX_REQUIRED", "gap_counts": {"high": 2, "med": 5, "low": 3}}`
|
|
115
|
+
- **Redundancy dominates — no gap, but the suite must SHRINK** → `{"verdict": "FIX_REQUIRED", "gap_counts": {"high": 0, "med": 1, "low": 2}, "redundancy_counts": {"duplicate": 14, "worthless": 9, "framework_only": 22}, "test_to_src_ratio": 3.8}`. The recommendation is consolidation, not writing: 9 worthless tests pass with the implementation deleted, 22 pin framework or prose behaviour, and 14 duplicate a sibling — the suite claims coverage it does not have. `FIX_REQUIRED` is correct here even with zero HIGH gaps, because the false confidence is itself the defect. Hand the test-writer a delete/merge list, never a "write more tests" instruction.
|
|
91
116
|
- Strategy review cannot complete → `{"verdict": "BLOCKED", "blockers": ["sources missing"]}`
|
|
92
117
|
|
|
93
118
|
## Edge Cases
|
|
@@ -27,6 +27,33 @@
|
|
|
27
27
|
"low": { "type": "integer", "minimum": 0 }
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
|
+
"redundancy_counts": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"description": "Over-testing findings — the symmetric counterpart to `gap_counts`. A high count here calls for consolidation/deletion, never for writing more tests.",
|
|
34
|
+
"properties": {
|
|
35
|
+
"duplicate": {
|
|
36
|
+
"type": "integer",
|
|
37
|
+
"minimum": 0,
|
|
38
|
+
"description": "Tests exercising the same branch with equivalent inputs; all but one can be deleted without losing catch-power."
|
|
39
|
+
},
|
|
40
|
+
"worthless": {
|
|
41
|
+
"type": "integer",
|
|
42
|
+
"minimum": 0,
|
|
43
|
+
"description": "Tests that still pass when the implementation body is replaced with `throw new Error()` — tautological computations, assert-nothing bodies, overly-generous assertions."
|
|
44
|
+
},
|
|
45
|
+
"framework_only": {
|
|
46
|
+
"type": "integer",
|
|
47
|
+
"minimum": 0,
|
|
48
|
+
"description": "Tests verifying the language, the framework, or the presence of a string in a document rather than this repo's behaviour."
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"test_to_src_ratio": {
|
|
53
|
+
"type": "number",
|
|
54
|
+
"minimum": 0,
|
|
55
|
+
"description": "Test LOC divided by source LOC over the reviewed scope. A signal, not a verdict — interpret only alongside `redundancy_counts`."
|
|
56
|
+
},
|
|
30
57
|
"source_files_reviewed": {
|
|
31
58
|
"type": "integer",
|
|
32
59
|
"minimum": 0,
|