role-os 1.0.2 → 1.1.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/CHANGELOG.md +55 -0
- package/README.md +54 -23
- package/bin/roleos.mjs +8 -1
- package/package.json +13 -3
- package/src/conflicts.mjs +217 -0
- package/src/dispatch.mjs +310 -0
- package/src/escalation.mjs +288 -0
- package/src/evidence.mjs +288 -0
- package/src/packs-cmd.mjs +143 -0
- package/src/packs.mjs +244 -0
- package/src/review.mjs +12 -0
- package/src/route.mjs +442 -82
- package/src/trial.mjs +252 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
#### Routing
|
|
8
|
+
- Full 31-role catalog — all roles scored by keyword, trigger phrase, packet type bias, and deliverable affinity
|
|
9
|
+
- Dynamic chain builder — phase-ordered assembly replacing static templates
|
|
10
|
+
- Routing confidence assessment (high/medium/low)
|
|
11
|
+
- `excludeWhen` enforcement — roles suppressed when exclusion patterns match packet content
|
|
12
|
+
- `detectType` false-positive prevention — "integration testing" no longer triggers integration type
|
|
13
|
+
- `--verbose` flag for `roleos route` — hides scoring noise by default
|
|
14
|
+
|
|
15
|
+
#### Conflict Detection
|
|
16
|
+
- 4-pass conflict engine: hard conflicts, sequence, redundancy, coverage gaps
|
|
17
|
+
- Per-role constraint registry: lateOnly, requiresBeforePacks
|
|
18
|
+
- Overlap pair detection
|
|
19
|
+
- Repair suggestions on every finding
|
|
20
|
+
|
|
21
|
+
#### Escalation Auto-Routing
|
|
22
|
+
- Blocked/rejected/conflict/split work auto-routes to named resolver
|
|
23
|
+
- Every escalation includes: target role, recovery type, required artifact, handoff context
|
|
24
|
+
|
|
25
|
+
#### Structured Evidence
|
|
26
|
+
- 12 evidence kinds, 4 statuses, closed 4-verdict enum (accept/accept-with-notes/reject/blocked)
|
|
27
|
+
- Role-aware evidence requirements for 15 roles
|
|
28
|
+
- Sufficiency checks with contradiction detection
|
|
29
|
+
|
|
30
|
+
#### Runtime Dispatch
|
|
31
|
+
- Execution manifests for multi-claude with per-role tool profiles and budgets
|
|
32
|
+
- 8 execution states with auto-advance
|
|
33
|
+
- Escalation packet generation for blocked/rejected steps
|
|
34
|
+
|
|
35
|
+
#### Proven Team Packs
|
|
36
|
+
- 7 battle-tested packs: feature, bugfix, security, docs, launch, research, treatment
|
|
37
|
+
- `roleos packs list` — show all packs with role counts
|
|
38
|
+
- `roleos packs suggest <packet>` — suggest best pack for a packet
|
|
39
|
+
- `roleos packs show <name>` — show pack details (roles, artifacts, stop conditions)
|
|
40
|
+
- Pack suggestion engine with confidence levels
|
|
41
|
+
|
|
42
|
+
#### Trials
|
|
43
|
+
- Full roster proven: 30/30 gold-task trials + 5/5 negative (wrong-task honesty) trials
|
|
44
|
+
- 7 pack execution trials — all packs ran full chains with honest Critic verdicts
|
|
45
|
+
- Trial framework: buildClusterTrials, evaluateTrialOutput, formatTrialReport
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- 32 → 31 roles: Information Architect merged into Docs Architect
|
|
49
|
+
- Verdict vocabulary unified: evidence.mjs now uses accept/reject/blocked (matching review.mjs)
|
|
50
|
+
- "worker" terminology replaced with "role" in dispatch.mjs
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- `excludeWhen` was declared on 14 roles but never enforced — now active in scoreRole
|
|
54
|
+
- `detectType` false-positived on "integration testing" — now uses word-boundary regex
|
|
55
|
+
- "Not triggered: N roles" noise hidden by default (shown with --verbose)
|
|
56
|
+
- Handbook: Team Packs page added, reference sidebar reordered
|
|
57
|
+
|
|
3
58
|
## 1.0.2
|
|
4
59
|
|
|
5
60
|
### Fixed
|
package/README.md
CHANGED
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
<a href="https://mcp-tool-shop-org.github.io/role-os/"><img src="https://img.shields.io/badge/Landing_Page-live-brightgreen" alt="Landing Page"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
A
|
|
18
|
+
A multi-Claude operating system that staffs, routes, validates, and runs work through 31 specialized role contracts. Creates task packets, assembles the right team from scored role matching, detects broken chains before execution, auto-routes recovery when work is blocked or rejected, and requires structured evidence in every verdict.
|
|
19
19
|
|
|
20
20
|
## What it does
|
|
21
21
|
|
|
22
|
-
Role OS prevents the specific failures that generic AI workflows produce:
|
|
22
|
+
Role OS is the professional way to use multi-Claude. It prevents the specific failures that generic AI workflows produce:
|
|
23
23
|
|
|
24
24
|
- **Drift** — roles stay in lane. Product doesn't redesign. Frontend doesn't redefine scope. Backend doesn't invent product direction.
|
|
25
25
|
- **False completion** — the done definition is concrete. Work that hides gaps, skips verification, or solves a different problem gets rejected.
|
|
@@ -29,9 +29,15 @@ Role OS prevents the specific failures that generic AI workflows produce:
|
|
|
29
29
|
## How it works
|
|
30
30
|
|
|
31
31
|
1. **Create a packet** — define what needs to exist when the work is done
|
|
32
|
-
2. **Route through a chain** —
|
|
33
|
-
3. **
|
|
34
|
-
4. **
|
|
32
|
+
2. **Route through a chain** — `roleos route` scores all 31 roles against the packet content, assembles a dynamic chain ordered by work phase, and explains why each role was chosen
|
|
33
|
+
3. **Validate the team** — 4-pass conflict detection catches hard conflicts, sequence errors, redundancy, and coverage gaps before execution starts
|
|
34
|
+
4. **Each role produces a handoff** — structured output with evidence items that reduce ambiguity for the next role
|
|
35
|
+
5. **Critic reviews against contract** — accepts, rejects, or blocks based on structured evidence, not impression
|
|
36
|
+
6. **Recovery routes automatically** — blocked or rejected work gets routed to the right resolver with a reason, recovery type, and required artifact
|
|
37
|
+
|
|
38
|
+
## Org rollout state
|
|
39
|
+
|
|
40
|
+
Org-wide rollout state (queue, decisions, audit records, per-repo lock packets) lives in a separate private repo: [`role-os-rollout`](https://github.com/mcp-tool-shop-org/role-os-rollout). This repo is the product; that repo is operational state.
|
|
35
41
|
|
|
36
42
|
## Memory and continuity
|
|
37
43
|
|
|
@@ -47,7 +53,7 @@ Full treatment is a canonical 7-phase protocol defined in Claude project memory
|
|
|
47
53
|
|
|
48
54
|
Order: Shipcheck first, then full treatment. No v1.0.0 without passing hard gates.
|
|
49
55
|
|
|
50
|
-
##
|
|
56
|
+
## 31 roles across 8 packs
|
|
51
57
|
|
|
52
58
|
| Pack | Roles |
|
|
53
59
|
|------|-------|
|
|
@@ -56,11 +62,11 @@ Order: Shipcheck first, then full treatment. No v1.0.0 without passing hard gate
|
|
|
56
62
|
| **Design** (2) | UI Designer, Brand Guardian |
|
|
57
63
|
| **Marketing** (1) | Launch Copywriter |
|
|
58
64
|
| **Treatment** (7) | Repo Researcher, Repo Translator, Docs Architect, Metadata Curator, Coverage Auditor, Deployment Verifier, Release Engineer |
|
|
59
|
-
| **Product** (
|
|
65
|
+
| **Product** (3) | Feedback Synthesizer, Roadmap Prioritizer, Spec Writer |
|
|
60
66
|
| **Research** (4) | UX Researcher, Competitive Analyst, Trend Researcher, User Interview Synthesizer |
|
|
61
67
|
| **Growth** (4) | Launch Strategist, Content Strategist, Community Manager, Support Triage Lead |
|
|
62
68
|
|
|
63
|
-
Every role has a full contract: mission, use when, do not use when, expected inputs, required outputs, quality bar, and escalation triggers.
|
|
69
|
+
Every role has a full contract: mission, use when, do not use when, expected inputs, required outputs, quality bar, and escalation triggers. Every role is routable — `roleos route` can recommend any of them based on packet content.
|
|
64
70
|
|
|
65
71
|
## Quick start
|
|
66
72
|
|
|
@@ -124,32 +130,57 @@ These are non-negotiable. If a change weakens any of them, reject it.
|
|
|
124
130
|
|
|
125
131
|
```
|
|
126
132
|
role-os/
|
|
127
|
-
README.md ← You are here
|
|
128
133
|
bin/roleos.mjs ← CLI entrypoint
|
|
129
|
-
src/
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
src/
|
|
135
|
+
route.mjs ← 31-role routing + dynamic chain builder
|
|
136
|
+
conflicts.mjs ← 4-pass conflict detection
|
|
137
|
+
escalation.mjs ← Auto-routing for blocked/rejected/split
|
|
138
|
+
evidence.mjs ← Structured evidence + role-aware requirements
|
|
139
|
+
dispatch.mjs ← Runtime dispatch manifests for multi-claude
|
|
140
|
+
trial.mjs ← Role execution trial framework
|
|
141
|
+
packet.mjs ← Packet creation
|
|
142
|
+
review.mjs ← Verdict recording + escalation integration
|
|
143
|
+
status.mjs ← Active packet + verdict status
|
|
144
|
+
test/
|
|
145
|
+
route.test.mjs ← 49 tests (routing + disambiguation)
|
|
146
|
+
conflicts.test.mjs ← 13 tests (4 conflict types)
|
|
147
|
+
escalation.test.mjs ← 22 tests (blocked/rejected/conflict/split)
|
|
148
|
+
evidence.test.mjs ← 23 tests (schema + sufficiency)
|
|
149
|
+
dispatch.test.mjs ← 21 tests (manifests + state + escalation packets)
|
|
150
|
+
trial.test.mjs ← 12 tests (trial framework)
|
|
151
|
+
cli.test.mjs ← 22 tests (CLI integration)
|
|
152
|
+
.claude/
|
|
153
|
+
agents/ ← 31 role contracts across 8 packs
|
|
135
154
|
schemas/ ← Packet, handoff, verdict formats
|
|
136
|
-
policy/ ← Routing, permissions, escalation, done
|
|
155
|
+
policy/ ← Routing rules, permissions, escalation, done
|
|
137
156
|
workflows/ ← Ship feature, fix bug, launch update, full treatment
|
|
157
|
+
context/ ← Fill these for your repo
|
|
158
|
+
trials/ ← Execution trial packets + results
|
|
138
159
|
```
|
|
139
160
|
|
|
140
161
|
## Security
|
|
141
162
|
|
|
142
163
|
Role OS operates **locally only**. It copies markdown templates and writes packet/verdict files to your repository's `.claude/` directory. It does not access the network, handle secrets, or collect telemetry. No dangerous operations — all file writes use skip-if-exists by default. See [SECURITY.md](SECURITY.md) for the full policy.
|
|
143
164
|
|
|
144
|
-
##
|
|
165
|
+
## The operating system
|
|
166
|
+
|
|
167
|
+
| Layer | What it does | Status |
|
|
168
|
+
|-------|-------------|--------|
|
|
169
|
+
| **Routing** | Scores all 31 roles against packet content, explains recommendations, assesses confidence | ✓ Shipped |
|
|
170
|
+
| **Chain builder** | Assembles phase-ordered chains from scored roles, packet-type biased not template-locked | ✓ Shipped |
|
|
171
|
+
| **Conflict detection** | 4-pass validation: hard conflicts, sequence, redundancy, coverage gaps. Repair suggestions. | ✓ Shipped |
|
|
172
|
+
| **Escalation** | Auto-routes blocked/rejected/split work to the right resolver with reason + required artifact | ✓ Shipped |
|
|
173
|
+
| **Evidence** | Role-aware structured evidence in verdicts. Sufficiency checks. 12 evidence kinds. | ✓ Shipped |
|
|
174
|
+
| **Dispatch** | Generates execution manifests for multi-claude. Per-role tool profiles, system prompts, budgets. | ✓ Shipped |
|
|
175
|
+
| **Trials** | Full roster proven: 30/30 gold-task + 5/5 negative trials. 7 pack trials complete. | ✓ Complete |
|
|
176
|
+
| **Team Packs** | 7 battle-tested packs for common task families. Pack suggestion engine. | ✓ Shipped |
|
|
145
177
|
|
|
146
|
-
|
|
178
|
+
## Status
|
|
147
179
|
|
|
148
|
-
- v0.1:
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
-
|
|
152
|
-
- v1.0.0: 32 roles across 8 packs, full CLI, proven treatment, multi-repo portability
|
|
180
|
+
- v0.1–v0.4: Foundation — trials, adoption, treatment pack, starter pack
|
|
181
|
+
- v1.0.0: 32 roles, full CLI, proven treatment, multi-repo portability
|
|
182
|
+
- v1.0.2: Role OS lockdown (bootstrap truth fixes, init --force)
|
|
183
|
+
- **v1.1.0**: 31 roles, full routing spine, conflict detection, escalation, evidence, dispatch, 7 proven team packs. 35 execution trials (30 gold + 5 negative). 212 tests.
|
|
153
184
|
|
|
154
185
|
## License
|
|
155
186
|
|
package/bin/roleos.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { packetCommand } from "../src/packet.mjs";
|
|
|
8
8
|
import { routeCommand } from "../src/route.mjs";
|
|
9
9
|
import { reviewCommand } from "../src/review.mjs";
|
|
10
10
|
import { statusCommand } from "../src/status.mjs";
|
|
11
|
+
import { packsCommand } from "../src/packs-cmd.mjs";
|
|
11
12
|
|
|
12
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
14
|
const VERSION = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")).version;
|
|
@@ -20,11 +21,14 @@ Usage:
|
|
|
20
21
|
roleos init Scaffold Role OS into .claude/
|
|
21
22
|
roleos init --force Update canonical files (protects context/)
|
|
22
23
|
roleos packet new <type> Create a new packet (feature|integration|identity)
|
|
23
|
-
roleos route <packet-file>
|
|
24
|
+
roleos route <packet-file> [--verbose] Recommend the smallest valid chain
|
|
24
25
|
roleos review <packet-file> <verdict> Record a review verdict
|
|
25
26
|
roleos status Show active work, verdicts, and health
|
|
26
27
|
roleos status --write Write .claude/status/index.md
|
|
27
28
|
roleos status --json Output as JSON
|
|
29
|
+
roleos packs list List all available team packs
|
|
30
|
+
roleos packs suggest <packet-file> Suggest a pack for a packet
|
|
31
|
+
roleos packs show <pack-key> Show full detail for a named pack
|
|
28
32
|
roleos help Show this help
|
|
29
33
|
|
|
30
34
|
Verdicts: accept | accept-with-notes | reject | blocked
|
|
@@ -74,6 +78,9 @@ try {
|
|
|
74
78
|
case "status":
|
|
75
79
|
await statusCommand(args);
|
|
76
80
|
break;
|
|
81
|
+
case "packs":
|
|
82
|
+
await packsCommand(args);
|
|
83
|
+
break;
|
|
77
84
|
case "help":
|
|
78
85
|
case "--help":
|
|
79
86
|
case "-h":
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "role-os",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Role OS — a
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Role OS — a multi-Claude operating system where 31 specialized roles execute work through contracts, conflict detection, escalation, and structured evidence. 7 proven team packs for common task families.",
|
|
5
|
+
"homepage": "https://mcp-tool-shop-org.github.io/role-os/",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/mcp-tool-shop-org/role-os/issues"
|
|
8
|
+
},
|
|
5
9
|
"type": "module",
|
|
6
10
|
"bin": {
|
|
7
11
|
"roleos": "bin/roleos.mjs"
|
|
@@ -33,7 +37,13 @@
|
|
|
33
37
|
"contracts",
|
|
34
38
|
"handoffs",
|
|
35
39
|
"review",
|
|
36
|
-
"workflow"
|
|
40
|
+
"workflow",
|
|
41
|
+
"multi-agent",
|
|
42
|
+
"ai-workflow",
|
|
43
|
+
"developer-tools",
|
|
44
|
+
"role-contracts",
|
|
45
|
+
"claude",
|
|
46
|
+
"multi-claude"
|
|
37
47
|
],
|
|
38
48
|
"publishConfig": {
|
|
39
49
|
"registry": "https://registry.npmjs.org"
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role conflict detection.
|
|
3
|
+
*
|
|
4
|
+
* Tells the operator when the staffed team is internally broken
|
|
5
|
+
* before work starts. Four passes: hard conflicts, sequence,
|
|
6
|
+
* redundancy, coverage gaps. Every finding includes a repair suggestion.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ── Per-role constraints ──────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
const ROLE_CONSTRAINTS = {
|
|
12
|
+
"Critic Reviewer": {
|
|
13
|
+
lateOnly: true,
|
|
14
|
+
requiresBeforePacks: ["engineering", "design", "treatment", "product"],
|
|
15
|
+
description: "review/gate role — needs something to review",
|
|
16
|
+
},
|
|
17
|
+
"Test Engineer": {
|
|
18
|
+
lateOnly: true,
|
|
19
|
+
requiresBeforePacks: ["engineering", "design"],
|
|
20
|
+
description: "test role — needs something to test",
|
|
21
|
+
},
|
|
22
|
+
"Coverage Auditor": {
|
|
23
|
+
lateOnly: true,
|
|
24
|
+
requiresBeforePacks: ["engineering"],
|
|
25
|
+
description: "coverage role — needs code to audit",
|
|
26
|
+
},
|
|
27
|
+
"Deployment Verifier": {
|
|
28
|
+
lateOnly: true,
|
|
29
|
+
requiresBeforePacks: ["engineering", "treatment"],
|
|
30
|
+
description: "verification role — needs something deployed to verify",
|
|
31
|
+
},
|
|
32
|
+
"Release Engineer": {
|
|
33
|
+
lateOnly: true,
|
|
34
|
+
requiresBeforePacks: ["engineering", "treatment"],
|
|
35
|
+
description: "release role — needs built or prepared artifacts to release",
|
|
36
|
+
},
|
|
37
|
+
"Launch Copywriter": {
|
|
38
|
+
requiresBeforePacks: ["engineering", "design", "product"],
|
|
39
|
+
description: "messaging role — needs product substance to write about",
|
|
40
|
+
},
|
|
41
|
+
"Launch Strategist": {
|
|
42
|
+
requiresBeforePacks: ["engineering", "design", "product"],
|
|
43
|
+
description: "launch role — needs product substance to plan launch around",
|
|
44
|
+
},
|
|
45
|
+
"Content Strategist": {
|
|
46
|
+
requiresBeforePacks: ["engineering", "design", "product"],
|
|
47
|
+
description: "content role — needs product substance for content planning",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// ── Overlap declarations ──────────────────────────────────────────────────────
|
|
52
|
+
// Roles that produce similar artifacts and rarely both need to be in the same chain.
|
|
53
|
+
|
|
54
|
+
const OVERLAP_PAIRS = [
|
|
55
|
+
["Coverage Auditor", "Test Engineer", "both assess test quality — consider keeping only one unless scope is very large"],
|
|
56
|
+
["Repo Researcher", "Docs Architect", "both map repo structure — Researcher maps truth, Architect builds docs from it"],
|
|
57
|
+
["Launch Strategist", "Launch Copywriter", "both serve launches — Strategist plans, Copywriter writes. Both needed only for major launches"],
|
|
58
|
+
["Competitive Analyst", "Trend Researcher", "both scan external landscape — consider whether one covers the need"],
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// ── Builder packs (roles that produce primary artifacts) ──────────────────────
|
|
62
|
+
|
|
63
|
+
const BUILDER_PACKS = new Set(["engineering", "design", "product", "treatment"]);
|
|
64
|
+
|
|
65
|
+
// ── Pack limits ───────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
const MAX_SAME_PACK = 3;
|
|
68
|
+
|
|
69
|
+
// ── Detection engine ──────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Detect conflicts in a staffed chain.
|
|
73
|
+
*
|
|
74
|
+
* @param {Array<{role: {name: string, pack: string, phase: number}}>} chainRoles
|
|
75
|
+
* @returns {Array<{type: string, severity: string, roles: string[], message: string, repair: string}>}
|
|
76
|
+
*/
|
|
77
|
+
export function detectConflicts(chainRoles) {
|
|
78
|
+
const findings = [];
|
|
79
|
+
const names = chainRoles.map(r => r.role.name);
|
|
80
|
+
const packs = chainRoles.map(r => r.role.pack);
|
|
81
|
+
const roles = chainRoles.map(r => r.role);
|
|
82
|
+
|
|
83
|
+
// ── Pass 1: Hard conflicts ──────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
// Check if review/gate roles are the only non-Orchestrator roles (no builders)
|
|
86
|
+
const nonCore = roles.filter(r => r.name !== "Orchestrator" && r.name !== "Critic Reviewer");
|
|
87
|
+
const builders = nonCore.filter(r => BUILDER_PACKS.has(r.pack));
|
|
88
|
+
|
|
89
|
+
if (builders.length === 0 && nonCore.length > 0) {
|
|
90
|
+
const nonCoreNames = nonCore.map(r => r.name);
|
|
91
|
+
findings.push({
|
|
92
|
+
type: "blocking",
|
|
93
|
+
severity: "error",
|
|
94
|
+
roles: nonCoreNames,
|
|
95
|
+
message: `Chain has no builder roles (engineering, design, product, or treatment). Only gate/growth/research roles present: ${nonCoreNames.join(", ")}.`,
|
|
96
|
+
repair: "Add at least one role that produces a primary artifact (e.g., Backend Engineer, UI Designer, Spec Writer).",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ── Pass 2: Sequence conflicts ──────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
for (const [roleName, constraints] of Object.entries(ROLE_CONSTRAINTS)) {
|
|
103
|
+
const roleIdx = names.indexOf(roleName);
|
|
104
|
+
if (roleIdx === -1) continue; // role not in chain
|
|
105
|
+
|
|
106
|
+
if (constraints.requiresBeforePacks) {
|
|
107
|
+
// Check if any role from the required packs appears BEFORE this role
|
|
108
|
+
const hasPriorBuilder = roles.slice(0, roleIdx).some(
|
|
109
|
+
r => constraints.requiresBeforePacks.includes(r.pack)
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (!hasPriorBuilder && builders.length > 0) {
|
|
113
|
+
// There ARE builders, but they're all AFTER this role
|
|
114
|
+
findings.push({
|
|
115
|
+
type: "sequence",
|
|
116
|
+
severity: "warning",
|
|
117
|
+
roles: [roleName],
|
|
118
|
+
message: `${roleName} (${constraints.description}) appears before any ${constraints.requiresBeforePacks.join("/")} role in the chain.`,
|
|
119
|
+
repair: `Move ${roleName} later in the chain, after the roles that produce what it needs.`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (builders.length === 0 && !constraints.lateOnly) {
|
|
124
|
+
// No builders at all — this was caught in Pass 1, skip double-reporting
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (constraints.lateOnly) {
|
|
129
|
+
// Check if this role appears in the first half of the chain (before most work)
|
|
130
|
+
const midpoint = Math.floor(chainRoles.length / 2);
|
|
131
|
+
if (roleIdx > 0 && roleIdx < midpoint && chainRoles.length > 3) {
|
|
132
|
+
findings.push({
|
|
133
|
+
type: "sequence",
|
|
134
|
+
severity: "warning",
|
|
135
|
+
roles: [roleName],
|
|
136
|
+
message: `${roleName} is a late-chain role but appears in the first half (position ${roleIdx + 1} of ${chainRoles.length}).`,
|
|
137
|
+
repair: `Move ${roleName} toward the end of the chain where it can act on completed work.`,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ── Pass 3: Redundancy ──────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
// Pack density check
|
|
146
|
+
const packCounts = {};
|
|
147
|
+
for (const pack of packs) {
|
|
148
|
+
packCounts[pack] = (packCounts[pack] || 0) + 1;
|
|
149
|
+
}
|
|
150
|
+
for (const [pack, count] of Object.entries(packCounts)) {
|
|
151
|
+
if (pack === "core") continue; // Orchestrator + Critic are always present
|
|
152
|
+
if (count > MAX_SAME_PACK) {
|
|
153
|
+
const packRoles = roles.filter(r => r.pack === pack).map(r => r.name);
|
|
154
|
+
findings.push({
|
|
155
|
+
type: "redundancy",
|
|
156
|
+
severity: "warning",
|
|
157
|
+
roles: packRoles,
|
|
158
|
+
message: `${count} roles from the "${pack}" pack: ${packRoles.join(", ")}. This may indicate an oversized or overlapping team.`,
|
|
159
|
+
repair: `Review whether all ${count} ${pack} roles are needed. Consider splitting into sub-packets if scope is broad.`,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Overlap pair check
|
|
165
|
+
for (const [roleA, roleB, note] of OVERLAP_PAIRS) {
|
|
166
|
+
if (names.includes(roleA) && names.includes(roleB)) {
|
|
167
|
+
findings.push({
|
|
168
|
+
type: "redundancy",
|
|
169
|
+
severity: "warning",
|
|
170
|
+
roles: [roleA, roleB],
|
|
171
|
+
message: `${roleA} and ${roleB} are both in the chain — ${note}.`,
|
|
172
|
+
repair: `Consider whether both are needed, or if one can cover the scope.`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── Pass 4: Coverage gaps ───────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
const engineeringCount = roles.filter(r => r.pack === "engineering").length;
|
|
180
|
+
const hasTestEngineer = names.includes("Test Engineer");
|
|
181
|
+
const hasCritic = names.includes("Critic Reviewer");
|
|
182
|
+
|
|
183
|
+
// Engineering-heavy with no tester
|
|
184
|
+
if (engineeringCount >= 2 && !hasTestEngineer) {
|
|
185
|
+
findings.push({
|
|
186
|
+
type: "coverage",
|
|
187
|
+
severity: "warning",
|
|
188
|
+
roles: roles.filter(r => r.pack === "engineering").map(r => r.name),
|
|
189
|
+
message: `Chain has ${engineeringCount} engineering roles but no Test Engineer. Code may ship without verification.`,
|
|
190
|
+
repair: "Add Test Engineer to verify the engineering output before review.",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Builders present but no critic (defensive — should be caught by always-include)
|
|
195
|
+
if (builders.length > 0 && !hasCritic) {
|
|
196
|
+
findings.push({
|
|
197
|
+
type: "coverage",
|
|
198
|
+
severity: "error",
|
|
199
|
+
roles: builders.map(r => r.name),
|
|
200
|
+
message: "Chain has builder roles but no Critic Reviewer. Work cannot be accepted without a final gate.",
|
|
201
|
+
repair: "Add Critic Reviewer as the final role in the chain.",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Large chain without Orchestrator (defensive)
|
|
206
|
+
if (chainRoles.length > 4 && !names.includes("Orchestrator")) {
|
|
207
|
+
findings.push({
|
|
208
|
+
type: "coverage",
|
|
209
|
+
severity: "warning",
|
|
210
|
+
roles: names,
|
|
211
|
+
message: "Chain has 5+ roles but no Orchestrator. Complex work needs coordination.",
|
|
212
|
+
repair: "Add Orchestrator at the start of the chain to decompose and sequence the work.",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return findings;
|
|
217
|
+
}
|