peaks-loop 4.0.0-beta → 4.0.0-beta.3

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 (179) hide show
  1. package/CHANGELOG.md +105 -87
  2. package/README-en.md +17 -4
  3. package/README.md +17 -4
  4. package/dist/src/cli/commands/asset-commands.d.ts +45 -0
  5. package/dist/src/cli/commands/asset-commands.js +404 -0
  6. package/dist/src/cli/commands/bee-commands.d.ts +26 -0
  7. package/dist/src/cli/commands/bee-commands.js +169 -0
  8. package/dist/src/cli/commands/{solo-commands.d.ts → code-commands.d.ts} +24 -24
  9. package/dist/src/cli/commands/{solo-commands.js → code-commands.js} +78 -78
  10. package/dist/src/cli/commands/core/skill-command.js +1 -1
  11. package/dist/src/cli/commands/dispatch-from-dag.js +1 -1
  12. package/dist/src/cli/commands/evolution-commands.d.ts +27 -0
  13. package/dist/src/cli/commands/evolution-commands.js +393 -0
  14. package/dist/src/cli/commands/hook-handle.js +7 -7
  15. package/dist/src/cli/commands/job-commands.js +2 -2
  16. package/dist/src/cli/commands/loop-commands.d.ts +19 -13
  17. package/dist/src/cli/commands/loop-commands.js +147 -13
  18. package/dist/src/cli/commands/sediment-commands.js +9 -0
  19. package/dist/src/cli/commands/session-auto-compact-hook-command.js +2 -2
  20. package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.d.ts +67 -0
  21. package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.js +173 -0
  22. package/dist/src/cli/commands/sub-agent-shared.d.ts +1 -1
  23. package/dist/src/cli/commands/user-touchpoint-commands.d.ts +4 -4
  24. package/dist/src/cli/commands/user-touchpoint-commands.js +14 -14
  25. package/dist/src/cli/commands/workflow-commands.js +22 -22
  26. package/dist/src/cli/program.js +23 -6
  27. package/dist/src/services/artifacts/repair-cycle-service.js +1 -1
  28. package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +1 -1
  29. package/dist/src/services/audit/enforcers/active-skill-resolver.js +1 -1
  30. package/dist/src/services/audit/enforcers/{solo-code-ban.d.ts → code-ban.d.ts} +6 -6
  31. package/dist/src/services/audit/enforcers/{solo-code-ban.js → code-ban.js} +6 -6
  32. package/dist/src/services/audit/red-line-catalog.d.ts +2 -2
  33. package/dist/src/services/audit/red-line-catalog.js +5 -5
  34. package/dist/src/services/audit/types.d.ts +2 -2
  35. package/dist/src/services/{solo → code}/auto-compact-orchestrator.d.ts +1 -1
  36. package/dist/src/services/{solo → code}/auto-compact-orchestrator.js +3 -3
  37. package/dist/src/services/{solo → code}/dag-orchestrator.d.ts +1 -1
  38. package/dist/src/services/{solo → code}/dag-orchestrator.js +1 -1
  39. package/dist/src/services/{solo → code}/emit-handoff.d.ts +1 -1
  40. package/dist/src/services/{solo → code}/emit-handoff.js +1 -1
  41. package/dist/src/services/{solo → code}/job-shape-decision.d.ts +1 -1
  42. package/dist/src/services/{solo → code}/job-shape-decision.js +5 -5
  43. package/dist/src/services/{solo → code}/mode-gate.d.ts +9 -9
  44. package/dist/src/services/{solo → code}/mode-gate.js +5 -5
  45. package/dist/src/services/{solo → code}/post-compact-detector.d.ts +3 -3
  46. package/dist/src/services/{solo → code}/post-compact-detector.js +4 -4
  47. package/dist/src/services/{solo → code}/step-08-gate.d.ts +4 -4
  48. package/dist/src/services/{solo → code}/step-08-gate.js +4 -4
  49. package/dist/src/services/{solo → code}/user-touchpoint-classifier.d.ts +1 -1
  50. package/dist/src/services/{solo → code}/user-touchpoint-classifier.js +1 -1
  51. package/dist/src/services/context/auto-compact-dispatcher.d.ts +2 -2
  52. package/dist/src/services/context/auto-compact-dispatcher.js +2 -2
  53. package/dist/src/services/context/auto-compact-types.d.ts +1 -1
  54. package/dist/src/services/crystallization/crystallization-service.d.ts +239 -0
  55. package/dist/src/services/crystallization/crystallization-service.js +397 -0
  56. package/dist/src/services/crystallization/crystallization-store.d.ts +75 -0
  57. package/dist/src/services/crystallization/crystallization-store.js +193 -0
  58. package/dist/src/services/crystallization/crystallization-types.d.ts +313 -0
  59. package/dist/src/services/crystallization/crystallization-types.js +299 -0
  60. package/dist/src/services/crystallization/evidence-brief-builder.d.ts +237 -0
  61. package/dist/src/services/crystallization/evidence-brief-builder.js +240 -0
  62. package/dist/src/services/dispatch/slice-dag.d.ts +2 -2
  63. package/dist/src/services/dispatch/test-tool-detection.d.ts +1 -1
  64. package/dist/src/services/dispatch/test-tool-detection.js +1 -1
  65. package/dist/src/services/evolution/evolution-service.d.ts +137 -0
  66. package/dist/src/services/evolution/evolution-service.js +281 -0
  67. package/dist/src/services/evolution/evolution-store.d.ts +57 -0
  68. package/dist/src/services/evolution/evolution-store.js +232 -0
  69. package/dist/src/services/evolution/evolution-types.d.ts +706 -0
  70. package/dist/src/services/evolution/evolution-types.js +286 -0
  71. package/dist/src/services/evolution/independent-evaluator-runner.d.ts +90 -0
  72. package/dist/src/services/evolution/independent-evaluator-runner.js +106 -0
  73. package/dist/src/services/evolution/regression-skeptic-runner.d.ts +64 -0
  74. package/dist/src/services/evolution/regression-skeptic-runner.js +113 -0
  75. package/dist/src/services/feedback/feedback-promotion-service.js +2 -2
  76. package/dist/src/services/job/job-progress-store.d.ts +1 -1
  77. package/dist/src/services/job/job-progress-store.js +1 -1
  78. package/dist/src/services/loop/loop-bee-relation-service.d.ts +107 -0
  79. package/dist/src/services/loop/loop-bee-relation-service.js +211 -0
  80. package/dist/src/services/loop/loop-bee-relation-store.d.ts +53 -0
  81. package/dist/src/services/loop/loop-bee-relation-store.js +130 -0
  82. package/dist/src/services/loop/loop-bee-relation-types.d.ts +118 -0
  83. package/dist/src/services/loop/loop-bee-relation-types.js +114 -0
  84. package/dist/src/services/loop/loop-release-service.d.ts +46 -0
  85. package/dist/src/services/loop/loop-release-service.js +66 -0
  86. package/dist/src/services/loop/loop-release-store.d.ts +55 -0
  87. package/dist/src/services/loop/loop-release-store.js +134 -0
  88. package/dist/src/services/loop/loop-release-types.d.ts +250 -0
  89. package/dist/src/services/loop/loop-release-types.js +162 -0
  90. package/dist/src/services/preferences/preferences-service.d.ts +1 -1
  91. package/dist/src/services/preferences/preferences-types.d.ts +1 -1
  92. package/dist/src/services/rd/standards-diagnostic.d.ts +1 -1
  93. package/dist/src/services/rd/standards-diagnostic.js +2 -2
  94. package/dist/src/services/recommendations/capability-seed-items.js +1 -1
  95. package/dist/src/services/recommendations/capability-seed-mappings.js +1 -1
  96. package/dist/src/services/recommendations/recommendation-service.js +1 -1
  97. package/dist/src/services/refactor/refactor-service.d.ts +1 -1
  98. package/dist/src/services/share/bundle-reader.d.ts +100 -0
  99. package/dist/src/services/share/bundle-reader.js +434 -0
  100. package/dist/src/services/share/bundle-types.d.ts +392 -0
  101. package/dist/src/services/share/bundle-types.js +318 -0
  102. package/dist/src/services/share/bundle-writer.d.ts +97 -0
  103. package/dist/src/services/share/bundle-writer.js +429 -0
  104. package/dist/src/services/share/run-state-contract.d.ts +133 -0
  105. package/dist/src/services/share/run-state-contract.js +138 -0
  106. package/dist/src/services/signal/cancel-handler.js +3 -3
  107. package/dist/src/services/skill/resume-detector.js +1 -1
  108. package/dist/src/services/skillhub/release-import.js +7 -2
  109. package/dist/src/services/skillhub/release-retain.js +6 -1
  110. package/dist/src/services/skillhub/sqlite-store.js +17 -1
  111. package/dist/src/services/skillhub/types.d.ts +10 -0
  112. package/dist/src/services/skills/skill-presence-service.d.ts +1 -1
  113. package/dist/src/services/standards/loop-engineering-lint.d.ts +38 -0
  114. package/dist/src/services/standards/loop-engineering-lint.js +101 -0
  115. package/dist/src/services/standards/loop-engineering-readiness-lint.d.ts +111 -0
  116. package/dist/src/services/standards/loop-engineering-readiness-lint.js +248 -0
  117. package/dist/src/services/upgrade/1x-detector-service.js +1 -1
  118. package/dist/src/services/workflow/pipeline-verify-service.d.ts +1 -1
  119. package/dist/src/services/workflow/pipeline-verify-service.js +3 -3
  120. package/dist/src/services/workflow/workflow-autonomous-service.d.ts +3 -3
  121. package/dist/src/services/workflow/workflow-autonomous-service.js +2 -2
  122. package/dist/src/services/workflow/workflow-router-service.d.ts +6 -6
  123. package/dist/src/services/workflow/workflow-router-service.js +33 -33
  124. package/dist/src/services/workspace/claude-settings-template.d.ts +1 -1
  125. package/dist/src/services/workspace/claude-settings-template.js +5 -5
  126. package/dist/src/shared/version.d.ts +1 -1
  127. package/dist/src/shared/version.js +1 -1
  128. package/examples/video-demo/README.md +57 -0
  129. package/examples/video-demo/out/en-closing-960.png +0 -0
  130. package/examples/video-demo/out/zh-closing-960.png +0 -0
  131. package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
  132. package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
  133. package/output-styles/peaks-skill-swarm.md +3 -3
  134. package/package.json +6 -2
  135. package/skills/bee/peaks-qa/SKILL.md +1 -1
  136. package/skills/bee/peaks-qa/references/artifact-per-request.md +3 -3
  137. package/skills/bee/peaks-qa/references/qa-sub-agent-dispatch.md +6 -6
  138. package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +1 -1
  139. package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
  140. package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +11 -11
  141. package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
  142. package/skills/bee/peaks-sc/SKILL.md +1 -1
  143. package/skills/bee/peaks-txt/SKILL.md +3 -3
  144. package/skills/bee/peaks-ui/SKILL.md +8 -8
  145. package/skills/peaks-code/SKILL.md +34 -21
  146. package/skills/peaks-code/references/anchoring-and-session-info.md +2 -2
  147. package/skills/peaks-code/references/artifact-contracts.md +1 -1
  148. package/skills/peaks-code/references/boundaries.md +3 -3
  149. package/skills/peaks-code/references/codegraph-orchestration.md +1 -1
  150. package/skills/peaks-code/references/dag-orchestrator.md +7 -7
  151. package/skills/peaks-code/references/external-references.md +2 -2
  152. package/skills/peaks-code/references/fanout-mandatory.md +3 -3
  153. package/skills/peaks-code/references/fast-mode.md +2 -2
  154. package/skills/peaks-code/references/frontend-only-mode.md +9 -9
  155. package/skills/peaks-code/references/job-loop.md +1 -1
  156. package/skills/peaks-code/references/local-artifact-workspace.md +2 -2
  157. package/skills/peaks-code/references/micro-cycle.md +14 -14
  158. package/skills/peaks-code/references/mode-selection-with-stale-presence.md +5 -5
  159. package/skills/peaks-code/references/mode-selection.md +3 -3
  160. package/skills/peaks-code/references/openspec-workflow.md +16 -16
  161. package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
  162. package/skills/peaks-code/references/quality-gate-cheatsheet.md +1 -1
  163. package/skills/peaks-code/references/refactor-mode.md +1 -1
  164. package/skills/peaks-code/references/runbook.md +15 -15
  165. package/skills/peaks-code/references/step-0-55-1x-detection.md +1 -1
  166. package/skills/peaks-code/references/step-0-8-gate.md +11 -11
  167. package/skills/peaks-code/references/sub-agent-dispatch.md +8 -8
  168. package/skills/peaks-code/references/swarm-dispatch-contract.md +17 -17
  169. package/skills/peaks-code/references/workflow-gates-and-types.md +2 -2
  170. package/skills/peaks-code/references/workflow.md +5 -5
  171. package/skills/peaks-content/SKILL.md +272 -0
  172. package/skills/peaks-issue-fix-orchestrator/SKILL.md +307 -0
  173. package/skills/peaks-resume/SKILL.md +2 -2
  174. package/skills/peaks-status/SKILL.md +2 -2
  175. package/skills/peaks-test/SKILL.md +2 -2
  176. /package/dist/src/services/{solo → code}/batch-heartbeat-poller.d.ts +0 -0
  177. /package/dist/src/services/{solo → code}/batch-heartbeat-poller.js +0 -0
  178. /package/dist/src/services/{solo → code}/status-line-renderer.d.ts +0 -0
  179. /package/dist/src/services/{solo → code}/status-line-renderer.js +0 -0
