mandrel 2.31.0 → 2.33.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 (267) hide show
  1. package/.agents/README.md +13 -17
  2. package/.agents/agents/acceptance-critic.md +1 -2
  3. package/.agents/docs/SDLC.md +12 -9
  4. package/.agents/docs/agentrc-reference.json +63 -58
  5. package/.agents/docs/configuration.md +275 -227
  6. package/.agents/docs/execution-reference.md +13 -14
  7. package/.agents/docs/quality-gates.md +195 -23
  8. package/.agents/instructions.md +2 -5
  9. package/.agents/rules/git-conventions-reference.md +27 -27
  10. package/.agents/rules/git-conventions.md +4 -2
  11. package/.agents/rules/known-tooling-behavior.md +66 -30
  12. package/.agents/rules/testing-standards.md +35 -71
  13. package/.agents/runtime-deps.json +2 -2
  14. package/.agents/schemas/agentrc.schema.json +1955 -1410
  15. package/.agents/schemas/lifecycle/README.md +21 -14
  16. package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
  17. package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
  18. package/.agents/scripts/README.md +16 -29
  19. package/.agents/scripts/apply-quality-bootstrap.js +27 -34
  20. package/.agents/scripts/audit-to-stories.js +160 -41
  21. package/.agents/scripts/bootstrap.js +28 -26
  22. package/.agents/scripts/check-baseline-drift.js +73 -13
  23. package/.agents/scripts/check-baseline-scope.js +362 -0
  24. package/.agents/scripts/check-dead-exports.js +9 -1
  25. package/.agents/scripts/check-gherkin-corpus.js +508 -0
  26. package/.agents/scripts/check-knip-entries.js +159 -0
  27. package/.agents/scripts/check-lifecycle-lint.js +108 -124
  28. package/.agents/scripts/check-schema-references.js +1 -1
  29. package/.agents/scripts/diagnose-friction.js +7 -4
  30. package/.agents/scripts/generate-config-docs.js +263 -171
  31. package/.agents/scripts/install-matrix-assert.js +0 -1
  32. package/.agents/scripts/lib/ITicketingProvider.js +0 -58
  33. package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
  34. package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
  35. package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
  36. package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
  37. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +81 -35
  38. package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +185 -0
  39. package/.agents/scripts/lib/baselines/envelope.js +41 -60
  40. package/.agents/scripts/lib/baselines/git-base.js +30 -37
  41. package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
  42. package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
  43. package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
  44. package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
  45. package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
  46. package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
  47. package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
  48. package/.agents/scripts/lib/bdd-step-index.js +326 -0
  49. package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
  50. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
  51. package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
  52. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
  53. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
  54. package/.agents/scripts/lib/checks/loop-health.js +9 -37
  55. package/.agents/scripts/lib/child-exec.js +193 -0
  56. package/.agents/scripts/lib/cli/standard-args.js +1 -1
  57. package/.agents/scripts/lib/cli-args.js +64 -0
  58. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  59. package/.agents/scripts/lib/close-validation/runner.js +3 -3
  60. package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
  61. package/.agents/scripts/lib/config/commands.js +3 -5
  62. package/.agents/scripts/lib/config/explain.js +5 -7
  63. package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
  64. package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
  65. package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
  66. package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
  67. package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
  68. package/.agents/scripts/lib/config/gates/index.js +5 -2
  69. package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
  70. package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
  71. package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
  72. package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
  73. package/.agents/scripts/lib/config/gates/shared.js +58 -9
  74. package/.agents/scripts/lib/config/github.js +0 -1
  75. package/.agents/scripts/lib/config/limits.js +3 -48
  76. package/.agents/scripts/lib/config/qa.js +105 -0
  77. package/.agents/scripts/lib/config/runners.js +38 -16
  78. package/.agents/scripts/lib/config/temp-paths.js +6 -5
  79. package/.agents/scripts/lib/config-settings-schema-delivery.js +245 -56
  80. package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
  81. package/.agents/scripts/lib/config-settings-schema.js +386 -39
  82. package/.agents/scripts/lib/crap-baseline-join.js +126 -9
  83. package/.agents/scripts/lib/crap-utils.js +84 -520
  84. package/.agents/scripts/lib/dead-exports-knip.js +79 -10
  85. package/.agents/scripts/lib/degraded-mode.js +2 -2
  86. package/.agents/scripts/lib/dependency-parser.js +20 -7
  87. package/.agents/scripts/lib/doc-tiers.js +3 -3
  88. package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
  89. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
  90. package/.agents/scripts/lib/findings/provenance-field.js +135 -0
  91. package/.agents/scripts/lib/findings/route-finding.js +57 -8
  92. package/.agents/scripts/lib/fs-walk.js +52 -0
  93. package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
  94. package/.agents/scripts/lib/git-utils.js +16 -36
  95. package/.agents/scripts/lib/knip-config-resolver.js +181 -0
  96. package/.agents/scripts/lib/knip-entry-sync.js +508 -0
  97. package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
  98. package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
  99. package/.agents/scripts/lib/observability/signal-validator.js +5 -85
  100. package/.agents/scripts/lib/observability/signals-writer.js +19 -62
  101. package/.agents/scripts/lib/observability/source-classifier.js +5 -7
  102. package/.agents/scripts/lib/observability/terse-result.js +3 -3
  103. package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
  104. package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
  105. package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
  106. package/.agents/scripts/lib/orchestration/code-review.js +2 -2
  107. package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
  108. package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
  109. package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
  110. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
  111. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
  112. package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
  113. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +7 -26
  114. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +69 -5
  115. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +69 -13
  116. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +49 -0
  117. package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
  118. package/.agents/scripts/lib/orchestration/resolve-stories.js +77 -50
  119. package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
  120. package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
  121. package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
  122. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
  123. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
  124. package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
  131. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +59 -25
  132. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
  134. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
  135. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
  136. package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
  137. package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
  138. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +116 -1
  139. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
  140. package/.agents/scripts/lib/orchestration/ticket-validator.js +38 -0
  141. package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
  142. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
  143. package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
  144. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
  145. package/.agents/scripts/lib/signals/detectors/common.js +1 -1
  146. package/.agents/scripts/lib/signals/index.js +8 -6
  147. package/.agents/scripts/lib/signals/schema.js +20 -25
  148. package/.agents/scripts/lib/signals/write.js +8 -8
  149. package/.agents/scripts/lib/story-body/footer-block.js +97 -0
  150. package/.agents/scripts/lib/story-body/story-body.js +18 -81
  151. package/.agents/scripts/lib/temp-retention.js +1 -1
  152. package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
  153. package/.agents/scripts/lib/ticket-body-sections.js +4 -5
  154. package/.agents/scripts/lib/wave-runner/footprint.js +306 -0
  155. package/.agents/scripts/lib/wave-runner/ready-set.js +198 -181
  156. package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
  157. package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
  158. package/.agents/scripts/lib/worktree-manager.js +2 -3
  159. package/.agents/scripts/lint-label-vocabulary.js +2 -24
  160. package/.agents/scripts/pr-watch-with-update.js +7 -5
  161. package/.agents/scripts/providers/github/blocked-by-add.js +25 -10
  162. package/.agents/scripts/providers/github/cache.js +2 -2
  163. package/.agents/scripts/providers/github/comments.js +6 -28
  164. package/.agents/scripts/providers/github/compose.js +0 -15
  165. package/.agents/scripts/providers/github/errors.js +10 -27
  166. package/.agents/scripts/providers/github/request-helpers.js +1 -2
  167. package/.agents/scripts/providers/github/sub-issues.js +10 -218
  168. package/.agents/scripts/providers/github.js +4 -7
  169. package/.agents/scripts/prune-baseline-orphans.js +181 -0
  170. package/.agents/scripts/resolve-stories.js +21 -7
  171. package/.agents/scripts/run-lint.js +61 -61
  172. package/.agents/scripts/run-test-profile.js +6 -6
  173. package/.agents/scripts/run-verify.js +48 -30
  174. package/.agents/scripts/single-story-close.js +20 -0
  175. package/.agents/scripts/single-story-init.js +12 -35
  176. package/.agents/scripts/stories-wave-tick.js +192 -9
  177. package/.agents/scripts/update-dead-exports-baseline.js +321 -0
  178. package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
  179. package/.agents/skills/skills.index.json +1 -11
  180. package/.agents/workflows/audit-documentation.md +5 -6
  181. package/.agents/workflows/audit-to-stories.md +28 -2
  182. package/.agents/workflows/helpers/audit-lens-core.md +11 -12
  183. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
  184. package/.agents/workflows/helpers/code-review.md +3 -8
  185. package/.agents/workflows/helpers/deliver-reference.md +30 -2
  186. package/.agents/workflows/helpers/deliver-story-reference.md +84 -16
  187. package/.agents/workflows/helpers/plan-reference.md +76 -0
  188. package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
  189. package/.agents/workflows/mandrel-update.md +10 -10
  190. package/.agents/workflows/qa-assist.md +15 -20
  191. package/.agents/workflows/qa-explore.md +9 -8
  192. package/README.md +1 -1
  193. package/docs/CHANGELOG.md +58 -0
  194. package/lib/migrations/index.js +2 -0
  195. package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
  196. package/package.json +14 -5
  197. package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
  198. package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
  199. package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
  200. package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
  201. package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
  202. package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
  203. package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
  204. package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
  205. package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
  206. package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
  207. package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
  208. package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
  209. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
  210. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
  211. package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
  212. package/.agents/scripts/check-gherkin-placeholders.js +0 -663
  213. package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
  214. package/.agents/scripts/lib/audit-suite/cli.js +0 -64
  215. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
  216. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
  217. package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
  218. package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
  219. package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
  220. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
  221. package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
  222. package/.agents/scripts/lib/crap-baseline-index.js +0 -46
  223. package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
  224. package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
  225. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
  226. package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
  227. package/.agents/scripts/lib/mutation/config-detector.js +0 -119
  228. package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
  229. package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
  230. package/.agents/scripts/lib/observability/active-story-env.js +0 -170
  231. package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
  232. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
  233. package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
  234. package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
  235. package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
  236. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
  237. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
  238. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
  239. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
  240. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
  241. package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
  242. package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
  243. package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
  244. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
  245. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
  246. package/.agents/scripts/lib/planning-corpus.js +0 -37
  247. package/.agents/scripts/lib/qa/coverage-report.js +0 -181
  248. package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
  249. package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
  250. package/.agents/scripts/lib/signals/detectors/index.js +0 -14
  251. package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
  252. package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
  253. package/.agents/scripts/lib/signals/read.js +0 -268
  254. package/.agents/scripts/lib/signals/span-tree.js +0 -291
  255. package/.agents/scripts/lib/story-lifecycle.js +0 -194
  256. package/.agents/scripts/lib/story-plan.js +0 -379
  257. package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
  258. package/.agents/scripts/lib/util/phase-timer.js +0 -163
  259. package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
  260. package/.agents/scripts/lint-baseline.js +0 -507
  261. package/.agents/scripts/providers/github/prs.js +0 -103
  262. package/.agents/scripts/signals-view.js +0 -309
  263. package/.agents/scripts/story-plan.js +0 -370
  264. package/.agents/scripts/sync-branch-from-base.js +0 -149
  265. package/.agents/scripts/validate-docs-freshness.js +0 -314
  266. package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
  267. package/.agents/workflows/helpers/signals.md +0 -112
