session-orchestrator 3.19.0 → 3.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.
Files changed (158) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.cursor/rules/030-wave-execution.mdc +10 -8
  5. package/CHANGELOG.md +494 -0
  6. package/README.md +16 -11
  7. package/agents/analyst.md +1 -1
  8. package/agents/architect-reviewer.md +1 -1
  9. package/agents/code-implementer.md +4 -2
  10. package/agents/db-specialist.md +1 -1
  11. package/agents/dialectic-deriver.md +1 -1
  12. package/agents/docs-writer.md +1 -1
  13. package/agents/memory-proposal-collector.md +1 -1
  14. package/agents/qa-strategist.md +1 -1
  15. package/agents/security-reviewer.md +1 -1
  16. package/agents/session-reviewer.md +42 -1
  17. package/agents/skill-applied-judge.md +1 -1
  18. package/agents/test-writer.md +1 -1
  19. package/agents/ui-developer.md +1 -1
  20. package/agents/ux-evaluator.md +1 -1
  21. package/commands/release.md +60 -0
  22. package/commands/session.md +6 -2
  23. package/docs/USER-GUIDE.md +1 -1
  24. package/docs/instruction-delivery.md +350 -0
  25. package/docs/migration-v3.md +9 -6
  26. package/docs/persona-panel.md +3 -1
  27. package/docs/scope-collision-guard.md +167 -0
  28. package/docs/session-config-reference.md +1 -41
  29. package/docs/session-config-template.md +0 -23
  30. package/hooks/_lib/guard-source-loader.mjs +304 -91
  31. package/hooks/enforce-commands.mjs +216 -17
  32. package/hooks/enforce-scope.mjs +236 -12
  33. package/hooks/hooks-codex.json +1 -1
  34. package/hooks/hooks.json +11 -1
  35. package/hooks/on-session-end.mjs +52 -5
  36. package/hooks/on-session-start.mjs +7 -4
  37. package/hooks/on-stop.mjs +127 -12
  38. package/hooks/post-bash-write-verify.mjs +8 -32
  39. package/hooks/pre-bash-destructive-guard.mjs +146 -59
  40. package/hooks/pre-bash-sessions-ledger-guard.mjs +493 -66
  41. package/hooks/pre-task-scope-disjoint.mjs +1042 -0
  42. package/package.json +2 -2
  43. package/pi/prompts/release.md +12 -0
  44. package/scripts/autopilot.mjs +3 -1
  45. package/scripts/backfill-learnings-from-vault.mjs +967 -0
  46. package/scripts/emit-session.mjs +45 -40
  47. package/scripts/export-hw-learnings.mjs +61 -2
  48. package/scripts/lib/autopilot/worktree-pipeline.mjs +5 -5
  49. package/scripts/lib/backlog-scan.mjs +106 -15
  50. package/scripts/lib/build-live-signals.mjs +7 -3
  51. package/scripts/lib/ci-status-banner.mjs +207 -23
  52. package/scripts/lib/command-blocker.mjs +322 -62
  53. package/scripts/lib/git-config-drift.mjs +471 -0
  54. package/scripts/lib/hardening.mjs +9 -9
  55. package/scripts/lib/harness-audit/categories/category6.mjs +65 -12
  56. package/scripts/lib/io.mjs +193 -7
  57. package/scripts/lib/learnings/affinity.mjs +434 -0
  58. package/scripts/lib/learnings/candidates.mjs +736 -0
  59. package/scripts/lib/learnings/expiry-sweep.mjs +408 -53
  60. package/scripts/lib/learnings/judgment.mjs +782 -0
  61. package/scripts/lib/learnings/kebab.mjs +128 -0
  62. package/scripts/lib/learnings/select.mjs +704 -0
  63. package/scripts/lib/memory-cleanup-stamp.mjs +132 -8
  64. package/scripts/lib/mirror-issues-banner.mjs +266 -0
  65. package/scripts/lib/named-vault-resolver.mjs +105 -16
  66. package/scripts/lib/peer-cards/schema.mjs +6 -2
  67. package/scripts/lib/reconcile/emitter.mjs +107 -22
  68. package/scripts/lib/reconcile/engine.mjs +9 -15
  69. package/scripts/lib/reconcile/renderer.mjs +141 -25
  70. package/scripts/lib/reconcile/sanitize.mjs +518 -0
  71. package/scripts/lib/reconcile/writer.mjs +134 -1
  72. package/scripts/lib/redact-spans.mjs +89 -0
  73. package/scripts/lib/scope-baseline.mjs +77 -17
  74. package/scripts/lib/scope-gate.mjs +852 -72
  75. package/scripts/lib/secret-masker.mjs +262 -0
  76. package/scripts/lib/session-close-backfill.mjs +2 -2
  77. package/scripts/lib/session-lock.mjs +34 -10
  78. package/scripts/lib/session-record-repair.mjs +551 -0
  79. package/scripts/lib/session-registry.mjs +9 -1
  80. package/scripts/lib/session-schema/serializer.mjs +54 -0
  81. package/scripts/lib/session-schema.mjs +1 -0
  82. package/scripts/lib/session-token-rollup.mjs +68 -6
  83. package/scripts/lib/soul-resolve.mjs +12 -0
  84. package/scripts/lib/state-md/mission-status.mjs +21 -12
  85. package/scripts/lib/tmux-layout/telemetry.mjs +43 -10
  86. package/scripts/lib/tmux-layout/vcs-detector.mjs +108 -4
  87. package/scripts/lib/validate/check-agents.mjs +77 -5
  88. package/scripts/lib/validate/check-banner-parity.mjs +376 -0
  89. package/scripts/lib/validate/check-commands.mjs +2 -20
  90. package/scripts/lib/validate/check-doc-cli-commands.mjs +514 -0
  91. package/scripts/lib/validate/check-guard-requires-parity.mjs +1148 -0
  92. package/scripts/lib/validate/check-hooks-symmetry.mjs +18 -0
  93. package/scripts/lib/validate/check-learning-provenance.mjs +511 -0
  94. package/scripts/lib/validate/check-owner-leakage.mjs +188 -20
  95. package/scripts/lib/validate/check-rules.mjs +31 -5
  96. package/scripts/lib/validate/check-skills.mjs +191 -0
  97. package/scripts/lib/validate/check-test-git-config-target.mjs +665 -0
  98. package/scripts/lib/validate/check-unicode-safety.mjs +22 -2
  99. package/scripts/lib/validate/check-untracked-test-deps.mjs +925 -0
  100. package/scripts/lib/validate/check-unwired-features.mjs +757 -0
  101. package/scripts/lib/validate/check-vcs-repo-flag.mjs +965 -0
  102. package/scripts/lib/validate/frontmatter-block.mjs +61 -0
  103. package/scripts/lib/validate/tier-inference.mjs +46 -8
  104. package/scripts/lib/vault-mirror/namespace.mjs +146 -1
  105. package/scripts/lib/vault-mirror/process.mjs +264 -31
  106. package/scripts/lib/vault-mirror/render-sessions.mjs +115 -4
  107. package/scripts/lib/vault-status/board-writer.mjs +300 -56
  108. package/scripts/lib/vault-status/narrative-mirror.mjs +119 -5
  109. package/scripts/lib/vcs-repo-spec.mjs +500 -19
  110. package/scripts/print-applicable-rules.mjs +170 -7
  111. package/scripts/print-learnings-index.mjs +501 -0
  112. package/scripts/release.mjs +616 -61
  113. package/scripts/repair-invalid-sessions.mjs +209 -0
  114. package/scripts/site-numbers.mjs +1049 -0
  115. package/scripts/sweep-expired-learnings.mjs +192 -32
  116. package/scripts/validate-plugin.mjs +82 -0
  117. package/scripts/validate-wave-scope.mjs +281 -12
  118. package/scripts/vault-mirror.mjs +26 -1
  119. package/skills/_shared/monitor-patterns.md +24 -4
  120. package/skills/_shared/state-ownership.md +17 -0
  121. package/skills/brainstorm/soul.md +47 -1
  122. package/skills/claude-md-drift-check/SKILL.md +9 -1
  123. package/skills/debug/SKILL.md +4 -1
  124. package/skills/discovery/issue-templates.md +4 -4
  125. package/skills/discovery/probes-code.md +2 -2
  126. package/skills/discovery/probes-feature.md +6 -6
  127. package/skills/discovery/probes-infra.md +2 -2
  128. package/skills/discovery/probes-session.md +5 -5
  129. package/skills/dispatcher/SKILL.md +10 -1
  130. package/skills/evolve/SKILL.md +116 -18
  131. package/skills/frontmatter-guard/SKILL.md +9 -1
  132. package/skills/gitlab-ops/SKILL.md +54 -39
  133. package/skills/gitlab-portfolio/SKILL.md +10 -1
  134. package/skills/grill/soul.md +44 -1
  135. package/skills/memory-cleanup/SKILL.md +18 -5
  136. package/skills/npm-publish/SKILL.md +22 -50
  137. package/skills/persona-panel/SKILL.md +3 -1
  138. package/skills/plan/mode-new.md +23 -5
  139. package/skills/plan/soul.md +46 -3
  140. package/skills/repo-audit/SKILL.md +10 -1
  141. package/skills/session-end/SKILL.md +45 -26
  142. package/skills/session-end/metrics-collection.md +1 -1
  143. package/skills/session-end/phase-3-6-tail.md +30 -1
  144. package/skills/session-end/plan-verification.md +1 -5
  145. package/skills/session-end/session-metrics-write.md +6 -10
  146. package/skills/session-plan/SKILL.md +2 -2
  147. package/skills/session-plan/wave-template.md +1 -1
  148. package/skills/session-start/SKILL.md +15 -1
  149. package/skills/session-start/soul.md +41 -1
  150. package/skills/spinout/SKILL.md +5 -1
  151. package/skills/sunset-review/SKILL.md +11 -1
  152. package/skills/tmux-layout/SKILL.md +7 -2
  153. package/skills/vault-mirror/SKILL.md +10 -1
  154. package/skills/vault-sync/SKILL.md +10 -1
  155. package/skills/vault-sync/validator.mjs +55 -6
  156. package/skills/wave-executor/SKILL.md +1 -5
  157. package/skills/wave-executor/wave-loop.md +77 -82
  158. package/scripts/lib/mission-status-schema.mjs +0 -114