@@ -0,0 +1,237 @@
1
+ import { z } from "zod";
2
+ import { type EvidenceBrief } from "./crystallization-types.js";
3
+ /**
4
+ * EvidenceBriefBuilder — spec §4.7 / §10 RL-7.
5
+ *
6
+ * The brief is a 4-section natural-language projection that MUST
7
+ * accompany every user-facing recommendation. The shape guard is
8
+ * encoded in `EvidenceBriefSchema` (see crystallization-types.ts);
9
+ * this module is the LLM-side entry point that PRODUCES the brief
10
+ * from a finished trace + evaluator summary and the validator that
11
+ * REFUSES to render a recommendation payload without all 4 sections.
12
+ *
13
+ * Hard rules (mirrored from spec):
14
+ *
15
+ * 1. Every section must be a non-empty NL string (1-2 sentences
16
+ * for what_happened / why_it_matters / what_learned; 1
17
+ * sentence for what_action). An empty section is a hard
18
+ * `MISSING_BRIEF_SECTION` error.
19
+ *
20
+ * 2. The build path is lenient on raw prose and strict on the
21
+ * final shape — `buildEvidenceBrief` calls
22
+ * `EvidenceBriefSchema.parse(...)` so a partial brief throws
23
+ * before reaching the database.
24
+ *
25
+ * 3. `renderRecommendationPayload` refuses to return a
26
+ * recommendation envelope unless the brief passes the 4-section
27
+ * guard. This is the CLI's single source of truth for "may I
28
+ * show this to the user?".
29
+ *
30
+ * 4. The `evaluator_summary` is a separate field on the
31
+ * crystallization_event row (spec §4.5) and is NOT part of the
32
+ * brief. It feeds the broader recommendation envelope.
33
+ *
34
+ * Out of scope (deferred to later slices):
35
+ * - LLM-authored brief generation from live trace evidence (M8 dogfood).
36
+ * - brief rewrite-on-update semantics.
37
+ */
38
+ /**
39
+ * The minimum viable trace shape that the builder needs to render
40
+ * a brief. The trace is the EVIDENCE; the builder is format-stable
41
+ * so a future slice can swap in a richer trace source without
42
+ * editing every caller.
43
+ */
44
+ export declare const BriefTraceInputSchema: z.ZodObject<{
45
+ trace_id: z.ZodString;
46
+ /**
47
+ * The full NL recap of the run. Required for what_happened.
48
+ * 1-2 sentences is the spec guidance; the builder does not
49
+ * truncate, but tests passing multi-paragraph input will be
50
+ * warned at the Zod boundary (max 4000 chars per section).
51
+ */
52
+ what_happened: z.ZodString;
53
+ /**
54
+ * The "why this matters" recap. Required for why_it_matters.
55
+ */
56
+ why_it_matters: z.ZodString;
57
+ /**
58
+ * Failure-mode and preference-extraction recap. Required for
59
+ * what_learned.
60
+ */
61
+ what_learned: z.ZodString;
62
+ /**
63
+ * The recommended action. Required for what_action (1
64
+ * sentence per spec).
65
+ */
66
+ what_action: z.ZodString;
67
+ /**
68
+ * Optional structured bullets (e.g. "4 phases, 3 gates passed,
69
+ * 1 evaluator verdict"). Counts are allowed at this layer; the
70
+ * brief section is the NL primary (RL-7).
71
+ */
72
+ bullets: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
73
+ /**
74
+ * Source trace ids backing the brief (the column on
75
+ * crystallization_event spec §4.5).
76
+ */
77
+ source_trace_pointers: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
78
+ }, "strip", z.ZodTypeAny, {
79
+ source_trace_pointers: string[];
80
+ what_happened: string;
81
+ why_it_matters: string;
82
+ what_learned: string;
83
+ what_action: string;
84
+ trace_id: string;
85
+ bullets: string[];
86
+ }, {
87
+ what_happened: string;
88
+ why_it_matters: string;
89
+ what_learned: string;
90
+ what_action: string;
91
+ trace_id: string;
92
+ source_trace_pointers?: string[] | undefined;
93
+ bullets?: string[] | undefined;
94
+ }>;
95
+ export type BriefTraceInput = z.input<typeof BriefTraceInputSchema>;
96
+ /**
97
+ * The summary emitted by the independent evaluators (spec §4.5
98
+ * `evaluator_summary` field). Optional for the brief builder — the
99
+ * brief can be built without it, but a filled evaluator_summary
100
+ * flows into the recommendation envelope.
101
+ */
102
+ export declare const EvaluatorSummarySchema: z.ZodObject<{
103
+ one_liner: z.ZodDefault<z.ZodString>;
104
+ risk_tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
105
+ }, "strip", z.ZodTypeAny, {
106
+ one_liner: string;
107
+ risk_tags: string[];
108
+ }, {
109
+ one_liner?: string | undefined;
110
+ risk_tags?: string[] | undefined;
111
+ }>;
112
+ export type EvaluatorSummary = z.input<typeof EvaluatorSummarySchema>;
113
+ export declare const RecommendationPayloadSchema: z.ZodObject<{
114
+ brief: z.ZodEffects<z.ZodObject<{
115
+ what_happened: z.ZodString;
116
+ why_it_matters: z.ZodString;
117
+ what_learned: z.ZodString;
118
+ what_action: z.ZodString;
119
+ }, "strict", z.ZodTypeAny, {
120
+ what_happened: string;
121
+ why_it_matters: string;
122
+ what_learned: string;
123
+ what_action: string;
124
+ }, {
125
+ what_happened: string;
126
+ why_it_matters: string;
127
+ what_learned: string;
128
+ what_action: string;
129
+ }>, {
130
+ what_happened: string;
131
+ why_it_matters: string;
132
+ what_learned: string;
133
+ what_action: string;
134
+ }, {
135
+ what_happened: string;
136
+ why_it_matters: string;
137
+ what_learned: string;
138
+ what_action: string;
139
+ }>;
140
+ bullets: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
141
+ source_trace_pointers: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
142
+ evaluator_summary: z.ZodDefault<z.ZodObject<{
143
+ one_liner: z.ZodDefault<z.ZodString>;
144
+ risk_tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
145
+ }, "strip", z.ZodTypeAny, {
146
+ one_liner: string;
147
+ risk_tags: string[];
148
+ }, {
149
+ one_liner?: string | undefined;
150
+ risk_tags?: string[] | undefined;
151
+ }>>;
152
+ }, "strip", z.ZodTypeAny, {
153
+ source_trace_pointers: string[];
154
+ evaluator_summary: {
155
+ one_liner: string;
156
+ risk_tags: string[];
157
+ };
158
+ bullets: string[];
159
+ brief: {
160
+ what_happened: string;
161
+ why_it_matters: string;
162
+ what_learned: string;
163
+ what_action: string;
164
+ };
165
+ }, {
166
+ brief: {
167
+ what_happened: string;
168
+ why_it_matters: string;
169
+ what_learned: string;
170
+ what_action: string;
171
+ };
172
+ source_trace_pointers?: string[] | undefined;
173
+ evaluator_summary?: {
174
+ one_liner?: string | undefined;
175
+ risk_tags?: string[] | undefined;
176
+ } | undefined;
177
+ bullets?: string[] | undefined;
178
+ }>;
179
+ export type RecommendationPayload = z.infer<typeof RecommendationPayloadSchema>;
180
+ export declare class BriefSectionError extends Error {
181
+ readonly code: "MISSING_BRIEF_SECTION";
182
+ readonly findings: ReadonlyArray<{
183
+ path: string;
184
+ message: string;
185
+ }>;
186
+ constructor(message: string, findings?: ReadonlyArray<{
187
+ path: string;
188
+ message: string;
189
+ }>);
190
+ }
191
+ /**
192
+ * Build a 4-section EvidenceBrief from a finished trace recap.
193
+ *
194
+ * The function is STRICT: it parses the input trace through
195
+ * `BriefTraceInputSchema`, then parses the assembled brief through
196
+ * `EvidenceBriefSchema`. Any missing section throws
197
+ * `BriefSectionError(MISSING_BRIEF_SECTION)` — the same code that
198
+ * `safeParseEvidenceBrief` returns — so a single error code is the
199
+ * user-facing signal for "brief incomplete, do not render".
200
+ *
201
+ * Brief-section related ZodErrors (e.g. `min(1)` on a section) are
202
+ * translated to `BriefSectionError` so callers only handle one
203
+ * shape of failure. Non-section ZodErrors (e.g. invalid `trace_id`)
204
+ * are re-raised unchanged.
205
+ *
206
+ * NOTE: callers who already have raw NL strings can also call
207
+ * `parseEvidenceBrief` directly; this function is the opinionated
208
+ * shape for trace -> brief.
209
+ */
210
+ export declare function buildEvidenceBrief(trace: BriefTraceInput, evaluatorSummary?: EvaluatorSummary): EvidenceBrief;
211
+ /**
212
+ * Render the user-facing recommendation envelope (brief + bullets +
213
+ * trace pointers + evaluator summary). The function refuses to
214
+ * return a payload unless ALL 4 brief sections are present — this
215
+ * is the single CLI-facing gate per spec §10 RL-7.
216
+ *
217
+ * On success, returns the validated `RecommendationPayload`. On a
218
+ * missing-section brief, throws `BriefSectionError`.
219
+ */
220
+ export declare function renderRecommendationPayload(trace: BriefTraceInput, evaluatorSummary?: EvaluatorSummary): RecommendationPayload;
221
+ /**
222
+ * Convenience: validate an arbitrary unknown payload AS IF it were a
223
+ * recommendation envelope. Returns a Result-like shape so the CLI can
224
+ * render a structured MISSING_BRIEF_SECTION error without try/catch
225
+ * noise.
226
+ */
227
+ export declare function safeRenderRecommendationPayload(input: unknown): {
228
+ ok: true;
229
+ payload: RecommendationPayload;
230
+ } | {
231
+ ok: false;
232
+ code?: "MISSING_BRIEF_SECTION";
233
+ findings: Array<{
234
+ path: string;
235
+ message: string;
236
+ }>;
237
+ };
@@ -0,0 +1,240 @@
1
+ import { z } from "zod";
2
+ import { EvidenceBriefSchema, } from "./crystallization-types.js";
3
+ /**
4
+ * EvidenceBriefBuilder — spec §4.7 / §10 RL-7.
5
+ *
6
+ * The brief is a 4-section natural-language projection that MUST
7
+ * accompany every user-facing recommendation. The shape guard is
8
+ * encoded in `EvidenceBriefSchema` (see crystallization-types.ts);
9
+ * this module is the LLM-side entry point that PRODUCES the brief
10
+ * from a finished trace + evaluator summary and the validator that
11
+ * REFUSES to render a recommendation payload without all 4 sections.
12
+ *
13
+ * Hard rules (mirrored from spec):
14
+ *
15
+ * 1. Every section must be a non-empty NL string (1-2 sentences
16
+ * for what_happened / why_it_matters / what_learned; 1
17
+ * sentence for what_action). An empty section is a hard
18
+ * `MISSING_BRIEF_SECTION` error.
19
+ *
20
+ * 2. The build path is lenient on raw prose and strict on the
21
+ * final shape — `buildEvidenceBrief` calls
22
+ * `EvidenceBriefSchema.parse(...)` so a partial brief throws
23
+ * before reaching the database.
24
+ *
25
+ * 3. `renderRecommendationPayload` refuses to return a
26
+ * recommendation envelope unless the brief passes the 4-section
27
+ * guard. This is the CLI's single source of truth for "may I
28
+ * show this to the user?".
29
+ *
30
+ * 4. The `evaluator_summary` is a separate field on the
31
+ * crystallization_event row (spec §4.5) and is NOT part of the
32
+ * brief. It feeds the broader recommendation envelope.
33
+ *
34
+ * Out of scope (deferred to later slices):
35
+ * - LLM-authored brief generation from live trace evidence (M8 dogfood).
36
+ * - brief rewrite-on-update semantics.
37
+ */
38
+ /* ---------------------------------------------------------------------- */
39
+ /* Input shapes — the builder is the only place these normalize. */
40
+ /* ---------------------------------------------------------------------- */
41
+ /**
42
+ * The minimum viable trace shape that the builder needs to render
43
+ * a brief. The trace is the EVIDENCE; the builder is format-stable
44
+ * so a future slice can swap in a richer trace source without
45
+ * editing every caller.
46
+ */
47
+ export const BriefTraceInputSchema = z.object({
48
+ trace_id: z.string().trim().min(1).max(256),
49
+ /**
50
+ * The full NL recap of the run. Required for what_happened.
51
+ * 1-2 sentences is the spec guidance; the builder does not
52
+ * truncate, but tests passing multi-paragraph input will be
53
+ * warned at the Zod boundary (max 4000 chars per section).
54
+ */
55
+ what_happened: z.string().trim().min(1).max(4000),
56
+ /**
57
+ * The "why this matters" recap. Required for why_it_matters.
58
+ */
59
+ why_it_matters: z.string().trim().min(1).max(4000),
60
+ /**
61
+ * Failure-mode and preference-extraction recap. Required for
62
+ * what_learned.
63
+ */
64
+ what_learned: z.string().trim().min(1).max(4000),
65
+ /**
66
+ * The recommended action. Required for what_action (1
67
+ * sentence per spec).
68
+ */
69
+ what_action: z.string().trim().min(1).max(4000),
70
+ /**
71
+ * Optional structured bullets (e.g. "4 phases, 3 gates passed,
72
+ * 1 evaluator verdict"). Counts are allowed at this layer; the
73
+ * brief section is the NL primary (RL-7).
74
+ */
75
+ bullets: z.array(z.string().trim().min(1).max(1000)).default([]),
76
+ /**
77
+ * Source trace ids backing the brief (the column on
78
+ * crystallization_event spec §4.5).
79
+ */
80
+ source_trace_pointers: z
81
+ .array(z.string().trim().min(1).max(256))
82
+ .default([]),
83
+ });
84
+ /**
85
+ * The summary emitted by the independent evaluators (spec §4.5
86
+ * `evaluator_summary` field). Optional for the brief builder — the
87
+ * brief can be built without it, but a filled evaluator_summary
88
+ * flows into the recommendation envelope.
89
+ */
90
+ export const EvaluatorSummarySchema = z.object({
91
+ one_liner: z.string().trim().max(1000).default(""),
92
+ risk_tags: z.array(z.string().trim().min(1).max(200)).default([]),
93
+ });
94
+ /* ---------------------------------------------------------------------- */
95
+ /* Recommendation envelope — the CLI renders this. */
96
+ /* ---------------------------------------------------------------------- */
97
+ export const RecommendationPayloadSchema = z.object({
98
+ brief: EvidenceBriefSchema,
99
+ bullets: z.array(z.string().trim().min(1).max(1000)).default([]),
100
+ source_trace_pointers: z
101
+ .array(z.string().trim().min(1).max(256))
102
+ .default([]),
103
+ evaluator_summary: EvaluatorSummarySchema.default({
104
+ one_liner: "",
105
+ risk_tags: [],
106
+ }),
107
+ });
108
+ /* ---------------------------------------------------------------------- */
109
+ /* Errors */
110
+ /* ---------------------------------------------------------------------- */
111
+ export class BriefSectionError extends Error {
112
+ code = "MISSING_BRIEF_SECTION";
113
+ findings;
114
+ constructor(message, findings = []) {
115
+ super(message);
116
+ this.name = "BriefSectionError";
117
+ this.findings = findings;
118
+ }
119
+ }
120
+ /* ---------------------------------------------------------------------- */
121
+ /* Builder */
122
+ /* ---------------------------------------------------------------------- */
123
+ /**
124
+ * Build a 4-section EvidenceBrief from a finished trace recap.
125
+ *
126
+ * The function is STRICT: it parses the input trace through
127
+ * `BriefTraceInputSchema`, then parses the assembled brief through
128
+ * `EvidenceBriefSchema`. Any missing section throws
129
+ * `BriefSectionError(MISSING_BRIEF_SECTION)` — the same code that
130
+ * `safeParseEvidenceBrief` returns — so a single error code is the
131
+ * user-facing signal for "brief incomplete, do not render".
132
+ *
133
+ * Brief-section related ZodErrors (e.g. `min(1)` on a section) are
134
+ * translated to `BriefSectionError` so callers only handle one
135
+ * shape of failure. Non-section ZodErrors (e.g. invalid `trace_id`)
136
+ * are re-raised unchanged.
137
+ *
138
+ * NOTE: callers who already have raw NL strings can also call
139
+ * `parseEvidenceBrief` directly; this function is the opinionated
140
+ * shape for trace -> brief.
141
+ */
142
+ export function buildEvidenceBrief(trace, evaluatorSummary) {
143
+ let parsedTrace;
144
+ try {
145
+ parsedTrace = BriefTraceInputSchema.parse(trace);
146
+ }
147
+ catch (err) {
148
+ throw translateBriefZodError(err);
149
+ }
150
+ // Assemble the 4 sections verbatim from the trace recap. The Zod
151
+ // parser below re-asserts the 4-section guard.
152
+ const candidate = {
153
+ what_happened: parsedTrace.what_happened,
154
+ why_it_matters: parsedTrace.why_it_matters,
155
+ what_learned: parsedTrace.what_learned,
156
+ what_action: parsedTrace.what_action,
157
+ };
158
+ const result = EvidenceBriefSchema.safeParse(candidate);
159
+ if (!result.success) {
160
+ const findings = result.error.issues.map((i) => ({
161
+ path: i.path.join("."),
162
+ message: i.message,
163
+ }));
164
+ throw new BriefSectionError("evidence_brief must contain all 4 sections (what_happened, why_it_matters, what_learned, what_action) with non-empty content (spec §4.7 / RL-7)", findings);
165
+ }
166
+ // Silence the unused-var lint on evaluatorSummary at this layer —
167
+ // the builder currently does not consume it (the brief is NL
168
+ // primary), but the surface is preserved for callers via
169
+ // `renderRecommendationPayload` below.
170
+ void evaluatorSummary;
171
+ return result.data;
172
+ }
173
+ /**
174
+ * Translate a ZodError raised on a brief-section path into a
175
+ * `BriefSectionError`. Non-brief errors are re-raised.
176
+ */
177
+ function translateBriefZodError(err) {
178
+ if (err instanceof z.ZodError) {
179
+ const issues = err.issues;
180
+ const allBrief = issues.every((i) => BRIEF_SECTION_KEYS.has(i.path.join(".")));
181
+ if (allBrief) {
182
+ const findings = issues.map((i) => ({
183
+ path: i.path.join("."),
184
+ message: i.message,
185
+ }));
186
+ throw new BriefSectionError("evidence_brief must contain all 4 sections (what_happened, why_it_matters, what_learned, what_action) with non-empty content (spec §4.7 / RL-7)", findings);
187
+ }
188
+ }
189
+ throw err;
190
+ }
191
+ const BRIEF_SECTION_KEYS = new Set([
192
+ "what_happened",
193
+ "why_it_matters",
194
+ "what_learned",
195
+ "what_action",
196
+ ]);
197
+ /**
198
+ * Render the user-facing recommendation envelope (brief + bullets +
199
+ * trace pointers + evaluator summary). The function refuses to
200
+ * return a payload unless ALL 4 brief sections are present — this
201
+ * is the single CLI-facing gate per spec §10 RL-7.
202
+ *
203
+ * On success, returns the validated `RecommendationPayload`. On a
204
+ * missing-section brief, throws `BriefSectionError`.
205
+ */
206
+ export function renderRecommendationPayload(trace, evaluatorSummary = { one_liner: "", risk_tags: [] }) {
207
+ const brief = buildEvidenceBrief(trace, evaluatorSummary);
208
+ const payload = RecommendationPayloadSchema.parse({
209
+ brief,
210
+ bullets: trace.bullets ?? [],
211
+ source_trace_pointers: trace.source_trace_pointers ?? [],
212
+ evaluator_summary: evaluatorSummary,
213
+ });
214
+ return payload;
215
+ }
216
+ /**
217
+ * Convenience: validate an arbitrary unknown payload AS IF it were a
218
+ * recommendation envelope. Returns a Result-like shape so the CLI can
219
+ * render a structured MISSING_BRIEF_SECTION error without try/catch
220
+ * noise.
221
+ */
222
+ export function safeRenderRecommendationPayload(input) {
223
+ const r = RecommendationPayloadSchema.safeParse(input);
224
+ if (r.success)
225
+ return { ok: true, payload: r.data };
226
+ const findings = r.error.issues.map((i) => ({
227
+ path: i.path.join("."),
228
+ message: i.message,
229
+ }));
230
+ // Map brief failures to MISSING_BRIEF_SECTION. A failure is
231
+ // recognized as brief iff (a) every issue points at the brief or
232
+ // its sections, OR (b) the explicit refine message is present.
233
+ const isBrief = r.error.issues.every((i) => i.message.includes("evidence_brief must contain all 4 sections") ||
234
+ BRIEF_SECTION_KEYS.has(i.path.join(".")) ||
235
+ i.path[0] === "brief" ||
236
+ (i.path.length >= 2 && i.path[0] === "brief"));
237
+ return isBrief
238
+ ? { ok: false, code: "MISSING_BRIEF_SECTION", findings }
239
+ : { ok: false, findings };
240
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Slice complexity tier (v2.15.0 follow-up, G2 in 12 Gaps).
3
- * Used by Solo to schedule complex slices during user-attended hours
3
+ * Used by Code to schedule complex slices during user-attended hours
4
4
  * and trivial / simple slices overnight.
5
5
  */
6
6
  export type SliceComplexity = 'trivial' | 'simple' | 'complex';
@@ -27,7 +27,7 @@ export interface SliceNode {
27
27
  */
28
28
  readonly upstreamSync?: boolean;
29
29
  /**
30
- * v2.15.0 follow-up — G2: complexity tier. Drives Solo's scheduling
30
+ * v2.15.0 follow-up — G2: complexity tier. Drives Code's scheduling
31
31
  * (complex = user-attended, simple/trivial = overnight). Optional.
32
32
  */
33
33
  readonly complexity?: SliceComplexity;
@@ -4,7 +4,7 @@
4
4
  * The Test Tool Detection block is prepended to every sub-agent prompt
5
5
  * dispatched by peaks-loop (both the single-dispatch chokepoint in
6
6
  * `src/cli/commands/dispatch-commands.ts` and the DAG-dispatch chokepoint
7
- * in `src/services/solo/dag-orchestrator.ts`). It tells the sub-agent
7
+ * in `src/services/code/dag-orchestrator.ts`). It tells the sub-agent
8
8
  * to read `package.json#scripts.test` first and use the project-local
9
9
  * runner — never `npx <runner>` — so it cannot bypass the lockfile or
10
10
  * spawn a network-bound tool call.
@@ -4,7 +4,7 @@
4
4
  * The Test Tool Detection block is prepended to every sub-agent prompt
5
5
  * dispatched by peaks-loop (both the single-dispatch chokepoint in
6
6
  * `src/cli/commands/dispatch-commands.ts` and the DAG-dispatch chokepoint
7
- * in `src/services/solo/dag-orchestrator.ts`). It tells the sub-agent
7
+ * in `src/services/code/dag-orchestrator.ts`). It tells the sub-agent
8
8
  * to read `package.json#scripts.test` first and use the project-local