@@ -1,3 +1,4 @@
1
+ import { resolveListValue } from '../config/shared.js';
1
2
  import { parse as parseStoryBody } from '../story-body/story-body.js';
2
3
  import { collectStoryAssumptionEntries } from './file-assumptions.js';
3
4
  import { computeStoryReachability } from './story-reachability.js';
@@ -108,8 +109,11 @@ const DEFAULT_POLICY = Object.freeze({
108
109
  * Patterns support two shapes:
109
110
  * - exact path — `lib/orchestration/lifecycle/listeners/index.js`
110
111
  * - `**` suffix — `**\/listeners/index.js` (matches any depth)
112
+ *
113
+ * Module-private since `resolveConflictPolicy` became the one production
114
+ * reader; tests reach it through `_internal`.
111
115
  */
112
- export const DEFAULT_REGISTRY_PATTERNS = Object.freeze([
116
+ const DEFAULT_REGISTRY_PATTERNS = Object.freeze([
113
117
  'lib/orchestration/lifecycle/listeners/index.js',
114
118
  '**/listeners/index.js',
115
119
  '**/handlers/index.js',
@@ -762,6 +766,117 @@ export function computeConflictFindings({ stories, policy } = {}) {
762
766
  ];
763
767
  }
764
768
 
769
+ /**
770
+ * Resolve the config-derived half of the conflict policy from
771
+ * `config.planning` — the severity flags, the fan-out threshold, and the
772
+ * registry patterns, in one place.
773
+ *
774
+ * Two passes consume `planning.*` and must not disagree: the raw
775
+ * pre-assembly pass (`persist-helpers.validateTickets`, which attaches its
776
+ * production `fanOutCounter` on top of this) and the post-assembly pass
777
+ * (`computeAssembledConflictFindings`, which forces `fanOutCounter: null`).
778
+ * Under Story #5045 each resolved its own copy, and the copies had already
779
+ * drifted — `failOnMissingBddScaffold` reached only the assembled pass,
780
+ * `failOnLargeFanOut` / `largeFanOutThreshold` / `crossCuttingRegistries`
781
+ * only the raw one — so a knob set in config silently applied on one of the
782
+ * two passes. A knob read here reaches both; that is the contract.
783
+ *
784
+ * `fanOutCounter` is deliberately absent: it is probe machinery, not
785
+ * config, and each caller owns its own.
786
+ *
787
+ * @param {object} [config] Resolved config carrying `planning.*`.
788
+ * @returns {object} A `computeConflictFindings` policy (no `fanOutCounter`).
789
+ */
790
+ export function resolveConflictPolicy(config) {
791
+ const planning = config?.planning;
792
+ const policy = {
793
+ failOnSharedEditors: planning?.failOnSharedEditors === true,
794
+ requireExplicitCrossStoryDeps:
795
+ planning?.requireExplicitCrossStoryDeps === true,
796
+ failOnRegistryConflicts: planning?.failOnRegistryConflicts === true,
797
+ failOnLargeFanOut: planning?.failOnLargeFanOut === true,
798
+ failOnMissingBddScaffold: planning?.failOnMissingBddScaffold === true,
799
+ };
800
+ if (Number.isFinite(planning?.largeFanOutThreshold)) {
801
+ policy.largeFanOutThreshold = planning.largeFanOutThreshold;
802
+ }
803
+ if (planning?.crossCuttingRegistries !== undefined) {
804
+ policy.registries = resolveListValue(
805
+ DEFAULT_REGISTRY_PATTERNS,
806
+ planning.crossCuttingRegistries,
807
+ );
808
+ }
809
+ return policy;
810
+ }
811
+
812
+ /**
813
+ * Re-run the cross-Story conflict passes over the **assembled** Story bodies —
814
+ * the artifact persist actually writes (Story #5045).
815
+ *
816
+ * `validateTickets` runs before `assemblePlanStories`, over the raw
817
+ * `stories.json` payload, so plan-time conflict analysis never saw what got
818
+ * persisted. That is not a cosmetic ordering nit: the canonical authoring shape
819
+ * carries `acceptance[]` / `verify[]` at the ticket's **top level**, and it is
820
+ * assembly's `syncContractFieldFromTopLevel` that folds them into the body.
821
+ * `indexConsumers` scans `body.acceptance` / `body.verify` for producer paths —
822
+ * so on the real payload it scanned two empty arrays, and every
823
+ * `implicit-cross-story-dep` and `missing-bdd-scaffold` finding was silently
824
+ * unreachable. Running the passes again over the serialized bodies restores
825
+ * them.
826
+ *
827
+ * **The fan-out pass is deliberately not re-run.** It is a `git grep` per
828
+ * deleted path and its inputs (`changes[]` deletes) are identical on both
829
+ * sides, so re-probing would double the git cost for a byte-identical answer;
830
+ * `enforceFanOutGate` already owns that class over the raw payload.
831
+ *
832
+ * @param {object} args
833
+ * @param {Array<{ slug: string, title?: string, body: string, depends_on?: string[] }>} args.stories
834
+ * Assembled Stories — `body` is the serialized, footer-stamped markdown.
835
+ * @param {object} [args.config] Resolved config; `planning.*` supplies the
836
+ * policy via {@link resolveConflictPolicy} — the same resolver the raw
837
+ * pass uses, so a knob cannot apply on only one of the two passes.
838
+ * @returns {ConflictFinding[]}
839
+ */
840
+ export function computeAssembledConflictFindings({ stories, config } = {}) {
841
+ return computeConflictFindings({
842
+ stories: (Array.isArray(stories) ? stories : []).map((story) => ({
843
+ slug: story.slug,
844
+ title: story.title,
845
+ body: story.body,
846
+ depends_on: Array.isArray(story.depends_on) ? story.depends_on : [],
847
+ })),
848
+ policy: {
849
+ ...resolveConflictPolicy(config),
850
+ fanOutCounter: null,
851
+ },
852
+ });
853
+ }
854
+
855
+ /**
856
+ * Stable identity for one conflict finding, so the post-assembly pass can be
857
+ * diffed against the raw pass and only the genuinely-new findings reported
858
+ * (Story #5045). Without it the two passes announce the same shared-editor
859
+ * collision twice per run, which is how a warning channel gets discounted.
860
+ *
861
+ * The separator is written as the `\u0000` escape and never as a raw byte — a
862
+ * literal NUL would make git classify this file as binary and drop its diffs.
863
+ *
864
+ * @param {object} finding
865
+ * @returns {string}
866
+ */
867
+ export function conflictFindingKey(finding) {
868
+ return [
869
+ finding?.kind ?? '',
870
+ finding?.path ?? finding?.registryPath ?? '',
871
+ Array.isArray(finding?.storySlugs)
872
+ ? [...finding.storySlugs].sort().join(',')
873
+ : (finding?.storySlug ?? ''),
874
+ finding?.producer?.storySlug ?? '',
875
+ finding?.consumer?.storySlug ?? '',
876
+ finding?.consumer?.sourceField ?? '',
877
+ ].join('\u0000');
878
+ }
879
+
765
880
  /**
766
881
  * Render the audit trail behind a fan-out finding's number, so an operator
767
882
  * can check the figure rather than trust it (Story #4547).
@@ -29,7 +29,7 @@
29
29
  */
30
30
 
31
31
  import { parse as parseStoryBody } from '../story-body/story-body.js';
32
- import { estimateTokens } from './context-envelope.js';
32
+ import { estimateTokens } from './spec-spill.js';
33
33
 
34
34
  /**
35
35
  * Normalize a Story's `body` to the structured object the sizing layers
@@ -1,4 +1,5 @@
1
1
  import { ValidationError } from '../errors/index.js';
2
+ import { normalizeOwnedProvenance } from '../findings/provenance-field.js';
2
3
  import { detectCycle } from '../Graph.js';
3
4
  import { gitSpawn } from '../git-utils.js';
4
5
 
@@ -528,6 +529,41 @@ function assertEveryStoryHasInlineContract({ stories }) {
528
529
  );
529
530
  }
530
531
 
532
+ /**
533
+ * Shape-check the optional per-Story `provenance` field (Story #5045).
534
+ *
535
+ * The field decides which audit identities persist stamps into a Story body,
536
+ * so a malformed entry has to fail at the validator rather than at the
537
+ * stamper: by the time assembly runs, an unnoticed drop is indistinguishable
538
+ * from a Story that legitimately owns nothing — and the cost lands a whole
539
+ * sweep later, when the next audit re-files work this plan already tracked.
540
+ *
541
+ * Absence is valid and common: a Story with no `provenance` inherits the
542
+ * whole-seed union carry, which is the recall-safe default.
543
+ *
544
+ * Errors are batched across the backlog so one pass names every offender.
545
+ *
546
+ * @param {{ stories: object[] }} args
547
+ * @throws {Error} naming each malformed field.
548
+ */
549
+ function assertStoryProvenanceShape({ stories }) {
550
+ const violations = [];
551
+ for (const story of stories) {
552
+ try {
553
+ normalizeOwnedProvenance(story?.provenance, story?.slug ?? '<unknown>');
554
+ } catch (err) {
555
+ violations.push(` - ${err.message}`);
556
+ }
557
+ }
558
+ if (violations.length === 0) return;
559
+ throw new Error(
560
+ `Cross-Validation Failed: ${violations.length} Story provenance field(s) ` +
561
+ `are malformed:\n${violations.join('\n')}\n\nAuthor provenance as ` +
562
+ '{ "fingerprints": ["<40-char sha1>"], "semanticKeys": ["<area␟path>"] }, ' +
563
+ 'or omit it entirely to inherit the seed-wide union.',
564
+ );
565
+ }
566
+
531
567
  function assertNoUnknownDeps({ tickets, ticketBySlug }) {
532
568
  const unknownDeps = [];
533
569
  for (const t of tickets) {
@@ -575,6 +611,7 @@ export function validateAndNormalizeTickets(tickets, opts = {}) {
575
611
 
576
612
  assertAllTicketsAreStories({ tickets, stories });
577
613
  assertEveryStoryHasInlineContract({ stories });
614
+ assertStoryProvenanceShape({ stories });
578
615
  assertNoUnknownDeps({ tickets, ticketBySlug });
579
616
 
580
617
  assertAcyclic(slugAdjacency);
@@ -704,6 +741,7 @@ export const _internal = {
704
741
  indexTicketsBySlug,
705
742
  assertAllTicketsAreStories,
706
743
  assertEveryStoryHasInlineContract,
744
+ assertStoryProvenanceShape,
707
745
  assertNoUnknownDeps,
708
746
  assertAcyclic,
709
747
  attachFindingsAndErrors,
@@ -146,14 +146,14 @@ export const STRUCTURED_COMMENT_TYPES = Object.freeze([
146
146
  // `--steal`, not by TTL expiry. One entry per ticket; re-acquires upsert
147
147
  // in place.
148
148
  'plan-lease',
149
- // Story #4415 (Epic #4406) — the feedback-loop graduators
150
- // (`audit-results-graduator.js` / `retro-proposals-graduator.js`) upsert a
151
- // `cross-repo-deferred` comment on the Epic listing findings that route
149
+ // Story #4415 (Epic #4406) — the feedback-loop graduator
150
+ // (`retro-proposals-graduator.js`) upserts a
151
+ // `cross-repo-deferred` comment listing findings that route
152
152
  // to a different repository and were therefore not filed here. Replaces
153
153
  // the prior log-line-only trace so the deferral survives the finalize
154
154
  // run as a durable, operator-visible record. Discriminated by a
155
- // `graduator="audit-results|code-review"` attr so the two graduators
156
- // upsert independent comments; re-runs upsert in place.
155
+ // `graduator="<name>"` attr so independent graduators do not clobber each
156
+ // other's comment; re-runs upsert in place.
157
157
  'cross-repo-deferred',
158
158
  // Epic #4474 (PR3) / v2 Stage 3 — `plan-persist.js` upserts a single
159
159
  // `plan-summary` comment on the primary Story at terminal persist
@@ -393,12 +393,13 @@ async function emitBlockedFriction(ticketId, fromState, newState, opts) {
393
393
  * `agent::done` at story-close (after the merge lands), not when the
394
394
  * last Task commit landed on the still-unmerged Story branch. The
395
395
  * parameter is preserved for callers that still suppress cascade
396
- * explicitly (e.g. batch-transition helpers).
396
+ * explicitly (`single-story-init.js`, and `bulk.js` where the upward
397
+ * recursion is driven by hand instead).
397
398
  *
398
399
  * `ticketSnapshot` (Story #1795 / Epic #1788) is an optional pre-fetched
399
- * ticket object. When the caller already holds the ticket (e.g.
400
- * `batchTransitionTickets`, which loops over a list it just hydrated),
401
- * passing the snapshot eliminates the two `getTicket` round-trips that
400
+ * ticket object. When the caller already holds the ticket e.g. it
401
+ * hydrated the ticket to inspect its labels first — passing the
402
+ * snapshot eliminates the two `getTicket` round-trips that
402
403
  * `transitionTicketState` would otherwise issue — one for the notify
403
404
  * `fromState` lookup and one inside `provider.updateTicket`'s label
404
405
  * merge path. Backwards compatible: when omitted, behaviour is unchanged.
@@ -0,0 +1,107 @@
1
+ /**
2
+ * verify-tier-repair.js — repair-before-judging for the `verify[]` tier suffix
3
+ * (Story #5005).
4
+ *
5
+ * The tier suffix (`… (unit)`) is a deterministic, mechanically-derivable
6
+ * formality. `task-body-validator.js` already computed the corrected entry in
7
+ * order to print it as a "Suggested fix" — then rejected the plan anyway and
8
+ * charged the author a full re-drafting round to paste that exact string back.
9
+ * This module applies the inference the validator already trusts, so the hard
10
+ * error is reserved for the entries only the author can resolve.
11
+ *
12
+ * It lives beside the validator rather than inside it because the validator's
13
+ * job is to *judge*: mixing a mutating repair pass into a module of pure
14
+ * collectors muddies both. `persist-helpers.js#validateTickets` calls this
15
+ * first, then `validateTaskBodies`.
16
+ *
17
+ * @module lib/orchestration/verify-tier-repair
18
+ */
19
+
20
+ import { suggestVerifyFix } from '../story-body/body-format-lints.js';
21
+ import {
22
+ parse as parseStoryBody,
23
+ serialize as serializeStoryBody,
24
+ } from '../story-body/story-body.js';
25
+ import { VERIFY_TIER_VALUES } from './task-body-validator.js';
26
+
27
+ /** A parenthesised tier drawn from the canonical vocabulary, at end of entry. */
28
+ const VERIFY_TIER_RE = new RegExp(
29
+ `\\((?:${VERIFY_TIER_VALUES.join('|')})\\)\\s*$`,
30
+ );
31
+
32
+ /**
33
+ * Rewrite one `verify[]` list, appending the inferable testing tier to any
34
+ * entry missing one. Returns `null` when nothing changed, so callers can keep
35
+ * an already-compliant list byte-identical (and skip re-serializing the body
36
+ * it came from).
37
+ *
38
+ * @param {unknown} rawVerify
39
+ * @returns {string[]|null} The corrected list, or `null` when no fix applied.
40
+ */
41
+ function repairVerifyList(rawVerify) {
42
+ if (!Array.isArray(rawVerify)) return null;
43
+ let changed = false;
44
+ const next = rawVerify.map((entry) => {
45
+ if (typeof entry !== 'string') return entry;
46
+ if (entry.startsWith('manual:') || VERIFY_TIER_RE.test(entry)) return entry;
47
+ const fix = suggestVerifyFix(entry);
48
+ if (fix === null) return entry;
49
+ changed = true;
50
+ return fix;
51
+ });
52
+ return changed ? next : null;
53
+ }
54
+
55
+ /**
56
+ * Repair the `## Verify` section of a serialized (string) body, in place on
57
+ * the ticket. Only re-serializes when a fix actually applied, so a compliant
58
+ * body is never round-tripped through `parse → serialize`.
59
+ *
60
+ * Leaving the body untouched while the top level was repaired would be worse
61
+ * than not repairing at all: `syncContractFieldFromTopLevel` fails closed on a
62
+ * body section that disagrees with its top-level array, so both sides must be
63
+ * repaired by the same rule or neither.
64
+ *
65
+ * @param {object} ticket
66
+ */
67
+ function repairStringBodyVerify(ticket) {
68
+ let parsed;
69
+ try {
70
+ parsed = parseStoryBody(ticket.body).body;
71
+ } catch {
72
+ // An unparseable body is already a hard error in `validateTaskBodyShape`;
73
+ // there is nothing to repair and nothing to report twice.
74
+ return;
75
+ }
76
+ const repaired = repairVerifyList(parsed.verify);
77
+ if (repaired === null) return;
78
+ ticket.body = serializeStoryBody({ ...parsed, verify: repaired });
79
+ }
80
+
81
+ /**
82
+ * Auto-append the testing tier to `verify[]` entries that omit one, wherever
83
+ * `suggestVerifyFix` can infer it from the command. An entry whose tier cannot
84
+ * be inferred is left untouched and still hard-errors downstream.
85
+ *
86
+ * Mutates `tickets` in place (the persist pipeline threads this same array on
87
+ * to assembly) and returns it. Already-compliant tickets are untouched, so
88
+ * their persisted output stays byte-identical. Total — a non-array argument
89
+ * and non-Story tickets are no-ops.
90
+ *
91
+ * @param {object[]} tickets
92
+ * @returns {object[]} `tickets`
93
+ */
94
+ export function normalizeVerifyTiers(tickets) {
95
+ for (const ticket of Array.isArray(tickets) ? tickets : []) {
96
+ if (!ticket || ticket.type !== 'story' || ticket.body == null) continue;
97
+ const topLevel = repairVerifyList(ticket.verify);
98
+ if (topLevel !== null) ticket.verify = topLevel;
99
+ if (typeof ticket.body === 'string') {
100
+ repairStringBodyVerify(ticket);
101
+ continue;
102
+ }
103
+ const bodyLevel = repairVerifyList(ticket.body.verify);
104
+ if (bodyLevel !== null) ticket.body.verify = bodyLevel;
105
+ }
106
+ return tickets;
107
+ }
@@ -34,17 +34,12 @@
34
34
  // operator-facing string explaining the verdict (always populated,
35
35
  // including for present tiers).
36
36
  //
37
- // acceptanceMatrix(criteria) -> {
38
- // tiers: TIERS,
39
- // rows: [{ id, label, verdict }, ...],
40
- // }
41
- //
42
- // Maps each acceptance criterion to its per-tier `coverageVerdict`, giving
43
- // the AC × test-tier matrix the markdown report (lib/qa/coverage-report.js)
44
- // renders.
37
+ // Story #5008 removed the `acceptanceMatrix` feeder and the markdown report it
38
+ // fed: the QA workflows read the per-tier verdict and author the missing-test
39
+ // prose directly, so the AC x tier matrix was a round-trip with no reader.
45
40
 
46
- /** The three test tiers, in pyramid order (base top). */
47
- export const TIERS = Object.freeze(['unit', 'contract', 'acceptance']);
41
+ /** The three test tiers, in pyramid order (base -> top). */
42
+ const TIERS = Object.freeze(['unit', 'contract', 'acceptance']);
48
43
 
49
44
  const PRESENT = 'present';
50
45
  const ABSENT = 'absent';
@@ -217,80 +212,3 @@ export function coverageVerdict(surface = {}) {
217
212
 
218
213
  return verdict;
219
214
  }
220
-
221
- /**
222
- * Normalize a single criterion descriptor into `{id, label, surface}`. A
223
- * descriptor may carry `id`, `label` (falls back to id), and either a nested
224
- * `surface` or a flat `{symbol, tests}` shape.
225
- */
226
- function normalizeOne(entry, index) {
227
- const e = entry && typeof entry === 'object' ? entry : {};
228
- const id =
229
- typeof e.id === 'string' && e.id.trim() !== ''
230
- ? e.id.trim()
231
- : `AC-${index + 1}`;
232
- const label =
233
- typeof e.label === 'string' && e.label.trim() !== '' ? e.label.trim() : id;
234
-
235
- let surface;
236
- if (e.surface && typeof e.surface === 'object') {
237
- surface = e.surface;
238
- } else if (Array.isArray(e.tests) || typeof e.symbol === 'string') {
239
- surface = { symbol: e.symbol, tests: e.tests };
240
- } else {
241
- surface = {};
242
- }
243
-
244
- return { id, label, surface };
245
- }
246
-
247
- /**
248
- * Normalize the criteria input for {@link acceptanceMatrix}. Accepts either an
249
- * array of criterion descriptors or a plain object keyed by criterion id whose
250
- * values are surfaces (or `{surface}` wrappers). Returns a normalized array of
251
- * `{id, label, surface}`.
252
- *
253
- * @param {Array<object>|object} criteria
254
- * @returns {Array<{id:string,label:string,surface:object}>}
255
- */
256
- function normalizeCriteria(criteria) {
257
- if (Array.isArray(criteria)) {
258
- return criteria.map((entry, index) => normalizeOne(entry, index));
259
- }
260
- if (criteria && typeof criteria === 'object') {
261
- return Object.entries(criteria).map(([id, value], index) =>
262
- normalizeOne(
263
- value && typeof value === 'object' && !Array.isArray(value)
264
- ? { id, ...value }
265
- : { id, surface: { tests: value } },
266
- index,
267
- ),
268
- );
269
- }
270
- throw new TypeError(
271
- 'acceptanceMatrix: criteria must be an array or an object',
272
- );
273
- }
274
-
275
- /**
276
- * Build the AC × test-tier matrix: for each acceptance criterion, the per-tier
277
- * {@link coverageVerdict}. This is the structured shape the markdown report
278
- * (`lib/qa/coverage-report.js`) renders into a table.
279
- *
280
- * @param {Array<{id?:string,label?:string,surface?:object,symbol?:string,tests?:Array}>|Record<string,object>} criteria
281
- * Acceptance criteria, either as an array of descriptors or an object keyed
282
- * by criterion id. Each descriptor names a surface (nested `surface`, or a
283
- * flat `{symbol, tests}`).
284
- * @returns {{tiers: ReadonlyArray<string>,
285
- * rows: Array<{id:string,label:string,
286
- * verdict:ReturnType<typeof coverageVerdict>}>}}
287
- */
288
- export function acceptanceMatrix(criteria) {
289
- const normalized = normalizeCriteria(criteria);
290
- const rows = normalized.map(({ id, label, surface }) => ({
291
- id,
292
- label,
293
- verdict: coverageVerdict(surface),
294
- }));
295
- return { tiers: TIERS, rows };
296
- }
@@ -2,7 +2,7 @@
2
2
  * detectors/common.js — shared helpers for the signals layer.
3
3
  *
4
4
  * Hoisted out of the detector modules (retry, rework) plus
5
- * `signals/read.js` and `signals/schema.js`, all of which shipped
5
+ * the since-deleted `signals/read.js`, and `signals/schema.js`, all of which shipped
6
6
  * byte-equivalent copies of these predicates. See Story #2464.
7
7
  */
8
8
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `lib/signals/` barrel.
3
3
  *
4
- * Consumers do `import { read, schema, buildSpanTree, appendSignal } from './lib/signals/index.js'`
4
+ * Consumers do `import { schema, appendSignal } from './lib/signals/index.js'`
5
5
  * (or `import * as signals from './lib/signals/index.js'`) so a future
6
6
  * shape migration only has to touch this file.
7
7
  *
@@ -9,18 +9,20 @@
9
9
  * - Epic #1181 / Story #1438 / Task #1459 — initial barrel with `read`
10
10
  * + `schema`; `buildSpanTree` was a throwing placeholder.
11
11
  * - Epic #1181 / Story #1440 / Task #1461 — placeholder replaced by
12
- * the real export from `./span-tree.js`.
12
+ * the real span-tree builder.
13
13
  * - Story #1476 — `appendSignal` / `appendTrace` re-exported here
14
14
  * via `./write.js` so the gate scripts (and any
15
15
  * new code) converge on `lib/signals/` instead of importing the
16
16
  * writer directly from `lib/observability/`.
17
+ * - Story #5003 — the reader half (`read`, `buildSpanTree`) went with the
18
+ * debug viewer that consumed it: it walked a `run-<id>/` layout no v2
19
+ * writer populates. `appendTrace` went with the trace hook, its only
20
+ * producer. What remains is the live write surface.
17
21
  *
18
22
  * @module lib/signals
19
23
  */
20
24
 
21
- import { read } from './read.js';
22
25
  import * as schema from './schema.js';
23
- import { buildSpanTree } from './span-tree.js';
24
- import { appendSignal, appendTrace, forEachLine } from './write.js';
26
+ import { appendSignal, forEachLine } from './write.js';
25
27
 
26
- export { appendSignal, appendTrace, buildSpanTree, forEachLine, read, schema };
28
+ export { appendSignal, forEachLine, schema };
@@ -2,10 +2,10 @@
2
2
  * Signals schema — single source of truth for event-kind constants and
3
3
  * shape guards (Epic #1181 / Story #1438 / Task #1458).
4
4
  *
5
- * Both writers (`lib/observability/signals-writer.js` callers) and
6
- * readers (`lib/signals/read.js`, the retro's gather-signals phase)
7
- * import their field names from this module so the on-disk NDJSON shape
8
- * stays under one schema.
5
+ * Both writers (`lib/observability/signals-writer.js` callers) and readers
6
+ * (its `forEachLine` / `forEachSignalStreamLine` walkers, and the retro's
7
+ * gather-signals phase) import their field names from this module so the
8
+ * on-disk NDJSON shape stays under one schema.
9
9
  *
10
10
  * Pure module: importing has **no I/O side effects**. The exported
11
11
  * `EVENT_KINDS` object is `Object.freeze`'d so consumers can use it as a
@@ -14,30 +14,25 @@
14
14
  * ## Event-kind enumeration
15
15
  *
16
16
  * The set below is the audited union of `kind:` literals emitted via
17
- * `signals-writer.appendSignal` and `signals-writer.appendTrace` across
18
- * the codebase as of Epic #1181 (audit-snapshot 2026-05-11):
17
+ * `signals-writer.appendSignal` across the codebase as of Epic #1181
18
+ * (audit-snapshot 2026-05-11):
19
19
  *
20
20
  * Signals-writer `appendSignal` call sites:
21
21
  * - `friction` — quality-gate / runtime friction (diagnose-friction.js,
22
22
  * lib/gates/friction.js)
23
23
  * - `acceptance-eval` — acceptance-eval.js per-criterion terminus signal.
24
- * - `wave-start` / `wave-complete` — wave-window anchors; `wave-start` also
25
- * anchors span-tree Story spans
26
- * - `wave-end` — span-tree pairing anchor (retained for span-tree)
24
+ * - `wave-start` / `wave-complete` — wave-window anchors.
25
+ * - `wave-end` — wave-window pairing anchor.
27
26
  * - `state-transition` — notification-derived window anchor.
28
27
  *
29
28
  * The `dispatched` kind was deleted in the Epic #4406 signal-contract
30
29
  * cutover — it had no live emitter and no consumer.
31
30
  *
32
- * Signals-writer `appendTrace` call sites (traces.ndjson sibling, but
33
- * sharing the same envelope shape `tool-trace-hook.js`):
34
- * - `trace` per-tool-call timing record
35
- *
36
- * Detector-emitted / aggregator-consumed kinds (`rework`, `retry` are
37
- * emitted by `lib/signals/detectors/*`; `hotspot`, `churn`, `idle` remain
38
- * pinned in the enum for the aggregator's kind-count rollup even though no
39
- * live detector emits them):
40
- * - `hotspot`, `rework`, `churn`, `idle`, `retry`
31
+ * Producerless kinds, pinned in the enum so a re-introduction needs no schema
32
+ * bump. Story #5003 deleted the last emitters of `trace` (the tool-trace hook
33
+ * and its `appendTrace` writer limb) and of `rework` / `retry` (the detector
34
+ * pair the hook fed); `hotspot`, `churn`, `idle` never had one:
35
+ * - `trace`, `hotspot`, `rework`, `churn`, `idle`, `retry`
41
36
  *
42
37
  * ## Common envelope (canonical — Epic #4406 / Story #4413)
43
38
  *
@@ -68,18 +63,18 @@ import { isPositiveInt } from './detectors/common.js';
68
63
 
69
64
  /**
70
65
  * Frozen enumeration of every event kind currently emitted by
71
- * `signals-writer.appendSignal` / `appendTrace`, plus the
72
- * aggregator-consumed kinds whose detectors are future Stories.
66
+ * `signals-writer.appendSignal`, plus the producerless kinds a future Story
67
+ * may re-introduce an emitter for.
73
68
  *
74
69
  * Field names are kebab-cased to match the on-disk literals.
75
70
  */
76
71
  export const EVENT_KINDS = Object.freeze({
77
72
  FRICTION: 'friction',
78
73
  TRACE: 'trace',
79
- // Wave-window forensics signals: `wave-start` / `wave-end` anchor the
80
- // span-tree's Story spans. Story #4545 deleted the `waveParallelism`
81
- // consumer (perf-aggregator) with the execution-analysis surface; these
82
- // kinds stay as the span-tree's anchors.
74
+ // Wave-window forensics signals. Story #4545 deleted the `waveParallelism`
75
+ // consumer (perf-aggregator) with the execution-analysis surface, and
76
+ // Story #5003 deleted the span-tree that paired them; the kinds stay
77
+ // pinned so a re-introduced window reader needs no schema bump.
83
78
  WAVE_START: 'wave-start',
84
79
  WAVE_END: 'wave-end',
85
80
  WAVE_COMPLETE: 'wave-complete',
@@ -156,7 +151,7 @@ function isTimestamp(v) {
156
151
  * recognised `kind`. Canonical keys only — the legacy `timestamp` / `epic`
157
152
  * aliases were deleted in the Epic #4406 cutover.
158
153
  *
159
- * Returns true when the envelope is well-formed. Used by `lib/signals/read`
154
+ * Returns true when the envelope is well-formed. Used by the stream readers
160
155
  * to discard malformed lines before yielding them to the consumer.
161
156
  *
162
157
  * @param {unknown} evt
@@ -1,18 +1,18 @@
1
1
  /**
2
- * `lib/signals/write.js` — thin re-export of the signals/traces writer.
2
+ * `lib/signals/write.js` — thin re-export of the signals writer.
3
3
  *
4
4
  * The real implementation lives at `../observability/signals-writer.js`
5
5
  * (Epic #1030 / Story #1041). This module exists so callers can converge
6
- * on `lib/signals/` for both reads and writes the reader barrel landed
7
- * in Epic #1181 / Story #1438, but the writer surface was still split
8
- * across `lib/observability/`. New code should `import { appendSignal }
9
- * from './lib/signals/index.js'` (or `'./lib/signals/write.js'` for a
10
- * narrower import); legacy direct imports from `lib/observability/` keep
11
- * working unchanged.
6
+ * on `lib/signals/` for the write surface. New code should
7
+ * `import { appendSignal } from './lib/signals/index.js'` (or
8
+ * `'./lib/signals/write.js'` for a narrower import); legacy direct imports
9
+ * from `lib/observability/` keep working unchanged.
10
+ *
11
+ * `appendTrace` was removed in Story #5003 together with the tool-trace
12
+ * hook — its only producer — and the viewer that was its only reader.
12
13
  */
13
14
 
14
15
  export {
15
16
  appendSignal,
16
- appendTrace,
17
17
  forEachLine,
18
18
  } from '../observability/signals-writer.js';