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.
@@ -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
- return {
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-03T06:58:13.504Z'
4
- entityCount: 813
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:a505eb0429e05d6c38e0836d7d60e98815aa70f10c855c0936dfde6731682343
2963
- lastVerified: '2026-07-03T06:55:48.479Z'
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:92a4170f3ed0b6b214608c80e17c8c6b1769a50b849532af4ae34db070a6931f
11753
- lastVerified: '2026-06-27T21:56:17.335Z'
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:330be2c76c3eb5a9a1f1c975837308802b8fc6fb871f9b584787ae4e2aa8fcb1
11968
- lastVerified: '2026-06-30T18:30:20.192Z'
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:c7aca8a292efcf20185cd30d6a582c6239a55a9871e4e63ed1c49a6aebf35f7a
12258
- lastVerified: '2026-06-30T18:30:20.195Z'
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:6de267f13f4fd996450ed228ac6bb109d4d75f91eef515c946d5885e464f4fc9
15063
- lastVerified: '2026-06-15T00:26:26.478Z'
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:f795fafa52113f199a186bbb00624c1d93491363f5198d46b6793fb9fee63a5d
15210
- lastVerified: '2026-07-03T06:55:48.584Z'
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.20.1
10
+ version: 1.21.0
11
11
  generator: scripts/generate-install-manifest.js
12
- file_count: 1153
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:92a4170f3ed0b6b214608c80e17c8c6b1769a50b849532af4ae34db070a6931f
959
+ hash: sha256:e309338d1ca98d70953563a2cf92bae261264fac8001f389afdb7fbf968be353
956
960
  type: core
957
- size: 14592
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:330be2c76c3eb5a9a1f1c975837308802b8fc6fb871f9b584787ae4e2aa8fcb1
1007
+ hash: sha256:5f40108470bf2602e9ccb72c241ece5d1b9e801ba83e1864b8b1d5f34ae3e9e7
1004
1008
  type: core
1005
- size: 40129
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:c7aca8a292efcf20185cd30d6a582c6239a55a9871e4e63ed1c49a6aebf35f7a
1063
+ hash: sha256:aa21bf15ac3fec1170b6bf5a446051c93718c069b5afa44d75ed5557427597a6
1060
1064
  type: core
1061
- size: 37636
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:166203aac0d019e100aff6a79145b2e83cf6b31d7d69374ffdc019e463ebf384
1367
+ hash: sha256:c3e211656dbfb4dd5628e403728bc90ace0c1d2a1faa55385d60c8c873e46e08
1364
1368
  type: data
1365
- size: 557171
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:a505eb0429e05d6c38e0836d7d60e98815aa70f10c855c0936dfde6731682343
2167
+ hash: sha256:222b56327fd175c90bea4c89e3a1b82e27e94c28085a74530489682483038edd
2164
2168
  type: task
2165
- size: 25478
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:6de267f13f4fd996450ed228ac6bb109d4d75f91eef515c946d5885e464f4fc9
2967
+ hash: sha256:1cda821dcfd9dde90c00a9566588a6d5155d6265deaf926caf3477d9f8def921
2964
2968
  type: workflow
2965
- size: 33356
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:f795fafa52113f199a186bbb00624c1d93491363f5198d46b6793fb9fee63a5d
2991
+ hash: sha256:fd22d105cfce45cf7202d947fcc145987ed07b8503ec8dfdd260fa5a43886345
2988
2992
  type: workflow
2989
- size: 16953
2993
+ size: 17712
2990
2994
  - path: development/workflows/fast-track.yaml
2991
2995
  hash: sha256:1a4f5665af164b8c6425d2ff3c2e713ff8559a66066aa0c7cbd1c6773aaa8266
2992
2996
  type: workflow