@@ -69,6 +69,50 @@ function renderDuration(durationSeconds, durationMinutes) {
69
69
  return minutes === undefined || minutes === null ? MISSING_VALUE : `${minutes}m`;
70
70
  }
71
71
 
72
+ /**
73
+ * Coerce ONE wave-object count field to a renderable number (#1074).
74
+ *
75
+ * ── WHY A TYPE GUARD AND NOT A BARE `??` CHAIN ─────────────────────────────
76
+ *
77
+ * The wave-object count fields are POLYMORPHIC across producer generations.
78
+ * Census over the live ledger (253 records / 599 wave objects, 2026-08-19):
79
+ *
80
+ * agent_count number 359
81
+ * agents number 210, **ARRAY 14** ← array-of-agent-descriptors
82
+ * agents_dispatched number 20
83
+ * dispatched number 5
84
+ * files_changed number 366, **ARRAY 1** ← array-of-file-paths
85
+ * files number 5
86
+ *
87
+ * A naive `w.agent_count ?? w.agents` therefore interpolates an array of
88
+ * objects into a Markdown table cell — `[object Object],[object Object],…` for
89
+ * the 4 waves of `main-2026-04-27-2231`. That is STRICTLY WORSE than the `?` it
90
+ * replaces: `?` reads as "unknown", `[object Object]` reads as content. The
91
+ * array-of-paths half of the same defect is already in production —
92
+ * `main-2026-05-26-housekeeping-1` renders its whole file list into the Files
93
+ * cell today, via the plain `w.files_changed` read that predates this helper.
94
+ *
95
+ * An array IS a measurement (its length is the count), so it is converted, not
96
+ * dropped. Any OTHER shape returns `undefined` so the caller's `??` chain keeps
97
+ * walking to the next alias and ultimately to `MISSING_CELL` — an unrecognised
98
+ * shape must degrade to "unknown", never to a coerced string. `NaN` is out of
99
+ * reach here by construction: JSON cannot encode it, and every caller feeds
100
+ * this JSONL-parsed values.
101
+ *
102
+ * ABSENT IS NOT ZERO applies unchanged (see the banner above `MISSING_CELL`):
103
+ * this returns `0` for a measured `0` and `0` for an empty array, and only
104
+ * `undefined` for a field the producer never wrote. Callers MUST chain with
105
+ * `??`, never `||` — `agents_dispatched: 0` occurs 20× in the live ledger.
106
+ *
107
+ * @param {unknown} value — one raw wave-object field.
108
+ * @returns {number|undefined} the count, or `undefined` to continue the chain.
109
+ */
110
+ function waveCount(value) {
111
+ if (typeof value === 'number') return value;
112
+ if (Array.isArray(value)) return value.length;
113
+ return undefined;
114
+ }
115
+
72
116
  /**
73
117
  * ── RENDERABLE ⊋ SCHEMA-VALID (#964) ───────────────────────────────────────
74
118
  *
@@ -259,6 +303,29 @@ function fmLine(key, value) {
259
303
  * reachability is therefore zero; see the follow-up note in the #964 report
260
304
  * before treating it as dead code — deletion is a separate decision, and the
261
305
  * `normalizeSessionEntry` alias path can still synthesize a scalar `waves`.
306
+ *
307
+ * #1074 — THE v2 BRANCH WAS DEAD AT BIRTH, AND THE NUMBER IS PINNED. Re-measured
308
+ * 2026-08-19 over 253 records: **v1 253, v2 0, v3 0**, both raw and
309
+ * post-`normalizeSessionEntry`. This is not a coincidence of the current data —
310
+ * the v2 clause is UNSATISFIABLE by construction: it requires
311
+ * `total_agents === undefined`, while `total_agents` is in `REQUIRED_FIELDS`
312
+ * (scripts/lib/session-schema/constants.mjs) and enforced by
313
+ * `validateSession`, so every record the writer accepts carries it (measured:
314
+ * 253/253 define it). Commit 9cb6d9c added the branch 4h23m BEFORE the first
315
+ * record using the `agents` alias was written, and no historical tracked ledger
316
+ * state would have routed one either.
317
+ *
318
+ * The consequence is the reason `generateSessionNote`'s wave table no longer
319
+ * consults this function for its alias handling at all: version detection is
320
+ * the WRONG AXIS for per-wave producer-key drift, because the alias varies per
321
+ * wave object and no session-level field — `schema_version` included — predicts
322
+ * it. See the census in the `waveRows` comment there. This function still
323
+ * routes the three GENERATORS and is unchanged; do not "repair" the wave table
324
+ * by re-anchoring it here.
325
+ *
326
+ * The generators are intentionally NOT deleted (operator decision, deferred
327
+ * once already in #964). Pinning the number here is the point: the next reader
328
+ * inherits the measurement instead of re-running it.
262
329
  */
