chati-dev 4.2.2 → 4.3.1
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/README.md +80 -53
- package/bin/chati.js +170 -5
- package/framework/agents/build/dev.md +509 -76
- package/framework/agents/deploy/devops.md +40 -25
- package/framework/agents/discover/brief.md +158 -22
- package/framework/agents/discover/brownfield-wu.md +26 -14
- package/framework/agents/discover/greenfield-wu.md +102 -14
- package/framework/agents/plan/architect-data-engineer.md +6 -6
- package/framework/agents/plan/architect-system.md +46 -12
- package/framework/agents/plan/architect.md +40 -20
- package/framework/agents/plan/detail.md +38 -24
- package/framework/agents/plan/phases.md +36 -26
- package/framework/agents/plan/tasks.md +114 -33
- package/framework/agents/plan/ux-brand-architect.md +240 -8
- package/framework/agents/plan/ux-component-engineer.md +28 -13
- package/framework/agents/plan/ux-researcher.md +7 -6
- package/framework/agents/plan/ux.md +55 -22
- package/framework/agents/quality/qa-implementation.md +143 -74
- package/framework/agents/quality/qa-planning.md +115 -42
- package/framework/agents/quality/qa-visual.md +448 -0
- package/framework/agents/shared/visualizer.md +128 -0
- package/framework/config.yaml +7 -6
- package/framework/constitution.md +127 -44
- package/framework/context/governance.md +12 -7
- package/framework/context/quality.md +6 -5
- package/framework/context/root.md +6 -6
- package/framework/data/entity-registry.yaml +377 -4
- package/framework/data/model-limits.json +19 -0
- package/framework/domains/agents/qa-visual.yaml +74 -0
- package/framework/domains/constitution.yaml +46 -2
- package/framework/domains/workflows/greenfield-fullstack.yaml +2 -2
- package/framework/hooks/advance-trigger.js +131 -0
- package/framework/hooks/brief-validator.js +83 -0
- package/framework/hooks/constitution-guard.js +24 -5
- package/framework/hooks/license-guard.js +62 -27
- package/framework/hooks/mode-governance.js +13 -2
- package/framework/hooks/model-governance.js +1 -0
- package/framework/hooks/post-dev.js +207 -0
- package/framework/hooks/prism-engine.js +274 -105
- package/framework/hooks/reasoning-escalator.js +371 -0
- package/framework/hooks/reference-trigger.js +117 -0
- package/framework/hooks/session-digest.js +50 -1
- package/framework/hooks/settings.json +32 -1
- package/framework/hooks/style-guard.js +25 -6
- package/framework/hooks/team-quality-gate.js +19 -12
- package/framework/hooks/undercover-guard.js +4 -2
- package/framework/i18n/en.yaml +3 -3
- package/framework/i18n/es.yaml +3 -3
- package/framework/i18n/fr.yaml +3 -3
- package/framework/i18n/pt.yaml +3 -3
- package/framework/intelligence/context-engine.md +4 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/intelligence/hooks-performance.md +3 -3
- package/framework/migrations/v1.0-to-v1.1.yaml +1 -1
- package/framework/migrations/v1.4-to-v2.0.yaml +11 -11
- package/framework/migrations/v4.0-to-v4.1.yaml +2 -2
- package/framework/migrations/v4.2-to-v4.3.yaml +29 -0
- package/framework/orchestrator/chati-router.js +441 -0
- package/framework/orchestrator/chati-update.md +40 -40
- package/framework/orchestrator/chati.md +295 -94
- package/framework/rules/human-writing-style.md +47 -0
- package/framework/scaffold/motion-premium/README.md +99 -0
- package/framework/scaffold/motion-premium/app/globals.css.template +400 -0
- package/framework/scaffold/motion-premium/app/layout.tsx.template +110 -0
- package/framework/scaffold/motion-premium/components/animation/BackgroundCrossfadeProvider.tsx.template +170 -0
- package/framework/scaffold/motion-premium/components/animation/LenisProvider.tsx.template +49 -0
- package/framework/scaffold/motion-premium/components/animation/PageTransitionWrapper.tsx.template +83 -0
- package/framework/scaffold/motion-premium/components/animation/Preloader.tsx.template +171 -0
- package/framework/scaffold/motion-premium/components/ui/Container.tsx.template +69 -0
- package/framework/scaffold/motion-premium/components/ui/PageSection.tsx.template +74 -0
- package/framework/scaffold/motion-premium/lib/animations/gsap.ts.template +112 -0
- package/framework/scaffold/motion-premium/lib/animations/refreshCoordinator.ts.template +75 -0
- package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +119 -0
- package/framework/scaffold/motion-premium/lib/animations/useGsapContext.ts.template +92 -0
- package/framework/scaffold/motion-premium/lib/animations/useScrollSnapStepper.ts.template +265 -0
- package/framework/scaffold/motion-premium/lib/animations/useSmoothScroll.ts.template +67 -0
- package/framework/scaffold/motion-premium/lib/brand.ts.template +43 -0
- package/framework/scaffold/motion-premium/scaffold.yaml +178 -0
- package/framework/scaffold/motion-premium-3d/README.md +90 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoCanvas.tsx.template +81 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoClient.tsx.template +75 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/page.tsx.template +26 -0
- package/framework/scaffold/motion-premium-3d/components/3d/CameraRig.tsx.template +100 -0
- package/framework/scaffold/motion-premium-3d/components/3d/CanvasProvider.tsx.template +85 -0
- package/framework/scaffold/motion-premium-3d/components/3d/InvalidateOnScroll.tsx.template +51 -0
- package/framework/scaffold/motion-premium-3d/components/3d/MeshCrossfade.tsx.template +79 -0
- package/framework/scaffold/motion-premium-3d/components/3d/ScrollCrossfade.tsx.template +88 -0
- package/framework/scaffold/motion-premium-3d/components/3d/ScrollScene.tsx.template +121 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/SceneFallback.tsx.template +65 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +68 -0
- package/framework/scaffold/motion-premium-3d/lib/webgl/detect.ts.template +69 -0
- package/framework/scaffold/motion-premium-3d/scaffold.yaml +136 -0
- package/framework/schemas/session.schema.json +109 -21
- package/framework/scripts/reference-capture.js +430 -0
- package/framework/scripts/visual-qa.js +686 -0
- package/framework/tasks/orchestrator-handoff.md +1 -1
- package/framework/tasks/orchestrator-resume.md +1 -1
- package/framework/tasks/orchestrator-route.md +1 -1
- package/framework/tasks/orchestrator-status.md +3 -3
- package/framework/tasks/qa-planning-gate-define.md +1 -1
- package/framework/templates/brandbook-html-tmpl.md +2 -2
- package/framework/templates/brandbook-tmpl.yaml +1 -1
- package/framework/templates/component-spec-tmpl.yaml +1 -1
- package/framework/templates/design-token-tmpl.yaml +1 -1
- package/framework/templates/icon-system-tmpl.yaml +1 -1
- package/framework/templates/team-planning-tasks.yaml +6 -5
- package/framework/workflows/brownfield-discovery.yaml +2 -2
- package/framework/workflows/brownfield-fullstack.yaml +15 -11
- package/framework/workflows/brownfield-service.yaml +14 -10
- package/framework/workflows/brownfield-ui.yaml +15 -11
- package/framework/workflows/greenfield-fullstack.yaml +16 -13
- package/framework/workflows/quick-flow.yaml +3 -3
- package/framework/workflows/standard-flow.yaml +12 -9
- package/package.json +12 -6
- package/src/autonomy/autonomous-gate.js +1 -0
- package/src/autonomy/build-state.js +1 -2
- package/src/autonomy/progress-reporter.js +1 -1
- package/src/config/agent-customizer.js +11 -3
- package/src/config/claude-settings-generator.js +27 -7
- package/src/config/context-file-generator.js +41 -21
- package/src/config/framework-adapter.js +1 -0
- package/src/config/gemini-hooks-generator.js +19 -7
- package/src/config/mcp-configs.js +1 -0
- package/src/context/layers/l1-global.js +2 -1
- package/src/dashboard/data-reader.js +4 -3
- package/src/dashboard/layout.js +2 -1
- package/src/decision/analyzer.js +6 -30
- package/src/decision/engine.js +4 -28
- package/src/decision/registry-healer.js +3 -2
- package/src/decision/registry-updater.js +23 -14
- package/src/extensions/loader.js +2 -8
- package/src/gates/g1-planning-complete.js +2 -1
- package/src/gates/g2-qa-planning.js +2 -1
- package/src/gates/g3-implementation.js +2 -1
- package/src/gates/g4-qa-implementation.js +3 -2
- package/src/gates/g5-deploy-ready.js +2 -1
- package/src/health/engine.js +4 -3
- package/src/installer/core.js +431 -81
- package/src/installer/preflight.js +131 -0
- package/src/installer/provider-overlay.js +3 -3
- package/src/installer/scaffold-applier.js +358 -0
- package/src/installer/templates.js +46 -29
- package/src/installer/validator.js +17 -12
- package/src/intelligence/registry-manager.js +22 -29
- package/src/intelligence/timeline.js +11 -6
- package/src/license/commands.js +1 -1
- package/src/license/wait.js +102 -0
- package/src/memory/agent-memory.js +81 -0
- package/src/memory/dream.js +32 -1
- package/src/merger/replace-merger.js +28 -15
- package/src/orchestrator/agent-selector.js +2 -1
- package/src/orchestrator/cli.js +1880 -71
- package/src/orchestrator/doctor.js +270 -0
- package/src/orchestrator/handoff-engine.js +4 -3
- package/src/orchestrator/index.js +2 -0
- package/src/orchestrator/pipeline-manager.js +306 -15
- package/src/orchestrator/session-manager.js +339 -6
- package/src/tasks/handoff.js +3 -2
- package/src/telemetry/config.js +4 -3
- package/src/telemetry/schema.js +1 -0
- package/src/terminal/collector.js +3 -2
- package/src/terminal/index.js +1 -2
- package/src/terminal/isolation.js +52 -18
- package/src/terminal/prompt-builder.js +42 -25
- package/src/terminal/run-parallel.js +1 -1
- package/src/terminal/run-team.js +3 -3
- package/src/terminal/team-task-list.js +43 -4
- package/src/upgrade/backup.js +3 -2
- package/src/upgrade/checker.js +3 -2
- package/src/upgrade/migrator.js +65 -7
- package/src/upgrade/tracked-files-detector.js +86 -0
- package/src/upgrade/user-messages.js +94 -0
- package/src/utils/config-parser.js +2 -1
- package/src/utils/feature-flags.js +2 -1
- package/src/utils/flatten-entities.js +69 -0
- package/src/utils/framework-dir.js +16 -0
- package/src/utils/model-id.js +85 -0
- package/src/utils/provider-limits.js +84 -23
- package/src/utils/schema-validator.js +1 -1
- package/src/wizard/i18n.js +5 -4
- package/src/wizard/index.js +14 -0
- package/assets/logo - c/303/263pia.png +0 -0
- package/assets/logo.svg +0 -42
- package/assets/logo2.png +0 -0
- package/assets/social-preview.png +0 -0
- package/scripts/bundle-framework.js +0 -69
- package/scripts/changelog-generator.js +0 -222
- package/scripts/codebase-mapper.js +0 -728
- package/scripts/commit-message-generator.js +0 -167
- package/scripts/coverage-analyzer.js +0 -260
- package/scripts/dependency-analyzer.js +0 -280
- package/scripts/doctor/checks/agents.js +0 -77
- package/scripts/doctor/checks/constitution.js +0 -41
- package/scripts/doctor/checks/domain-alignment.js +0 -58
- package/scripts/doctor/checks/prism-layers.js +0 -84
- package/scripts/doctor/checks/registry.js +0 -55
- package/scripts/doctor/checks/schemas.js +0 -61
- package/scripts/doctor/fixes/reference-fix.js +0 -100
- package/scripts/doctor/fixes/registry-fix.js +0 -56
- package/scripts/doctor/index.js +0 -212
- package/scripts/framework-analyzer.js +0 -308
- package/scripts/generate-constitution-domain.js +0 -253
- package/scripts/generate-signing-key.js +0 -33
- package/scripts/health-check.js +0 -481
- package/scripts/ide-sync.js +0 -326
- package/scripts/performance-analyzer.js +0 -325
- package/scripts/plan-tracker.js +0 -278
- package/scripts/populate-entity-registry.js +0 -481
- package/scripts/pr-review.js +0 -317
- package/scripts/rollback-manager.js +0 -310
- package/scripts/semantic-lint.js +0 -328
- package/scripts/sign-manifest.js +0 -53
- package/scripts/stuck-detector.js +0 -343
- package/scripts/test-quality-assessment.js +0 -257
- package/scripts/validate-agents.js +0 -368
- package/scripts/validate-package.js +0 -505
- package/scripts/validate-tasks.js +0 -465
- package/src/autonomy/worktree-manager.js +0 -250
- package/src/intelligence/decision-engine.js +0 -256
- package/src/intelligence/document-sharder.js +0 -221
- package/src/intelligence/elicitation.js +0 -265
|
@@ -55,6 +55,7 @@ export const AGENT_STATUS = {
|
|
|
55
55
|
COMPLETED: 'completed',
|
|
56
56
|
SKIPPED: 'skipped',
|
|
57
57
|
NEEDS_REVALIDATION: 'needs_revalidation',
|
|
58
|
+
PENDING_REWORK: 'pending_rework',
|
|
58
59
|
FAILED: 'failed',
|
|
59
60
|
};
|
|
60
61
|
|
|
@@ -63,6 +64,131 @@ export const AGENT_STATUS = {
|
|
|
63
64
|
*/
|
|
64
65
|
const QA_PLANNING_THRESHOLD = 95;
|
|
65
66
|
const QA_IMPLEMENTATION_THRESHOLD = 95;
|
|
67
|
+
const QA_VISUAL_THRESHOLD = 90;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Fault Vector Protocol (Article XXII) — max correction cycles per (QA, target) pair
|
|
71
|
+
* before escalating to human.
|
|
72
|
+
*/
|
|
73
|
+
export const MAX_CORRECTION_CYCLES = 2;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fault Vector Protocol routing table. Given a failing QA agent and the majority
|
|
77
|
+
* fault_origin of its Decision Trail entries, returns the agent that should
|
|
78
|
+
* re-work. Origins not listed default to UNKNOWN → each QA's primary rework target.
|
|
79
|
+
*/
|
|
80
|
+
const FVP_ROUTING = {
|
|
81
|
+
'qa-planning': {
|
|
82
|
+
INTENT: 'brief',
|
|
83
|
+
SPEC: 'architect',
|
|
84
|
+
CODE: 'detail',
|
|
85
|
+
UNKNOWN: 'architect',
|
|
86
|
+
},
|
|
87
|
+
'qa-implementation': {
|
|
88
|
+
INTENT: 'brief',
|
|
89
|
+
SPEC: 'tasks',
|
|
90
|
+
CODE: 'dev',
|
|
91
|
+
UNKNOWN: 'dev',
|
|
92
|
+
},
|
|
93
|
+
'qa-visual': {
|
|
94
|
+
INTENT: 'brief',
|
|
95
|
+
SPEC: 'ux',
|
|
96
|
+
CODE: 'dev',
|
|
97
|
+
UNKNOWN: 'dev',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* QA thresholds by agent name.
|
|
103
|
+
*/
|
|
104
|
+
const QA_THRESHOLDS = {
|
|
105
|
+
'qa-planning': QA_PLANNING_THRESHOLD,
|
|
106
|
+
'qa-implementation': QA_IMPLEMENTATION_THRESHOLD,
|
|
107
|
+
'qa-visual': QA_VISUAL_THRESHOLD,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Route a failing QA to the correct rework target via Fault Vector Protocol.
|
|
112
|
+
*
|
|
113
|
+
* @param {string} qaAgent - The QA agent that failed ('qa-planning' | 'qa-implementation' | 'qa-visual')
|
|
114
|
+
* @param {string} faultOrigin - INTENT | SPEC | CODE | DEFER | UNKNOWN
|
|
115
|
+
* @param {object} state - Pipeline state (used to honor brownfield greenfield-wu routing)
|
|
116
|
+
* @returns {{ nextAgent: string|null, reason: string }}
|
|
117
|
+
*/
|
|
118
|
+
export function routeByFaultVector(qaAgent, faultOrigin, state = {}) {
|
|
119
|
+
const origin = (faultOrigin || 'UNKNOWN').toUpperCase();
|
|
120
|
+
|
|
121
|
+
// DEFER = defect acknowledged but out of scope for current pipeline — no rework.
|
|
122
|
+
if (origin === 'DEFER') {
|
|
123
|
+
return { nextAgent: null, reason: `${qaAgent} flagged DEFER — logging only, no rework` };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const table = FVP_ROUTING[qaAgent];
|
|
127
|
+
if (!table) {
|
|
128
|
+
return { nextAgent: null, reason: `Unknown QA agent: ${qaAgent}` };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let target = table[origin] || table.UNKNOWN;
|
|
132
|
+
|
|
133
|
+
// Honor greenfield/brownfield: INTENT issues in brownfield route to brownfield-wu
|
|
134
|
+
if (origin === 'INTENT' && state.isGreenfield === false) {
|
|
135
|
+
target = 'brownfield-wu';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
nextAgent: target,
|
|
140
|
+
reason: `${qaAgent} failed with fault_origin=${origin}, routing to ${target}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Determine the primary fault_origin from Decision Trail entries (majority vote of
|
|
146
|
+
* unresolved entries). Falls back to UNKNOWN when no data is available.
|
|
147
|
+
*
|
|
148
|
+
* @param {object} handoffData - { decision_trail_entries?: object[], resolved_decision_trail?: string[] }
|
|
149
|
+
* @returns {string} INTENT | SPEC | CODE | DEFER | UNKNOWN
|
|
150
|
+
*/
|
|
151
|
+
export function extractPrimaryFaultOrigin(handoffData) {
|
|
152
|
+
const entries = handoffData?.decision_trail_entries || [];
|
|
153
|
+
if (entries.length === 0) return 'UNKNOWN';
|
|
154
|
+
|
|
155
|
+
// Consider only unresolved entries — resolved ones describe historical routing.
|
|
156
|
+
const active = entries.filter(e => !e.resolved);
|
|
157
|
+
if (active.length === 0) return 'UNKNOWN';
|
|
158
|
+
|
|
159
|
+
const counts = {};
|
|
160
|
+
for (const e of active) {
|
|
161
|
+
const origin = (e.fault_origin || 'UNKNOWN').toUpperCase();
|
|
162
|
+
counts[origin] = (counts[origin] || 0) + 1;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let winner = 'UNKNOWN';
|
|
166
|
+
let max = 0;
|
|
167
|
+
for (const [origin, count] of Object.entries(counts)) {
|
|
168
|
+
if (count > max) {
|
|
169
|
+
max = count;
|
|
170
|
+
winner = origin;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return winner;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Build the key used to track correction cycles per (qa, target) pair.
|
|
178
|
+
*/
|
|
179
|
+
function correctionKey(qaAgent, target) {
|
|
180
|
+
return `${qaAgent}->${target}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Check if a QA agent's score is below its threshold.
|
|
185
|
+
*/
|
|
186
|
+
function qaScoreBelowThreshold(qaAgent, score) {
|
|
187
|
+
const threshold = QA_THRESHOLDS[qaAgent];
|
|
188
|
+
if (threshold === undefined) return false;
|
|
189
|
+
if (score === null || score === undefined) return true;
|
|
190
|
+
return score < threshold;
|
|
191
|
+
}
|
|
66
192
|
|
|
67
193
|
/**
|
|
68
194
|
* Initialize a new pipeline for a project.
|
|
@@ -119,6 +245,7 @@ export function initPipeline(options = {}) {
|
|
|
119
245
|
currentAgent: null,
|
|
120
246
|
modeTransitions: [],
|
|
121
247
|
history: [],
|
|
248
|
+
correctionCycles: {},
|
|
122
249
|
};
|
|
123
250
|
}
|
|
124
251
|
|
|
@@ -128,7 +255,8 @@ export function initPipeline(options = {}) {
|
|
|
128
255
|
*/
|
|
129
256
|
const STANDARD_FLOW_AGENTS = [
|
|
130
257
|
'brief', 'detail', 'architect', 'tasks',
|
|
131
|
-
|
|
258
|
+
// qa-planning removed — now inside Planning Team, score synced via handleTeamDissolve
|
|
259
|
+
'dev', 'qa-implementation', 'devops',
|
|
132
260
|
];
|
|
133
261
|
|
|
134
262
|
/**
|
|
@@ -183,6 +311,7 @@ export function initQuickFlowPipeline(options = {}) {
|
|
|
183
311
|
currentAgent: null,
|
|
184
312
|
modeTransitions: [],
|
|
185
313
|
history: [],
|
|
314
|
+
correctionCycles: {},
|
|
186
315
|
};
|
|
187
316
|
}
|
|
188
317
|
|
|
@@ -233,6 +362,7 @@ export function initStandardFlowPipeline(options = {}) {
|
|
|
233
362
|
currentAgent: null,
|
|
234
363
|
modeTransitions: [],
|
|
235
364
|
history: [],
|
|
365
|
+
correctionCycles: {},
|
|
236
366
|
};
|
|
237
367
|
}
|
|
238
368
|
|
|
@@ -279,14 +409,15 @@ export function advancePipeline(pipelineState, completedAgent, results = {}) {
|
|
|
279
409
|
});
|
|
280
410
|
|
|
281
411
|
// Special handling for QA agents - check if they meet thresholds
|
|
282
|
-
const isQAAgent = completedAgent === 'qa-planning' || completedAgent === 'qa-implementation';
|
|
412
|
+
const isQAAgent = completedAgent === 'qa-planning' || completedAgent === 'qa-implementation' || completedAgent === 'qa-visual';
|
|
283
413
|
if (isQAAgent) {
|
|
284
414
|
const transitionCheck = checkPhaseTransition(newState);
|
|
285
415
|
|
|
286
416
|
if (transitionCheck.canAdvance) {
|
|
287
|
-
// User Preview gate: when QA-
|
|
288
|
-
// don't advance to deploy yet — let user preview first.
|
|
289
|
-
|
|
417
|
+
// User Preview gate: when the final QA gate (qa-visual) passes in build phase,
|
|
418
|
+
// don't advance to deploy yet — let user preview first. (4.3.0+: qa-visual is
|
|
419
|
+
// the final build gate; previously this was qa-implementation.)
|
|
420
|
+
if (completedAgent === 'qa-visual' && newState.phase === 'build') {
|
|
290
421
|
return {
|
|
291
422
|
state: newState,
|
|
292
423
|
nextAction: 'user_preview',
|
|
@@ -294,7 +425,9 @@ export function advancePipeline(pipelineState, completedAgent, results = {}) {
|
|
|
294
425
|
needsModeSwitch: false,
|
|
295
426
|
contextBracket,
|
|
296
427
|
previewContext: {
|
|
297
|
-
|
|
428
|
+
qaImplScore: newState.agents['qa-implementation']?.score,
|
|
429
|
+
qaVisualScore: newState.agents['qa-visual']?.score,
|
|
430
|
+
qaScore: newState.agents['qa-visual']?.score,
|
|
298
431
|
},
|
|
299
432
|
};
|
|
300
433
|
}
|
|
@@ -334,13 +467,119 @@ export function advancePipeline(pipelineState, completedAgent, results = {}) {
|
|
|
334
467
|
contextBracket,
|
|
335
468
|
};
|
|
336
469
|
} else {
|
|
337
|
-
// QA failed
|
|
470
|
+
// QA failed — trigger backward transition via Fault Vector Protocol.
|
|
471
|
+
// We re-open the rework target, NOT wait for manual intervention.
|
|
472
|
+
const faultOrigin = (results.faultOrigin || extractPrimaryFaultOrigin(results.handoffData)).toUpperCase();
|
|
473
|
+
const { nextAgent: correctionTarget, reason: routingReason } = routeByFaultVector(
|
|
474
|
+
completedAgent,
|
|
475
|
+
faultOrigin,
|
|
476
|
+
newState,
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
// DEFER or unroutable — log and stay in wait (legacy behavior)
|
|
480
|
+
if (!correctionTarget) {
|
|
481
|
+
newState.history.push({
|
|
482
|
+
agent: completedAgent,
|
|
483
|
+
action: 'qa_failed_no_rework',
|
|
484
|
+
timestamp: new Date().toISOString(),
|
|
485
|
+
faultOrigin,
|
|
486
|
+
score: results.score ?? null,
|
|
487
|
+
});
|
|
488
|
+
return {
|
|
489
|
+
state: newState,
|
|
490
|
+
nextAction: 'wait',
|
|
491
|
+
nextAgent: null,
|
|
492
|
+
needsModeSwitch: false,
|
|
493
|
+
contextBracket,
|
|
494
|
+
correction: {
|
|
495
|
+
source: completedAgent,
|
|
496
|
+
target: null,
|
|
497
|
+
faultOrigin,
|
|
498
|
+
reason: routingReason,
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Increment correction cycle counter for (qa → target) pair
|
|
504
|
+
newState.correctionCycles = newState.correctionCycles || {};
|
|
505
|
+
const key = correctionKey(completedAgent, correctionTarget);
|
|
506
|
+
const cycle = (newState.correctionCycles[key] || 0) + 1;
|
|
507
|
+
newState.correctionCycles[key] = cycle;
|
|
508
|
+
|
|
509
|
+
// Exceeded max cycles — escalate to human, don't loop forever
|
|
510
|
+
if (cycle > MAX_CORRECTION_CYCLES) {
|
|
511
|
+
newState.history.push({
|
|
512
|
+
agent: completedAgent,
|
|
513
|
+
action: 'correction_escalated',
|
|
514
|
+
target: correctionTarget,
|
|
515
|
+
cycle,
|
|
516
|
+
faultOrigin,
|
|
517
|
+
timestamp: new Date().toISOString(),
|
|
518
|
+
});
|
|
519
|
+
return {
|
|
520
|
+
state: newState,
|
|
521
|
+
nextAction: 'escalate',
|
|
522
|
+
nextAgent: null,
|
|
523
|
+
needsModeSwitch: false,
|
|
524
|
+
contextBracket,
|
|
525
|
+
correction: {
|
|
526
|
+
source: completedAgent,
|
|
527
|
+
target: correctionTarget,
|
|
528
|
+
faultOrigin,
|
|
529
|
+
cycle,
|
|
530
|
+
exceeded: true,
|
|
531
|
+
reason: `Max ${MAX_CORRECTION_CYCLES} correction cycles exceeded for ${key}. Human intervention required.`,
|
|
532
|
+
findings: results.findings || [],
|
|
533
|
+
score: results.score ?? null,
|
|
534
|
+
},
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Re-open target and every agent after it (they will need to re-run
|
|
539
|
+
// after target re-completes).
|
|
540
|
+
const targetIndex = AGENT_PIPELINE.findIndex(a => a.name === correctionTarget);
|
|
541
|
+
if (targetIndex >= 0) {
|
|
542
|
+
const toReset = AGENT_PIPELINE.slice(targetIndex).map(a => a.name);
|
|
543
|
+
for (const agentName of toReset) {
|
|
544
|
+
if (!newState.agents[agentName]) continue;
|
|
545
|
+
const isTarget = agentName === correctionTarget;
|
|
546
|
+
newState.agents[agentName] = {
|
|
547
|
+
status: isTarget ? AGENT_STATUS.PENDING_REWORK : AGENT_STATUS.PENDING,
|
|
548
|
+
score: null,
|
|
549
|
+
startedAt: isTarget ? new Date().toISOString() : null,
|
|
550
|
+
completedAt: null,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
newState.completedAgents = newState.completedAgents.filter(a => !toReset.includes(a));
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
newState.currentAgent = correctionTarget;
|
|
557
|
+
newState.history.push({
|
|
558
|
+
agent: completedAgent,
|
|
559
|
+
action: 'triggered_correction',
|
|
560
|
+
target: correctionTarget,
|
|
561
|
+
cycle,
|
|
562
|
+
faultOrigin,
|
|
563
|
+
score: results.score ?? null,
|
|
564
|
+
timestamp: new Date().toISOString(),
|
|
565
|
+
});
|
|
566
|
+
|
|
338
567
|
return {
|
|
339
568
|
state: newState,
|
|
340
|
-
nextAction: '
|
|
341
|
-
nextAgent:
|
|
569
|
+
nextAction: 'correction_loop',
|
|
570
|
+
nextAgent: correctionTarget,
|
|
342
571
|
needsModeSwitch: false,
|
|
343
572
|
contextBracket,
|
|
573
|
+
correction: {
|
|
574
|
+
source: completedAgent,
|
|
575
|
+
target: correctionTarget,
|
|
576
|
+
faultOrigin,
|
|
577
|
+
cycle,
|
|
578
|
+
exceeded: false,
|
|
579
|
+
reason: routingReason,
|
|
580
|
+
findings: results.findings || [],
|
|
581
|
+
score: results.score ?? null,
|
|
582
|
+
},
|
|
344
583
|
};
|
|
345
584
|
}
|
|
346
585
|
}
|
|
@@ -454,8 +693,16 @@ export function checkPhaseTransition(pipelineState) {
|
|
|
454
693
|
|
|
455
694
|
// Check based on current phase
|
|
456
695
|
if (phase === 'discover') {
|
|
457
|
-
// DISCOVER -> PLAN transition:
|
|
458
|
-
// (brief must
|
|
696
|
+
// DISCOVER -> PLAN transition: brief must be completed
|
|
697
|
+
// (WU runs first, then brief — both must finish before advancing to plan)
|
|
698
|
+
const brief = agents['brief'];
|
|
699
|
+
if (!brief || brief.status !== AGENT_STATUS.COMPLETED) {
|
|
700
|
+
return {
|
|
701
|
+
canAdvance: false,
|
|
702
|
+
reason: 'Brief agent not yet completed',
|
|
703
|
+
requiredScore: null,
|
|
704
|
+
};
|
|
705
|
+
}
|
|
459
706
|
return {
|
|
460
707
|
canAdvance: true,
|
|
461
708
|
reason: 'Discover phase agents completed',
|
|
@@ -464,8 +711,14 @@ export function checkPhaseTransition(pipelineState) {
|
|
|
464
711
|
}
|
|
465
712
|
|
|
466
713
|
if (phase === 'plan') {
|
|
467
|
-
//
|
|
714
|
+
// PLAN -> BUILD transition requires:
|
|
715
|
+
// 1. QA-Planning completed with score >= 95 (validates Planning Team output)
|
|
716
|
+
// 2. Phases completed (work broken into phases)
|
|
717
|
+
// 3. Tasks completed (task list created)
|
|
468
718
|
const qaPlanning = agents['qa-planning'];
|
|
719
|
+
const phases = agents['phases'];
|
|
720
|
+
const tasks = agents['tasks'];
|
|
721
|
+
|
|
469
722
|
if (!qaPlanning) {
|
|
470
723
|
return {
|
|
471
724
|
canAdvance: false,
|
|
@@ -490,17 +743,37 @@ export function checkPhaseTransition(pipelineState) {
|
|
|
490
743
|
};
|
|
491
744
|
}
|
|
492
745
|
|
|
746
|
+
if (!phases || phases.status !== AGENT_STATUS.COMPLETED) {
|
|
747
|
+
return {
|
|
748
|
+
canAdvance: false,
|
|
749
|
+
reason: 'Phases agent not yet completed',
|
|
750
|
+
requiredScore: null,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (!tasks || tasks.status !== AGENT_STATUS.COMPLETED) {
|
|
755
|
+
return {
|
|
756
|
+
canAdvance: false,
|
|
757
|
+
reason: 'Tasks agent not yet completed',
|
|
758
|
+
requiredScore: null,
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
493
762
|
return {
|
|
494
763
|
canAdvance: true,
|
|
495
|
-
reason: `QA-Planning
|
|
764
|
+
reason: `Plan phase complete: QA-Planning ${qaPlanning.score}%, phases + tasks done`,
|
|
496
765
|
requiredScore: null,
|
|
497
766
|
};
|
|
498
767
|
}
|
|
499
768
|
|
|
500
769
|
if (phase === 'build') {
|
|
501
|
-
//
|
|
770
|
+
// BUILD -> DEPLOY transition requires:
|
|
771
|
+
// 1. Dev completed (implementation)
|
|
772
|
+
// 2. QA-Implementation completed with score >= 95 (code quality)
|
|
773
|
+
// 3. QA-Visual completed with score >= 90 (visual quality)
|
|
502
774
|
const dev = agents['dev'];
|
|
503
775
|
const qaImpl = agents['qa-implementation'];
|
|
776
|
+
const qaVisual = agents['qa-visual'];
|
|
504
777
|
|
|
505
778
|
if (!dev || !qaImpl) {
|
|
506
779
|
return {
|
|
@@ -534,9 +807,27 @@ export function checkPhaseTransition(pipelineState) {
|
|
|
534
807
|
};
|
|
535
808
|
}
|
|
536
809
|
|
|
810
|
+
// QA-Visual is optional if agent is not in pipeline (older sessions)
|
|
811
|
+
if (qaVisual) {
|
|
812
|
+
if (qaVisual.status !== AGENT_STATUS.COMPLETED) {
|
|
813
|
+
return {
|
|
814
|
+
canAdvance: false,
|
|
815
|
+
reason: 'QA-Visual not yet completed',
|
|
816
|
+
requiredScore: 90,
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
if (qaVisual.score === null || qaVisual.score < 90) {
|
|
820
|
+
return {
|
|
821
|
+
canAdvance: false,
|
|
822
|
+
reason: `QA-Visual score ${qaVisual.score || 0} below threshold 90`,
|
|
823
|
+
requiredScore: 90,
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
537
828
|
return {
|
|
538
829
|
canAdvance: true,
|
|
539
|
-
reason: `
|
|
830
|
+
reason: `Build phase complete: QA-Impl ${qaImpl.score}%, QA-Visual ${qaVisual?.score ?? 'n/a'}%`,
|
|
540
831
|
requiredScore: null,
|
|
541
832
|
};
|
|
542
833
|
}
|