session-orchestrator 3.16.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 +130 -412
- package/README.md +17 -12
- 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/README.md +2 -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 +7 -7
- package/docs/cursor-setup.md +22 -9
- package/docs/events-schema.md +5 -1
- package/docs/instruction-delivery.md +444 -0
- package/docs/pi-setup.md +1 -1
- package/docs/rule-authoring.md +58 -9
- package/docs/session-config-reference.md +306 -6
- package/docs/session-config-template.md +66 -3
- package/docs/telemetry/telemetry-claims.md +204 -0
- package/docs/telemetry.md +158 -0
- 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/skill-invocation-telemetry.mjs +109 -10
- package/hooks/subagent-telemetry.mjs +527 -37
- package/package.json +16 -3
- 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/compute-grounding-injection.sh +18 -3
- package/scripts/dialectic-deriver.mjs +7 -2
- package/scripts/eval-session.mjs +50 -9
- package/scripts/fleet-instruction-scan.mjs +141 -0
- package/scripts/lib/auto-dialectic.mjs +11 -2
- package/scripts/lib/auto-dream.mjs +16 -5
- 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/build-live-signals.mjs +7 -4
- 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/context-coverage.mjs +82 -0
- 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/moc-staleness.mjs +98 -0
- package/scripts/lib/config/reconcile.mjs +21 -0
- package/scripts/lib/config/section-extractor.mjs +121 -1
- package/scripts/lib/config/worktree-orphans.mjs +138 -0
- package/scripts/lib/config-schema.mjs +23 -3
- package/scripts/lib/config.mjs +32 -0
- package/scripts/lib/context-coverage-banner.mjs +223 -0
- package/scripts/lib/convergence-monitor.mjs +49 -3
- package/scripts/lib/description-surface.mjs +535 -0
- package/scripts/lib/dispatcher/enumerate.mjs +136 -30
- package/scripts/lib/dispatcher/rank.mjs +22 -8
- 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/evolve/autonomy-verdict.mjs +5 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +54 -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 +22 -5
- 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/moc-staleness-banner.mjs +267 -0
- 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-end/worktree-orphan-sweep.mjs +252 -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/filters.mjs +88 -0
- package/scripts/lib/session-schema/validator.mjs +16 -0
- package/scripts/lib/session-schema.mjs +1 -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/skill-health/join.mjs +35 -9
- 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/telemetry/anon-id.mjs +141 -0
- package/scripts/lib/telemetry/consent.mjs +299 -0
- package/scripts/lib/telemetry/paths.mjs +27 -0
- package/scripts/lib/telemetry/queue.mjs +287 -0
- package/scripts/lib/telemetry/schema.mjs +384 -0
- package/scripts/lib/telemetry/sync.mjs +312 -0
- 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/vault-status/board-writer.mjs +63 -5
- package/scripts/lib/vault-status/narrative-mirror.mjs +13 -7
- 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 +32 -6
- 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/telemetry.mjs +250 -0
- 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 +97 -0
- 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 +108 -14
- 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 +149 -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/SKILL.md +1 -1
- package/skills/vault-sync/package-lock.json +3 -3
- package/skills/vault-sync/validator.mjs +228 -40
- 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
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"properties": {
|
|
10
10
|
"status": {
|
|
11
11
|
"type": "string",
|
|
12
|
-
"enum": ["done", "partial", "blocked"],
|
|
12
|
+
"enum": ["done", "no-tests-needed", "partial", "blocked"],
|
|
13
13
|
"deprecated": true,
|
|
14
|
-
"description": "DEPRECATED (#472): emit `verdict` instead. Removed in v4.0. Mapping: done→PROCEED, partial→PROCEED_WITH_FOLLOWUPS, blocked→BLOCKED."
|
|
14
|
+
"description": "DEPRECATED (#472): emit `verdict` instead. Removed in v4.0. Mapping: done→PROCEED, partial→PROCEED_WITH_FOLLOWUPS, blocked→BLOCKED. `no-tests-needed` is a SUCCESS status (also →PROCEED): the scope was analysed and no test was worth adding; it requires a written justification and is neither `partial` nor `blocked`."
|
|
15
15
|
},
|
|
16
16
|
"verdict": {
|
|
17
17
|
"type": "string",
|
|
@@ -38,10 +38,68 @@
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
+
"test_delta": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"description": "Net effect on the test suite. Supersedes `coverage_delta` — removals and merges are first-class outcomes, not regressions. A negative `net_loc` alongside a green suite is a good result.",
|
|
45
|
+
"properties": {
|
|
46
|
+
"added": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"minimum": 0,
|
|
49
|
+
"description": "Tests added. Each one needs a matching `justifications[]` entry."
|
|
50
|
+
},
|
|
51
|
+
"removed": {
|
|
52
|
+
"type": "integer",
|
|
53
|
+
"minimum": 0,
|
|
54
|
+
"description": "Tests deleted because they failed the falsification check, duplicated a sibling, or only exercised framework/language/prose-presence behaviour. Each removal is justified individually in the prose report."
|
|
55
|
+
},
|
|
56
|
+
"consolidated": {
|
|
57
|
+
"type": "integer",
|
|
58
|
+
"minimum": 0,
|
|
59
|
+
"description": "Pre-existing tests folded into parameterised or merged cases (counted as the number of source tests absorbed)."
|
|
60
|
+
},
|
|
61
|
+
"net_loc": {
|
|
62
|
+
"type": "integer",
|
|
63
|
+
"description": "Signed line delta across all touched test files. MAY be negative."
|
|
64
|
+
},
|
|
65
|
+
"happy_path": { "type": "integer", "minimum": 0 },
|
|
66
|
+
"error_path": { "type": "integer", "minimum": 0 },
|
|
67
|
+
"boundary": { "type": "integer", "minimum": 0 },
|
|
68
|
+
"falsification_check": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"description": "Summary of falsification check results."
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"justifications": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"description": "One entry per ADDED test, naming the concrete bug it catches that no existing test catches. Required in substance whenever `test_delta.added > 0`; kept structurally optional for backward-compatibility with pre-#472 consumers. 'Improves coverage' is not a bug and is not an acceptable `bug_caught` value. Omit when `added` is 0.",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"additionalProperties": false,
|
|
80
|
+
"required": ["test", "bug_caught"],
|
|
81
|
+
"properties": {
|
|
82
|
+
"test": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"minLength": 1,
|
|
85
|
+
"description": "The test name as written in the suite."
|
|
86
|
+
},
|
|
87
|
+
"bug_caught": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"minLength": 1,
|
|
90
|
+
"description": "The specific bug this test catches that no existing test catches."
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
41
95
|
"coverage_delta": {
|
|
42
96
|
"type": "object",
|
|
43
97
|
"additionalProperties": false,
|
|
98
|
+
"deprecated": true,
|
|
99
|
+
"description": "DEPRECATED: emit `test_delta` instead. Retained as an alias so pre-existing consumers keep validating; counts only additions and therefore cannot express consolidation. Do not emit alongside `test_delta`.",
|
|
44
100
|
"properties": {
|
|
101
|
+
"added": { "type": "integer", "minimum": 0 },
|
|
102
|
+
"removed": { "type": "integer", "minimum": 0 },
|
|
45
103
|
"happy_path": { "type": "integer", "minimum": 0 },
|
|
46
104
|
"error_path": { "type": "integer", "minimum": 0 },
|
|
47
105
|
"boundary": { "type": "integer", "minimum": 0 },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: security-reviewer
|
|
3
3
|
description: Use this agent for security analysis — OWASP checks, authentication flows, input validation, authorization, and vulnerability assessment. Read-only analysis with actionable findings. Prioritizes high-confidence exploitable issues over theoretical ones. <example>Context: Quality wave includes security review of new endpoints. user: "Review the new API endpoints for security vulnerabilities" assistant: "I'll dispatch the security-reviewer agent to audit the new endpoints." <commentary>Security review after implementation catches auth gaps, injection risks, and missing validation.</commentary></example> <example>Context: Pre-deployment security check. user: "Run a security audit on the authentication changes" assistant: "I'll use the security-reviewer to verify the auth changes are secure." <commentary>Auth changes are high-risk — dedicated security review prevents vulnerabilities in production.</commentary></example>
|
|
4
|
-
model:
|
|
4
|
+
model: inherit
|
|
5
5
|
color: red
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
sandbox-tier: read-only
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-reviewer
|
|
3
3
|
description: Use this agent between waves or at session end to verify work quality against the session plan. Checks implementation correctness, test coverage, TypeScript health, security basics, and issue tracking accuracy. <example>Context: Impl-Core wave is complete, coordinator needs quality check before Impl-Polish. user: "Impl-Core wave done, review before continuing" assistant: "I'll dispatch the session-reviewer to verify Impl-Core outputs." <commentary>Inter-wave quality gate ensures issues are caught early, not at session end.</commentary></example> <example>Context: Session end, verifying all work before committing. user: "/close" assistant: "Running session-reviewer to verify all session work before committing." <commentary>Final quality gate before any code is committed.</commentary></example>
|
|
4
|
-
model:
|
|
4
|
+
model: inherit
|
|
5
5
|
color: pink
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
sandbox-tier: read-only
|
package/agents/test-writer.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-writer
|
|
3
|
-
description: Use this agent
|
|
4
|
-
model:
|
|
3
|
+
description: Use this agent to close NAMED test gaps and to consolidate redundant tests. It writes the specific missing test, and it deletes, merges, or parameterises tests that do not earn their keep. <example>Context: Quality wave named one concrete gap — the invoice service never exercises the declined-payment branch. user: "The invoice service has no test for a declined payment" assistant: "I'll dispatch the test-writer to add that one error-path test and run the falsification check on it." <commentary>A named gap states a bug that would ship undetected; 'improve coverage' names nothing and is not a dispatchable task.</commentary></example> <example>Context: The auth test file has 14 tests — 6 assert the same validation branch and 3 only pin prose strings. user: "Clean up the auth test file" assistant: "I'll use the test-writer to merge the 6 duplicates into one parameterised test and delete the 3 prose-pinning tests — net test count falls 14 to 6 while catch-power rises, reported as test_delta.removed plus test_delta.consolidated." <commentary>Consolidation is a success outcome: fewer tests that each catch a distinct bug beat many that catch none, and a scope with no real gap legitimately ends with status no-tests-needed.</commentary></example>
|
|
4
|
+
model: inherit
|
|
5
5
|
color: orange
|
|
6
6
|
tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
|
|
7
7
|
sandbox-tier: repo-write
|
|
@@ -16,7 +16,8 @@ You are a focused testing agent. You write tests — unit, integration, and edge
|
|
|
16
16
|
2. **Integration Tests**: Test interactions between modules with realistic fixtures
|
|
17
17
|
3. **Edge Cases**: Cover boundary conditions, error paths, empty inputs, Unicode, and unusual values
|
|
18
18
|
4. **Test Quality**: Write behavioral tests (test what code does, not how it's structured); enforce assertion specificity
|
|
19
|
-
5. **
|
|
19
|
+
5. **Named Gaps**: Read existing tests, name each untested behaviour as a concrete bug that would ship, and close exactly those gaps
|
|
20
|
+
6. **Consolidation**: Delete, merge, and parameterise tests that fail the falsification check, duplicate a sibling, or only pin framework/language/prose behaviour
|
|
20
21
|
|
|
21
22
|
## Test Process
|
|
22
23
|
|
|
@@ -31,6 +32,10 @@ You are a focused testing agent. You write tests — unit, integration, and edge
|
|
|
31
32
|
## Rules
|
|
32
33
|
|
|
33
34
|
- Do NOT modify production code — only test files (`*.test.*`, `*.spec.*`, `__tests__/`, `tests/`).
|
|
35
|
+
- **You MAY delete, merge, and parameterise existing test files.** Removal is in scope — and expected — when (a) a test fails the falsification check, (b) two or more tests verify the same behaviour, or (c) a test only exercises framework, language, or prose-presence behaviour (`expect(typeof fn).toBe('function')`, a snapshot of a doc string, an assertion that a Markdown heading exists). Count every removal in `test_delta.removed` and justify each one individually in the report. **A deletion is a success, not a regression** — a suite that shrinks while its catch-power rises is the intended outcome.
|
|
36
|
+
- Do NOT delete a test merely because it fails or is inconvenient. Deletion requires one of the three named grounds above; a failing test that *would* catch a real bug is a bug report, not a deletion candidate.
|
|
37
|
+
- Do NOT write a test you cannot justify. Every added test needs a one-line answer to *"which concrete bug does this catch that no existing test catches?"* — recorded in `justifications[]`. If you cannot answer, do not write the test.
|
|
38
|
+
- If the scope genuinely has no gap worth a new test, report `no-tests-needed` with the reasoning. Writing filler tests to avoid an empty diff is the failure mode this status exists to prevent.
|
|
34
39
|
- Do NOT mock what you can test directly. Mock only external I/O (DB, HTTP, filesystem, time). Pure functions should never be mocked.
|
|
35
40
|
- Do NOT write trivial tests. `expect(typeof add).toBe('function')` does not test behavior.
|
|
36
41
|
- Do NOT add test utilities unless the same pattern appears 3+ times. Premature abstraction in tests obscures what's being tested.
|
|
@@ -80,20 +85,27 @@ Report back in this shape:
|
|
|
80
85
|
- src/services/invoice.test.ts — added 8 unit tests
|
|
81
86
|
- tests/integration/auth-flow.test.ts — added 3 integration tests
|
|
82
87
|
|
|
83
|
-
###
|
|
84
|
-
-
|
|
88
|
+
### Test delta
|
|
89
|
+
- Added: <N> (<N> happy-path + <N> error-path + <N> boundary) — net LOC <±N>
|
|
90
|
+
- Removed: <N> — each with its ground (falsification-fail | duplicate | framework-only)
|
|
91
|
+
- Consolidated: <N> tests merged into <N> parameterised cases
|
|
85
92
|
- Falsification-check: all pass (<N> tests verified would fail if logic removed)
|
|
86
93
|
|
|
94
|
+
### Justifications (one per added test)
|
|
95
|
+
- "<test name>" → catches: <the concrete bug this test catches that no existing test catches>
|
|
96
|
+
|
|
87
97
|
### Run results
|
|
88
98
|
- All tests pass: <suite> — <N> passed, 0 failed
|
|
89
99
|
- New tests run in <seconds>s
|
|
90
100
|
|
|
91
101
|
### Blockers / Notes
|
|
92
|
-
-
|
|
102
|
+
- Named gaps not addressed (e.g., "rate-limit middleware integration deferred — needs test fixture")
|
|
93
103
|
|
|
94
|
-
Status: done | partial | blocked
|
|
104
|
+
Status: done | no-tests-needed | partial | blocked
|
|
95
105
|
```
|
|
96
106
|
|
|
107
|
+
`no-tests-needed` is a **success status**, equal in standing to `done`: the scope was analysed and no test was worth adding (behaviour already covered by an existing test, code is a trivial pass-through, or the only candidate tests would fail the falsification check). It is NOT `partial` and NOT `blocked` — nothing is outstanding. It REQUIRES a written justification naming what was examined and why each candidate test was rejected; an unjustified `no-tests-needed` is indistinguishable from doing nothing. A scope where the only work was consolidation reports `done` with `test_delta.added: 0` and a non-zero `removed`/`consolidated`.
|
|
108
|
+
|
|
97
109
|
### Machine-readable contract (#417)
|
|
98
110
|
|
|
99
111
|
Append a fenced ```json block per `agents/schemas/test-writer.schema.json`:
|
|
@@ -103,14 +115,21 @@ Append a fenced ```json block per `agents/schemas/test-writer.schema.json`:
|
|
|
103
115
|
"status": "done",
|
|
104
116
|
"verdict": "PROCEED",
|
|
105
117
|
"task_id": "<wave-id>",
|
|
106
|
-
"files_changed": ["tests/path/file.test.mjs"],
|
|
107
|
-
"
|
|
118
|
+
"files_changed": [{"path": "tests/path/file.test.mjs", "tests_added": 3}],
|
|
119
|
+
"test_delta": {"added": 3, "removed": 5, "consolidated": 6, "net_loc": -118},
|
|
120
|
+
"justifications": [
|
|
121
|
+
{"test": "rejects the invoice when the payment is declined", "bug_caught": "a declined payment currently persists the invoice as PAID; no existing test enters the decline branch"}
|
|
122
|
+
],
|
|
108
123
|
"run_results": {"passed": 12, "failed": 0, "skipped": 0},
|
|
109
124
|
"blockers": []
|
|
110
125
|
}
|
|
111
126
|
```
|
|
112
127
|
|
|
113
|
-
Required: `status`, `task_id`, `files_changed`, `blockers`. Optional: `verdict`. **Emit `verdict` alongside `status` (status→verdict mapping: done→PROCEED, partial→PROCEED_WITH_FOLLOWUPS, blocked→BLOCKED)
|
|
128
|
+
Required: `status`, `task_id`, `files_changed`, `blockers`. Optional: `verdict`, `test_delta`, `justifications`, `run_results`. **Emit `verdict` alongside `status` (status→verdict mapping: done→PROCEED, partial→PROCEED_WITH_FOLLOWUPS, blocked→BLOCKED; `no-tests-needed` also maps to PROCEED — it is a success outcome).** **`status` is deprecated and will be removed in v4.0 (#472).** The coordinator parses the LAST fenced ```json block.
|
|
129
|
+
|
|
130
|
+
**`test_delta` supersedes `coverage_delta`.** Emit `test_delta` — `{added, removed, consolidated, net_loc}` — so removals and merges are first-class numbers rather than invisible work. `net_loc` is the signed line delta across all touched test files and MAY be negative; a negative `net_loc` paired with a green suite is a good result. `coverage_delta` is retained in the schema as a deprecated alias for older consumers; do not emit both.
|
|
131
|
+
|
|
132
|
+
**`justifications` is required in substance whenever `test_delta.added > 0`** (the schema keeps it structurally optional for backward-compatibility with pre-existing consumers): one entry per added test, each naming a concrete bug that no existing test catches. "Improves coverage", "tests the happy path", and "good practice" are not bugs and are not acceptable `bug_caught` values. When `test_delta.added` is 0, omit the field.
|
|
114
133
|
|
|
115
134
|
## Edge Cases
|
|
116
135
|
|
package/agents/ui-developer.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ui-developer
|
|
3
3
|
description: Use this agent for frontend implementation — UI components, pages, styling, accessibility, and responsive design. Handles React/Next.js components, CSS, and design system work. <example>Context: Implementation wave includes UI component work. user: "Build the invoice list page with filters and pagination" assistant: "I'll dispatch the ui-developer agent to implement the invoice list UI." <commentary>Frontend page implementation with interactive components is the ui-developer's specialty.</commentary></example> <example>Context: Accessibility improvements needed. user: "Fix WCAG violations in the dashboard components" assistant: "I'll use the ui-developer to audit and fix the accessibility issues." <commentary>WCAG compliance requires understanding semantic HTML, ARIA attributes, and keyboard navigation.</commentary></example>
|
|
4
|
-
model:
|
|
4
|
+
model: inherit
|
|
5
5
|
color: magenta
|
|
6
6
|
tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
|
|
7
7
|
sandbox-tier: repo-write
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Classify and apply a version bump to a machine-readable contract (JSON Schema, API spec, config schema) — version literals, consumer compatibility, changelog entry, downstream drift
|
|
3
|
+
argument-hint: "[--contract <path>]"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Contract Version Bump
|
|
7
|
+
|
|
8
|
+
The user wants to bump the version of a machine-readable contract (JSON Schema, API spec, or
|
|
9
|
+
config schema) after changing it. Invoke the contract-version-bump skill with arguments:
|
|
10
|
+
**$ARGUMENTS**.
|
|
11
|
+
|
|
12
|
+
Runs six phases: classify the change against the CONTRACT'S OWN versioning rule (not generic
|
|
13
|
+
semver instinct), find every version literal and vendored copy across this repo and every repo
|
|
14
|
+
in the instruction file's `cross-repos:` list (`CLAUDE.md`, or `AGENTS.md` on Codex CLI — the two
|
|
15
|
+
are transparent aliases), check whether every known consumer actually evaluates each
|
|
16
|
+
new/changed schema keyword, apply the bump consistently (with written exceptions, never silent
|
|
17
|
+
ones), write a Keep-a-Changelog entry that calls out breaking-for-consumers risk explicitly
|
|
18
|
+
regardless of version tier, and report any dependent repo/copy left un-synced as follow-up work.
|
|
19
|
+
|
|
20
|
+
**Usage:**
|
|
21
|
+
|
|
22
|
+
- `/contract-version-bump` — infer the contract file from conversation context
|
|
23
|
+
- `/contract-version-bump --contract docs/spec/estate.schema.json` — target a specific contract file explicitly
|
|
24
|
+
|
|
25
|
+
Codifies three traps from a real case (GitLab issue #17, `aiat-enablement` repo, 2026-07-25): a
|
|
26
|
+
missing Patch clause that silently forbade a legitimate constraint tightening, five version-
|
|
27
|
+
literal locations including a vendored copy in a different repo, and a `maxLength` keyword a
|
|
28
|
+
hand-written consumer would have silently ignored.
|
package/commands/portfolio.md
CHANGED
package/docs/README.md
CHANGED
|
@@ -91,7 +91,8 @@ Two things worth knowing about this split:
|
|
|
91
91
|
| `docs/examples/` | Living reference | Example Session Config blocks per project shape (Express API, integration test, Next.js, Swift/iOS). |
|
|
92
92
|
| `docs/recipes/` | Living reference | Narrow how-to write-ups for a specific recurring pattern (e.g. the quality-gate container test-runner pattern). |
|
|
93
93
|
| `docs/templates/` | Living reference | Copy-paste config snippets referenced directly by the setup guides (e.g. the `AGENTS.md` Session Config template). |
|
|
94
|
-
| `docs/telemetry
|
|
94
|
+
| `docs/telemetry.md` (root) | Living reference | Public transparency page for the opt-in usage-telemetry client — exact field list, kill switches, consent precedence, retention. |
|
|
95
|
+
| `docs/telemetry/` | Living reference | `telemetry-claims.md` — provenance/methodology notes for cross-repo telemetry numbers cited elsewhere in the docs (a separate, local-corpus data flow from the opt-in client telemetry above). |
|
|
95
96
|
| `docs/adr/` | Public decision history | Architecture Decision Records — permanent, never archived, cited externally. |
|
|
96
97
|
| `docs/prd/` | Active work document | PRDs of currently open epics only. Auto-archived to the Meta-Vault on epic close. |
|
|
97
98
|
| `docs/plans/` | Active work document | `/write-executable-plan` artifacts for in-progress work. May not exist when nothing is mid-plan. |
|
package/docs/USER-GUIDE.md
CHANGED
|
@@ -155,7 +155,7 @@ Suitable for: a small SaaS product, an internal admin tool, a personal project y
|
|
|
155
155
|
Sets up everything in Fast, plus:
|
|
156
156
|
- Standard `CLAUDE.md` with full Session Config
|
|
157
157
|
- Baseline directory structure per archetype
|
|
158
|
-
- VCS labels created (`priority
|
|
158
|
+
- VCS labels created (`priority::*`, `status:*`, `type:*`)
|
|
159
159
|
- Initial `STATUS.md` SSOT file
|
|
160
160
|
|
|
161
161
|
#### Deep — customer-facing systems, team repos, production
|
|
@@ -397,6 +397,9 @@ Add a `## Session Config` section to your project's Session Config host file to
|
|
|
397
397
|
| `discovery-exclude-paths` | list | `[]` | Glob patterns to exclude from discovery scanning (e.g., `vendor/**`, `dist/**`). |
|
|
398
398
|
| `discovery-severity-threshold` | string | `low` | Minimum severity for reported findings: `critical`, `high`, `medium`, `low`. |
|
|
399
399
|
| `discovery-confidence-threshold` | integer | `60` | Minimum confidence score (0-100) for discovery findings to be reported. Findings below this threshold are auto-deferred. |
|
|
400
|
+
| `issue-budget.max-per-session` | integer | `12` | Per-session cap on non-exempt issue creations. A **quantity** gate — unlike the two `discovery-*-threshold` filters above, which score individual findings and cannot bound volume. `priority::critical`, the carryover class and `broken-window` issues are exempt. |
|
|
401
|
+
| `issue-budget.mode` | string | `strict` | `strict` blocks over-cap creations and parks them; `warn` allows with a stderr notice; `off` disables the gate. |
|
|
402
|
+
| `issue-budget.overflow` | string | `collect-issue` | Where parked creations are drained at session-end: `collect-issue` (one `[Backlog-Sammel]` issue) or `vault-note` (one file under `vault/00-inbox/`). |
|
|
400
403
|
| `persistence` | boolean | `true` | Enable session resumption via STATE.md and session memory files. |
|
|
401
404
|
| `plan-baseline-path` | string | none | Path to projects-baseline directory (e.g., `~/Projects/projects-baseline`). Optional. When absent, `/bootstrap` falls back to plugin-bundled minimal templates. Only required if you want to scaffold from your own baseline during `/plan new`. |
|
|
402
405
|
| `plan-default-visibility` | string | `internal` | Default repo visibility for `/plan new`: `internal`, `private`, or `public`. |
|
|
@@ -481,6 +484,8 @@ One or two agents update SSOT files, close or update issues, write session hando
|
|
|
481
484
|
|
|
482
485
|
The `agents-per-wave` config value caps the maximum. These counts are guidelines — the orchestrator adjusts based on task complexity.
|
|
483
486
|
|
|
487
|
+
The **Quality column is a cap, not a target**: since this version, test-writing capacity is need-gated on measured demand — roughly one test-writer per three HIGH/MED gaps the review panel actually found, capped by the number above. If no gaps were measured, the Quality wave writes no tests and is skipped (the read-only review panel still runs); with no measurement signal at all, the orchestrator allocates a conservative 1-2 rather than the full cap.
|
|
488
|
+
|
|
484
489
|
### Inter-Wave Checkpoints
|
|
485
490
|
|
|
486
491
|
Between each wave, the orchestrator:
|
|
@@ -725,7 +730,7 @@ Before any code is committed, `/close` runs all checks:
|
|
|
725
730
|
| Debug artifacts | No `console.log`, `debugger`, or `TODO: remove` in changed files |
|
|
726
731
|
| Git status | All changes accounted for |
|
|
727
732
|
|
|
728
|
-
If any check fails and cannot be quickly fixed, the orchestrator creates a `priority
|
|
733
|
+
If any check fails and cannot be quickly fixed, the orchestrator creates a `priority::high` issue for immediate follow-up rather than committing broken code.
|
|
729
734
|
|
|
730
735
|
### Deterministic Scripts
|
|
731
736
|
|
|
@@ -808,7 +813,7 @@ Enable ecosystem health and configure your endpoints in Session Config:
|
|
|
808
813
|
Each configured endpoint is queried with a simple HTTP check. If the endpoint returns JSON with a `status` field, that value is reported. Otherwise, the check reports OK or unreachable.
|
|
809
814
|
|
|
810
815
|
**Cross-repo critical issues:**
|
|
811
|
-
For each related repository, the orchestrator queries open issues with `priority
|
|
816
|
+
For each related repository, the orchestrator queries open issues with `priority::critical` or `priority::high` labels. This surfaces blocking problems in other parts of your ecosystem before you start working.
|
|
812
817
|
|
|
813
818
|
**CI pipeline status:**
|
|
814
819
|
The latest CI pipeline runs are checked for the current repository.
|
package/docs/ci-setup.md
CHANGED
|
@@ -20,8 +20,69 @@ token or PAT stored as the masked CI variable `SCHEMA_DRIFT_TOKEN`.
|
|
|
20
20
|
|---|---|---|---|---|
|
|
21
21
|
| `SCHEMA_DRIFT_TOKEN` | Variable | Yes | Optional | deploy token or PAT (see below) |
|
|
22
22
|
|
|
23
|
-
If `SCHEMA_DRIFT_TOKEN` is **not set**, the job prints a
|
|
24
|
-
|
|
23
|
+
If `SCHEMA_DRIFT_TOKEN` is **not set**, the job prints a `NOT VERIFIED` notice
|
|
24
|
+
and exits **3** — which `allow_failure.exit_codes` renders as an amber *warning*,
|
|
25
|
+
never as a pass — provided `SCHEMA_DRIFT_OPTIONAL` is still `"true"`. Once that
|
|
26
|
+
flag is flipped, the same missing token exits **4** and hard-fails. Set the
|
|
27
|
+
variable to activate the real drift check; the full exit taxonomy is the table
|
|
28
|
+
in the next section.
|
|
29
|
+
|
|
30
|
+
Until 2026-07-30 this path exited **0**, so a job that had checked nothing
|
|
31
|
+
reported exactly the same green tick as a job that had checked everything. It
|
|
32
|
+
was visible in the timings: in pipeline 6815 `schema-drift-check` reported
|
|
33
|
+
success after 17 seconds, which is not enough time to clone the baseline repo,
|
|
34
|
+
let alone diff a schema against it. Issue #933.
|
|
35
|
+
|
|
36
|
+
### Activating the hard gate (`SCHEMA_DRIFT_OPTIONAL`)
|
|
37
|
+
|
|
38
|
+
`schema-drift-check` carries a committed job variable:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
variables:
|
|
42
|
+
SCHEMA_DRIFT_OPTIONAL: "true"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
It is the review-visible declaration that "no token" is *currently* an accepted
|
|
46
|
+
state. The behaviour matrix:
|
|
47
|
+
|
|
48
|
+
| `SCHEMA_DRIFT_TOKEN` | `SCHEMA_DRIFT_OPTIONAL` | Exit | State | Pipeline effect |
|
|
49
|
+
|---|---|---|---|---|
|
|
50
|
+
| unset | `"true"` | 3 | `SKIPPED` | amber warning; `pipeline-gate` prints `schema-drift: NOT VERIFIED` |
|
|
51
|
+
| unset | anything else | 4 | `MISCONFIGURED` | hard failure — the token is required and the check never ran |
|
|
52
|
+
| set, clone fails | either | 5 | `UNAVAILABLE` | hard failure — token scope/expiry/masking or network, **not** drift |
|
|
53
|
+
| set, clone works | either | 0 | `IN-SYNC` | pass; writes the `.ci-markers/schema-drift.ok` marker |
|
|
54
|
+
| set, clone works | either | 1 | `DRIFT` | hard failure — **the only code that means drift** |
|
|
55
|
+
|
|
56
|
+
**One code per fact.** Exit 1 is reserved for a real schema divergence; 3, 4 and
|
|
57
|
+
5 all mean NOT VERIFIED and none of them is a drift verdict. That split is the
|
|
58
|
+
point of the taxonomy: before it, "you forgot the token" and "the schema has
|
|
59
|
+
diverged" were the same red, so the first person to see the failure went hunting
|
|
60
|
+
a schema diff that does not exist. Only 3 is listed in
|
|
61
|
+
`allow_failure.exit_codes`; 4 and 5 are hard failures by construction. Every
|
|
62
|
+
outcome also prints its own `[schema-drift] RESULT: <STATE>` line, so the job log
|
|
63
|
+
answers "what happened" without the reader having to know this table.
|
|
64
|
+
|
|
65
|
+
**After completing the token setup below, change `SCHEMA_DRIFT_OPTIONAL` to
|
|
66
|
+
`"false"` in `.gitlab-ci.yml`** — in **both** places: the `schema-drift-check`
|
|
67
|
+
job and `pipeline-gate`. One flag, two enforcement points;
|
|
68
|
+
`tests/ci/schema-drift-check.test.mjs` asserts the mirroring, so a half-flip
|
|
69
|
+
fails the suite locally rather than silently leaving one point advisory. The
|
|
70
|
+
flip is what converts a missing token from a tolerated warning into a hard red,
|
|
71
|
+
and it is the whole point of the flag: the opt-out is a line in a reviewed file,
|
|
72
|
+
not the accidental side effect of an unset CI variable.
|
|
73
|
+
|
|
74
|
+
> **Before you flip it, run ONE pipeline with the token present while
|
|
75
|
+
> `SCHEMA_DRIFT_OPTIONAL` is still `"true"`, and check the job's DURATION.**
|
|
76
|
+
> A `schema-drift-check` that "succeeds" in under ~20 seconds did not clone the
|
|
77
|
+
> baseline repo — that is the signature of the exit-3 soft-skip path, i.e. the
|
|
78
|
+
> token is still not reaching the job (misspelled key, protected-variable on an
|
|
79
|
+
> unprotected branch, or masking rejection). Flipping the flag on that state
|
|
80
|
+
> converts a silent skip into a red pipeline whose message points at the wrong
|
|
81
|
+
> problem. Confirm a real run first: the log must show
|
|
82
|
+
> `RESULT: IN-SYNC (exit 0)` and the job must produce the
|
|
83
|
+
> `.ci-markers/schema-drift.ok` artifact. This job has a recorded history of
|
|
84
|
+
> exactly this failure — pipeline 6815 reported SUCCESS in 17 s having checked
|
|
85
|
+
> nothing (issue #933).
|
|
25
86
|
|
|
26
87
|
### Option A — Deploy Token (recommended, least-privilege)
|
|
27
88
|
|
|
@@ -60,11 +121,21 @@ After setting the variable:
|
|
|
60
121
|
1. Push to a feature branch or open an MR against `main`.
|
|
61
122
|
2. Observe the `schema-drift-check` job in the pipeline — it should now clone
|
|
62
123
|
`infrastructure/projects-baseline` and run the sync check instead of
|
|
63
|
-
printing the skip warning.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
124
|
+
printing the skip warning. Read the job's `[schema-drift] RESULT:` line; it
|
|
125
|
+
names the state directly, and the duration corroborates it (a real run
|
|
126
|
+
clones a repo, so it cannot finish in seconds).
|
|
127
|
+
3. Read the exit code against the table above before diagnosing anything:
|
|
128
|
+
- **0 (`IN-SYNC`)** — the vendored schema matches the canonical source.
|
|
129
|
+
- **1 (`DRIFT`)** — and only 1 — means drift was detected. Run
|
|
130
|
+
`node scripts/sync-vault-schema.mjs --update` locally and commit the
|
|
131
|
+
refreshed copy.
|
|
132
|
+
- **3 (`SKIPPED`)** — the token still is not reaching the job. Nothing was
|
|
133
|
+
compared; do not read the amber tick as a pass.
|
|
134
|
+
- **4 (`MISCONFIGURED`)** — `SCHEMA_DRIFT_OPTIONAL` is no longer `"true"` and
|
|
135
|
+
the token is missing. Provision the variable; there is no schema diff to
|
|
136
|
+
look for.
|
|
137
|
+
- **5 (`UNAVAILABLE`)** — the clone failed. Check the token's
|
|
138
|
+
`read_repository` scope, its expiry, and its masking. Also not drift.
|
|
68
139
|
|
|
69
140
|
### Why not configure the CI Job Token allowlist in projects-baseline?
|
|
70
141
|
|
|
@@ -79,3 +150,46 @@ Documenting it here for completeness:
|
|
|
79
150
|
and `SCHEMA_DRIFT_TOKEN` is not needed.
|
|
80
151
|
- Issue #279 chose the deploy-token path because it requires no admin action
|
|
81
152
|
in the foreign project and works immediately after variable creation.
|
|
153
|
+
|
|
154
|
+
## `pipeline-gate` — the fan-in job
|
|
155
|
+
|
|
156
|
+
The last stage holds one job that depends on every blocking gate. It exists
|
|
157
|
+
because until #933 nothing depended on anything: a gate could be deleted, or
|
|
158
|
+
ruled out for a whole pipeline type, and the pipeline still went green.
|
|
159
|
+
|
|
160
|
+
Two mechanisms, because "the gate is gone" and "the gate ran but verified
|
|
161
|
+
nothing" are different failures:
|
|
162
|
+
|
|
163
|
+
1. **Hard `needs:`** on every gate that runs on all non-scheduled pipelines.
|
|
164
|
+
On GitLab 18.11, needing a job that is absent from the pipeline is a
|
|
165
|
+
pipeline-*creation* error, not a silent skip (verified via
|
|
166
|
+
`POST /projects/74/ci/lint` with `dry_run`). Removing a gate from
|
|
167
|
+
`.gitlab-ci.yml` therefore produces no pipeline at all instead of a green
|
|
168
|
+
one — which is exactly the alarm we want, so these needs are intentionally
|
|
169
|
+
**not** `optional`.
|
|
170
|
+
2. **Marker artifacts** for the two conditional jobs, `coverage` and
|
|
171
|
+
`schema-drift-check`. Each writes `.ci-markers/<name>.ok` as the final line
|
|
172
|
+
of its script, so the marker is reachable only from the path where the job
|
|
173
|
+
really verified something. `pipeline-gate` reads those markers and prints one
|
|
174
|
+
line per gate. This is what catches an amber `schema-drift-check`: an
|
|
175
|
+
`allow_failure` job never blocks a dependent job, so `needs:` alone is blind
|
|
176
|
+
to it.
|
|
177
|
+
|
|
178
|
+
Coverage is required only on merge-request and default-branch pipelines (it is
|
|
179
|
+
the slowest job at ~148s, and it re-runs a suite `test` has already run). On a
|
|
180
|
+
plain branch pipeline `pipeline-gate` states that coverage was not measured —
|
|
181
|
+
absent, but never silently absent.
|
|
182
|
+
|
|
183
|
+
## Local pre-push gate
|
|
184
|
+
|
|
185
|
+
`.husky/pre-push` runs `npm run quality-gate`
|
|
186
|
+
(`scripts/run-quality-gate.mjs --variant full-gate`: typecheck + full vitest
|
|
187
|
+
suite + lint) and blocks the push on any non-zero exit.
|
|
188
|
+
|
|
189
|
+
- `full-gate` is used because it is the only **blocking** variant — the
|
|
190
|
+
`incremental` handler ends in an unconditional `process.exit(0)` and reports
|
|
191
|
+
rather than gates.
|
|
192
|
+
- Delete-only pushes skip the gate (no code ships).
|
|
193
|
+
- `SKIP_QUALITY_GATE=1 git push` is the named bypass. Prefer it over
|
|
194
|
+
`git push --no-verify`, which disables every hook silently and leaves no
|
|
195
|
+
record of what was skipped.
|
package/docs/codex-setup.md
CHANGED
|
@@ -90,7 +90,7 @@ The plugin bundle includes the Codex role definitions under `.codex-plugin/agent
|
|
|
90
90
|
|
|
91
91
|
The Codex hook command uses Codex's native `${PLUGIN_ROOT}` expansion. The wrapper also exports `CODEX_PLUGIN_ROOT="${PLUGIN_ROOT}"` for shared compatibility code and sets `SO_PLATFORM=codex` so Codex wins when multiple harness variables are present.
|
|
92
92
|
|
|
93
|
-
Claude-only events (`SessionEnd`, `PostToolUseFailure`, `PostToolBatch`, and `CwdChanged`) are intentionally absent because Codex 0.144.4 does not expose them as supported project events. Claude Edit/Write payload handlers are also absent: Codex emits canonical `apply_patch` data, while those handlers currently expect Claude's Edit/Write payload shape. They will remain unwired until a real `apply_patch` adapter exists; pretending the payloads are compatible would create false enforcement.
|
|
93
|
+
Claude-only events (`SessionEnd`, `PostToolUseFailure`, `PostToolBatch`, and `CwdChanged`) are intentionally absent because Codex 0.144.4 does not expose them as supported project events. Claude Edit/Write payload handlers are also absent: Codex emits canonical `apply_patch` data, while those handlers currently expect Claude's Edit/Write payload shape. They will remain unwired until a real `apply_patch` adapter exists; pretending the payloads are compatible would create false enforcement. The same applies to the Bash-payload handlers, including `post-bash-write-verify.mjs` (#942): they gate on Claude's `tool_name === 'Bash'`, which no Codex bridge delivers, so wiring them today would be a silent no-op (the #919-P2 class). These per-event gaps are tracked as documented asymmetries in `scripts/lib/validate/check-hooks-symmetry.mjs` (Check 6, `handlerAsymmetries`) — an UNDOCUMENTED one-platform-only handler now fails validation.
|
|
94
94
|
|
|
95
95
|
An empty `PreToolUse` or `SubagentStart` array means the event belongs to the validated Codex surface but currently has no payload-compatible handler. It does not mean installation or hook trust failed.
|
|
96
96
|
|
package/docs/components.md
CHANGED
|
@@ -7,8 +7,8 @@ Detailed component inventory and architecture reference for Session Orchestrator
|
|
|
7
7
|
```mermaid
|
|
8
8
|
flowchart LR
|
|
9
9
|
USER([Operator]) -->|invokes /session| COORD[Coordinator]
|
|
10
|
-
COORD -->|reads| SK[Skills<br/>
|
|
11
|
-
COORD -->|invokes| CMD[Commands<br/>
|
|
10
|
+
COORD -->|reads| SK[Skills<br/>46 user-facing]
|
|
11
|
+
COORD -->|invokes| CMD[Commands<br/>25 slash-cmds]
|
|
12
12
|
COORD -->|dispatches| AG[Agents<br/>15 typed sub-agents]
|
|
13
13
|
AG -.->|parallel waves| W1[code-implementer]
|
|
14
14
|
AG -.-> W2[test-writer]
|
|
@@ -18,22 +18,22 @@ flowchart LR
|
|
|
18
18
|
COORD -->|writes| METRIC[.orchestrator/metrics/<br/>sessions · learnings · events]
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
## Skills (
|
|
21
|
+
## Skills (46 user-facing)
|
|
22
22
|
|
|
23
23
|
- **Lifecycle:** `session-start`, `session-plan`, `wave-executor`, `session-end`, `quality-gates`, `using-orchestrator`
|
|
24
|
-
- **Authoring:** `skill-creator`, `mcp-builder`, `hook-development`, `frontmatter-guard`
|
|
24
|
+
- **Authoring:** `skill-creator`, `mcp-builder`, `hook-development`, `frontmatter-guard`, `contract-version-bump`
|
|
25
25
|
- **Planning & discovery:** `plan`, `discovery`, `repo-audit`, `brainstorm`, `write-executable-plan`, `debug`, `claude-md-drift-check`, `grill`
|
|
26
26
|
- **Architecture:** `architecture`, `domain-model`, `ubiquitous-language`
|
|
27
27
|
- **Cross-session:** `evolve`, `convergence-monitoring`, `memory-cleanup`, `reconcile`, `sunset-review`, `eval`
|
|
28
28
|
- **Vault & docs:** `vault-sync`, `vault-mirror`, `daily`, `docs-orchestrator`
|
|
29
|
-
- **Ecosystem:** `bootstrap`, `gitlab-ops`, `gitlab-portfolio`, `ecosystem-health`, `mode-selector`, `autopilot`, `dispatcher`, `spinout`
|
|
29
|
+
- **Ecosystem:** `bootstrap`, `gitlab-ops`, `gitlab-portfolio`, `ecosystem-health`, `mode-selector`, `autopilot`, `dispatcher`, `spinout`, `npm-publish`
|
|
30
30
|
- **Testing:** `test-runner`, `playwright-driver`, `peekaboo-driver`
|
|
31
31
|
- **Content review:** `persona-panel`
|
|
32
32
|
- **Visualization:** `tmux-layout` (opt-in operator side-channel — [ADR-0007](adr/0007-tmux-visualization-substrate.md))
|
|
33
33
|
|
|
34
|
-
## Commands (
|
|
34
|
+
## Commands (25)
|
|
35
35
|
|
|
36
|
-
`/session`, `/go`, `/close`, `/discovery`, `/plan`, `/evolve`, `/bootstrap`, `/harness-audit`, `/autopilot`, `/autopilot-multi`, `/repo-audit`, `/test`, `/memory-cleanup`, `/portfolio`, `/brainstorm`, `/debug`, `/persona-panel`, `/grill`, `/sunset-review`, `/templates-ack`, `/dispatcher`, `/reconcile`, `/spinout`, `/eval`.
|
|
36
|
+
`/session`, `/go`, `/close`, `/discovery`, `/plan`, `/evolve`, `/bootstrap`, `/harness-audit`, `/autopilot`, `/autopilot-multi`, `/repo-audit`, `/test`, `/memory-cleanup`, `/portfolio`, `/brainstorm`, `/debug`, `/persona-panel`, `/grill`, `/sunset-review`, `/templates-ack`, `/dispatcher`, `/reconcile`, `/spinout`, `/eval`, `/contract-version-bump`.
|
|
37
37
|
|
|
38
38
|
## Agents (15 typed sub-agents)
|
|
39
39
|
|
package/docs/cursor-setup.md
CHANGED
|
@@ -47,12 +47,25 @@ vcs: github
|
|
|
47
47
|
|
|
48
48
|
Note: `agents-per-wave` is ignored on Cursor since tasks execute sequentially (no parallel Agent dispatch).
|
|
49
49
|
|
|
50
|
-
### Hooks (Optional)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
### Hooks (Optional — not yet enforcing)
|
|
51
|
+
|
|
52
|
+
> **The hook handlers do not currently fire on Cursor (#919).** Both are written
|
|
53
|
+
> against Claude Code's `PreToolUse` payload — they require `tool_name === "Bash"`
|
|
54
|
+
> plus `tool_input.command`, and they signal a decision with a Claude Code
|
|
55
|
+
> `hookSpecificOutput` envelope. Fed a Cursor `beforeShellExecution` payload,
|
|
56
|
+
> `hooks/enforce-commands.mjs` short-circuits at its first gate and writes **0
|
|
57
|
+
> bytes to stdout and 0 bytes to stderr, exit 0** — so the harness sees no
|
|
58
|
+
> decision and **the command runs**. It is a silent no-op, not a block and not
|
|
59
|
+
> even a warning. Making this real needs a Cursor input/output adapter, the way
|
|
60
|
+
> Pi has `scripts/lib/pi-hook-bridge.mjs`; no such adapter exists yet.
|
|
61
|
+
>
|
|
62
|
+
> Until then, treat `hooks/hooks-cursor.json` as the *intended* mapping and do
|
|
63
|
+
> not rely on it for command or scope enforcement on Cursor.
|
|
64
|
+
|
|
65
|
+
Cursor supports hooks via Settings > Hooks. The intended mapping is:
|
|
66
|
+
|
|
67
|
+
- **afterFileEdit**: `hooks/enforce-scope.mjs` for scope enforcement (post-hoc warning)
|
|
68
|
+
- **beforeShellExecution**: `hooks/enforce-commands.mjs` for dangerous-command enforcement
|
|
56
69
|
|
|
57
70
|
See `hooks/hooks-cursor.json` for the hook mapping reference.
|
|
58
71
|
|
|
@@ -75,15 +88,15 @@ Commands work the same as in Claude Code:
|
|
|
75
88
|
| State directory | .claude/ | .cursor/ |
|
|
76
89
|
| Config file | CLAUDE.md | CLAUDE.md (same!) |
|
|
77
90
|
| Task tracking | TaskCreate/TaskUpdate | Text-based checklists |
|
|
78
|
-
| Pre-edit enforcement | PreToolUse hook (blocks) | afterFileEdit
|
|
79
|
-
| Command enforcement | PreToolUse hook (blocks) | beforeShellExecution
|
|
91
|
+
| Pre-edit enforcement | PreToolUse hook (blocks) | None today — `afterFileEdit` handler is a no-op (#919) |
|
|
92
|
+
| Command enforcement | PreToolUse hook (blocks) | None today — `beforeShellExecution` handler is a no-op (#919) |
|
|
80
93
|
| Model | Claude via API | Model selected in Cursor settings |
|
|
81
94
|
| Plan mode | EnterPlanMode tool | Instruction-based |
|
|
82
95
|
|
|
83
96
|
## Limitations
|
|
84
97
|
|
|
85
98
|
1. **No parallel agents** — All wave tasks execute sequentially. Sessions take longer than in Claude Code.
|
|
86
|
-
2. **
|
|
99
|
+
2. **No hook enforcement yet (#919)** — the handlers in `hooks/hooks-cursor.json` are Claude Code `PreToolUse` handlers. On a Cursor payload both `enforce-commands.mjs` and `enforce-scope.mjs` short-circuit at their first gate and produce **0 bytes on stdout and stderr with exit 0** — a silent no-op, so nothing is blocked and nothing is warned. Two independent adapters are missing: Cursor's payload field names differ from `tool_name` / `tool_input.*`, and Cursor does not read Claude Code's `hookSpecificOutput` decision envelope. Even once adapted, Cursor's `afterFileEdit` fires *after* the edit, so scope enforcement could at best warn, never prevent.
|
|
87
100
|
3. **Model preference advisory** — The `model-preference-cursor` frontmatter in skills is advisory only. Select your model in Cursor settings.
|
|
88
101
|
4. **No native plugin loader** — Skills are delivered as `.cursor/rules/*.mdc` files, not loaded from a plugin directory.
|
|
89
102
|
|
package/docs/events-schema.md
CHANGED
|
@@ -59,10 +59,14 @@ namespace we own. The validator + regex live in `scripts/lib/events-schema.mjs`
|
|
|
59
59
|
| `orchestrator.session.ended` | `hooks/on-session-end.mjs` | SessionEnd |
|
|
60
60
|
| `orchestrator.session.stopped` | `hooks/on-stop.mjs` | Stop |
|
|
61
61
|
| `orchestrator.session.lock.acquired` | `hooks/_lib/lock-bootstrap.mjs` | SessionStart |
|
|
62
|
+
| `orchestrator.session.lock.released` | `hooks/on-session-end.mjs` · `scripts/lib/autopilot/worktree-pipeline.mjs` (`teardownWorktree`) | after a `release()` that matched ownership (#952). Payload: `session_id`, `caller` (`on-session-end`\|`worktree-pipeline`), `outcome` (`deleted`\|`already-gone`), `verified`; hook-side additionally `lock_session_id`, `semantic_session_id`, `end_reason` (the SessionEnd reason — deliberately NOT `reason`, which the sibling `release_failed` uses for the failure reason); pipeline-side additionally `worktree_path`, `issue_iid`. `outcome: 'already-gone'` means the lock had ALREADY vanished between `readLock()` and `release()` — the forensically interesting case, since a successful release previously left no trace at all and a missing lock was therefore indistinguishable from a lock someone else deleted (#914 residual 3) |
|
|
63
|
+
| `orchestrator.session.lock.release_failed` | `hooks/on-session-end.mjs` · `scripts/lib/autopilot/worktree-pipeline.mjs` (`teardownWorktree`) | ownership matched but `release()` did NOT delete the lock (#724). Payload: `session_id`, `reason` (`fs-error`\|`session-mismatch`\|`not-deleted`\|`threw`), `caller`; pipeline-side additionally `worktree_path`, `issue_iid` |
|
|
64
|
+
| `orchestrator.session.lock.reconcile_attempted` | `hooks/_lib/lock-reconcile.mjs` | SessionEnd, when NEITHER ownership check matched the recorded lock (#748). Payload: `session_id`, `action` (`reaped`\|`skipped`\|`unknown`), `reason` (e.g. `own-host-pid-alive`) |
|
|
65
|
+
| `orchestrator.session.lock.reaped` | `scripts/lib/lock-reaper.mjs` | a dead lease was reaped. Payload: `session_id`, `semantic_session_id`, `host`, `pid`, `age_hours`, `reap_mode`, `current_session` |
|
|
62
66
|
| `orchestrator.agent.stopped` | `hooks/on-stop.mjs` | SubagentStop |
|
|
63
67
|
| `orchestrator.memory.propose_invoked` | `hooks/pre-bash-memory-propose-audit.mjs` | PreToolUse(Bash) |
|
|
64
68
|
| `orchestrator.wave.started` / `.completed` | `hooks/post-tool-batch-wave-signal.mjs` | PostToolBatch — fires live via `.claude/wave-scope.json` `.wave` increase (mechanical fallback, #612); an explicit injected `wave_signal` still takes precedence |
|
|
65
|
-
| `orchestrator.quality_gate.passed` / `.failed` | `scripts/run-quality-gate.mjs` | per gate-CLI run (
|
|
69
|
+
| `orchestrator.quality_gate.passed` / `.failed` | `scripts/run-quality-gate.mjs` (the gate CLI — live between waves) · `scripts/lib/quality-gate.mjs` (`emitGateEvent` inside `runQualityGateWithRetry`, reached ONLY under `verification-auto-fix.enabled: true` — default `false`, and `false` in this repo) | CLI: once per gate-CLI run. Library: once per `runQualityGateWithRetry` **call**, never per retry attempt (`attempts` carries that detail). The two paths never nest, so one run passes through exactly one emitter. **Payload (both):** `variant`, `exit_code`, plus `session_id` / `semantic_session_id` when `sessionAttribution()` finds a session lock (both omitted when it does not). CLI `variant` is the `--variant` value (`baseline`\|`incremental`\|`full-gate`\|`per-file`); the library pins `variant: 'auto-fix-loop'`. **CLI only:** `wave_number`. **Library only:** `attempts` (1…`maxRetries+1`) and `gate` (`lint`\|`typecheck`\|`test` — the fail-fast gate of the last attempt; omitted on the passing path). **Optional on both:** `counts: {passed, failed, total}`. **Absent is not zero — for both optional fields.** `counts` is admitted by the ONE shared policy `admitSuiteCounts()` (`scripts/lib/gates/gate-helpers.mjs`, #967 item 2), which returns `null` — never a zero triple — for an unmeasured or inconsistent input (test gate skipped/stubbed, fail-fast on lint or typecheck before the test step, no parseable `<N> passed` marker, or `passed + failed !== total`); both callers spread `...(counts ? { counts } : {})`, so the KEY is missing in those runs. A present `counts.failed: 0` therefore means "measured, zero failures", while an absent `counts` means "not measured" — reading a missing field as `0` mis-analyses the ledger in both directions. Same contract for `wave_number` (CLI, #966 step 1): resolved from the `.{pi,cursor,codex,claude}/wave-scope.json` sidecar, **omitted** — never `0` — when there is no sidecar or its `wave` is non-numeric/non-positive; a human running `npm run quality-gate` from a `git push` has no wave at all, so an invented wave 0 would have to be special-cased by every consumer. Note `total` is `passed + failed` and EXCLUDES skipped/todo (see `extractTestCounts`) |
|
|
66
70
|
| `orchestrator.grounding.injected` | `scripts/compute-grounding-injection.sh` (via `scripts/emit-event.mjs`) | grounding injection, when `PERSISTENCE=true` |
|
|
67
71
|
| `orchestrator.handover.gated` | `skills/session-end/SKILL.md` Phase 1.65 (skill-prose, via `scripts/emit-event.mjs`) | Handover-Alignment-Gate outcome (#773). Payload: `candidates_total`, `auto_carry`, `asked`, `dropped`, `questions_asked`, `questions_answered`, `questions_deferred`, `path` (`fast_path`\|`triage`\|`weiterarbeiten`\|`fail_open`). Emitted exactly once per close — including the fail-open skip and the "Weiterarbeiten" abort — so never-measured paths become observable |
|
|
68
72
|
|