sinapse-ai 1.20.1 → 1.21.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/.sinapse-ai/core/orchestration/brownfield-progress.js +219 -0
- package/.sinapse-ai/core/orchestration/doc-first-resolver.js +3 -0
- package/.sinapse-ai/core/orchestration/greenfield-handler.js +97 -0
- package/.sinapse-ai/core/orchestration/workflow-executor.js +17 -1
- package/.sinapse-ai/data/entity-registry.yaml +39 -14
- package/.sinapse-ai/development/tasks/execute-epic-plan.md +3 -0
- package/.sinapse-ai/development/workflows/brownfield-discovery.yaml +16 -0
- package/.sinapse-ai/development/workflows/epic-orchestration.yaml +11 -0
- package/.sinapse-ai/install-manifest.yaml +20 -16
- package/CHANGELOG.md +29 -14
- package/package.json +3 -1
- package/scripts/eval-e2e.js +149 -0
- package/scripts/validate-all.js +3 -0
- package/scripts/validate-article-iv.js +289 -0
- package/scripts/validate-evals.js +9 -2
- package/scripts/wave-gate.js +207 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brownfield Discovery — deterministic progress + QA gate in code.
|
|
3
|
+
*
|
|
4
|
+
* Story onda3-s3-brownfield-progress-gate (AF-20260702 item 3.3).
|
|
5
|
+
*
|
|
6
|
+
* The 10 phases of brownfield-discovery.yaml are executed by agents (prose,
|
|
7
|
+
* orchestrate-then-handoff). What was missing — and what this module adds —
|
|
8
|
+
* is the DETERMINISTIC layer around that prose:
|
|
9
|
+
*
|
|
10
|
+
* 1. resolveBrownfieldProgress(): where the assessment actually stands,
|
|
11
|
+
* measured from artifacts ON DISK (not from what anyone claims), giving
|
|
12
|
+
* an exact resume point per phase.
|
|
13
|
+
* 2. evaluateQaGate() / recordRework(): the Phase 7 verdict (APPROVED /
|
|
14
|
+
* NEEDS WORK) parsed from docs/reviews/qa-review.md by code, with a
|
|
15
|
+
* persisted rework counter capped at MAX_REWORK — the NEEDS WORK loop
|
|
16
|
+
* escalates instead of spinning forever.
|
|
17
|
+
*
|
|
18
|
+
* Honesty contract: an unfilled template ("[APPROVED / NEEDS WORK]") is
|
|
19
|
+
* PENDING, not a verdict. Autonomous fan-out of phases 1-3 remains gated on
|
|
20
|
+
* a measured pilot (same pre-registered gate as epic waves — see the epic
|
|
21
|
+
* README of epic-onda3-estrutural); this module is the safe deterministic
|
|
22
|
+
* substrate either way.
|
|
23
|
+
*
|
|
24
|
+
* @module core/orchestration/brownfield-progress
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
|
|
32
|
+
const { fileHasContent } = require('./doc-first-resolver');
|
|
33
|
+
|
|
34
|
+
const QA_REVIEW_RELPATH = path.join('docs', 'reviews', 'qa-review.md');
|
|
35
|
+
const STATE_RELPATH = path.join('.sinapse', 'workflow-state', 'brownfield-discovery.json');
|
|
36
|
+
|
|
37
|
+
/** Rework ceiling for the Phase 7 loop (NEEDS WORK → fix → re-review). */
|
|
38
|
+
const MAX_REWORK = 2;
|
|
39
|
+
|
|
40
|
+
/** Normalize a step's `creates` (string | string[]) into a string list. */
|
|
41
|
+
function listArtifacts(step) {
|
|
42
|
+
if (!step || !step.creates) return [];
|
|
43
|
+
const raw = Array.isArray(step.creates) ? step.creates : [step.creates];
|
|
44
|
+
return raw.filter((a) => typeof a === 'string' && a.trim().length > 0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Glob-ish artifacts ("story-X.X-*.md") cannot be verified deterministically. */
|
|
48
|
+
function isCheckable(artifact) {
|
|
49
|
+
return !artifact.includes('*');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the real state of the brownfield discovery from disk.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} projectRoot
|
|
56
|
+
* @param {Object} workflow - Parsed `workflow` node (needs `.sequence`)
|
|
57
|
+
* @returns {{phases: Array, nextPhase: ?number, complete: boolean}}
|
|
58
|
+
*/
|
|
59
|
+
function resolveBrownfieldProgress(projectRoot, workflow) {
|
|
60
|
+
const sequence = (workflow && Array.isArray(workflow.sequence)) ? workflow.sequence : [];
|
|
61
|
+
const byPhase = new Map();
|
|
62
|
+
|
|
63
|
+
for (const step of sequence) {
|
|
64
|
+
if (!step || typeof step.phase !== 'number') continue;
|
|
65
|
+
if (!byPhase.has(step.phase)) {
|
|
66
|
+
byPhase.set(step.phase, { phase: step.phase, name: step.phase_name || null, steps: [] });
|
|
67
|
+
}
|
|
68
|
+
const artifacts = listArtifacts(step).map((artifact) => {
|
|
69
|
+
const checkable = isCheckable(artifact);
|
|
70
|
+
return {
|
|
71
|
+
path: artifact,
|
|
72
|
+
checkable,
|
|
73
|
+
exists: checkable ? fileHasContent(path.join(projectRoot, artifact)) : null,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
byPhase.get(step.phase).steps.push({
|
|
77
|
+
id: step.step || step.id || null,
|
|
78
|
+
agent: step.agent || null,
|
|
79
|
+
conditional: Boolean(step.condition),
|
|
80
|
+
condition: step.condition || null,
|
|
81
|
+
artifacts,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const phases = [...byPhase.values()].sort((a, b) => a.phase - b.phase);
|
|
86
|
+
|
|
87
|
+
for (const phase of phases) {
|
|
88
|
+
// Required = checkable artifacts of unconditional steps. Conditional steps
|
|
89
|
+
// (e.g. project_has_database) never block completeness — but when their
|
|
90
|
+
// artifacts DO exist they are reported, so nothing done is invisible.
|
|
91
|
+
const required = phase.steps
|
|
92
|
+
.filter((s) => !s.conditional)
|
|
93
|
+
.flatMap((s) => s.artifacts.filter((a) => a.checkable));
|
|
94
|
+
const present = required.filter((a) => a.exists);
|
|
95
|
+
phase.requiredCount = required.length;
|
|
96
|
+
phase.presentCount = present.length;
|
|
97
|
+
if (required.length === 0) {
|
|
98
|
+
phase.status = 'unverifiable';
|
|
99
|
+
} else if (present.length === required.length) {
|
|
100
|
+
phase.status = 'complete';
|
|
101
|
+
} else if (present.length > 0) {
|
|
102
|
+
phase.status = 'partial';
|
|
103
|
+
} else {
|
|
104
|
+
phase.status = 'pending';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const firstIncomplete = phases.find(
|
|
109
|
+
(p) => p.status === 'pending' || p.status === 'partial',
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
phases,
|
|
114
|
+
nextPhase: firstIncomplete ? firstIncomplete.phase : null,
|
|
115
|
+
complete: phases.length > 0 && !firstIncomplete,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Parse the Phase 7 verdict out of qa-review.md content.
|
|
121
|
+
*
|
|
122
|
+
* @param {string} content
|
|
123
|
+
* @returns {'approved'|'needs_work'|'pending'|'malformed'}
|
|
124
|
+
*/
|
|
125
|
+
function parseQaGateStatus(content) {
|
|
126
|
+
if (typeof content !== 'string') return 'malformed';
|
|
127
|
+
const m = content.match(/gate status:\s*(.*)$/im);
|
|
128
|
+
if (!m) return 'pending';
|
|
129
|
+
const value = m[1].trim();
|
|
130
|
+
const hasApproved = /approved/i.test(value);
|
|
131
|
+
const hasNeedsWork = /needs\s+work/i.test(value);
|
|
132
|
+
// The unfilled template is "[APPROVED / NEEDS WORK]" — both tokens present
|
|
133
|
+
// means the reviewer never picked. That is PENDING, never a verdict.
|
|
134
|
+
if (hasApproved && hasNeedsWork) return 'pending';
|
|
135
|
+
if (hasApproved) return 'approved';
|
|
136
|
+
if (hasNeedsWork) return 'needs_work';
|
|
137
|
+
return 'malformed';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function statePath(projectRoot) {
|
|
141
|
+
return path.join(projectRoot, STATE_RELPATH);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function readState(projectRoot) {
|
|
145
|
+
try {
|
|
146
|
+
const parsed = JSON.parse(fs.readFileSync(statePath(projectRoot), 'utf8'));
|
|
147
|
+
return { reworkCount: 0, ...parsed };
|
|
148
|
+
} catch {
|
|
149
|
+
return { reworkCount: 0 };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function writeState(projectRoot, state) {
|
|
154
|
+
const file = statePath(projectRoot);
|
|
155
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
156
|
+
fs.writeFileSync(file, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Evaluate the Phase 7 QA gate deterministically (read-only — never mutates
|
|
161
|
+
* the rework counter; that is recordRework's job).
|
|
162
|
+
*
|
|
163
|
+
* @param {string} projectRoot
|
|
164
|
+
* @returns {{verdict: string, reworkCount: number, maxRework: number, escalate: boolean, reviewPath: string, reason?: string}}
|
|
165
|
+
*/
|
|
166
|
+
function evaluateQaGate(projectRoot) {
|
|
167
|
+
const reviewPath = path.join(projectRoot, QA_REVIEW_RELPATH);
|
|
168
|
+
const state = readState(projectRoot);
|
|
169
|
+
const base = {
|
|
170
|
+
reworkCount: state.reworkCount,
|
|
171
|
+
maxRework: MAX_REWORK,
|
|
172
|
+
reviewPath: QA_REVIEW_RELPATH,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
if (!fileHasContent(reviewPath)) {
|
|
176
|
+
return { ...base, verdict: 'pending', escalate: false, reason: 'qa-review.md ausente ou vazio' };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let content;
|
|
180
|
+
try {
|
|
181
|
+
content = fs.readFileSync(reviewPath, 'utf8');
|
|
182
|
+
} catch (error) {
|
|
183
|
+
return { ...base, verdict: 'malformed', escalate: false, reason: `qa-review.md ilegível: ${error.message}` };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const verdict = parseQaGateStatus(content);
|
|
187
|
+
const escalate = verdict === 'needs_work' && state.reworkCount >= MAX_REWORK;
|
|
188
|
+
return { ...base, verdict, escalate };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Record one NEEDS WORK → rework loop iteration. Call it when the flow
|
|
193
|
+
* returns to Phase 4 after a NEEDS WORK verdict. At MAX_REWORK the gate
|
|
194
|
+
* escalates instead of looping.
|
|
195
|
+
*
|
|
196
|
+
* @param {string} projectRoot
|
|
197
|
+
* @returns {{reworkCount: number, escalate: boolean}}
|
|
198
|
+
*/
|
|
199
|
+
function recordRework(projectRoot) {
|
|
200
|
+
const state = readState(projectRoot);
|
|
201
|
+
state.reworkCount += 1;
|
|
202
|
+
state.lastReworkAt = new Date().toISOString();
|
|
203
|
+
writeState(projectRoot, state);
|
|
204
|
+
return { reworkCount: state.reworkCount, escalate: state.reworkCount >= MAX_REWORK };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Reset the rework counter (new assessment cycle). */
|
|
208
|
+
function resetQaGateState(projectRoot) {
|
|
209
|
+
writeState(projectRoot, { reworkCount: 0 });
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
module.exports = {
|
|
213
|
+
resolveBrownfieldProgress,
|
|
214
|
+
parseQaGateStatus,
|
|
215
|
+
evaluateQaGate,
|
|
216
|
+
recordRework,
|
|
217
|
+
resetQaGateState,
|
|
218
|
+
MAX_REWORK,
|
|
219
|
+
};
|
|
@@ -319,4 +319,7 @@ module.exports = {
|
|
|
319
319
|
TYPE_KEYWORDS,
|
|
320
320
|
// re-exported for callers that want the raw map
|
|
321
321
|
GREENFIELD_WORKFLOW_BY_TYPE,
|
|
322
|
+
// Onda3-S2 (AF-20260702 item 3.4): exported so artifact gates share ONE
|
|
323
|
+
// definition of "artifact exists and is non-empty" instead of forking it.
|
|
324
|
+
fileHasContent,
|
|
322
325
|
};
|
|
@@ -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
|
|
@@ -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
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
metadata:
|
|
2
2
|
version: 1.0.0
|
|
3
|
-
lastUpdated: '2026-07-
|
|
4
|
-
entityCount:
|
|
3
|
+
lastUpdated: '2026-07-03T09:35:03.324Z'
|
|
4
|
+
entityCount: 814
|
|
5
5
|
checksumAlgorithm: sha256
|
|
6
6
|
resolutionRate: 100
|
|
7
7
|
entities:
|
|
@@ -2959,8 +2959,8 @@ entities:
|
|
|
2959
2959
|
score: 0.8
|
|
2960
2960
|
constraints: []
|
|
2961
2961
|
extensionPoints: []
|
|
2962
|
-
checksum: sha256:
|
|
2963
|
-
lastVerified: '2026-07-
|
|
2962
|
+
checksum: sha256:222b56327fd175c90bea4c89e3a1b82e27e94c28085a74530489682483038edd
|
|
2963
|
+
lastVerified: '2026-07-03T09:35:03.116Z'
|
|
2964
2964
|
export-design-tokens-dtcg:
|
|
2965
2965
|
path: .sinapse-ai/development/tasks/export-design-tokens-dtcg.md
|
|
2966
2966
|
layer: L2
|
|
@@ -11582,6 +11582,27 @@ entities:
|
|
|
11582
11582
|
extensionPoints: []
|
|
11583
11583
|
checksum: sha256:d4ad190353fc751e874bad5b3013137dcccfc84100edd6cead80c8fa5e83af11
|
|
11584
11584
|
lastVerified: '2026-06-30T18:30:20.187Z'
|
|
11585
|
+
brownfield-progress:
|
|
11586
|
+
path: .sinapse-ai/core/orchestration/brownfield-progress.js
|
|
11587
|
+
layer: L1
|
|
11588
|
+
type: module
|
|
11589
|
+
purpose: Entity at .sinapse-ai\core\orchestration\brownfield-progress.js
|
|
11590
|
+
keywords:
|
|
11591
|
+
- brownfield
|
|
11592
|
+
- progress
|
|
11593
|
+
usedBy:
|
|
11594
|
+
- workflow-executor
|
|
11595
|
+
dependencies:
|
|
11596
|
+
- doc-first-resolver
|
|
11597
|
+
externalDeps: []
|
|
11598
|
+
plannedDeps: []
|
|
11599
|
+
lifecycle: production
|
|
11600
|
+
adaptability:
|
|
11601
|
+
score: 0.4
|
|
11602
|
+
constraints: []
|
|
11603
|
+
extensionPoints: []
|
|
11604
|
+
checksum: sha256:919fa899b32e584842f370df84cfefdc5d450136f13699c1916d82f3e1833b7d
|
|
11605
|
+
lastVerified: '2026-07-03T08:52:22.751Z'
|
|
11585
11606
|
build-command:
|
|
11586
11607
|
path: .sinapse-ai/core/orchestration/build-command.js
|
|
11587
11608
|
layer: L1
|
|
@@ -11738,7 +11759,9 @@ entities:
|
|
|
11738
11759
|
- first
|
|
11739
11760
|
- resolver
|
|
11740
11761
|
usedBy:
|
|
11762
|
+
- brownfield-progress
|
|
11741
11763
|
- build-command
|
|
11764
|
+
- greenfield-handler
|
|
11742
11765
|
- route-command
|
|
11743
11766
|
dependencies:
|
|
11744
11767
|
- greenfield-handler
|
|
@@ -11749,8 +11772,8 @@ entities:
|
|
|
11749
11772
|
score: 0.4
|
|
11750
11773
|
constraints: []
|
|
11751
11774
|
extensionPoints: []
|
|
11752
|
-
checksum: sha256:
|
|
11753
|
-
lastVerified: '2026-
|
|
11775
|
+
checksum: sha256:e309338d1ca98d70953563a2cf92bae261264fac8001f389afdb7fbf968be353
|
|
11776
|
+
lastVerified: '2026-07-03T08:39:26.307Z'
|
|
11754
11777
|
epic-context-accumulator:
|
|
11755
11778
|
path: .sinapse-ai/core/orchestration/epic-context-accumulator.js
|
|
11756
11779
|
layer: L1
|
|
@@ -11954,6 +11977,7 @@ entities:
|
|
|
11954
11977
|
- bob-orchestrator
|
|
11955
11978
|
- doc-first-resolver
|
|
11956
11979
|
dependencies:
|
|
11980
|
+
- doc-first-resolver
|
|
11957
11981
|
- workflow-executor
|
|
11958
11982
|
- surface-checker
|
|
11959
11983
|
- session-state
|
|
@@ -11964,8 +11988,8 @@ entities:
|
|
|
11964
11988
|
score: 0.4
|
|
11965
11989
|
constraints: []
|
|
11966
11990
|
extensionPoints: []
|
|
11967
|
-
checksum: sha256:
|
|
11968
|
-
lastVerified: '2026-
|
|
11991
|
+
checksum: sha256:5f40108470bf2602e9ccb72c241ece5d1b9e801ba83e1864b8b1d5f34ae3e9e7
|
|
11992
|
+
lastVerified: '2026-07-03T08:39:26.309Z'
|
|
11969
11993
|
lock-manager:
|
|
11970
11994
|
path: .sinapse-ai/core/orchestration/lock-manager.js
|
|
11971
11995
|
layer: L1
|
|
@@ -12247,6 +12271,7 @@ entities:
|
|
|
12247
12271
|
- executor-assignment
|
|
12248
12272
|
- session-state
|
|
12249
12273
|
- gate-evaluator
|
|
12274
|
+
- brownfield-progress
|
|
12250
12275
|
externalDeps: []
|
|
12251
12276
|
plannedDeps: []
|
|
12252
12277
|
lifecycle: production
|
|
@@ -12254,8 +12279,8 @@ entities:
|
|
|
12254
12279
|
score: 0.4
|
|
12255
12280
|
constraints: []
|
|
12256
12281
|
extensionPoints: []
|
|
12257
|
-
checksum: sha256:
|
|
12258
|
-
lastVerified: '2026-
|
|
12282
|
+
checksum: sha256:aa21bf15ac3fec1170b6bf5a446051c93718c069b5afa44d75ed5557427597a6
|
|
12283
|
+
lastVerified: '2026-07-03T08:52:22.755Z'
|
|
12259
12284
|
workflow-orchestrator:
|
|
12260
12285
|
path: .sinapse-ai/core/orchestration/workflow-orchestrator.js
|
|
12261
12286
|
layer: L1
|
|
@@ -15059,8 +15084,8 @@ entities:
|
|
|
15059
15084
|
score: 0.4
|
|
15060
15085
|
constraints: []
|
|
15061
15086
|
extensionPoints: []
|
|
15062
|
-
checksum: sha256:
|
|
15063
|
-
lastVerified: '2026-
|
|
15087
|
+
checksum: sha256:1cda821dcfd9dde90c00a9566588a6d5155d6265deaf926caf3477d9f8def921
|
|
15088
|
+
lastVerified: '2026-07-03T08:52:22.790Z'
|
|
15064
15089
|
brownfield-fullstack:
|
|
15065
15090
|
path: .sinapse-ai/development/workflows/brownfield-fullstack.yaml
|
|
15066
15091
|
layer: L2
|
|
@@ -15206,8 +15231,8 @@ entities:
|
|
|
15206
15231
|
score: 0.4
|
|
15207
15232
|
constraints: []
|
|
15208
15233
|
extensionPoints: []
|
|
15209
|
-
checksum: sha256:
|
|
15210
|
-
lastVerified: '2026-07-
|
|
15234
|
+
checksum: sha256:fd22d105cfce45cf7202d947fcc145987ed07b8503ec8dfdd260fa5a43886345
|
|
15235
|
+
lastVerified: '2026-07-03T09:35:03.241Z'
|
|
15211
15236
|
fast-track:
|
|
15212
15237
|
path: .sinapse-ai/development/workflows/fast-track.yaml
|
|
15213
15238
|
layer: L2
|
|
@@ -835,6 +835,9 @@ Each story spawns the full development-cycle:
|
|
|
835
835
|
### epic-orchestration.yaml (template)
|
|
836
836
|
Provides the generic wave pattern that this task instantiates with project-specific data from the EXECUTION.yaml.
|
|
837
837
|
|
|
838
|
+
### Wave gate executável (scripts/wave-gate.js)
|
|
839
|
+
Gate determinístico por wave: para cada diretório de story, verifica testes verdes E arquivos de produto realmente escritos (um plano não é implementação) → APPROVED/NEEDS_WORK com exit code. Uso: `node scripts/wave-gate.js --stories <dir1> <dir2> [--test-cmd "..."]`. **Nota de honestidade (medição 2026-07-03):** o wrapper autônomo de waves foi REPROVADO pelo protocolo pré-registrado (ver `docs/epics/epic-onda3-estrutural/CHECKPOINT-waves-2026-07-03.md`) — para multi-story prefira o caminho nativo; o gate permanece como utilitário de verificação por lote.
|
|
840
|
+
|
|
838
841
|
### po-epic-context.md
|
|
839
842
|
Used by @product-lead during story validation to understand accumulated changes across the epic.
|
|
840
843
|
|
|
@@ -17,6 +17,22 @@ workflow:
|
|
|
17
17
|
metadata:
|
|
18
18
|
elicit: true
|
|
19
19
|
confirmation_required: true
|
|
20
|
+
# Onda3-S3 (AF-20260702 item 3.3): phases 1-3 are declared parallelizable —
|
|
21
|
+
# their artifacts are independent (system/db/frontend). Autonomous fan-out
|
|
22
|
+
# of these phases is GATED on a measured pilot (same pre-registered gate as
|
|
23
|
+
# epic waves — docs/epics/epic-onda3-estrutural/README.md): until a
|
|
24
|
+
# measurement shows fan-out beating sequential handoff, execution stays
|
|
25
|
+
# manual per-agent. Deterministic progress + the Phase 7 QA gate come from
|
|
26
|
+
# core/orchestration/brownfield-progress.js (attached to the executeWorkflow
|
|
27
|
+
# handoff): resume points and the APPROVED/NEEDS WORK loop (max 2 reworks,
|
|
28
|
+
# then escalate) are measured from disk, not from prose.
|
|
29
|
+
parallelizable_phases: [1, 2, 3]
|
|
30
|
+
qa_gate:
|
|
31
|
+
phase: 7
|
|
32
|
+
review_artifact: docs/reviews/qa-review.md
|
|
33
|
+
verdicts: [APPROVED, NEEDS_WORK]
|
|
34
|
+
max_rework_cycles: 2
|
|
35
|
+
evaluator: .sinapse-ai/core/orchestration/brownfield-progress.js
|
|
20
36
|
action_types:
|
|
21
37
|
task-reference: "Action references an existing task file in .sinapse-ai/development/tasks/"
|
|
22
38
|
agent-command: "Action references an agent-level command (e.g., *create-front-end-spec)"
|
|
@@ -35,6 +35,17 @@ workflow:
|
|
|
35
35
|
metadata:
|
|
36
36
|
elicit: true
|
|
37
37
|
confirmation_required: true
|
|
38
|
+
# HONESTIDADE (Onda3-S5, medido 2026-07-03): este template descreve o
|
|
39
|
+
# PATTERN de waves, mas não existe executor de waves em produção — e o
|
|
40
|
+
# piloto medido (docs/epics/epic-onda3-estrutural/CHECKPOINT-waves-2026-07-03.md)
|
|
41
|
+
# REPROVOU o wrapper de waves pelo critério pré-registrado (empate em
|
|
42
|
+
# correctness, ~2x o custo vs caminho nativo). Para multi-story, use o
|
|
43
|
+
# caminho nativo. O gate determinístico de wave existe como utilitário
|
|
44
|
+
# standalone: scripts/wave-gate.js (testes verdes + arquivos realmente
|
|
45
|
+
# escritos, por story). Reabertura só via novo piloto pelo mesmo protocolo
|
|
46
|
+
# (tests/evals/epic-gates/PROTOCOL.md).
|
|
47
|
+
production_status: pattern-only-no-executor
|
|
48
|
+
wave_gate_utility: scripts/wave-gate.js
|
|
38
49
|
|
|
39
50
|
# ═══════════════════════════════════════════════════════════════════════════════════
|
|
40
51
|
# EXECUTION MODES
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
# - SHA256 hashes for change detection
|
|
8
8
|
# - File types for categorization
|
|
9
9
|
#
|
|
10
|
-
version: 1.
|
|
10
|
+
version: 1.21.0
|
|
11
11
|
generator: scripts/generate-install-manifest.js
|
|
12
|
-
file_count:
|
|
12
|
+
file_count: 1154
|
|
13
13
|
files:
|
|
14
14
|
- path: cli/commands/config/index.js
|
|
15
15
|
hash: sha256:bfa83cb1dc111b0b30dd298dc0abc2150b73f939b6cd4458effa8e6d407bc9e2
|
|
@@ -923,6 +923,10 @@ files:
|
|
|
923
923
|
hash: sha256:d4ad190353fc751e874bad5b3013137dcccfc84100edd6cead80c8fa5e83af11
|
|
924
924
|
type: core
|
|
925
925
|
size: 28745
|
|
926
|
+
- path: core/orchestration/brownfield-progress.js
|
|
927
|
+
hash: sha256:919fa899b32e584842f370df84cfefdc5d450136f13699c1916d82f3e1833b7d
|
|
928
|
+
type: core
|
|
929
|
+
size: 7585
|
|
926
930
|
- path: core/orchestration/build-command.js
|
|
927
931
|
hash: sha256:b758cfc7c0fad3d0d875460630b9ac7b2c968b82cdec14e9885e0744ee7012d0
|
|
928
932
|
type: core
|
|
@@ -952,9 +956,9 @@ files:
|
|
|
952
956
|
type: core
|
|
953
957
|
size: 10880
|
|
954
958
|
- path: core/orchestration/doc-first-resolver.js
|
|
955
|
-
hash: sha256:
|
|
959
|
+
hash: sha256:e309338d1ca98d70953563a2cf92bae261264fac8001f389afdb7fbf968be353
|
|
956
960
|
type: core
|
|
957
|
-
size:
|
|
961
|
+
size: 14762
|
|
958
962
|
- path: core/orchestration/epic-context-accumulator.js
|
|
959
963
|
hash: sha256:9f38c7e3b4de7fbcfeae5fe1dc88aa3f0ae38667f1dc1da025519d40b3b9daa9
|
|
960
964
|
type: core
|
|
@@ -1000,9 +1004,9 @@ files:
|
|
|
1000
1004
|
type: core
|
|
1001
1005
|
size: 23437
|
|
1002
1006
|
- path: core/orchestration/greenfield-handler.js
|
|
1003
|
-
hash: sha256:
|
|
1007
|
+
hash: sha256:5f40108470bf2602e9ccb72c241ece5d1b9e801ba83e1864b8b1d5f34ae3e9e7
|
|
1004
1008
|
type: core
|
|
1005
|
-
size:
|
|
1009
|
+
size: 44211
|
|
1006
1010
|
- path: core/orchestration/index.js
|
|
1007
1011
|
hash: sha256:ee215f855804448dcb02375128f4ff1f39e6861f37d1762dde19c80e77b8f4a6
|
|
1008
1012
|
type: core
|
|
@@ -1056,9 +1060,9 @@ files:
|
|
|
1056
1060
|
type: core
|
|
1057
1061
|
size: 16495
|
|
1058
1062
|
- path: core/orchestration/workflow-executor.js
|
|
1059
|
-
hash: sha256:
|
|
1063
|
+
hash: sha256:aa21bf15ac3fec1170b6bf5a446051c93718c069b5afa44d75ed5557427597a6
|
|
1060
1064
|
type: core
|
|
1061
|
-
size:
|
|
1065
|
+
size: 38414
|
|
1062
1066
|
- path: core/orchestration/workflow-orchestrator.js
|
|
1063
1067
|
hash: sha256:6e97eec88c8261f15bad79c47b0eafcfe39fbda5c837e156fe803802c3a1c18f
|
|
1064
1068
|
type: core
|
|
@@ -1360,9 +1364,9 @@ files:
|
|
|
1360
1364
|
type: data
|
|
1361
1365
|
size: 9671
|
|
1362
1366
|
- path: data/entity-registry.yaml
|
|
1363
|
-
hash: sha256:
|
|
1367
|
+
hash: sha256:c3e211656dbfb4dd5628e403728bc90ace0c1d2a1faa55385d60c8c873e46e08
|
|
1364
1368
|
type: data
|
|
1365
|
-
size:
|
|
1369
|
+
size: 557940
|
|
1366
1370
|
- path: data/learned-patterns.yaml
|
|
1367
1371
|
hash: sha256:1a4cd045c087b9dfd7046ff1464a9d2edb85fba77cf0b6fba14f4bb9004c741e
|
|
1368
1372
|
type: data
|
|
@@ -2160,9 +2164,9 @@ files:
|
|
|
2160
2164
|
type: task
|
|
2161
2165
|
size: 8809
|
|
2162
2166
|
- path: development/tasks/execute-epic-plan.md
|
|
2163
|
-
hash: sha256:
|
|
2167
|
+
hash: sha256:222b56327fd175c90bea4c89e3a1b82e27e94c28085a74530489682483038edd
|
|
2164
2168
|
type: task
|
|
2165
|
-
size:
|
|
2169
|
+
size: 26107
|
|
2166
2170
|
- path: development/tasks/export-design-tokens-dtcg.md
|
|
2167
2171
|
hash: sha256:ce37d53f78d6ddab720e6d534d9da629497264ed72b620bc4ff1306ad0f6ffeb
|
|
2168
2172
|
type: task
|
|
@@ -2960,9 +2964,9 @@ files:
|
|
|
2960
2964
|
type: workflow
|
|
2961
2965
|
size: 18594
|
|
2962
2966
|
- path: development/workflows/brownfield-discovery.yaml
|
|
2963
|
-
hash: sha256:
|
|
2967
|
+
hash: sha256:1cda821dcfd9dde90c00a9566588a6d5155d6265deaf926caf3477d9f8def921
|
|
2964
2968
|
type: workflow
|
|
2965
|
-
size:
|
|
2969
|
+
size: 34298
|
|
2966
2970
|
- path: development/workflows/brownfield-fullstack.yaml
|
|
2967
2971
|
hash: sha256:7be5f76d80bddea70b560c4fe9caa35d0534ec84e4d4ed0e120a99f68b73950d
|
|
2968
2972
|
type: workflow
|
|
@@ -2984,9 +2988,9 @@ files:
|
|
|
2984
2988
|
type: workflow
|
|
2985
2989
|
size: 15633
|
|
2986
2990
|
- path: development/workflows/epic-orchestration.yaml
|
|
2987
|
-
hash: sha256:
|
|
2991
|
+
hash: sha256:fd22d105cfce45cf7202d947fcc145987ed07b8503ec8dfdd260fa5a43886345
|
|
2988
2992
|
type: workflow
|
|
2989
|
-
size:
|
|
2993
|
+
size: 17712
|
|
2990
2994
|
- path: development/workflows/fast-track.yaml
|
|
2991
2995
|
hash: sha256:1a4f5665af164b8c6425d2ff3c2e713ff8559a66066aa0c7cbd1c6773aaa8266
|
|
2992
2996
|
type: workflow
|