263
330
  export function detectSessionSchema(entry) {
264
331
  if (!entry) return 'v1';
@@ -368,11 +435,55 @@ export function generateSessionNote(entry, options = {}) {
368
435
  // validated, so all three are optional and were rendering as the literal
369
436
  // string `undefined`. Guarded with the same `?? '?'` the v2 generator's wave
370
437
  // rows already used — `??` so a measured `0` still renders `0`.
438
+ //
439
+ // ── #1074: PER-WAVE ALIASES, NOT PER-SESSION VERSION DETECTION ────────────
440
+ //
441
+ // #M1 stopped the cells reading `undefined`, but left them reading `?` for
442
+ // every record whose producer used a different key — and that is most of the
443
+ // ledger. Census over 253 records / 599 wave objects (2026-08-19):
444
+ //
445
+ // Agents `?` 240 cells in 55 records (recoverable: agents 214, agents_dispatched 20, dispatched 5)
446
+ // Files `?` 232 cells in 52 records (recoverable: files 5)
447
+ // Quality `?` 386 cells in 88 records (recoverable: quality_check 168, status 72, result 35, outcome 5)
448
+ //
449
+ // The version-detection route cannot fix this. `detectSessionSchema` keys on
450
+ // SESSION-level fields, but the alias in use varies PER WAVE OBJECT and no
451
+ // session-level field predicts it — not even `schema_version` (under
452
+ // `schema_version: 1` the ledger carries agent_count 75, agents 33, none 30,
453
+ // agents_dispatched 4, both 2, dispatched 1). The axis is empirically
454
+ // refuted, so the repair is a per-wave alias chain instead.
455
+ //
456
+ // v1-canonical names come FIRST in every chain, so a cell that rendered a
457
+ // value before renders the identical value now: this can only ever replace a
458
+ // `?`. Verified over all 599 wave objects — repaired 239 agents / 5 files /
459
+ // 280 quality, with ZERO existing agents or quality values changed. The one
460
+ // deliberate change is the Files cell of `main-2026-05-26-housekeeping-1`,
461
+ // which stops printing a raw file-path list and prints `3` (see `waveCount`).
462
+ //
463
+ // The Quality chain needs no `waveCount`: all five of its aliases are 100%
464
+ // strings across the ledger (quality 213, quality_check 168, status 72,
465
+ // result 35, outcome 5 — zero objects or arrays), so there is no
466
+ // `[object Object]` hazard to guard. Should a producer ever emit a structured
467
+ // quality verdict, the fixture-coverage test in render-sessions.test.mjs is
468
+ // what surfaces it — this comment is the ceiling, that test is the trigger.
469
+ //
470
+ // A wave with no count under ANY alias keeps rendering `?`, and must: the
471
+ // coord-direct wave of `main-2026-05-26-housekeeping-1` dispatched no agents
472
+ // and recorded no number, so its Agents cell is genuinely unknown. A chain
473
+ // that "repaired" that one too would be inventing a measurement.
371
474
  const waveRows = waves
372
- .map(
373
- (w) =>
374
- `| ${w.wave} | ${w.role} | ${w.agent_count ?? MISSING_CELL} | ${w.files_changed ?? MISSING_CELL} | ${w.quality ?? MISSING_CELL} |`,
375
- )
475
+ .map((w) => {
476
+ const agentsCell =
477
+ waveCount(w.agent_count) ??
478
+ waveCount(w.agents) ??
479
+ waveCount(w.agents_dispatched) ??
480
+ waveCount(w.dispatched) ??
481
+ MISSING_CELL;
482
+ const filesCell = waveCount(w.files_changed) ?? waveCount(w.files) ?? MISSING_CELL;
483
+ const qualityCell =
484
+ w.quality ?? w.quality_check ?? w.status ?? w.result ?? w.outcome ?? MISSING_CELL;
485
+ return `| ${w.wave} | ${w.role} | ${agentsCell} | ${filesCell} | ${qualityCell} |`;
486
+ })
376
487
  .join('\n');
377
488
 
378
489
  // Skip-emit guard: avoid `platform: undefined` literal coercion (issue #343).