@chllming/wave-orchestration 0.9.10 → 0.9.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.11 - 2026-04-07
4
+
5
+ ### Fixed
6
+ - **Verdict parsing: first-match-wins** — `parseVerdictFromText()` now returns the **first** regex match instead of the last. In append-only cont-QA report files, stale `Verdict: BLOCKED` entries from earlier attempts would linger at the bottom of the file while newer `Verdict: PASS` entries were written above them. The last-match-wins behavior caused the cont-QA gate to read the stale blocked verdict, creating an infinite retry loop. This was the root cause of 17 blocked waves in React Word Editor (DOCX W20+).
7
+ - **Log verdict priority over report verdict** — `buildAgentExecutionSummary()` now prefers the log-based `[wave-verdict]` marker over the report file `Verdict:` line. The log is authoritative for the current run, while report files may accumulate conflicting entries across retry attempts.
8
+ - **Integration steward closure is now sticky** — When the integration steward (A8) explicitly reports `state=ready-for-doc-closure` with zero blockers, synthesized proof gaps and doc gaps from implementation agent validation are cleared from the integration summary. Previously, `buildWaveIntegrationSummary()` would re-inject gaps derived from agent summaries on every `refreshDerivedState()` call, overriding the steward's explicit sign-off and causing unnecessary retry cycles (observed as 15+ loops in DOCX W20).
9
+
10
+ ### Added
11
+ - Test suite for `parseVerdictFromText` covering first-match behavior, null/empty inputs, multi-verdict report files, and `[wave-verdict]` marker parsing.
12
+
3
13
  ## 0.9.10 - 2026-04-07
4
14
 
5
15
  ### Fixed
@@ -0,0 +1,44 @@
1
+ # Recommendations for 0.9.11
2
+
3
+ ## Upgrade
4
+
5
+ ```bash
6
+ wave self-update
7
+ # or: npm install -g @chllming/wave-orchestration@0.9.11
8
+ ```
9
+
10
+ ## What changed
11
+
12
+ ### Verdict parsing (P0 fix)
13
+
14
+ The `parseVerdictFromText()` function now returns the **first** regex match instead of the last. This fixes a critical bug where append-only cont-QA report files accumulated `Verdict:` lines across retries, and the stale `Verdict: BLOCKED` at the bottom would override newer `Verdict: PASS` entries above it.
15
+
16
+ **If you have waves stuck in cont-QA retry loops**, upgrading to 0.9.11 should unblock them on the next attempt. No manual intervention needed — the runner will re-evaluate the gate with the fixed parser.
17
+
18
+ **For ongoing work**: the log-based `[wave-verdict]` marker is now preferred over the report file `Verdict:` line. Both still work, but if both are present, the log marker wins. This is more reliable because the log is per-run while report files persist across attempts.
19
+
20
+ ### Log verdict priority
21
+
22
+ `buildAgentExecutionSummary()` now reads verdicts in this order:
23
+ 1. `[wave-verdict]` from the agent's log (authoritative per-run)
24
+ 2. `Verdict:` from the cont-QA report file (fallback)
25
+
26
+ Previously the report file took priority. If your cont-QA role prompt instructs the agent to write `Verdict: PASS/BLOCKED` in the report, that still works — it just won't override a contradicting `[wave-verdict]` marker in the same run's log.
27
+
28
+ ### Integration steward sticky closure
29
+
30
+ When A8 (integration steward) explicitly reports `state=ready-for-doc-closure` with zero blockers, the orchestrator no longer re-injects synthesized proof/doc gaps on the next `refreshDerivedState()` cycle. This prevents the pattern where:
31
+
32
+ 1. A8 closes all gaps → integration summary says "ready-for-doc-closure"
33
+ 2. Launcher calls `refreshDerivedState()` on next attempt
34
+ 3. `buildIntegrationEvidence()` re-derives gaps from agent summaries
35
+ 4. Integration summary regresses to "needs-more-work"
36
+ 5. Retry → goto 1
37
+
38
+ **No action required** — the fix is automatic. If your waves were stuck in integration retry loops, they should resolve on the next attempt.
39
+
40
+ ## Recommendations
41
+
42
+ - **Stuck cont-QA waves**: Just upgrade and let the runner retry. The fixed verdict parser will read the correct verdict.
43
+ - **Stuck integration loops**: Same — upgrade and let the runner retry.
44
+ - **Report file hygiene**: Consider having your cont-QA role prompt write verdicts with a clear section header (e.g., `## Final Verdict`) to make the file structure unambiguous. The first-match-wins behavior rewards putting the definitive verdict early in the file.
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@chllming/wave-orchestration",
3
- "version": "0.9.10",
3
+ "version": "0.9.11",
4
4
  "license": "MIT",
