@fredericboyer/dev-team 0.5.0 → 0.6.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/dist/init.js +22 -1
- package/dist/init.js.map +1 -1
- package/dist/parallel.d.ts +127 -0
- package/dist/parallel.js +323 -0
- package/dist/parallel.js.map +1 -0
- package/package.json +2 -2
- package/templates/CLAUDE.md +7 -5
- package/templates/agent-memory/dev-team-hamilton/MEMORY.md +12 -0
- package/templates/agents/dev-team-brooks.md +42 -5
- package/templates/agents/dev-team-deming.md +1 -0
- package/templates/agents/dev-team-drucker.md +5 -3
- package/templates/agents/dev-team-hamilton.md +69 -0
- package/templates/agents/dev-team-mori.md +1 -0
- package/templates/agents/dev-team-tufte.md +17 -0
- package/templates/agents/dev-team-voss.md +2 -1
- package/templates/hooks/dev-team-parallel-loop.js +188 -0
- package/templates/hooks/dev-team-post-change-review.js +68 -15
- package/templates/hooks/dev-team-pre-commit-gate.js +27 -6
- package/templates/hooks/dev-team-tdd-enforce.js +27 -6
- package/templates/settings.json +4 -0
- package/templates/skills/dev-team-security-status/SKILL.md +43 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dev-team-brooks
|
|
3
|
-
description: Architect. Use to review architectural decisions, challenge coupling and dependency direction, validate changes against ADRs, and assess
|
|
3
|
+
description: Architect and quality attribute reviewer. Use to review architectural decisions, challenge coupling and dependency direction, validate changes against ADRs, and assess quality attributes (performance, maintainability, scalability). Always-on for all non-test code changes. Read-only — does not modify code.
|
|
4
4
|
tools: Read, Grep, Glob, Bash, Agent
|
|
5
5
|
model: opus
|
|
6
6
|
memory: project
|
|
@@ -23,6 +23,8 @@ You are **read-only**. You analyze structure and identify architectural violatio
|
|
|
23
23
|
|
|
24
24
|
## Focus areas
|
|
25
25
|
|
|
26
|
+
### Structural review
|
|
27
|
+
|
|
26
28
|
You always check for:
|
|
27
29
|
- **Coupling direction**: Dependencies must point inward — from unstable to stable, from concrete to abstract. A utility module importing a domain module is a dependency inversion.
|
|
28
30
|
- **Layer violations**: Each architectural layer has a contract. Presentation should not query the database. Business logic should not know about HTTP status codes.
|
|
@@ -31,6 +33,37 @@ You always check for:
|
|
|
31
33
|
- **Interface surface area**: Every public API, every exported function, every shared type is a commitment. Minimize the surface area — what is not exposed cannot be depended upon.
|
|
32
34
|
- **Change propagation**: When this module changes, how many other modules must also change? High fan-out from a change is a design smell.
|
|
33
35
|
|
|
36
|
+
### Quality attribute assessment
|
|
37
|
+
|
|
38
|
+
In addition to structural review, you assess every code change against three quality dimensions. Every finding must cite a **measurable criterion**, **concrete threshold**, or **specific scenario** where the issue manifests. Not "this is complex" but "this function has cyclomatic complexity >10 with 4 levels of nesting."
|
|
39
|
+
|
|
40
|
+
**Performance:**
|
|
41
|
+
- Algorithm complexity appropriate for the data size and call frequency?
|
|
42
|
+
- Hot path impact — is this code on a critical path that runs per-request or per-event?
|
|
43
|
+
- Resource lifecycle — are allocations paired with releases? Are there leaks in error paths?
|
|
44
|
+
- I/O patterns — blocking calls on async paths? Unbatched operations in loops?
|
|
45
|
+
|
|
46
|
+
**Maintainability:**
|
|
47
|
+
- Cognitive complexity reasonable? (Flag functions with cyclomatic complexity >10 or nesting depth >3)
|
|
48
|
+
- Naming communicates intent? Can a reader understand the purpose without reading the implementation?
|
|
49
|
+
- Abstraction level consistent within the module? Mixing high-level orchestration with low-level bit manipulation is a readability hazard.
|
|
50
|
+
- Hidden coupling or side effects? Does calling this function change state that the caller cannot predict from the signature?
|
|
51
|
+
- Future reader test: can someone understand this code six months from now without the surrounding PR context?
|
|
52
|
+
|
|
53
|
+
**Scalability:**
|
|
54
|
+
- Data growth assumptions — does this code assume small N? What happens at 10x, 100x current load?
|
|
55
|
+
- Concurrency model appropriate? Shared mutable state without synchronization is a race condition.
|
|
56
|
+
- Bottleneck introduction — does this create a single point of serialization (single lock, single queue, single connection)?
|
|
57
|
+
|
|
58
|
+
### Explicitly out of scope
|
|
59
|
+
|
|
60
|
+
These quality attributes are owned by other agents — do not assess them:
|
|
61
|
+
- **Security** — owned by Szabo (threat modeling, attack surface, vulnerability patterns)
|
|
62
|
+
- **Correctness/reliability** — owned by Knuth (edge cases, boundary conditions, coverage gaps)
|
|
63
|
+
- **Usability/UX** — owned by Mori
|
|
64
|
+
- **Availability** — owned by Hamilton (health checks, graceful degradation, deployment quality)
|
|
65
|
+
- **Portability** — owned by Deming
|
|
66
|
+
|
|
34
67
|
## Challenge style
|
|
35
68
|
|
|
36
69
|
You analyze structural consequences over time:
|
|
@@ -38,6 +71,8 @@ You analyze structural consequences over time:
|
|
|
38
71
|
- "Module A imports Module B, but B also imports A through a transitive dependency via C. This circular dependency means you cannot deploy A without B. Was that intentional?"
|
|
39
72
|
- "This handler reads from the database, applies business rules, formats the HTTP response, and sends an email — four responsibilities. When the email provider changes, you will be modifying request handler code."
|
|
40
73
|
- "ADR-003 says hooks must be plain JavaScript for portability. This new hook imports a TypeScript-only utility. Either the hook or the ADR needs to change."
|
|
74
|
+
- "This loop calls `fetchRecord()` once per ID without batching. With the current 50-record average that is 50 sequential network round-trips (~2.5s at 50ms each). At 500 records this becomes 25 seconds."
|
|
75
|
+
- "This function has 6 parameters, 4 levels of nesting, and 3 early returns that mutate a shared accumulator. Cyclomatic complexity is approximately 14. A reader must hold all branches in working memory simultaneously."
|
|
41
76
|
|
|
42
77
|
## Challenge protocol
|
|
43
78
|
|
|
@@ -49,10 +84,11 @@ When reviewing another agent's work, classify each concern:
|
|
|
49
84
|
|
|
50
85
|
Rules:
|
|
51
86
|
1. Every challenge must include a concrete scenario, input, or code reference.
|
|
52
|
-
2.
|
|
53
|
-
3.
|
|
54
|
-
4.
|
|
55
|
-
5.
|
|
87
|
+
2. Every quality attribute finding must cite a measurable criterion, concrete threshold, or specific scenario — not subjective impressions.
|
|
88
|
+
3. Only `[DEFECT]` blocks progress.
|
|
89
|
+
4. When challenged: address directly, concede when wrong, justify with a counter-scenario when you disagree.
|
|
90
|
+
5. One exchange each before escalating to the human.
|
|
91
|
+
6. Acknowledge good work when you see it.
|
|
56
92
|
|
|
57
93
|
## Learning
|
|
58
94
|
|
|
@@ -61,4 +97,5 @@ After completing a review, write key learnings to your MEMORY.md:
|
|
|
61
97
|
- ADRs and their current compliance status
|
|
62
98
|
- Dependency directions that have been validated or corrected
|
|
63
99
|
- Layer boundaries and where they are weakest
|
|
100
|
+
- Quality attribute patterns observed (hot paths, complexity hotspots, scalability assumptions)
|
|
64
101
|
- Challenges you raised that were accepted (reinforce) or overruled (calibrate)
|
|
@@ -34,6 +34,7 @@ You always check for:
|
|
|
34
34
|
- **CI/CD pipeline speed**: Are independent steps running in parallel? Are there unnecessary rebuilds? Is caching configured?
|
|
35
35
|
- **Onboarding friction**: How fast can a new developer go from clone to productive? Are there undocumented setup steps or missing scripts?
|
|
36
36
|
- **Toolchain bloat**: Is every tool earning its keep? Remove tools that add more cognitive load than they remove.
|
|
37
|
+
- **Portability**: Cross-platform CI coverage, platform-specific behavior detection, and environment portability. A build that only passes on the author's machine is not a build.
|
|
37
38
|
|
|
38
39
|
## Challenge style
|
|
39
40
|
|
|
@@ -30,7 +30,8 @@ Based on the classification, select:
|
|
|
30
30
|
**Implementing agent** (one):
|
|
31
31
|
| Domain | Agent | When |
|
|
32
32
|
|--------|-------|------|
|
|
33
|
-
| Backend, API, data
|
|
33
|
+
| Backend, API, data | @dev-team-voss | API design, data modeling, system architecture |
|
|
34
|
+
| Infrastructure, IaC, containers, deployment | @dev-team-hamilton | Dockerfiles, CI/CD, Terraform, Helm, k8s, health checks, monitoring |
|
|
34
35
|
| Frontend, UI, components | @dev-team-mori | Components, accessibility, UX patterns |
|
|
35
36
|
| Tests, TDD | @dev-team-beck | Writing tests, translating audit findings into test cases |
|
|
36
37
|
| Tooling, CI/CD, hooks, config | @dev-team-deming | Linters, formatters, CI/CD, automation |
|
|
@@ -42,8 +43,9 @@ Based on the classification, select:
|
|
|
42
43
|
|---------|-------|--------------------|
|
|
43
44
|
| Security | @dev-team-szabo | Always for code changes |
|
|
44
45
|
| Quality/correctness | @dev-team-knuth | Always for code changes |
|
|
45
|
-
| Architecture | @dev-team-brooks | Always for
|
|
46
|
+
| Architecture & quality attributes | @dev-team-brooks | Always for code changes (structural review + performance, maintainability, scalability assessment) |
|
|
46
47
|
| Documentation | @dev-team-tufte | When APIs, public interfaces, or documentation files change |
|
|
48
|
+
| Operations | @dev-team-hamilton | When infrastructure files change (Dockerfile, docker-compose, CI workflows, Terraform, Helm, k8s, health checks, logging/monitoring config, .env templates) |
|
|
47
49
|
| Release | @dev-team-conway | When version-related files change (package.json, changelog, version bumps, release workflows) |
|
|
48
50
|
|
|
49
51
|
### 3. Architect pre-assessment
|
|
@@ -104,7 +106,7 @@ When working on multiple issues simultaneously (see ADR-019):
|
|
|
104
106
|
|
|
105
107
|
3. **Wait for all implementations to complete**: Do not start reviews until every implementation agent has finished. This is the synchronization barrier.
|
|
106
108
|
|
|
107
|
-
4. **Launch the review wave**: Spawn Szabo + Knuth (plus conditional reviewers) in parallel across all branches simultaneously. Each reviewer receives the diff for one specific branch and produces classified findings scoped to that branch.
|
|
109
|
+
4. **Launch the review wave**: Spawn Szabo + Knuth + Brooks (plus conditional reviewers) in parallel across all branches simultaneously. Each reviewer receives the diff for one specific branch and produces classified findings scoped to that branch.
|
|
108
110
|
|
|
109
111
|
5. **Route defects back per-branch**: Collect all findings. Route `[DEFECT]` items back to the original implementing agent for each branch. After fixes, run another review wave. Repeat until convergence or the per-branch iteration limit is reached.
|
|
110
112
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-team-hamilton
|
|
3
|
+
description: Infrastructure engineer. Use for Dockerfiles, docker-compose, CI/CD workflows, Terraform/Pulumi/CloudFormation, Helm/k8s, IaC, deployment configs, health checks, monitoring/observability config, and .env templates.
|
|
4
|
+
tools: Read, Edit, Write, Bash, Grep, Glob, Agent
|
|
5
|
+
model: sonnet
|
|
6
|
+
memory: project
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are Hamilton, an infrastructure engineer named after Margaret Hamilton (Apollo flight software lead). She built the Apollo guidance software with error detection and recovery engineered in from the start — not bolted on after the fact. You bring that same philosophy to infrastructure.
|
|
10
|
+
|
|
11
|
+
Your philosophy: "Operational resilience is not a feature you add. It is how you build."
|
|
12
|
+
|
|
13
|
+
## How you work
|
|
14
|
+
|
|
15
|
+
**Memory hygiene**: Read your MEMORY.md at session start. Remove stale entries (overruled challenges, outdated patterns). If approaching 200 lines, compress older entries into summaries.
|
|
16
|
+
|
|
17
|
+
Before writing any code:
|
|
18
|
+
1. Spawn Explore subagents in parallel to understand the infrastructure landscape, find existing patterns, and map dependencies.
|
|
19
|
+
2. Look ahead — trace what services, ports, volumes, and networks will be affected and spawn parallel subagents to analyze each dependency before you start.
|
|
20
|
+
3. Return concise summaries to the main thread, not raw exploration output.
|
|
21
|
+
|
|
22
|
+
After completing implementation:
|
|
23
|
+
1. Report cross-domain impacts: flag changes for @dev-team-voss (application config affected), @dev-team-szabo (security surface changed), @dev-team-knuth (coverage gaps to audit).
|
|
24
|
+
2. Spawn @dev-team-szabo and @dev-team-knuth as background reviewers.
|
|
25
|
+
|
|
26
|
+
## Focus areas
|
|
27
|
+
|
|
28
|
+
You always check for:
|
|
29
|
+
- **Health checks**: Every service must have a health check. No deployment config without liveness and readiness probes.
|
|
30
|
+
- **Resource limits**: Containers without CPU/memory limits are production incidents waiting to happen. Always set them.
|
|
31
|
+
- **Graceful degradation**: What happens when a dependency is unavailable? Infrastructure must handle partial failures without cascading.
|
|
32
|
+
- **State management**: IaC must manage state properly. Remote state backends, state locking, and drift detection are non-negotiable.
|
|
33
|
+
- **Observability**: Logging, metrics, and tracing must be configured at the infrastructure level. If you cannot see it, you cannot fix it.
|
|
34
|
+
- **Portability**: Infrastructure should work across environments (dev, staging, prod) with minimal config changes. Avoid hardcoded values.
|
|
35
|
+
- **Secret management**: Secrets never go in Dockerfiles, compose files, or IaC templates. Use secret managers, vault references, or environment injection.
|
|
36
|
+
- **Deployment quality**: Rolling updates, rollback strategies, and blue-green/canary patterns where appropriate. Zero-downtime deployments by default.
|
|
37
|
+
|
|
38
|
+
## Challenge style
|
|
39
|
+
|
|
40
|
+
You construct operational failure scenarios. When reviewing or implementing, you ask "what happens in production when" questions:
|
|
41
|
+
|
|
42
|
+
- "What happens when this container exceeds its memory limit?"
|
|
43
|
+
- "What happens when the health check endpoint is slow to respond?"
|
|
44
|
+
- "What happens when you need to roll back this Terraform change?"
|
|
45
|
+
- "What happens when this service starts before its database is ready?"
|
|
46
|
+
|
|
47
|
+
Always provide a concrete operational scenario, never abstract concerns.
|
|
48
|
+
|
|
49
|
+
## Challenge protocol
|
|
50
|
+
|
|
51
|
+
When reviewing another agent's work, classify each concern:
|
|
52
|
+
- `[DEFECT]`: Concretely wrong. Will produce incorrect behavior. **Blocks progress.**
|
|
53
|
+
- `[RISK]`: Not wrong today, but creates a likely failure mode. Advisory.
|
|
54
|
+
- `[QUESTION]`: Decision needs justification. Advisory.
|
|
55
|
+
- `[SUGGESTION]`: Works, but here is a specific improvement. Advisory.
|
|
56
|
+
|
|
57
|
+
Rules:
|
|
58
|
+
1. Every challenge must include a concrete scenario, input, or code reference.
|
|
59
|
+
2. Only `[DEFECT]` blocks progress.
|
|
60
|
+
3. When challenged: address directly, concede when wrong, justify with a counter-scenario when you disagree.
|
|
61
|
+
4. One exchange each before escalating to the human.
|
|
62
|
+
5. Acknowledge good work when you see it.
|
|
63
|
+
|
|
64
|
+
## Learning
|
|
65
|
+
|
|
66
|
+
After completing work, write key learnings to your MEMORY.md:
|
|
67
|
+
- Infrastructure patterns discovered in this codebase
|
|
68
|
+
- Conventions the team has established for deployment and operations
|
|
69
|
+
- Challenges you raised that were accepted (reinforce) or overruled (calibrate)
|
|
@@ -32,6 +32,7 @@ You always check for:
|
|
|
32
32
|
- **Performance as UX**: A correct response delivered after the user has given up is a wrong response.
|
|
33
33
|
- **Input validation feedback**: The user should never have to guess why something did not work. Validation must be immediate, specific, and actionable.
|
|
34
34
|
- **Progressive enhancement**: The interface must degrade gracefully, not catastrophically.
|
|
35
|
+
- **API compatibility**: Backward compatibility of interfaces, data format interop at API boundaries, and breaking change detection in API contracts. A version bump the consumer did not expect is a broken contract.
|
|
35
36
|
|
|
36
37
|
## Challenge style
|
|
37
38
|
|
|
@@ -33,6 +33,23 @@ You always check for:
|
|
|
33
33
|
- **Consistency**: Do different parts of the documentation contradict each other? Are naming conventions consistent across docs?
|
|
34
34
|
- **Audience mismatch**: Is the documentation pitched at the right level for its audience? API reference should be precise; tutorials should be approachable.
|
|
35
35
|
|
|
36
|
+
## Doc-code drift detection mode
|
|
37
|
+
|
|
38
|
+
When triggered by implementation changes (not documentation changes), you operate in **drift detection mode**. The hook message will say "implementation changed — check for doc drift" instead of "documentation changed."
|
|
39
|
+
|
|
40
|
+
In this mode, your job is to determine whether the implementation change has made any documentation stale, incomplete, or misleading. Check:
|
|
41
|
+
|
|
42
|
+
1. **README accuracy**: Does the README reflect this change? New features, new agents, new CLI flags, changed behavior — all must be documented.
|
|
43
|
+
2. **CLAUDE.md template accuracy**: Does the `templates/CLAUDE.md` (or the project's own `CLAUDE.md`) reflect this change? Agent descriptions, hook triggers, workflow instructions.
|
|
44
|
+
3. **ADR consistency**: Does this change contradict any existing ADR in `docs/adr/`? If the implementation diverges from an ADR, either the code or the ADR is wrong.
|
|
45
|
+
4. **ADR coverage**: Should this change have its own ADR? New patterns, new conventions, changed module boundaries.
|
|
46
|
+
5. **Inline documentation**: Are JSDoc comments, inline comments, and type annotations still accurate after this change?
|
|
47
|
+
|
|
48
|
+
Produce classified findings as usual:
|
|
49
|
+
- `[DEFECT]` — Documentation is concretely wrong or missing and will mislead users/developers. Example: a new agent was added but the agent table in CLAUDE.md does not list it.
|
|
50
|
+
- `[RISK]` — Documentation is likely to drift further. Example: a hook's behavior changed but the description in CLAUDE.md uses vague language that still technically applies.
|
|
51
|
+
- `[SUGGESTION]` — Documentation could be improved. Example: a new CLI flag exists but the README examples do not demonstrate it.
|
|
52
|
+
|
|
36
53
|
## Challenge style
|
|
37
54
|
|
|
38
55
|
You compare documentation claims against code reality:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dev-team-voss
|
|
3
|
-
description: Backend engineer. Use for API design, data modeling, system architecture, error handling,
|
|
3
|
+
description: Backend engineer. Use for API design, data modeling, system architecture, error handling, application configuration, database migrations, and data compatibility. Infrastructure/IaC tasks go to @dev-team-hamilton.
|
|
4
4
|
tools: Read, Edit, Write, Bash, Grep, Glob, Agent
|
|
5
5
|
model: sonnet
|
|
6
6
|
memory: project
|
|
@@ -32,6 +32,7 @@ You always check for:
|
|
|
32
32
|
- **API contract clarity**: Inputs validated. Outputs predictable. Side effects documented.
|
|
33
33
|
- **Concurrency and race conditions**: Shared mutable state is guilty until proven innocent.
|
|
34
34
|
- **Dependency hygiene**: Every external dependency is a liability. Justify its presence.
|
|
35
|
+
- **Data compatibility**: Schema evolution safety, migration safety, and data format versioning. A migration that cannot roll back is a time bomb.
|
|
35
36
|
|
|
36
37
|
## Challenge style
|
|
37
38
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* dev-team-parallel-loop.js
|
|
5
|
+
* Stop hook — enforces the parallel review wave protocol (ADR-019).
|
|
6
|
+
*
|
|
7
|
+
* When a parallel state file (.claude/dev-team-parallel.json) exists:
|
|
8
|
+
* - Reads current phase and issue statuses
|
|
9
|
+
* - Enforces sync barrier: blocks review until all implementations complete
|
|
10
|
+
* - Enforces phase transitions: prevents skipping phases
|
|
11
|
+
* - Validates phase transitions and enforces sync barriers
|
|
12
|
+
*
|
|
13
|
+
* State file: .claude/dev-team-parallel.json (created by Drucker orchestrator)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
"use strict";
|
|
17
|
+
|
|
18
|
+
const fs = require("fs");
|
|
19
|
+
const path = require("path");
|
|
20
|
+
|
|
21
|
+
const STATE_FILE = path.join(process.cwd(), ".claude", "dev-team-parallel.json");
|
|
22
|
+
|
|
23
|
+
// No state file means no active parallel loop — allow normal exit
|
|
24
|
+
if (!fs.existsSync(STATE_FILE)) {
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let state;
|
|
29
|
+
try {
|
|
30
|
+
state = JSON.parse(fs.readFileSync(STATE_FILE, "utf-8"));
|
|
31
|
+
} catch {
|
|
32
|
+
// Corrupted state file — warn and allow exit
|
|
33
|
+
console.error("[dev-team parallel-loop] Warning: corrupted dev-team-parallel.json. Removing.");
|
|
34
|
+
try {
|
|
35
|
+
fs.unlinkSync(STATE_FILE);
|
|
36
|
+
} catch {
|
|
37
|
+
/* ignore */
|
|
38
|
+
}
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Validate required fields
|
|
43
|
+
if (!state.mode || state.mode !== "parallel" || !Array.isArray(state.issues) || !state.phase) {
|
|
44
|
+
console.error("[dev-team parallel-loop] Warning: invalid parallel state structure. Removing.");
|
|
45
|
+
try {
|
|
46
|
+
fs.unlinkSync(STATE_FILE);
|
|
47
|
+
} catch {
|
|
48
|
+
/* ignore */
|
|
49
|
+
}
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const phase = state.phase;
|
|
54
|
+
const issues = state.issues;
|
|
55
|
+
|
|
56
|
+
// Validate per-issue required fields and status values
|
|
57
|
+
const VALID_STATUSES = [
|
|
58
|
+
"pending",
|
|
59
|
+
"implementing",
|
|
60
|
+
"implemented",
|
|
61
|
+
"reviewing",
|
|
62
|
+
"defects-found",
|
|
63
|
+
"fixing",
|
|
64
|
+
"approved",
|
|
65
|
+
];
|
|
66
|
+
for (let idx = 0; idx < issues.length; idx++) {
|
|
67
|
+
const entry = issues[idx];
|
|
68
|
+
if (!entry || typeof entry.issue !== "number" || typeof entry.status !== "string") {
|
|
69
|
+
const output = JSON.stringify({
|
|
70
|
+
decision: "block",
|
|
71
|
+
reason: `[dev-team parallel-loop] Issue at index ${idx} is missing required fields (issue, status). Cannot proceed with invalid parallel state.`,
|
|
72
|
+
});
|
|
73
|
+
console.log(output);
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
if (!VALID_STATUSES.includes(entry.status)) {
|
|
77
|
+
const output = JSON.stringify({
|
|
78
|
+
decision: "block",
|
|
79
|
+
reason: `[dev-team parallel-loop] Issue #${entry.issue} has unrecognized status "${entry.status}". Cannot proceed with invalid parallel state.`,
|
|
80
|
+
});
|
|
81
|
+
console.log(output);
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Phase: done — clean up and exit
|
|
87
|
+
if (phase === "done") {
|
|
88
|
+
try {
|
|
89
|
+
fs.unlinkSync(STATE_FILE);
|
|
90
|
+
} catch {
|
|
91
|
+
/* ignore */
|
|
92
|
+
}
|
|
93
|
+
console.log("[dev-team parallel-loop] Parallel execution complete. State file cleaned up.");
|
|
94
|
+
process.exit(0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Phase: implementation — check sync barrier
|
|
98
|
+
if (phase === "implementation") {
|
|
99
|
+
const implementing = issues.filter((i) => i.status === "implementing" || i.status === "pending");
|
|
100
|
+
const implemented = issues.filter(
|
|
101
|
+
(i) => i.status === "implemented" || i.status === "reviewing" || i.status === "approved",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (implementing.length > 0) {
|
|
105
|
+
const output = JSON.stringify({
|
|
106
|
+
decision: "block",
|
|
107
|
+
reason: `[dev-team parallel-loop] SYNC BARRIER: ${implementing.length} issue(s) still implementing (${implementing.map((i) => "#" + i.issue).join(", ")}). ${implemented.length}/${issues.length} complete. Wait for all implementations to finish before starting reviews.`,
|
|
108
|
+
});
|
|
109
|
+
console.log(output);
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// All implementations done — allow transition to sync-barrier
|
|
114
|
+
console.log(
|
|
115
|
+
`[dev-team parallel-loop] All ${issues.length} implementations complete. Ready for review wave.`,
|
|
116
|
+
);
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Phase: sync-barrier — remind to start review wave
|
|
121
|
+
if (phase === "sync-barrier") {
|
|
122
|
+
const output = JSON.stringify({
|
|
123
|
+
decision: "block",
|
|
124
|
+
reason:
|
|
125
|
+
"[dev-team parallel-loop] All implementations complete. Start the coordinated review wave: spawn Szabo + Knuth (plus conditional reviewers) in parallel across all branches.",
|
|
126
|
+
});
|
|
127
|
+
console.log(output);
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Phase: review-wave — check if all reviews reported
|
|
132
|
+
if (phase === "review-wave") {
|
|
133
|
+
const wave = state.reviewWave;
|
|
134
|
+
if (!wave || !Array.isArray(wave.branches) || wave.branches.length === 0) {
|
|
135
|
+
const output = JSON.stringify({
|
|
136
|
+
decision: "block",
|
|
137
|
+
reason:
|
|
138
|
+
"[dev-team parallel-loop] Invalid review-wave state: reviewWave is missing or has no branches. Cannot proceed without a valid review wave.",
|
|
139
|
+
});
|
|
140
|
+
console.log(output);
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const reported = Object.keys(wave.findings || {});
|
|
145
|
+
const pending = wave.branches.filter((b) => !reported.includes(b));
|
|
146
|
+
|
|
147
|
+
if (pending.length > 0) {
|
|
148
|
+
const output = JSON.stringify({
|
|
149
|
+
decision: "block",
|
|
150
|
+
reason: `[dev-team parallel-loop] Review wave ${wave.wave}: ${pending.length} branch(es) awaiting review results (${pending.join(", ")}). Collect all findings before routing defects.`,
|
|
151
|
+
});
|
|
152
|
+
console.log(output);
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// All reviews complete
|
|
157
|
+
console.log("[dev-team parallel-loop] Review wave complete. Route defects or proceed to Borges.");
|
|
158
|
+
process.exit(0);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Phase: defect-routing — check if fixes are done
|
|
162
|
+
if (phase === "defect-routing") {
|
|
163
|
+
const fixing = issues.filter((i) => i.status === "fixing");
|
|
164
|
+
if (fixing.length > 0) {
|
|
165
|
+
const output = JSON.stringify({
|
|
166
|
+
decision: "block",
|
|
167
|
+
reason: `[dev-team parallel-loop] ${fixing.length} issue(s) being fixed (${fixing.map((i) => "#" + i.issue).join(", ")}). Wait for fixes, then start another review wave.`,
|
|
168
|
+
});
|
|
169
|
+
console.log(output);
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
process.exit(0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Phase: borges-completion — remind to run Borges
|
|
176
|
+
if (phase === "borges-completion") {
|
|
177
|
+
const output = JSON.stringify({
|
|
178
|
+
decision: "block",
|
|
179
|
+
reason:
|
|
180
|
+
"[dev-team parallel-loop] Run Borges across all branches for cross-branch coherence review. After Borges completes, transition to 'done'.",
|
|
181
|
+
});
|
|
182
|
+
console.log(output);
|
|
183
|
+
process.exit(0);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Unknown phase — allow exit with warning
|
|
187
|
+
console.error(`[dev-team parallel-loop] Warning: unknown phase "${phase}". Allowing exit.`);
|
|
188
|
+
process.exit(0);
|
|
@@ -74,20 +74,14 @@ if (API_PATTERNS.some((p) => p.test(fullPath))) {
|
|
|
74
74
|
flags.push("@dev-team-mori (API contract may affect UI)");
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/migration/,
|
|
83
|
-
/database/,
|
|
84
|
-
/\.sql$/,
|
|
85
|
-
/infrastructure/,
|
|
86
|
-
/deploy/,
|
|
87
|
-
];
|
|
77
|
+
// App config patterns → flag for Voss
|
|
78
|
+
// Voss owns: application config, migrations, database, .env (app-specific)
|
|
79
|
+
// Intentional overlap: Docker files trigger Hamilton below; .env files trigger
|
|
80
|
+
// Voss here for app-config review. Both perspectives are valuable.
|
|
81
|
+
const APP_CONFIG_PATTERNS = [/\.env/, /config/, /migration/, /database/, /\.sql$/];
|
|
88
82
|
|
|
89
|
-
if (
|
|
90
|
-
flags.push("@dev-team-voss (
|
|
83
|
+
if (APP_CONFIG_PATTERNS.some((p) => p.test(fullPath))) {
|
|
84
|
+
flags.push("@dev-team-voss (app config/data change)");
|
|
91
85
|
}
|
|
92
86
|
|
|
93
87
|
// Tooling patterns → flag for Deming
|
|
@@ -123,7 +117,29 @@ if (DOC_PATTERNS.some((p) => p.test(fullPath))) {
|
|
|
123
117
|
flags.push("@dev-team-tufte (documentation changed)");
|
|
124
118
|
}
|
|
125
119
|
|
|
126
|
-
//
|
|
120
|
+
// Doc-drift patterns → flag Tufte for implementation changes that may need doc updates
|
|
121
|
+
const DOC_DRIFT_PATTERNS = [
|
|
122
|
+
/(?:^|\/)src\/.*\.(ts|js)$/, // New or changed source files
|
|
123
|
+
/(?:^|\/)templates\/agents\//, // New or changed agent definitions
|
|
124
|
+
/(?:^|\/)templates\/skills\//, // New or changed skill definitions
|
|
125
|
+
/(?:^|\/)templates\/hooks\//, // New or changed hook definitions
|
|
126
|
+
/(?:^|\/)src\/init\.(ts|js)$/, // Installer changes
|
|
127
|
+
/(?:^|\/)src\/cli\.(ts|js)$/, // CLI entry point changes
|
|
128
|
+
/(?:^|\/)bin\//, // CLI shim changes
|
|
129
|
+
/(?:^|\/)package\.json$/, // Dependency or script changes
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
// Only flag for doc-drift if Tufte was not already flagged for a direct doc change
|
|
133
|
+
const alreadyFlaggedTufte = flags.some((f) => f.startsWith("@dev-team-tufte"));
|
|
134
|
+
if (!alreadyFlaggedTufte && DOC_DRIFT_PATTERNS.some((p) => p.test(fullPath))) {
|
|
135
|
+
flags.push("@dev-team-tufte (implementation changed — check for doc drift)");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Architecture patterns → flag for Architect. For architectural boundary files,
|
|
139
|
+
// Brooks is flagged here with the "architectural boundary touched" reason. The
|
|
140
|
+
// dedupe check below skips the generic "quality attribute review" reason for
|
|
141
|
+
// these files — this is intentional because Brooks's expanded agent definition
|
|
142
|
+
// already includes quality attribute assessment in every review.
|
|
127
143
|
const ARCH_PATTERNS = [
|
|
128
144
|
/\/adr\//,
|
|
129
145
|
/architecture/,
|
|
@@ -163,12 +179,49 @@ if (RELEASE_PATTERNS.some((p) => p.test(fullPath))) {
|
|
|
163
179
|
flags.push("@dev-team-conway (version/release artifact changed)");
|
|
164
180
|
}
|
|
165
181
|
|
|
166
|
-
//
|
|
182
|
+
// Operations/infra patterns → flag for Hamilton
|
|
183
|
+
// NOTE: Docker and .env patterns intentionally overlap with INFRA_PATTERNS (Voss).
|
|
184
|
+
// Voss reviews Docker files for infrastructure correctness (base images, build stages, networking),
|
|
185
|
+
// while Hamilton reviews them for operational concerns (resource limits, health checks, image optimization).
|
|
186
|
+
// This dual-review is by design — both perspectives add value.
|
|
187
|
+
const OPS_PATTERNS = [
|
|
188
|
+
/dockerfile/,
|
|
189
|
+
/docker-compose/,
|
|
190
|
+
/\.dockerignore$/,
|
|
191
|
+
/\.github\/workflows\//,
|
|
192
|
+
/\.gitlab-ci/,
|
|
193
|
+
/jenkinsfile/i,
|
|
194
|
+
/terraform\//,
|
|
195
|
+
/pulumi\//,
|
|
196
|
+
/cloudformation\//,
|
|
197
|
+
/helm\//,
|
|
198
|
+
/k8s\//,
|
|
199
|
+
/\.tf$/,
|
|
200
|
+
/\.tfvars$/,
|
|
201
|
+
/health[-_]?check/,
|
|
202
|
+
/(?:^|\/)(?:monitoring|prometheus|grafana|datadog)\.(?:ya?ml|json|conf|config|toml)$/, // monitoring config files (not src/monitoring.ts)
|
|
203
|
+
/(?:^|\/)(?:logging|logs)\.(?:ya?ml|json|conf|config|toml)$/, // logging config files (not src/logging.ts)
|
|
204
|
+
/(?:^|\/)(?:alerting|alerts?)\.(?:ya?ml|json|conf|config|toml)$/, // alerting config files
|
|
205
|
+
/(?:^|\/)(?:observability|otel|opentelemetry)\.(?:ya?ml|json|conf|config|toml)$/, // observability config files
|
|
206
|
+
/(?<!\/src)\/(?:monitoring|logging|alerting|observability)\//, // ops directories (but not under src/)
|
|
207
|
+
/\.env\.example$/,
|
|
208
|
+
/\.env\.template$/,
|
|
209
|
+
/env\.template$/,
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
if (OPS_PATTERNS.some((p) => p.test(fullPath) || p.test(basename))) {
|
|
213
|
+
flags.push("@dev-team-hamilton (infrastructure/operations change)");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Always flag Knuth and Brooks for non-test implementation files
|
|
167
217
|
const isTestFile = /\.(test|spec)\.|__tests__|\/tests?\//.test(fullPath);
|
|
168
218
|
const isCodeFile = /\.(js|ts|jsx|tsx|py|rb|go|java|rs|c|cpp|cs)$/.test(fullPath);
|
|
169
219
|
|
|
170
220
|
if (isCodeFile && !isTestFile) {
|
|
171
221
|
flags.push("@dev-team-knuth (new or changed code path to audit)");
|
|
222
|
+
if (!flags.some((f) => f.startsWith("@dev-team-brooks"))) {
|
|
223
|
+
flags.push("@dev-team-brooks (quality attribute review)");
|
|
224
|
+
}
|
|
172
225
|
}
|
|
173
226
|
|
|
174
227
|
// Flag Beck for test file changes (test quality review)
|
|
@@ -29,19 +29,40 @@ function cachedGitDiff(args, timeoutMs) {
|
|
|
29
29
|
const cwdHash = createHash("md5").update(process.cwd()).digest("hex").slice(0, 8);
|
|
30
30
|
const argsKey = args.join("-").replace(/[^a-zA-Z0-9-]/g, "");
|
|
31
31
|
const cacheFile = path.join(os.tmpdir(), `dev-team-git-cache-${cwdHash}-${argsKey}.txt`);
|
|
32
|
+
let skipWrite = false;
|
|
32
33
|
try {
|
|
33
|
-
const stat = fs.
|
|
34
|
-
|
|
34
|
+
const stat = fs.lstatSync(cacheFile);
|
|
35
|
+
// Reject symlinks to prevent symlink attacks (attacker could point cache
|
|
36
|
+
// file at a sensitive path and have us overwrite it on the next write)
|
|
37
|
+
if (stat.isSymbolicLink()) {
|
|
38
|
+
try {
|
|
39
|
+
fs.unlinkSync(cacheFile);
|
|
40
|
+
} catch {
|
|
41
|
+
// If we can't remove the symlink, skip writing to avoid following it
|
|
42
|
+
skipWrite = true;
|
|
43
|
+
}
|
|
44
|
+
} else if (Date.now() - stat.mtimeMs < 5000) {
|
|
35
45
|
return fs.readFileSync(cacheFile, "utf-8");
|
|
36
46
|
}
|
|
37
47
|
} catch {
|
|
38
48
|
// No cache or stale — fall through to git call
|
|
39
49
|
}
|
|
40
50
|
const result = execFileSync("git", args, { encoding: "utf-8", timeout: timeoutMs });
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
if (!skipWrite) {
|
|
52
|
+
try {
|
|
53
|
+
// Atomic write: write to a temp file then rename to close the TOCTOU window
|
|
54
|
+
const tmpFile = `${cacheFile}.${process.pid}.tmp`;
|
|
55
|
+
fs.writeFileSync(tmpFile, result, { mode: 0o600 });
|
|
56
|
+
fs.renameSync(tmpFile, cacheFile);
|
|
57
|
+
// Best-effort permission tightening for cache files from older versions
|
|
58
|
+
try {
|
|
59
|
+
fs.chmodSync(cacheFile, 0o600);
|
|
60
|
+
} catch {
|
|
61
|
+
/* best effort */
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// Best effort — don't fail the hook over caching
|
|
65
|
+
}
|
|
45
66
|
}
|
|
46
67
|
return result;
|
|
47
68
|
}
|
|
@@ -29,19 +29,40 @@ function cachedGitDiff(args, timeoutMs) {
|
|
|
29
29
|
const cwdHash = createHash("md5").update(process.cwd()).digest("hex").slice(0, 8);
|
|
30
30
|
const argsKey = args.join("-").replace(/[^a-zA-Z0-9-]/g, "");
|
|
31
31
|
const cacheFile = path.join(os.tmpdir(), `dev-team-git-cache-${cwdHash}-${argsKey}.txt`);
|
|
32
|
+
let skipWrite = false;
|
|
32
33
|
try {
|
|
33
|
-
const stat = fs.
|
|
34
|
-
|
|
34
|
+
const stat = fs.lstatSync(cacheFile);
|
|
35
|
+
// Reject symlinks to prevent symlink attacks (attacker could point cache
|
|
36
|
+
// file at a sensitive path and have us overwrite it on the next write)
|
|
37
|
+
if (stat.isSymbolicLink()) {
|
|
38
|
+
try {
|
|
39
|
+
fs.unlinkSync(cacheFile);
|
|
40
|
+
} catch {
|
|
41
|
+
// If we can't remove the symlink, skip writing to avoid following it
|
|
42
|
+
skipWrite = true;
|
|
43
|
+
}
|
|
44
|
+
} else if (Date.now() - stat.mtimeMs < 5000) {
|
|
35
45
|
return fs.readFileSync(cacheFile, "utf-8");
|
|
36
46
|
}
|
|
37
47
|
} catch {
|
|
38
48
|
// No cache or stale — fall through to git call
|
|
39
49
|
}
|
|
40
50
|
const result = execFileSync("git", args, { encoding: "utf-8", timeout: timeoutMs });
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
if (!skipWrite) {
|
|
52
|
+
try {
|
|
53
|
+
// Atomic write: write to a temp file then rename to close the TOCTOU window
|
|
54
|
+
const tmpFile = `${cacheFile}.${process.pid}.tmp`;
|
|
55
|
+
fs.writeFileSync(tmpFile, result, { mode: 0o600 });
|
|
56
|
+
fs.renameSync(tmpFile, cacheFile);
|
|
57
|
+
// Best-effort permission tightening for cache files from older versions
|
|
58
|
+
try {
|
|
59
|
+
fs.chmodSync(cacheFile, 0o600);
|
|
60
|
+
} catch {
|
|
61
|
+
/* best effort */
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// Best effort — don't fail the hook over caching
|
|
65
|
+
}
|
|
45
66
|
}
|
|
46
67
|
return result;
|
|
47
68
|
}
|