9
9
  * runner — never `npx <runner>` — so it cannot bypass the lockfile or
10
10
  * spawn a network-bound tool call.
@@ -0,0 +1,137 @@
1
+ import type Database from "better-sqlite3";
2
+ import { ZodError } from "zod";
3
+ import { EVOLUTION_DEFAULT_DELTA_MIN, type EvolutionEvaluation, type EvolutionProposal, type EvolutionProposalInput, type EvolutionTargetKind, type EvolutionVerdict } from "./evolution-types.js";
4
+ /**
5
+ * EvolutionService — Darwin-style ratchet enforcement.
6
+ *
7
+ * Hard rules enforced at THIS layer (not just the Zod schema) so
8
+ * the ratchet cannot be bypassed by a malformed input:
9
+ *
10
+ * - AC-8: exactly one target (target_count === 1) AND
11
+ * exactly one optimization dimension per round.
12
+ * Code: EVOLUTION_MULTI_OBJECT, EVOLUTION_MULTI_DIMENSION.
13
+ * - AC-10: the scorer (evaluator) MUST NOT be the author.
14
+ * Code: EVOLUTION_SELF_SCORE.
15
+ * - AC-11: a `keep` verdict is BLOCKED when
16
+ * score_delta < score_delta_min (default 1.0).
17
+ * Code: EVOLUTION_DELTA_BELOW_THRESHOLD.
18
+ * - AC-12: evaluator_id MUST be a separate agent from
19
+ * author_id and skeptic_id.
20
+ * - AC-14: skeptic_id MUST be a separate agent from
21
+ * author_id and evaluator_id.
22
+ *
23
+ * The service is intentionally narrow: createProposal / score /
24
+ * markVerdict / list / get. The actual scoring agents
25
+ * (IndependentEvaluatorRunner, RegressionSkepticRunner) live in
26
+ * separate files so the author reasoning is NEVER imported into
27
+ * the evaluator's process boundary.
28
+ */
29
+ export type EvolutionIntegrityErrorCode = "EVOLUTION_MULTI_OBJECT" | "EVOLUTION_MULTI_DIMENSION" | "EVOLUTION_SELF_SCORE" | "EVOLUTION_DELTA_BELOW_THRESHOLD" | "EVOLUTION_MISSING_USER_CONFIRMATION" | "EVOLUTION_BELOW_RUBRIC";
30
+ export declare class EvolutionIntegrityError extends Error {
31
+ readonly code: EvolutionIntegrityErrorCode;
32
+ readonly findings: ReadonlyArray<{
33
+ path: string;
34
+ message: string;
35
+ }>;
36
+ constructor(code: EvolutionIntegrityErrorCode, message: string, findings?: ReadonlyArray<{
37
+ path: string;
38
+ message: string;
39
+ }>);
40
+ }
41
+ export declare class EvolutionService {
42
+ private readonly db;
43
+ constructor(db: Database.Database);
44
+ /**
45
+ * Persist a new EvolutionProposal. Enforces AC-8 (single object /
46
+ * single dimension) BEFORE writing the row.
47
+ *
48
+ * The proposal id is auto-generated (`eval-<hex>`); callers supply
49
+ * the proposal content only. The proposal's `verdict` is set to
50
+ * `needs-user-decision` until the score + skeptic step lands.
51
+ *
52
+ * Throws:
53
+ * - ZodError if the input fails schema validation.
54
+ * - EvolutionIntegrityError(EVOLUTION_MULTI_OBJECT) if
55
+ * single_object !== true.
56
+ * - EvolutionIntegrityError(EVOLUTION_MULTI_DIMENSION) if
57
+ * single_optimization_dimension !== true.
58
+ */
59
+ createProposal(input: EvolutionProposalInput): EvolutionProposal;
60
+ /**
61
+ * Score an existing proposal. Enforces AC-10 (no self-score:
62
+ * `evaluator_id !== proposal.author_id`) and AC-11 (delta
63
+ * threshold: cannot mark `keep` when `score_delta <
64
+ * score_delta_min`).
65
+ *
66
+ * Returns the FINAL evaluation row with verdict derived from the
67
+ * evaluator + skeptic results:
68
+ * - `verdict = 'revert'` if the skeptic returned a blocker.
69
+ * - `verdict = 'revert'` if the score delta is below threshold.
70
+ * - `verdict = 'needs-user-decision'` otherwise; the CLI
71
+ * (`peaks evolution evaluate`) surfaces this to the user for
72
+ * a `keep` / `revert` choice.
73
+ *
74
+ * Throws:
75
+ * - EvolutionIntegrityError(EVOLUTION_SELF_SCORE) if
76
+ * evaluator_id === proposal.author_id.
77
+ * - EvolutionIntegrityError(EVOLUTION_DELTA_BELOW_THRESHOLD) if
78
+ * a `verdict = 'keep'` is requested and the delta is below
79
+ * the proposal's `score_delta_min`.
80
+ */
81
+ score(proposalId: string, args: {
82
+ evaluator_id: string;
83
+ skeptic_id: string;
84
+ evaluator_result: import("./evolution-types.js").IndependentEvaluatorResult;
85
+ skeptic_result: import("./evolution-types.js").RegressionSkepticResult;
86
+ brief_pointer?: string;
87
+ user_confirmation_pointer?: string;
88
+ }): EvolutionEvaluation;
89
+ /**
90
+ * Mark a verdict explicitly (after the user has confirmed via
91
+ * natural-language or a pick). Enforces:
92
+ * - AC-11: cannot mark `keep` when score_delta <
93
+ * score_delta_min.
94
+ * - AC-15: `keep` requires a user_confirmation_pointer.
95
+ *
96
+ * Throws:
97
+ * - EvolutionIntegrityError(EVOLUTION_DELTA_BELOW_THRESHOLD)
98
+ * when `verdict = 'keep'` and the delta is below threshold.
99
+ * - EvolutionIntegrityError(EVOLUTION_MISSING_USER_CONFIRMATION)
100
+ * when `verdict = 'keep'` and no user_confirmation_pointer
101
+ * is supplied.
102
+ */
103
+ markVerdict(proposalId: string, verdict: EvolutionVerdict, userConfirmationPointer?: string): EvolutionEvaluation | undefined;
104
+ /** Revert a proposal (universal recovery). Always allowed. */
105
+ revert(proposalId: string, userConfirmationPointer?: string): EvolutionEvaluation | undefined;
106
+ /** Read an evolution evaluation by id. */
107
+ read(proposalId: string): EvolutionEvaluation | undefined;
108
+ /** List evaluations for a given target. */
109
+ listByTarget(opts: {
110
+ target_kind: EvolutionTargetKind;
111
+ target_release_id: string;
112
+ verdict?: EvolutionVerdict;
113
+ }): EvolutionEvaluation[];
114
+ /**
115
+ * Status snapshot for `peaks evolution status`. Returns counts of
116
+ * evaluations by verdict for the given target, plus the latest
117
+ * evaluation id (if any).
118
+ */
119
+ status(target: {
120
+ target_kind: EvolutionTargetKind;
121
+ target_release_id: string;
122
+ }): {
123
+ target_kind: EvolutionTargetKind;
124
+ target_release_id: string;
125
+ total: number;
126
+ byVerdict: Record<EvolutionVerdict, number>;
127
+ latest: EvolutionEvaluation | undefined;
128
+ };
129
+ }
130
+ /**
131
+ * Convenience: re-export the Zod error guard.
132
+ */
133
+ export declare function isZodError(err: unknown): err is ZodError;
134
+ /**
135
+ * Convenience: get the default `score_delta_min` from the spec.
136
+ */
137
+ export { EVOLUTION_DEFAULT_DELTA_MIN };