5
5
  "description": "Generic wave-based multi-agent orchestration for repository work.",
6
+ "packageManager": "pnpm@10.23.0",
6
7
  "repository": {
7
8
  "type": "git",
8
9
  "url": "git+https://github.com/chllming/agent-wave-orchestrator.git"
@@ -31,12 +32,6 @@
31
32
  "wave-dashboard": "scripts/wave-dashboard.mjs",
32
33
  "wave-local-executor": "scripts/wave-local-executor.mjs"
33
34
  },
34
- "devDependencies": {
35
- "@mozilla/readability": "^0.6.0",
36
- "jsdom": "^29.0.1",
37
- "pdfjs-dist": "^5.5.207",
38
- "vitest": "3.2.4"
39
- },
40
35
  "scripts": {
41
36
  "context7:api-check": "bash scripts/context7-export-env.sh run bash scripts/context7-api-check.sh",
42
37
  "research:import-agent-context": "node scripts/research/import-agent-context-archive.mjs scripts/research/manifests/agent-context-expanded-2026-03-22.mjs",
@@ -50,5 +45,11 @@
50
45
  "wave:feedback": "node scripts/wave-human-feedback.mjs",
51
46
  "wave:launch": "node scripts/wave-launcher.mjs",
52
47
  "wave:local": "node scripts/wave-local-executor.mjs"
48
+ },
49
+ "devDependencies": {
50
+ "@mozilla/readability": "^0.6.0",
51
+ "jsdom": "^29.0.1",
52
+ "pdfjs-dist": "^5.5.207",
53
+ "vitest": "3.2.4"
53
54
  }
54
- }
55
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -509,7 +509,9 @@ export function buildAgentExecutionSummary({ agent, statusRecord, logPath, repor
509
509
  : "";
510
510
  const reportVerdict = parseVerdictFromText(reportText, REPORT_VERDICT_REGEX);
511
511
  const logVerdict = parseVerdictFromText(signalText, WAVE_VERDICT_REGEX);
512
- const verdict = reportVerdict.verdict ? reportVerdict : logVerdict;
512
+ // Prefer log verdict (authoritative for the current run) over report verdict
513
+ // (may accumulate stale entries across retries in append-only report files).
514
+ const verdict = logVerdict.verdict ? logVerdict : reportVerdict;
513
515
  const termination = detectTermination(agent, logText, statusRecord);
514
516
  return {
515
517
  agentId: agent?.agentId || null,
@@ -573,6 +573,11 @@ export function buildWaveIntegrationSummary({
573
573
  securitySummary,
574
574
  });
575
575
  if (explicitIntegration) {
576
+ // When the integration steward explicitly asserts ready-for-doc-closure,
577
+ // clear synthesized proof/doc gaps — the steward has signed off on them.
578
+ const stewardClearedGaps =
579
+ explicitIntegration.state === "ready-for-doc-closure" &&
580
+ (explicitIntegration.blockers || 0) === 0;
576
581
  return {
577
582
  wave: wave.wave,
578
583
  lane: lanePaths.lane,
@@ -595,8 +600,8 @@ export function buildWaveIntegrationSummary({
595
600
  ),
596
601
  changedInterfaces: evidence.changedInterfaces,
597
602
  crossComponentImpacts: evidence.crossComponentImpacts,
598
- proofGaps: evidence.proofGaps,
599
- docGaps: evidence.docGaps,
603
+ proofGaps: stewardClearedGaps ? [] : evidence.proofGaps,
604
+ docGaps: stewardClearedGaps ? [] : evidence.docGaps,
600
605
  deployRisks: evidence.deployRisks,
601
606
  securityState: evidence.securityState,
602
607
  securityFindings: evidence.securityFindings,
@@ -443,16 +443,16 @@ export function parseVerdictFromText(text, regex) {
443
443
  }
444
444
  regex.lastIndex = 0;
445
445
  let match = regex.exec(text);
446
- let verdict = null;
447
- let detail = "";
448
- while (match !== null) {
449
- verdict = normalizeWaveVerdict(match[1]);
450
- detail = String(match[2] || "")
451
- .trim()
452
- .replace(/^detail=/i, "")
453
- .trim();
454
- match = regex.exec(text);
446
+ if (!match) {
447
+ return { verdict: null, detail: "" };
455
448
  }
449
+ // Use the first match — in append-only reports the latest verdict is written
450
+ // at the top of the newest section, while stale entries linger at the bottom.
451
+ const verdict = normalizeWaveVerdict(match[1]);
452
+ const detail = String(match[2] || "")
453
+ .trim()
454
+ .replace(/^detail=/i, "")
455
+ .trim();
456
456
  return { verdict, detail };
457
457
  }
458
458
 
File without changes
File without changes
package/scripts/wave.mjs CHANGED
File without changes