sinapse-ai 1.20.1 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/coderabbit-integration.md +6 -0
- package/.claude/rules/documentation-first-reference.md +146 -0
- package/.claude/rules/documentation-first.md +27 -119
- package/.claude/rules/mandatory-delegation-reference.md +93 -0
- package/.claude/rules/mandatory-delegation.md +29 -93
- package/.claude/rules/project-intelligence-reference.md +159 -0
- package/.claude/rules/project-intelligence.md +37 -155
- package/.claude/rules/safe-collaboration-reference.md +163 -0
- package/.claude/rules/safe-collaboration.md +32 -173
- package/.sinapse-ai/core/doctor/checks/index.js +1 -1
- package/.sinapse-ai/core/execution/build-orchestrator.js +4 -3
- package/.sinapse-ai/core/execution/subagent-dispatcher.js +2 -2
- package/.sinapse-ai/core/ideation/ideation-engine.js +2 -1
- package/.sinapse-ai/core/orchestration/brownfield-progress.js +219 -0
- package/.sinapse-ai/core/orchestration/cli-commands.js +13 -0
- package/.sinapse-ai/core/orchestration/doc-first-resolver.js +96 -2
- package/.sinapse-ai/core/orchestration/executors/epic-3-executor.js +15 -2
- package/.sinapse-ai/core/orchestration/executors/epic-4-executor.js +3 -1
- package/.sinapse-ai/core/orchestration/greenfield-handler.js +97 -0
- package/.sinapse-ai/core/orchestration/index.js +5 -0
- package/.sinapse-ai/core/orchestration/spec-complexity.js +141 -0
- package/.sinapse-ai/core/orchestration/workflow-executor.js +17 -1
- package/.sinapse-ai/core-config.yaml +30 -0
- package/.sinapse-ai/data/entity-registry.yaml +81 -35
- package/.sinapse-ai/development/agents/architect.md +3 -15
- package/.sinapse-ai/development/agents/data-engineer.md +3 -15
- package/.sinapse-ai/development/agents/developer.md +3 -24
- package/.sinapse-ai/development/agents/devops.md +4 -25
- package/.sinapse-ai/development/agents/quality-gate.md +3 -25
- package/.sinapse-ai/development/knowledge-base/token-economy-guide.md +1 -1
- package/.sinapse-ai/development/tasks/execute-epic-plan.md +3 -0
- package/.sinapse-ai/development/tasks/resolve-github-issue.md +1 -1
- package/.sinapse-ai/development/workflows/brownfield-discovery.yaml +16 -0
- package/.sinapse-ai/development/workflows/epic-orchestration.yaml +11 -0
- package/.sinapse-ai/docs/standards/SINAPSE-LIVRO-DE-OURO-V2.1-COMPLETE.md +6 -2
- package/.sinapse-ai/docs/standards/SINAPSE-LIVRO-DE-OURO-V2.2-SUMMARY.md +4 -1
- package/.sinapse-ai/install-manifest.yaml +58 -50
- package/.sinapse-ai/product/templates/story-tmpl.yaml +11 -6
- package/.sinapse-ai/quality/judge-calibration/README.md +75 -0
- package/.sinapse-ai/quality/judge-calibration/calibration-log.md +70 -0
- package/.sinapse-ai/quality/judge-calibration/golden-set.json +105 -0
- package/.sinapse-ai/quality/judge-calibration/scenarios.json +90 -0
- package/CHANGELOG.md +55 -10
- package/README.en.md +1 -1
- package/README.md +6 -6
- package/bin/sinapse-minimal.js +5 -4
- package/docs/community/README-community-snippet-core.md +1 -1
- package/docs/community/README-community-snippet-mcp.md +2 -2
- package/docs/framework/README.md +2 -2
- package/docs/framework/architecture-overview.md +2 -2
- package/docs/framework/core-architecture.md +1 -1
- package/docs/framework/feature-process.md +5 -5
- package/docs/framework/guiding-principles.md +1 -1
- package/docs/framework/roadmap.md +4 -4
- package/docs/framework/source-tree.md +1 -1
- package/docs/framework/versioning-and-releases.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/guides/agent-selection-guide.md +1 -1
- package/docs/guides/agents/traces/README.md +1 -1
- package/docs/guides/config-migration-guide.md +1 -1
- package/docs/guides/development-setup.md +1 -1
- package/docs/guides/docker-mcp-setup.md +5 -5
- package/docs/guides/getting-started.md +1 -1
- package/docs/guides/git-workflow-guide.md +3 -3
- package/docs/guides/ide-integration.md +3 -3
- package/docs/guides/ide-sync-guide.md +1 -1
- package/docs/guides/mcp/desktop-commander.md +2 -2
- package/docs/guides/mcp/docker-gateway-tutorial.md +1 -1
- package/docs/guides/mcp-global-setup.md +3 -3
- package/docs/guides/memory-intelligence-system.md +10 -10
- package/docs/guides/meta-agent-commands.md +1 -1
- package/docs/guides/quality-gates.md +1 -1
- package/docs/guides/security-hardening.md +1 -1
- package/docs/guides/service-discovery.md +1 -1
- package/docs/guides/squad-examples/README.md +1 -1
- package/docs/guides/squads-guide.md +1 -1
- package/docs/guides/testing-guide.md +2 -2
- package/docs/guides/user-guide.md +22 -22
- package/docs/guides/workflows/BROWNFIELD-DISCOVERY-WORKFLOW.md +3 -3
- package/docs/guides/workflows/BROWNFIELD-SERVICE-WORKFLOW.md +1 -1
- package/docs/guides/workflows/GREENFIELD-UI-WORKFLOW.md +2 -2
- package/docs/guides/workflows/SPEC-PIPELINE-WORKFLOW.md +3 -3
- package/docs/guides/workflows/STORY-DEVELOPMENT-CYCLE-WORKFLOW.md +3 -3
- package/docs/guides/workflows/pro-developer-workflow.md +2 -2
- package/docs/guides/workflows-guide.md +1 -1
- package/docs/guides/workflows-overview.md +1 -1
- package/docs/installation/npx-install.md +1 -1
- package/docs/installation/uninstallation.md +1 -1
- package/docs/installation/v4-quick-start.md +1 -1
- package/docs/pt/guides/user-guide.md +18 -18
- package/docs/pt/security.md +2 -2
- package/docs/security/overview.md +2 -2
- package/docs/security/security-best-practices.md +1 -1
- package/docs/sinapse-agent-flows/architect-system.md +1 -1
- package/docs/sinapse-agent-flows/data-engineer-system.md +1 -1
- package/docs/sinapse-agent-flows/dev-system.md +1 -1
- package/docs/sinapse-agent-flows/devops-system.md +2 -2
- package/docs/sinapse-agent-flows/qa-system.md +1 -1
- package/docs/sinapse-agent-flows/sm-system.md +2 -2
- package/docs/sinapse-agent-flows/snps-orqx-system.md +4 -4
- package/docs/sinapse-agent-flows/squad-creator-system.md +1 -1
- package/docs/sinapse-workflows/README.md +2 -2
- package/docs/sinapse-workflows/brownfield-discovery-workflow.md +3 -3
- package/docs/sinapse-workflows/brownfield-service-workflow.md +3 -3
- package/docs/sinapse-workflows/greenfield-ui-workflow.md +2 -2
- package/docs/sinapse-workflows/spec-pipeline-workflow.md +3 -3
- package/docs/sinapse-workflows/story-development-cycle-workflow.md +3 -3
- package/docs/troubleshooting.md +1 -1
- package/package.json +7 -1
- package/scripts/calibrate-judge.js +134 -0
- package/scripts/eval-e2e.js +149 -0
- package/scripts/validate-all.js +8 -0
- package/scripts/validate-article-iv.js +289 -0
- package/scripts/validate-constitution.js +58 -0
- package/scripts/validate-evals.js +9 -2
- package/scripts/validate-story-acs.js +174 -0
- package/scripts/validate-tool-descriptions.js +128 -0
- package/scripts/wave-gate.js +207 -0
- package/squads/claude-code-mastery/agents/project-integrator.md +3 -10
- package/squads/claude-code-mastery/knowledge-base/context-window-optimization.md +2 -2
- package/squads/claude-code-mastery/knowledge-base/memory-systems-reference.md +1 -1
- package/squads/squad-copy/knowledge-base/ai-copy-human-loop-canon.md +1 -1
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
const fs = require('fs-extra');
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const EpicExecutor = require('./epic-executor');
|
|
17
|
+
const { classifyComplexity } = require('../spec-complexity');
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Spec Pipeline phases
|
|
@@ -131,14 +132,26 @@ class Epic3Executor extends EpicExecutor {
|
|
|
131
132
|
this._addArtifact('spec', specPath);
|
|
132
133
|
|
|
133
134
|
// Collect complexity and requirements from phases
|
|
134
|
-
const
|
|
135
|
+
const assess = phaseResults['assess-complexity'] || {};
|
|
136
|
+
const complexity = assess.complexity || 'STANDARD';
|
|
135
137
|
const requirements = phaseResults['gather-requirements']?.requirements || [];
|
|
136
138
|
|
|
139
|
+
// M4 (AF-20260704 #9b): turn the COMPLEX≥16 rule from prose into a
|
|
140
|
+
// deterministic classification. Prefer the numeric dimension score when the
|
|
141
|
+
// assess phase provides one; otherwise fall back to the level string.
|
|
142
|
+
const classification = classifyComplexity(
|
|
143
|
+
typeof assess.score === 'number' ? assess.score : assess.dimensions || complexity,
|
|
144
|
+
);
|
|
145
|
+
|
|
137
146
|
// Honesty invariant (epic: orchestration-consolidation, F0a):
|
|
138
147
|
// if the spec was auto-stubbed (no real agent ran), report STUB, not success.
|
|
139
148
|
const specResult = {
|
|
140
149
|
specPath,
|
|
141
|
-
complexity,
|
|
150
|
+
complexity: classification.level,
|
|
151
|
+
complexityScore: classification.score,
|
|
152
|
+
requiresRevisionCycle: classification.requiresRevisionCycle,
|
|
153
|
+
requiresFullSpecPipeline: classification.requiresFullSpecPipeline,
|
|
154
|
+
specPipelinePhases: classification.phases,
|
|
142
155
|
requirements,
|
|
143
156
|
phases: Object.keys(phaseResults),
|
|
144
157
|
};
|
|
@@ -193,12 +193,14 @@ class Epic4Executor extends EpicExecutor {
|
|
|
193
193
|
async _executeViaBuildOrchestrator(storyId, context) {
|
|
194
194
|
try {
|
|
195
195
|
const { BuildOrchestrator } = require('../../execution/build-orchestrator');
|
|
196
|
+
// buildOptions is passed once, via build() — which already merges it over
|
|
197
|
+
// the constructor config ({...this.config, ...options}). Passing it in both
|
|
198
|
+
// places (AF-20260704 Lote B) was redundant, not wrong.
|
|
196
199
|
const builder = new BuildOrchestrator({
|
|
197
200
|
rootPath: this.projectRoot,
|
|
198
201
|
useWorktree: false,
|
|
199
202
|
autoMerge: false,
|
|
200
203
|
runQA: false,
|
|
201
|
-
...(context.buildOptions || {}),
|
|
202
204
|
});
|
|
203
205
|
return await builder.build(storyId, context.buildOptions || {});
|
|
204
206
|
} catch (err) {
|
|
@@ -152,9 +152,63 @@ class GreenfieldHandler extends EventEmitter {
|
|
|
152
152
|
// Phase progress tracking
|
|
153
153
|
this.phaseProgress = {};
|
|
154
154
|
|
|
155
|
+
// Onda3-S2: cached read of workflow metadata (confirmation_required).
|
|
156
|
+
this._confirmationRequired = null;
|
|
157
|
+
|
|
155
158
|
this._log('GreenfieldHandler initialized');
|
|
156
159
|
}
|
|
157
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Reads `metadata.confirmation_required` from the resolved workflow YAML.
|
|
163
|
+
* Onda3-S2 (AF-20260702 item 3.4): the field used to be decorative — no code
|
|
164
|
+
* consumed it. Now `false` turns go_pause surfaces into auto-GO; `true` or
|
|
165
|
+
* any read/parse failure preserves the safe default (pause for the human).
|
|
166
|
+
*
|
|
167
|
+
* @returns {boolean} true = pause between phases (default), false = auto-GO
|
|
168
|
+
*/
|
|
169
|
+
getConfirmationRequired() {
|
|
170
|
+
if (this._confirmationRequired !== null) return this._confirmationRequired;
|
|
171
|
+
let required = true;
|
|
172
|
+
try {
|
|
173
|
+
const yaml = require('js-yaml');
|
|
174
|
+
const raw = fs.readFileSync(this.workflowPath, 'utf8');
|
|
175
|
+
const parsed = yaml.load(raw);
|
|
176
|
+
if (parsed && parsed.metadata && parsed.metadata.confirmation_required === false) {
|
|
177
|
+
required = false;
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
this._log(`confirmation_required unreadable (default: true): ${error.message}`, 'warn');
|
|
181
|
+
}
|
|
182
|
+
this._confirmationRequired = required;
|
|
183
|
+
return required;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Deterministic artifact gate (Onda3-S2, AF-20260702 item 3.4).
|
|
188
|
+
* For every step that declares a file artifact (`creates` ending in .md),
|
|
189
|
+
* verifies the artifact exists on disk with content. Echoes the empty-build
|
|
190
|
+
* honesty fix: a phase does not advance on promises, only on artifacts.
|
|
191
|
+
*
|
|
192
|
+
* @param {Array<{agent: string, task: string, creates: ?string}>} sequence
|
|
193
|
+
* @returns {{passed: boolean, missing: Array<{agent: string, task: string, artifact: string}>, checked: number}}
|
|
194
|
+
*/
|
|
195
|
+
evaluateArtifactGate(sequence) {
|
|
196
|
+
// Lazy require: doc-first-resolver imports constants from this module, so a
|
|
197
|
+
// top-level require here would create a load-order cycle with partial exports.
|
|
198
|
+
const { fileHasContent } = require('./doc-first-resolver');
|
|
199
|
+
const missing = [];
|
|
200
|
+
let checked = 0;
|
|
201
|
+
for (const step of sequence) {
|
|
202
|
+
if (!step.creates || !step.creates.endsWith('.md')) continue;
|
|
203
|
+
checked += 1;
|
|
204
|
+
const artifactPath = path.join(this.projectRoot, step.creates);
|
|
205
|
+
if (!fileHasContent(artifactPath)) {
|
|
206
|
+
missing.push({ agent: step.agent, task: step.task, artifact: step.creates });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { passed: missing.length === 0, missing, checked };
|
|
210
|
+
}
|
|
211
|
+
|
|
158
212
|
// ═══════════════════════════════════════════════════════════════════════════════════
|
|
159
213
|
// LAZY DEPENDENCY LOADING
|
|
160
214
|
// ═══════════════════════════════════════════════════════════════════════════════════
|
|
@@ -453,10 +507,45 @@ class GreenfieldHandler extends EventEmitter {
|
|
|
453
507
|
}
|
|
454
508
|
}
|
|
455
509
|
|
|
510
|
+
// Onda3-S2: deterministic artifact gate — the phase only completes when
|
|
511
|
+
// every declared artifact actually exists with content on disk.
|
|
512
|
+
const gate = this.evaluateArtifactGate(PHASE_1_SEQUENCE);
|
|
513
|
+
if (!gate.passed) {
|
|
514
|
+
this.phaseProgress[GreenfieldPhase.DISCOVERY] = {
|
|
515
|
+
status: 'gated',
|
|
516
|
+
endTime: Date.now(),
|
|
517
|
+
stepResults,
|
|
518
|
+
gate,
|
|
519
|
+
};
|
|
520
|
+
this.emit('phaseGated', { phase: GreenfieldPhase.DISCOVERY, gate, context });
|
|
521
|
+
|
|
522
|
+
const missingList = gate.missing
|
|
523
|
+
.map((m) => ` - ${m.artifact} (${m.agent} → *${m.task})`)
|
|
524
|
+
.join('\n');
|
|
525
|
+
return {
|
|
526
|
+
action: 'greenfield_gate_blocked',
|
|
527
|
+
phase: GreenfieldPhase.DISCOVERY,
|
|
528
|
+
nextPhase: 1,
|
|
529
|
+
data: {
|
|
530
|
+
gate: 'missing_artifact',
|
|
531
|
+
missing: gate.missing,
|
|
532
|
+
message:
|
|
533
|
+
'Gate de artefato: a Phase 1 não avança sem os artefatos no disco.\n' +
|
|
534
|
+
`Faltando:\n${missingList}\n\n` +
|
|
535
|
+
'Execute os agentes indicados (ou crie os documentos) e responda GO para revalidar.',
|
|
536
|
+
promptType: 'go_pause',
|
|
537
|
+
options: ['GO', 'PAUSE'],
|
|
538
|
+
resumeFromPhase: 1,
|
|
539
|
+
context: { ...context, phase1Results: stepResults },
|
|
540
|
+
},
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
456
544
|
this.phaseProgress[GreenfieldPhase.DISCOVERY] = {
|
|
457
545
|
status: 'complete',
|
|
458
546
|
endTime: Date.now(),
|
|
459
547
|
stepResults,
|
|
548
|
+
gate,
|
|
460
549
|
};
|
|
461
550
|
|
|
462
551
|
this.emit('phaseComplete', { phase: GreenfieldPhase.DISCOVERY, result: stepResults, context });
|
|
@@ -667,6 +756,14 @@ class GreenfieldHandler extends EventEmitter {
|
|
|
667
756
|
* @private
|
|
668
757
|
*/
|
|
669
758
|
_surfaceBetweenPhases(fromPhase, toPhase, surfaceConfig) {
|
|
759
|
+
// Onda3-S2: honor metadata.confirmation_required from the workflow YAML.
|
|
760
|
+
// Only go_pause surfaces auto-advance — text_input needs the human's words,
|
|
761
|
+
// and gate blocks never route through here.
|
|
762
|
+
if (surfaceConfig.promptType === 'go_pause' && this.getConfirmationRequired() === false) {
|
|
763
|
+
this._log(`confirmation_required=false — auto-GO Phase ${fromPhase} → ${toPhase}`);
|
|
764
|
+
return this._executeFromPhase(toPhase, surfaceConfig.context);
|
|
765
|
+
}
|
|
766
|
+
|
|
670
767
|
const surfaceChecker = this._getSurfaceChecker();
|
|
671
768
|
|
|
672
769
|
// Build options based on prompt type
|
|
@@ -158,6 +158,8 @@ const {
|
|
|
158
158
|
|
|
159
159
|
module.exports = {
|
|
160
160
|
// Main orchestrators
|
|
161
|
+
// @deprecated WorkflowOrchestrator has no internal consumers (AF-20260704);
|
|
162
|
+
// kept exported because the barrel is public package API. Prefer MasterOrchestrator.
|
|
161
163
|
WorkflowOrchestrator,
|
|
162
164
|
MasterOrchestrator, // Epic 0: ADE Master Orchestrator
|
|
163
165
|
|
|
@@ -290,6 +292,9 @@ module.exports = {
|
|
|
290
292
|
STALE_SNAPSHOT_DAYS,
|
|
291
293
|
|
|
292
294
|
// Story 12.4: Epic Context Accumulator (Projeto Bob)
|
|
295
|
+
// @deprecated EpicContextAccumulator has no internal consumers (AF-20260704;
|
|
296
|
+
// multi-story orchestration was measured and rejected — see KNOWN-LIMITATIONS.md).
|
|
297
|
+
// Kept exported because the barrel is public package API.
|
|
293
298
|
EpicContextAccumulator,
|
|
294
299
|
createEpicContextAccumulator,
|
|
295
300
|
CompressionLevel,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec-Pipeline Complexity — deterministic threshold + phase plan.
|
|
3
|
+
*
|
|
4
|
+
* The COMPLEX≥16 rule lived only in prose (`workflow-execution.md` §3,
|
|
5
|
+
* `documentation-first.md` complexity gate): "score ≥16 → COMPLEX → run the full
|
|
6
|
+
* Spec Pipeline (6 phases + revision cycle) FIRST". Nothing in code enforced the
|
|
7
|
+
* threshold or derived the phase plan from it, so the assessment was advisory.
|
|
8
|
+
*
|
|
9
|
+
* This module turns the threshold and the per-level phase plan into deterministic,
|
|
10
|
+
* tested code (Story rodada2-m4, AF-20260704 #9b). It does NOT invent HOW the five
|
|
11
|
+
* dimensions are scored — those values come from the `assess-complexity` phase; it
|
|
12
|
+
* only encodes the mapping score → level → required phases, canonically defined in
|
|
13
|
+
* `workflow-execution.md`.
|
|
14
|
+
*
|
|
15
|
+
* @module core/orchestration/spec-complexity
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
/** The five complexity dimensions, each scored 1-5 (min 5, max 25). */
|
|
21
|
+
const DIMENSIONS = Object.freeze(['scope', 'integration', 'infrastructure', 'knowledge', 'risk']);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Canonical thresholds (`workflow-execution.md` §3):
|
|
25
|
+
* score <= 8 → SIMPLE
|
|
26
|
+
* 9..15 → STANDARD
|
|
27
|
+
* score >= 16 → COMPLEX
|
|
28
|
+
*/
|
|
29
|
+
const THRESHOLDS = Object.freeze({ SIMPLE_MAX: 8, COMPLEX_MIN: 16 });
|
|
30
|
+
|
|
31
|
+
const LEVELS = Object.freeze({ SIMPLE: 'SIMPLE', STANDARD: 'STANDARD', COMPLEX: 'COMPLEX' });
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Phase plans per level (`workflow-execution.md` §3 table):
|
|
35
|
+
* SIMPLE → gather → spec → critique (3)
|
|
36
|
+
* STANDARD → gather → assess → research → spec → critique → plan (6)
|
|
37
|
+
* COMPLEX → the 6 phases + a revision cycle (6 + revision)
|
|
38
|
+
*/
|
|
39
|
+
const PHASES_BY_LEVEL = Object.freeze({
|
|
40
|
+
SIMPLE: Object.freeze(['gather-requirements', 'write-spec', 'critique']),
|
|
41
|
+
STANDARD: Object.freeze([
|
|
42
|
+
'gather-requirements',
|
|
43
|
+
'assess-complexity',
|
|
44
|
+
'research-dependencies',
|
|
45
|
+
'write-spec',
|
|
46
|
+
'critique',
|
|
47
|
+
'plan',
|
|
48
|
+
]),
|
|
49
|
+
COMPLEX: Object.freeze([
|
|
50
|
+
'gather-requirements',
|
|
51
|
+
'assess-complexity',
|
|
52
|
+
'research-dependencies',
|
|
53
|
+
'write-spec',
|
|
54
|
+
'critique',
|
|
55
|
+
'plan',
|
|
56
|
+
]),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Map a numeric complexity score to its level. Deterministic; no side effects.
|
|
61
|
+
* @param {number} score - Sum of the five dimensions (nominally 5..25).
|
|
62
|
+
* @returns {'SIMPLE'|'STANDARD'|'COMPLEX'}
|
|
63
|
+
*/
|
|
64
|
+
function scoreToLevel(score) {
|
|
65
|
+
const n = Number(score);
|
|
66
|
+
if (!Number.isFinite(n)) return LEVELS.STANDARD; // conservative default
|
|
67
|
+
if (n <= THRESHOLDS.SIMPLE_MAX) return LEVELS.SIMPLE;
|
|
68
|
+
if (n >= THRESHOLDS.COMPLEX_MIN) return LEVELS.COMPLEX;
|
|
69
|
+
return LEVELS.STANDARD;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Normalize a level-ish input (a level string, in any case) to a canonical level. */
|
|
73
|
+
function normalizeLevel(level) {
|
|
74
|
+
const u = String(level || '').trim().toUpperCase();
|
|
75
|
+
return LEVELS[u] || null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Sum an object of dimension → score (1-5). Missing dimensions count as 0.
|
|
80
|
+
* @param {Record<string, number>} dimensions
|
|
81
|
+
* @returns {number}
|
|
82
|
+
*/
|
|
83
|
+
function sumDimensions(dimensions) {
|
|
84
|
+
if (!dimensions || typeof dimensions !== 'object') return NaN;
|
|
85
|
+
return DIMENSIONS.reduce((total, d) => {
|
|
86
|
+
const v = Number(dimensions[d]);
|
|
87
|
+
return total + (Number.isFinite(v) ? v : 0);
|
|
88
|
+
}, 0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Classify complexity from either a numeric score, a dimensions object, or an
|
|
93
|
+
* already-decided level string. Returns the deterministic plan.
|
|
94
|
+
*
|
|
95
|
+
* @param {number|string|Record<string, number>} input
|
|
96
|
+
* @returns {{
|
|
97
|
+
* level: 'SIMPLE'|'STANDARD'|'COMPLEX',
|
|
98
|
+
* score: number|null,
|
|
99
|
+
* phases: string[],
|
|
100
|
+
* requiresRevisionCycle: boolean,
|
|
101
|
+
* requiresFullSpecPipeline: boolean
|
|
102
|
+
* }}
|
|
103
|
+
*/
|
|
104
|
+
function classifyComplexity(input) {
|
|
105
|
+
let level;
|
|
106
|
+
let score = null;
|
|
107
|
+
|
|
108
|
+
if (typeof input === 'number') {
|
|
109
|
+
score = input;
|
|
110
|
+
level = scoreToLevel(input);
|
|
111
|
+
} else if (typeof input === 'string') {
|
|
112
|
+
level = normalizeLevel(input) || LEVELS.STANDARD;
|
|
113
|
+
} else if (input && typeof input === 'object') {
|
|
114
|
+
const s = sumDimensions(input);
|
|
115
|
+
score = Number.isFinite(s) ? s : null;
|
|
116
|
+
level = Number.isFinite(s) ? scoreToLevel(s) : LEVELS.STANDARD;
|
|
117
|
+
} else {
|
|
118
|
+
level = LEVELS.STANDARD; // conservative default when nothing usable is given
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
level,
|
|
123
|
+
score,
|
|
124
|
+
phases: [...PHASES_BY_LEVEL[level]],
|
|
125
|
+
// COMPLEX is the only level that adds the revision cycle.
|
|
126
|
+
requiresRevisionCycle: level === LEVELS.COMPLEX,
|
|
127
|
+
// SIMPLE runs the trimmed 3-phase pipeline; STANDARD/COMPLEX run the full one.
|
|
128
|
+
requiresFullSpecPipeline: level !== LEVELS.SIMPLE,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
DIMENSIONS,
|
|
134
|
+
THRESHOLDS,
|
|
135
|
+
LEVELS,
|
|
136
|
+
PHASES_BY_LEVEL,
|
|
137
|
+
scoreToLevel,
|
|
138
|
+
normalizeLevel,
|
|
139
|
+
sumDimensions,
|
|
140
|
+
classifyComplexity,
|
|
141
|
+
};
|
|
@@ -474,7 +474,7 @@ class WorkflowExecutor {
|
|
|
474
474
|
return { success: false, error: `Workflow definition is empty: ${workflowPath}` };
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
|
|
477
|
+
const result = {
|
|
478
478
|
success: true,
|
|
479
479
|
workflowPath,
|
|
480
480
|
workflow,
|
|
@@ -484,6 +484,22 @@ class WorkflowExecutor {
|
|
|
484
484
|
techStack: options.techStack || {},
|
|
485
485
|
},
|
|
486
486
|
};
|
|
487
|
+
|
|
488
|
+
// Onda3-S3 (AF-20260702 item 3.3): the brownfield handoff now carries
|
|
489
|
+
// deterministic state — phase progress measured from artifacts on disk and
|
|
490
|
+
// the Phase 7 QA gate parsed by code (with capped rework loop). Fail-open:
|
|
491
|
+
// enrichment errors degrade to the plain handoff, never to a crash.
|
|
492
|
+
if (workflow.id === 'brownfield-discovery') {
|
|
493
|
+
try {
|
|
494
|
+
const { resolveBrownfieldProgress, evaluateQaGate } = require('./brownfield-progress');
|
|
495
|
+
result.progress = resolveBrownfieldProgress(result.context.projectRoot, workflow);
|
|
496
|
+
result.qaGate = evaluateQaGate(result.context.projectRoot);
|
|
497
|
+
} catch (error) {
|
|
498
|
+
result.progressError = `brownfield progress unavailable: ${error.message}`;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return result;
|
|
487
503
|
}
|
|
488
504
|
|
|
489
505
|
/**
|
|
@@ -193,6 +193,12 @@ github:
|
|
|
193
193
|
draft_by_default: false
|
|
194
194
|
semantic_release:
|
|
195
195
|
enabled: true
|
|
196
|
+
# ── CodeRabbit integration — SINGLE SOURCE OF TRUTH ──────────────────────────
|
|
197
|
+
# This section (machine config) + .claude/rules/coderabbit-integration.md
|
|
198
|
+
# (auto-loaded, human-readable) are the ONE canonical source for WSL execution
|
|
199
|
+
# mechanics, self-healing thresholds, canonical review commands and report
|
|
200
|
+
# location. Agents REFERENCE this — they must NOT copy the mechanics into their
|
|
201
|
+
# own definitions. (Dedup: Story rodada2-m6-coderabbit-dedup.)
|
|
196
202
|
coderabbit_integration:
|
|
197
203
|
enabled: true
|
|
198
204
|
installation_mode: wsl
|
|
@@ -213,11 +219,35 @@ coderabbit_integration:
|
|
|
213
219
|
graceful_degradation:
|
|
214
220
|
skip_if_not_installed: true
|
|
215
221
|
fallback_message: 'CodeRabbit CLI not found. Skipping automated review. Install via: pip install coderabbit-cli'
|
|
222
|
+
# Canonical review commands (referenced by all agents; keyed by intent, not by agent).
|
|
216
223
|
commands:
|
|
224
|
+
review_uncommitted: |
|
|
225
|
+
wsl bash -c 'cd ${PROJECT_ROOT} && ~/.local/bin/coderabbit --prompt-only -t uncommitted'
|
|
226
|
+
review_committed_base_main: |
|
|
227
|
+
wsl bash -c 'cd ${PROJECT_ROOT} && ~/.local/bin/coderabbit --prompt-only -t committed --base main'
|
|
228
|
+
review_against_main: |
|
|
229
|
+
wsl bash -c 'cd ${PROJECT_ROOT} && ~/.local/bin/coderabbit --prompt-only --base main'
|
|
230
|
+
review_committed: |
|
|
231
|
+
wsl bash -c 'cd ${PROJECT_ROOT} && ~/.local/bin/coderabbit --prompt-only -t committed'
|
|
232
|
+
# Back-compat aliases (previous key names):
|
|
217
233
|
qa_pre_review_uncommitted: |
|
|
218
234
|
wsl bash -c 'cd ${PROJECT_ROOT} && ~/.local/bin/coderabbit --prompt-only -t uncommitted'
|
|
219
235
|
qa_story_review_committed: |
|
|
220
236
|
wsl bash -c 'cd ${PROJECT_ROOT} && ~/.local/bin/coderabbit --prompt-only -t committed --base main'
|
|
237
|
+
execution_guidelines: |
|
|
238
|
+
CRITICAL: CodeRabbit CLI is installed in WSL, not Windows.
|
|
239
|
+
|
|
240
|
+
**How to Execute:**
|
|
241
|
+
1. Use 'wsl bash -c' wrapper for all commands
|
|
242
|
+
2. Navigate to project directory in WSL path format (/mnt/c/...)
|
|
243
|
+
3. Use full path to coderabbit binary (~/.local/bin/coderabbit)
|
|
244
|
+
|
|
245
|
+
**Timeout:** dev/pre-push 15 min (900000ms); full QA review 30 min (1800000ms) — reviews take 7-30 min.
|
|
246
|
+
|
|
247
|
+
**Error Handling:**
|
|
248
|
+
- If "coderabbit: command not found" → verify installation in WSL (wsl_config.installation_path)
|
|
249
|
+
- If timeout → increase timeout, review is still processing
|
|
250
|
+
- If "not authenticated" → user needs to run: wsl bash -c '~/.local/bin/coderabbit auth status'
|
|
221
251
|
report_location: docs/qa/coderabbit-reports/
|
|
222
252
|
squads:
|
|
223
253
|
templateLocation: templates/squad
|