avorelo 0.1.0 → 0.3.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 (260) hide show
  1. package/LICENSE +23 -16
  2. package/README.md +90 -51
  3. package/bin/avorelo.mjs +7 -0
  4. package/dist/avorelo.mjs +19741 -0
  5. package/package.json +135 -120
  6. package/bin/avorelo +0 -9
  7. package/scripts/README.md +0 -40
  8. package/scripts/cco-dashboard.js +0 -252
  9. package/scripts/cco-status.js +0 -430
  10. package/scripts/lib/activation/account-state.js +0 -37
  11. package/scripts/lib/activation/activation-runner.js +0 -546
  12. package/scripts/lib/activation/activation-self-healing.js +0 -480
  13. package/scripts/lib/activation/activation-state.js +0 -83
  14. package/scripts/lib/activation/activation-summary.js +0 -191
  15. package/scripts/lib/activation/adapters/claude-code.js +0 -77
  16. package/scripts/lib/activation/adapters/codex-cli.js +0 -52
  17. package/scripts/lib/activation/adapters/cursor.js +0 -37
  18. package/scripts/lib/activation/adapters/github-agent.js +0 -39
  19. package/scripts/lib/activation/adapters/terminal.js +0 -42
  20. package/scripts/lib/activation/adapters/vscode.js +0 -39
  21. package/scripts/lib/activation/adapters/windsurf.js +0 -37
  22. package/scripts/lib/activation/ai-surface-detector.js +0 -151
  23. package/scripts/lib/activation/connect-account.js +0 -145
  24. package/scripts/lib/activation/detect-environment.js +0 -75
  25. package/scripts/lib/activation/detect-hosts.js +0 -62
  26. package/scripts/lib/activation/format-activation-output.js +0 -109
  27. package/scripts/lib/activation/next-action.js +0 -43
  28. package/scripts/lib/activation/repair-engine.js +0 -219
  29. package/scripts/lib/activation-distribution-readiness.js +0 -507
  30. package/scripts/lib/adapter-conformance.js +0 -176
  31. package/scripts/lib/adapter-readiness.js +0 -417
  32. package/scripts/lib/adapter-safety-boundaries.js +0 -335
  33. package/scripts/lib/adapter-technical-readiness-gate.js +0 -205
  34. package/scripts/lib/agent-access-governance.js +0 -455
  35. package/scripts/lib/agent-enforcement.js +0 -765
  36. package/scripts/lib/agent-policy-profile.js +0 -210
  37. package/scripts/lib/agent-security/action-evaluator.js +0 -507
  38. package/scripts/lib/agent-security/adapter-registry.js +0 -98
  39. package/scripts/lib/agent-security/auto-policy.js +0 -139
  40. package/scripts/lib/agent-security/bounded-scan.js +0 -93
  41. package/scripts/lib/agent-security/enforcement-adapter.js +0 -174
  42. package/scripts/lib/agent-security/enforcement-engine.js +0 -1129
  43. package/scripts/lib/agent-security/file-write-adapter.js +0 -183
  44. package/scripts/lib/agent-security/file-write-rules.js +0 -178
  45. package/scripts/lib/agent-security/index.js +0 -3342
  46. package/scripts/lib/agent-security/instruction-risk.js +0 -181
  47. package/scripts/lib/agent-security/mcp-action-adapter.js +0 -185
  48. package/scripts/lib/agent-security/mcp-action-rules.js +0 -184
  49. package/scripts/lib/agent-security/package-action-adapter.js +0 -175
  50. package/scripts/lib/agent-security/package-action-rules.js +0 -233
  51. package/scripts/lib/agent-security/performance.js +0 -148
  52. package/scripts/lib/agent-security/permission-minimizer.js +0 -403
  53. package/scripts/lib/agent-security/scan-cache.js +0 -74
  54. package/scripts/lib/agent-security/source-trust.js +0 -146
  55. package/scripts/lib/ai-install-prompt.js +0 -288
  56. package/scripts/lib/ai-workspace-hygiene.js +0 -1499
  57. package/scripts/lib/alpha-activation.js +0 -520
  58. package/scripts/lib/alpha-feedback.js +0 -263
  59. package/scripts/lib/alpha-readiness-gate.js +0 -332
  60. package/scripts/lib/anti-gaming.js +0 -169
  61. package/scripts/lib/artifact-health.js +0 -431
  62. package/scripts/lib/attribution.js +0 -180
  63. package/scripts/lib/audit.js +0 -289
  64. package/scripts/lib/avorelo-skill-registry.js +0 -810
  65. package/scripts/lib/batch-jobs.js +0 -71
  66. package/scripts/lib/brain-pack.js +0 -578
  67. package/scripts/lib/brand-boundary.js +0 -424
  68. package/scripts/lib/brand.js +0 -74
  69. package/scripts/lib/browser-capability.js +0 -1048
  70. package/scripts/lib/browser-proof-preflight.js +0 -321
  71. package/scripts/lib/cache-readiness.js +0 -187
  72. package/scripts/lib/canonical-reentry.js +0 -162
  73. package/scripts/lib/capability-packs.js +0 -314
  74. package/scripts/lib/capability-recommender.js +0 -512
  75. package/scripts/lib/capability-registry.js +0 -1059
  76. package/scripts/lib/carry-forward-surfacing.js +0 -194
  77. package/scripts/lib/ccusage-adapter.js +0 -188
  78. package/scripts/lib/company-loop.js +0 -1149
  79. package/scripts/lib/config.js +0 -637
  80. package/scripts/lib/context-acquisition-plan.js +0 -287
  81. package/scripts/lib/context-budget-guard.js +0 -170
  82. package/scripts/lib/context-budget-scanner.js +0 -257
  83. package/scripts/lib/context-optimizer.js +0 -715
  84. package/scripts/lib/context-reduction-plan.js +0 -178
  85. package/scripts/lib/context-safety.js +0 -88
  86. package/scripts/lib/context-savings-engine.js +0 -158
  87. package/scripts/lib/cost-evidence.js +0 -254
  88. package/scripts/lib/cross-host-install-plan.js +0 -308
  89. package/scripts/lib/cross-host-install-readiness.js +0 -237
  90. package/scripts/lib/cross-host-value-flow.js +0 -268
  91. package/scripts/lib/dashboard.js +0 -900
  92. package/scripts/lib/design-partner-feedback.js +0 -346
  93. package/scripts/lib/entitlements.js +0 -100
  94. package/scripts/lib/execution-packet.js +0 -559
  95. package/scripts/lib/experimentation-events.js +0 -547
  96. package/scripts/lib/external-capability-compliance.js +0 -107
  97. package/scripts/lib/external-user-simulation.js +0 -166
  98. package/scripts/lib/failure-recovery-readiness.js +0 -81
  99. package/scripts/lib/failure-recovery.js +0 -419
  100. package/scripts/lib/feedback-intelligence.js +0 -537
  101. package/scripts/lib/feedback-signals.js +0 -205
  102. package/scripts/lib/file-integrity.js +0 -68
  103. package/scripts/lib/fsx.js +0 -127
  104. package/scripts/lib/full-readiness-gate.js +0 -451
  105. package/scripts/lib/guidance-builder.js +0 -174
  106. package/scripts/lib/hook-apply.js +0 -1019
  107. package/scripts/lib/hook-baseline.js +0 -310
  108. package/scripts/lib/hook-config-preview.js +0 -275
  109. package/scripts/lib/hook-contracts.js +0 -290
  110. package/scripts/lib/hook-safety-boundary-readiness.js +0 -80
  111. package/scripts/lib/host-capability-matrix.js +0 -351
  112. package/scripts/lib/host-support-context.js +0 -254
  113. package/scripts/lib/http-hook-action.js +0 -538
  114. package/scripts/lib/install-ai-readiness.js +0 -84
  115. package/scripts/lib/install-intake-risk.js +0 -1037
  116. package/scripts/lib/install-journey-intelligence.js +0 -329
  117. package/scripts/lib/intervention-guidance.js +0 -57
  118. package/scripts/lib/known-limitations.js +0 -115
  119. package/scripts/lib/l8-path-truth.js +0 -146
  120. package/scripts/lib/launch-hardening-gate.js +0 -436
  121. package/scripts/lib/launch-readiness.js +0 -628
  122. package/scripts/lib/learning-memory.js +0 -686
  123. package/scripts/lib/lifecycle-hooks.js +0 -802
  124. package/scripts/lib/local-package-smoke.js +0 -423
  125. package/scripts/lib/local-pricing.js +0 -299
  126. package/scripts/lib/mcp-enforcement.js +0 -311
  127. package/scripts/lib/mcp-least-privilege-policy.js +0 -303
  128. package/scripts/lib/mcp-tool-inventory.js +0 -388
  129. package/scripts/lib/mcp-tool-risk.js +0 -0
  130. package/scripts/lib/memory.js +0 -335
  131. package/scripts/lib/metrics.js +0 -699
  132. package/scripts/lib/micro-proof.js +0 -133
  133. package/scripts/lib/next-run-context.js +0 -436
  134. package/scripts/lib/operating-value.js +0 -1648
  135. package/scripts/lib/optimization-v3.js +0 -122
  136. package/scripts/lib/orchestration/adapters/_shared.js +0 -49
  137. package/scripts/lib/orchestration/adapters/aider.js +0 -18
  138. package/scripts/lib/orchestration/adapters/claude-code.js +0 -35
  139. package/scripts/lib/orchestration/adapters/codex.js +0 -35
  140. package/scripts/lib/orchestration/adapters/gemini-cli.js +0 -18
  141. package/scripts/lib/orchestration/adapters/git.js +0 -25
  142. package/scripts/lib/orchestration/adapters/index.js +0 -31
  143. package/scripts/lib/orchestration/adapters/lm-studio.js +0 -18
  144. package/scripts/lib/orchestration/adapters/ollama.js +0 -18
  145. package/scripts/lib/orchestration/adapters/opencode.js +0 -18
  146. package/scripts/lib/orchestration/adapters/openrouter.js +0 -18
  147. package/scripts/lib/orchestration/adapters/test-runner.js +0 -25
  148. package/scripts/lib/orchestration/cli.js +0 -438
  149. package/scripts/lib/orchestration/execution-manager.js +0 -279
  150. package/scripts/lib/orchestration/handoff.js +0 -314
  151. package/scripts/lib/orchestration/index.js +0 -456
  152. package/scripts/lib/orchestration/inventory.js +0 -47
  153. package/scripts/lib/orchestration/model-discovery.js +0 -498
  154. package/scripts/lib/orchestration/model-profiler.js +0 -170
  155. package/scripts/lib/orchestration/model-profiles.js +0 -252
  156. package/scripts/lib/orchestration/model-refresh-policy.js +0 -72
  157. package/scripts/lib/orchestration/proof-writer.js +0 -349
  158. package/scripts/lib/orchestration/provider-discovery/aider.js +0 -49
  159. package/scripts/lib/orchestration/provider-discovery/claude-code.js +0 -56
  160. package/scripts/lib/orchestration/provider-discovery/codex.js +0 -49
  161. package/scripts/lib/orchestration/provider-discovery/common.js +0 -186
  162. package/scripts/lib/orchestration/provider-discovery/gemini.js +0 -106
  163. package/scripts/lib/orchestration/provider-discovery/lm-studio.js +0 -118
  164. package/scripts/lib/orchestration/provider-discovery/models-dev.js +0 -12
  165. package/scripts/lib/orchestration/provider-discovery/ollama.js +0 -100
  166. package/scripts/lib/orchestration/provider-discovery/opencode.js +0 -47
  167. package/scripts/lib/orchestration/provider-discovery/openrouter.js +0 -44
  168. package/scripts/lib/orchestration/risk-classifier.js +0 -130
  169. package/scripts/lib/orchestration/routing-policy.js +0 -486
  170. package/scripts/lib/orchestration/settings.js +0 -112
  171. package/scripts/lib/orchestration/state.js +0 -165
  172. package/scripts/lib/orchestration/verification-manager.js +0 -138
  173. package/scripts/lib/output-profiles.js +0 -146
  174. package/scripts/lib/package-content-audit.js +0 -368
  175. package/scripts/lib/package-runtime.js +0 -278
  176. package/scripts/lib/plan-surface.js +0 -53
  177. package/scripts/lib/plans.js +0 -2318
  178. package/scripts/lib/policy-provider.js +0 -27
  179. package/scripts/lib/prelaunch-activation-readiness.js +0 -409
  180. package/scripts/lib/prelaunch-evidence-store.js +0 -816
  181. package/scripts/lib/prelaunch-intelligence.js +0 -869
  182. package/scripts/lib/pricing-experiment.js +0 -118
  183. package/scripts/lib/pro-moment-events.js +0 -77
  184. package/scripts/lib/pro-moment-state.js +0 -227
  185. package/scripts/lib/pro-moments.js +0 -1216
  186. package/scripts/lib/product-learning-events.js +0 -629
  187. package/scripts/lib/project-profile.js +0 -555
  188. package/scripts/lib/prompt-compiler.js +0 -280
  189. package/scripts/lib/prompt-lint.js +0 -32
  190. package/scripts/lib/prompt-suggestions.js +0 -52
  191. package/scripts/lib/proof-canonical.js +0 -398
  192. package/scripts/lib/proof-drilldown.js +0 -383
  193. package/scripts/lib/proof-events.js +0 -342
  194. package/scripts/lib/proof-history.js +0 -243
  195. package/scripts/lib/proof-metrics.js +0 -296
  196. package/scripts/lib/proof-outcome-evidence.js +0 -134
  197. package/scripts/lib/proof-receipt.js +0 -335
  198. package/scripts/lib/proof-record.js +0 -461
  199. package/scripts/lib/public-activation-distribution-gate.js +0 -258
  200. package/scripts/lib/public-cli.js +0 -3891
  201. package/scripts/lib/public-distribution-truth.js +0 -211
  202. package/scripts/lib/public-install-claim-checker.js +0 -294
  203. package/scripts/lib/publish-provenance-readiness.js +0 -283
  204. package/scripts/lib/readiness-delta.js +0 -218
  205. package/scripts/lib/readiness-evidence-closure.js +0 -196
  206. package/scripts/lib/reentry-memory-capture.js +0 -241
  207. package/scripts/lib/reentry-memory-retrieval.js +0 -302
  208. package/scripts/lib/reentry-memory-status.js +0 -146
  209. package/scripts/lib/reentry-memory-store.js +0 -178
  210. package/scripts/lib/reentry-state.js +0 -66
  211. package/scripts/lib/release-candidate-bundle.js +0 -166
  212. package/scripts/lib/remediation.js +0 -81
  213. package/scripts/lib/repo-map.js +0 -391
  214. package/scripts/lib/run-improvements-lifecycle.js +0 -330
  215. package/scripts/lib/run-improvements.js +0 -789
  216. package/scripts/lib/runtime-decision-policy.js +0 -387
  217. package/scripts/lib/safe-path-engine.js +0 -705
  218. package/scripts/lib/safe-run-controller.js +0 -887
  219. package/scripts/lib/score.js +0 -262
  220. package/scripts/lib/seamless-enforcement.js +0 -329
  221. package/scripts/lib/seamless-outcome.js +0 -689
  222. package/scripts/lib/seamless-reality-gate.js +0 -5043
  223. package/scripts/lib/security-risk-classifier.js +0 -511
  224. package/scripts/lib/security-scan.js +0 -384
  225. package/scripts/lib/session-context-optimizer.js +0 -1211
  226. package/scripts/lib/session-timing.js +0 -315
  227. package/scripts/lib/skill-hygiene.js +0 -805
  228. package/scripts/lib/skill-packs.js +0 -161
  229. package/scripts/lib/skills-operating-layer.js +0 -580
  230. package/scripts/lib/smart-work-routing.js +0 -768
  231. package/scripts/lib/source-catalog.js +0 -700
  232. package/scripts/lib/status-value-summary.js +0 -32
  233. package/scripts/lib/support-bundle.js +0 -578
  234. package/scripts/lib/task-continuation.js +0 -440
  235. package/scripts/lib/test-helpers.js +0 -15
  236. package/scripts/lib/tier.js +0 -38
  237. package/scripts/lib/token-context-quality-gate.js +0 -370
  238. package/scripts/lib/token-cost-capture.js +0 -187
  239. package/scripts/lib/token-cost-intelligence.js +0 -358
  240. package/scripts/lib/token-efficiency-evidence.js +0 -213
  241. package/scripts/lib/token-evidence.js +0 -699
  242. package/scripts/lib/tokenish.js +0 -17
  243. package/scripts/lib/tool-output-sandbox.js +0 -304
  244. package/scripts/lib/trust-audit.js +0 -136
  245. package/scripts/lib/unified-events.js +0 -396
  246. package/scripts/lib/upgrade-interruption-recovery.js +0 -407
  247. package/scripts/lib/usage-ledger.js +0 -201
  248. package/scripts/lib/value-ledger.js +0 -130
  249. package/scripts/lib/value-proof-calibration.js +0 -531
  250. package/scripts/lib/visual-qa.js +0 -231
  251. package/scripts/lib/voice-alpha.js +0 -29
  252. package/scripts/lib/work-aware-orchestration.js +0 -976
  253. package/scripts/lib/work-control-receipts.js +0 -577
  254. package/scripts/lib/work-ledger.js +0 -1123
  255. package/scripts/lib/work-panel-preview.js +0 -352
  256. package/scripts/lib/workflow-discipline.js +0 -280
  257. package/scripts/lib/workflow-signals.js +0 -419
  258. package/scripts/lib/workspace-map.js +0 -281
  259. package/scripts/lib/workspace-registry.js +0 -1367
  260. package/scripts/lib/workspace-resolver.js +0 -480
@@ -1,1149 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require("node:fs");
4
- const path = require("node:path");
5
-
6
- const CONTRACT = "avorelo.companyLoop.v1";
7
- const SCHEMA_VERSION = 1;
8
-
9
- const LOOP_DIR_REL = ".claude/cco/orchestration/company-loop";
10
- const LATEST_REPORT_REL = `${LOOP_DIR_REL}/latest-report.json`;
11
-
12
- const PERSONAS = Object.freeze([
13
- "product_manager",
14
- "qa_verification",
15
- "ux_design",
16
- "security",
17
- "devex",
18
- "cost_cogs",
19
- "support_cs",
20
- "marketing_growth",
21
- ]);
22
-
23
- const PERSONA_LABELS = Object.freeze({
24
- product_manager: "Product Manager",
25
- qa_verification: "QA / Verification",
26
- ux_design: "UX / Design Reviewer",
27
- security: "Security Reviewer",
28
- devex: "DevEx",
29
- cost_cogs: "Cost / COGS",
30
- support_cs: "Support / Customer Success",
31
- marketing_growth: "Marketing / Growth",
32
- });
33
-
34
- const FRICTION_CLUSTER_TYPES = Object.freeze([
35
- "missing_evidence",
36
- "noisy_output",
37
- "manual_fallback_required",
38
- "generic_next_action",
39
- "verification_missing",
40
- "proof_missing",
41
- "unavailable_worker",
42
- "context_too_large",
43
- "unknown_asset_repeated",
44
- "high_risk_blocked_without_continuation",
45
- "value_claim_not_evidence_backed",
46
- "activation_friction",
47
- "support_explainability_gap",
48
- ]);
49
-
50
- const ROADMAP_CANDIDATES = Object.freeze([
51
- "hook_baseline_pack",
52
- "mcp_least_privilege_cleanup",
53
- "browser_proof_evidence",
54
- "plugin_adapter_technical_readiness",
55
- "activation_alpha_readiness",
56
- "repair_work_orchestration_accuracy",
57
- "repair_value_evidence_ledger",
58
- "repair_ux_noise_compactness",
59
- ]);
60
-
61
- function safeReadJson(filePath) {
62
- try {
63
- if (!fs.existsSync(filePath)) return null;
64
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
65
- } catch {
66
- return null;
67
- }
68
- }
69
-
70
- function makePersonaFinding(persona, status, finding, options = {}) {
71
- return {
72
- persona,
73
- status,
74
- finding,
75
- evidence: options.evidence || null,
76
- recommendedFix: options.recommendedFix || null,
77
- severity: options.severity || (status === "fail" ? "high" : status === "warn" ? "medium" : "low"),
78
- reasonCodes: options.reasonCodes || [],
79
- redacted: true,
80
- };
81
- }
82
-
83
- // --- Product Manager ---
84
- function reviewProductManager(ledger) {
85
- const rollup = ledger.rollup || {};
86
- const nextAction = rollup.nextAction;
87
- const completedItems = (rollup.completed || []).filter((c) => c !== "not_available");
88
- const orchEntry = (ledger.entries || []).find((e) => e.type === "orchestration");
89
-
90
- if (completedItems.length === 0 && !orchEntry) {
91
- return makePersonaFinding(
92
- "product_manager",
93
- "warn",
94
- "No completed work or orchestration plan found. Ledger may be empty or first run.",
95
- {
96
- evidence: "ledger.rollup.completed = not_available",
97
- recommendedFix: "Run a full Avorelo task to populate ledger entries.",
98
- reasonCodes: ["NO_COMPLETED_WORK"],
99
- }
100
- );
101
- }
102
-
103
- if (!nextAction || nextAction.includes("Run node bin/avorelo outcome")) {
104
- return makePersonaFinding(
105
- "product_manager",
106
- "warn",
107
- "Next action is generic. Recommend a more specific next action from ledger evidence.",
108
- {
109
- evidence: nextAction,
110
- recommendedFix: "Improve nextAction resolution from Reality Gate gaps or persona findings.",
111
- reasonCodes: ["GENERIC_NEXT_ACTION"],
112
- }
113
- );
114
- }
115
-
116
- return makePersonaFinding(
117
- "product_manager",
118
- "pass",
119
- `Next action clear. ${completedItems.length} completed item(s) in ledger.`,
120
- { evidence: nextAction }
121
- );
122
- }
123
-
124
- // --- QA / Verification ---
125
- function reviewQaVerification(ledger) {
126
- const gateEntry = (ledger.entries || []).find((e) => e.type === "reality_gate");
127
- const outcomeEntry = (ledger.entries || []).find((e) => e.type === "outcome");
128
- const verified = ledger.rollup?.verified || [];
129
-
130
- if (!gateEntry && !outcomeEntry) {
131
- return makePersonaFinding(
132
- "qa_verification",
133
- "warn",
134
- "No Reality Gate or outcome receipt found. Verification evidence missing.",
135
- {
136
- evidence: null,
137
- recommendedFix: "Run node bin/avorelo outcome --gate to generate Reality Gate.",
138
- reasonCodes: ["VERIFICATION_MISSING", "PROOF_MISSING"],
139
- }
140
- );
141
- }
142
-
143
- const gateStatus = gateEntry?.status;
144
- if (gateStatus === "fail") {
145
- return makePersonaFinding(
146
- "qa_verification",
147
- "fail",
148
- `Reality Gate failed. ${gateEntry.summary}`,
149
- {
150
- evidence: gateEntry.evidencePath,
151
- recommendedFix: "Fix Reality Gate failures before merging.",
152
- severity: "high",
153
- reasonCodes: gateEntry.reasonCodes || [],
154
- }
155
- );
156
- }
157
-
158
- if (gateStatus === "warn") {
159
- return makePersonaFinding(
160
- "qa_verification",
161
- "warn",
162
- `Reality Gate has warnings. ${gateEntry.summary}`,
163
- {
164
- evidence: gateEntry.evidencePath,
165
- recommendedFix: "Review Reality Gate warnings and address where possible.",
166
- reasonCodes: gateEntry.reasonCodes || [],
167
- }
168
- );
169
- }
170
-
171
- return makePersonaFinding(
172
- "qa_verification",
173
- "pass",
174
- `Verification evidence present. ${verified.length > 0 ? verified.join(", ") : "Reality Gate available."}`,
175
- { evidence: gateEntry?.evidencePath || outcomeEntry?.evidencePath }
176
- );
177
- }
178
-
179
- // --- UX / Design ---
180
- function reviewUxDesign(ledger) {
181
- const friction = ledger.rollup?.friction || [];
182
- const noisyFriction = friction.filter(
183
- (f) =>
184
- f.includes("noisy") ||
185
- f.includes("verbose") ||
186
- f.includes("dump") ||
187
- f.includes("scattered")
188
- );
189
-
190
- if (noisyFriction.length > 0) {
191
- return makePersonaFinding(
192
- "ux_design",
193
- "warn",
194
- `Noisy output signals detected: ${noisyFriction.join(", ")}.`,
195
- {
196
- evidence: noisyFriction.join(", "),
197
- recommendedFix: "Audit default CLI output for verbosity and move details behind --debug.",
198
- reasonCodes: ["NOISY_DEFAULT_OUTPUT"],
199
- }
200
- );
201
- }
202
-
203
- const orchEntry = (ledger.entries || []).find((e) => e.type === "orchestration");
204
- if (orchEntry?.status === "pass") {
205
- return makePersonaFinding(
206
- "ux_design",
207
- "pass",
208
- "Ledger compact by default. Debug detail available via --debug flag.",
209
- { evidence: "ledger.formatWorkLedgerText" }
210
- );
211
- }
212
-
213
- return makePersonaFinding(
214
- "ux_design",
215
- "skip",
216
- "No specific UX signal in current ledger. Compact default assumed.",
217
- {}
218
- );
219
- }
220
-
221
- // --- Security ---
222
- function reviewSecurity(ledger) {
223
- const guardEntry = (ledger.entries || []).find((e) => e.type === "guard");
224
- const hygieneEntry = (ledger.entries || []).find((e) => e.type === "workspace_hygiene");
225
-
226
- const riskSignals = ledger.entries
227
- ? ledger.entries.flatMap((e) => e.riskSignals || [])
228
- : [];
229
-
230
- if (!guardEntry && !hygieneEntry) {
231
- return makePersonaFinding(
232
- "security",
233
- "warn",
234
- "No guard or workspace hygiene receipt found. Security posture unverified.",
235
- {
236
- recommendedFix: "Run node bin/avorelo workspace-hygiene and node bin/avorelo guard.",
237
- reasonCodes: ["GUARD_RECEIPT_MISSING", "HYGIENE_RECEIPT_MISSING"],
238
- }
239
- );
240
- }
241
-
242
- const highRisk = riskSignals.filter(
243
- (r) =>
244
- r.includes("critical") ||
245
- r.includes("unknown_subjects") ||
246
- r.includes("high_risk")
247
- );
248
-
249
- if (highRisk.length > 0) {
250
- return makePersonaFinding(
251
- "security",
252
- "warn",
253
- `High-risk signals present: ${highRisk.join(", ")}.`,
254
- {
255
- evidence: riskSignals.join(", "),
256
- recommendedFix: "Review high-risk assets and unknown subjects before proceeding.",
257
- reasonCodes: highRisk,
258
- }
259
- );
260
- }
261
-
262
- return makePersonaFinding(
263
- "security",
264
- "pass",
265
- `Guard and hygiene evidence present. Risk signals: ${riskSignals.join(", ") || "none"}.`,
266
- { evidence: guardEntry?.evidencePath || hygieneEntry?.evidencePath }
267
- );
268
- }
269
-
270
- // --- DevEx ---
271
- function reviewDevEx(ledger) {
272
- const orchEntry = (ledger.entries || []).find((e) => e.type === "orchestration");
273
- const friction = ledger.rollup?.friction || [];
274
- const handoffFriction = friction.filter(
275
- (f) => f.includes("handoff") || f.includes("continuation") || f.includes("manual_fallback")
276
- );
277
-
278
- if (handoffFriction.length > 0) {
279
- return makePersonaFinding(
280
- "devex",
281
- "warn",
282
- `Handoff/continuation friction: ${handoffFriction.join(", ")}.`,
283
- {
284
- evidence: handoffFriction.join(", "),
285
- recommendedFix: "Improve stage handoff and continuation paths.",
286
- reasonCodes: ["HANDOFF_FRICTION"],
287
- }
288
- );
289
- }
290
-
291
- if (orchEntry?.status === "pass") {
292
- const orchData = orchEntry.summary;
293
- return makePersonaFinding(
294
- "devex",
295
- "pass",
296
- `Orchestration available and usable. ${orchData}`,
297
- { evidence: orchEntry.evidencePath }
298
- );
299
- }
300
-
301
- return makePersonaFinding(
302
- "devex",
303
- "skip",
304
- "DevEx signals not determinable from current ledger.",
305
- {}
306
- );
307
- }
308
-
309
- // --- Cost / COGS ---
310
- function reviewCostCogs(ledger) {
311
- const saved = ledger.rollup?.saved || [];
312
- const orchEntry = (ledger.entries || []).find((e) => e.type === "orchestration");
313
- const frictions = ledger.rollup?.friction || [];
314
- const contextLarge = frictions.filter(
315
- (f) => f.includes("context_too_large") || f.includes("broad_scan")
316
- );
317
-
318
- if (contextLarge.length > 0) {
319
- return makePersonaFinding(
320
- "cost_cogs",
321
- "warn",
322
- `Context/cost friction detected: ${contextLarge.join(", ")}.`,
323
- {
324
- evidence: contextLarge.join(", "),
325
- recommendedFix: "Reduce context budget or improve hygiene-guided exclusions.",
326
- reasonCodes: ["CONTEXT_TOO_LARGE"],
327
- }
328
- );
329
- }
330
-
331
- const localSignals = saved.filter((s) => s.includes("local") || s.includes("cheap"));
332
-
333
- if (localSignals.length > 0) {
334
- return makePersonaFinding(
335
- "cost_cogs",
336
- "pass",
337
- `Local/cheap stages used: ${localSignals.join(", ")}.`,
338
- {
339
- evidence: localSignals.join(", "),
340
- }
341
- );
342
- }
343
-
344
- return makePersonaFinding(
345
- "cost_cogs",
346
- "skip",
347
- "Cost/COGS signals not determinable. No local-stage evidence in ledger.",
348
- {
349
- recommendedFix: "Run orchestrate to generate stage worker evidence.",
350
- }
351
- );
352
- }
353
-
354
- // --- Support / CS ---
355
- function reviewSupportCs(ledger) {
356
- const outcomeEntry = (ledger.entries || []).find((e) => e.type === "outcome");
357
- const rollup = ledger.rollup || {};
358
-
359
- if (!outcomeEntry) {
360
- return makePersonaFinding(
361
- "support_cs",
362
- "warn",
363
- "No outcome receipt found. Customer-explainable summary unavailable.",
364
- {
365
- recommendedFix: "Run node bin/avorelo outcome to generate value summary.",
366
- reasonCodes: ["SUPPORT_EXPLAINABILITY_GAP"],
367
- }
368
- );
369
- }
370
-
371
- const hasEvidence = ledger.evidence?.receiptPaths?.length > 0;
372
- return makePersonaFinding(
373
- "support_cs",
374
- "pass",
375
- `Outcome summary available. Evidence paths: ${hasEvidence ? ledger.evidence.receiptPaths.length : 0}.`,
376
- { evidence: outcomeEntry.evidencePath }
377
- );
378
- }
379
-
380
- // --- Marketing / Growth ---
381
- function reviewMarketingGrowth(ledger) {
382
- const frictions = ledger.rollup?.friction || [];
383
- const valueClaims = frictions.filter((f) => f.includes("not_evidence_backed"));
384
-
385
- if (valueClaims.length > 0) {
386
- return makePersonaFinding(
387
- "marketing_growth",
388
- "warn",
389
- `Value claims not fully evidence-backed: ${valueClaims.join(", ")}.`,
390
- {
391
- evidence: valueClaims.join(", "),
392
- recommendedFix: "Ensure all value signals reference receipt evidence paths.",
393
- reasonCodes: ["VALUE_CLAIM_NOT_EVIDENCE_BACKED"],
394
- }
395
- );
396
- }
397
-
398
- return makePersonaFinding(
399
- "marketing_growth",
400
- "pass",
401
- "No positioning drift detected. Value claims reference receipt evidence.",
402
- {}
403
- );
404
- }
405
-
406
- function runInternalPersonaReview(ledger) {
407
- return [
408
- reviewProductManager(ledger),
409
- reviewQaVerification(ledger),
410
- reviewUxDesign(ledger),
411
- reviewSecurity(ledger),
412
- reviewDevEx(ledger),
413
- reviewCostCogs(ledger),
414
- reviewSupportCs(ledger),
415
- reviewMarketingGrowth(ledger),
416
- ];
417
- }
418
-
419
- function clusterFriction(ledger, personaFindings) {
420
- const clusters = [];
421
-
422
- function countFriction(signalMatches, clusterType, severity, examples, recommendedFix) {
423
- if (signalMatches.length === 0) return;
424
- clusters.push({
425
- clusterId: `cluster-${clusterType.replace(/_/g, "-")}`,
426
- type: clusterType,
427
- severity,
428
- count: signalMatches.length,
429
- examples: signalMatches.slice(0, 3),
430
- evidencePaths: ledger.evidence?.receiptPaths?.slice(0, 3) || [],
431
- recommendedFix,
432
- candidateRoadmapItem: mapFrictionToRoadmap(clusterType),
433
- redacted: true,
434
- });
435
- }
436
-
437
- const frictionSignals = [
438
- ...(ledger.rollup?.friction || []),
439
- ...personaFindings
440
- .filter((pf) => pf.status === "warn" || pf.status === "fail")
441
- .flatMap((pf) => pf.reasonCodes || []),
442
- ];
443
-
444
- const allEntries = ledger.entries || [];
445
-
446
- // Missing evidence
447
- const missingEv = frictionSignals.filter(
448
- (f) =>
449
- f.includes("missing") ||
450
- f.includes("not_available") ||
451
- f.includes("MISSING") ||
452
- f.includes("NO_")
453
- );
454
- countFriction(missingEv, "missing_evidence", "medium", missingEv,
455
- "Generate missing receipts with full Avorelo run.");
456
-
457
- // Noisy output
458
- const noisy = frictionSignals.filter((f) => f.includes("noisy") || f.includes("verbose"));
459
- countFriction(noisy, "noisy_output", "low", noisy,
460
- "Move debug detail behind --debug flag.");
461
-
462
- // Manual fallback
463
- const manual = frictionSignals.filter(
464
- (f) => f.includes("manual_fallback") || f.includes("INSPECT_MAP_FIRST")
465
- );
466
- countFriction(manual, "manual_fallback_required", "medium", manual,
467
- "Run workspace-hygiene before orchestrate to enable automatic context selection.");
468
-
469
- // Generic next action
470
- const generic = personaFindings.filter(
471
- (pf) => (pf.reasonCodes || []).includes("GENERIC_NEXT_ACTION")
472
- );
473
- if (generic.length > 0) {
474
- countFriction(
475
- generic.map((g) => g.persona),
476
- "generic_next_action",
477
- "medium",
478
- generic.map((g) => g.finding),
479
- "Resolve Reality Gate gaps to produce specific next action."
480
- );
481
- }
482
-
483
- // Verification missing
484
- const verMissing = frictionSignals.filter(
485
- (f) => f.includes("VERIFICATION_MISSING") || f.includes("reality_gate_failures")
486
- );
487
- countFriction(verMissing, "verification_missing", "high", verMissing,
488
- "Run node bin/avorelo outcome --gate to produce verification evidence.");
489
-
490
- // Proof missing
491
- const proofMissing = frictionSignals.filter((f) => f.includes("PROOF_MISSING"));
492
- countFriction(proofMissing, "proof_missing", "medium", proofMissing,
493
- "Run node bin/avorelo proof after task completion.");
494
-
495
- // Unknown asset repeated
496
- const unknownAsset = frictionSignals.filter(
497
- (f) => f.includes("unknown_asset") || f.includes("UNKNOWN_ASSET")
498
- );
499
- countFriction(unknownAsset, "unknown_asset_repeated", "medium", unknownAsset,
500
- "Review and classify unknown workspace assets.");
501
-
502
- // Value not evidence-backed
503
- const valueClaims = frictionSignals.filter(
504
- (f) => f.includes("not_evidence_backed") || f.includes("VALUE_CLAIM")
505
- );
506
- countFriction(valueClaims, "value_claim_not_evidence_backed", "medium", valueClaims,
507
- "Link value signals to receipt evidence paths.");
508
-
509
- // Context too large
510
- const contextLarge = frictionSignals.filter(
511
- (f) => f.includes("context_too_large") || f.includes("CONTEXT_TOO_LARGE")
512
- );
513
- countFriction(contextLarge, "context_too_large", "medium", contextLarge,
514
- "Reduce context budget or improve hygiene-guided exclusions.");
515
-
516
- // Support explainability gap
517
- const suppGap = frictionSignals.filter(
518
- (f) => f.includes("SUPPORT_EXPLAINABILITY_GAP") || f.includes("explainability")
519
- );
520
- countFriction(suppGap, "support_explainability_gap", "low", suppGap,
521
- "Generate outcome summary before completing task.");
522
-
523
- return clusters;
524
- }
525
-
526
- function mapFrictionToRoadmap(clusterType) {
527
- const map = {
528
- missing_evidence: "repair_value_evidence_ledger",
529
- noisy_output: "repair_ux_noise_compactness",
530
- manual_fallback_required: "hook_baseline_pack",
531
- generic_next_action: "repair_value_evidence_ledger",
532
- verification_missing: "repair_work_orchestration_accuracy",
533
- proof_missing: "browser_proof_evidence",
534
- unknown_asset_repeated: "mcp_least_privilege_cleanup",
535
- context_too_large: "repair_work_orchestration_accuracy",
536
- value_claim_not_evidence_backed: "repair_value_evidence_ledger",
537
- support_explainability_gap: "activation_alpha_readiness",
538
- activation_friction: "activation_alpha_readiness",
539
- high_risk_blocked_without_continuation: "repair_work_orchestration_accuracy",
540
- };
541
- return map[clusterType] || null;
542
- }
543
-
544
- function buildCostCogsQualityRollup(ledger, personaFindings) {
545
- const saved = ledger.rollup?.saved || [];
546
- const verified = ledger.rollup?.verified || [];
547
- const friction = ledger.rollup?.friction || [];
548
-
549
- const localStages = saved.filter((s) => s.includes("local")).length;
550
- const tokenSavings = saved
551
- .filter((s) => s.includes("token"))
552
- .map((s) => {
553
- const m = s.match(/(\d+)/);
554
- return m ? parseInt(m[1], 10) : 0;
555
- });
556
- const totalTokenSavingsEstimate = tokenSavings.reduce((a, b) => a + b, 0);
557
-
558
- const costPersona = personaFindings.find((p) => p.persona === "cost_cogs");
559
- const qaPersona = personaFindings.find((p) => p.persona === "qa_verification");
560
-
561
- return {
562
- estimatedLocalStagesUsed: localStages,
563
- estimatedContextTokensSaved: totalTokenSavingsEstimate,
564
- estimateMethod: totalTokenSavingsEstimate > 0 ? "receipt_based_estimate" : "not_available",
565
- qualityChecksVerified: verified.length,
566
- frictionPointsDetected: friction.length,
567
- costPersonaStatus: costPersona?.status || "skip",
568
- qualityPersonaStatus: qaPersona?.status || "skip",
569
- caveats: [
570
- "Token savings are estimates from receipt data, not exact billing amounts.",
571
- "No exact/guaranteed savings are claimed.",
572
- ],
573
- redacted: true,
574
- };
575
- }
576
-
577
- function recommendNextPr(ledger, personaFindings, frictionClusters) {
578
- const friction = ledger.rollup?.friction || [];
579
- const frictionTypes = frictionClusters.map((c) => c.type);
580
- const realityGateEntry = (ledger.entries || []).find((e) => e.type === "reality_gate");
581
- const gateStatus = realityGateEntry?.status;
582
- const evidencePaths = ledger.evidence?.receiptPaths || [];
583
-
584
- let recommended = null;
585
- let whyNow = null;
586
- let confidence = "low";
587
-
588
- // Hook Apply — lifecycle hooks not yet applied (PR #141)
589
- const hooksNotApplied = friction.some((f) => f === "hooks_not_yet_applied" || f === "hooks_not_yet_installed");
590
- const hooksApplied = evidencePaths.some((p) => p.includes("hook-apply/latest-apply.json"));
591
- if (hooksNotApplied && !hooksApplied) {
592
- recommended = "Explicit Hook Apply + Lifecycle Live";
593
- whyNow = "Lifecycle hooks are previewed but not yet applied. Apply to make Avorelo seamless.";
594
- confidence = "high";
595
- }
596
-
597
- // Hook Baseline Pack — lifecycle/hook evidence missing or manual fallback
598
- else if (
599
- frictionTypes.includes("manual_fallback_required") ||
600
- friction.some((f) => f.includes("INSPECT_MAP_FIRST") || f.includes("NO_HYGIENE_REPORT"))
601
- ) {
602
- recommended = "Hook Baseline Pack + Claude/OpenHands-compatible adapters";
603
- whyNow = "Manual fallback and missing lifecycle evidence are the top friction clusters.";
604
- confidence = "medium";
605
- }
606
-
607
- // MCP Least-Privilege Cleanup
608
- else if (frictionTypes.includes("unknown_asset_repeated")) {
609
- recommended = "MCP Least-Privilege Cleanup";
610
- whyNow = "Unknown/broad workspace assets repeatedly appear in hygiene and context receipts.";
611
- confidence = "medium";
612
- }
613
-
614
- // Browser Proof / Evidence
615
- else if (frictionTypes.includes("proof_missing")) {
616
- recommended = "Browser Proof / Evidence";
617
- whyNow = "Proof gaps detected across ledger entries.";
618
- confidence = "low";
619
- }
620
-
621
- // Post-activation: if alpha activation is present and gate passes, recommend next layer
622
- else if (
623
- evidencePaths.some((p) => p.includes("alpha-readiness/latest-gate.json")) &&
624
- evidencePaths.some((p) => p.includes("orchestration/activation/latest-activation.json"))
625
- ) {
626
- recommended = "MCP Least-Privilege Cleanup or Launch Hardening";
627
- whyNow = "Alpha activation and readiness gate are in place. Next: harden for launch or clean MCP surfaces.";
628
- confidence = "medium";
629
- }
630
-
631
- // Activation / Alpha Readiness
632
- else if (
633
- frictionTypes.includes("activation_friction") ||
634
- frictionTypes.includes("support_explainability_gap")
635
- ) {
636
- recommended = "Activation / Alpha Readiness / Customer Feedback Loop";
637
- whyNow = "Activation friction and support explainability gaps dominate.";
638
- confidence = "medium";
639
- }
640
-
641
- // Repair: Value evidence / ledger accuracy
642
- else if (
643
- frictionTypes.includes("missing_evidence") ||
644
- frictionTypes.includes("value_claim_not_evidence_backed")
645
- ) {
646
- recommended = "Repair: Value evidence / ledger accuracy";
647
- whyNow = "Missing or unevidenced value claims in ledger rollup.";
648
- confidence = "medium";
649
- }
650
-
651
- // Repair: Work-Aware Orchestration accuracy
652
- else if (
653
- frictionTypes.includes("verification_missing") ||
654
- frictionTypes.includes("context_too_large")
655
- ) {
656
- recommended = "Repair: Work-Aware Orchestration accuracy";
657
- whyNow = "Verification gaps or context overload in orchestration stage.";
658
- confidence = "low";
659
- }
660
-
661
- // Default — Repair UX/noise/compactness
662
- else if (frictionTypes.includes("noisy_output")) {
663
- recommended = "Repair: UX/noise/compactness";
664
- whyNow = "Noisy output friction detected in default surfaces.";
665
- confidence = "low";
666
- }
667
-
668
- // Fallback
669
- else {
670
- recommended = "Repair: Value evidence / ledger accuracy";
671
- whyNow = "No dominant friction cluster — ledger may need more receipt population.";
672
- confidence = "low";
673
- }
674
-
675
- const notRecommendedYet = [
676
- "Public positioning / pricing / website changes — deferred until Alpha Readiness passes.",
677
- "Cloud telemetry / external analytics — intentionally deferred.",
678
- "Browser Proof — deferred unless proof_missing is dominant cluster.",
679
- "Full execution runtime — deferred.",
680
- ];
681
-
682
- return {
683
- recommendedNextPr: recommended,
684
- whyNow,
685
- evidencePaths: evidencePaths.slice(0, 5),
686
- expectedValue: "Reduce top friction cluster and improve ledger completeness.",
687
- risk: "low",
688
- confidence,
689
- notRecommendedYet,
690
- redacted: true,
691
- };
692
- }
693
-
694
- function recommendNextPrWithIntelligence(ledger, personaFindings, frictionClusters, intelligenceSignals) {
695
- // Start with base recommendation
696
- const base = recommendNextPr(ledger, personaFindings, frictionClusters);
697
-
698
- if (!intelligenceSignals) return base;
699
-
700
- const topFriction = intelligenceSignals.topFriction;
701
- const prelaunchScore = intelligenceSignals.prelaunchScore || 0;
702
- const tokenLevel = intelligenceSignals.tokenEvidenceLevel;
703
- const journeyStatus = intelligenceSignals.journeyStatus;
704
-
705
- // Override with intelligence-backed recommendation
706
- if (topFriction === "browser_proof_missing") {
707
- return {
708
- ...base,
709
- recommendedNextPr: "Browser Proof / Visual QA Bridge",
710
- whyNow: "Visual proof friction dominates feedback intelligence clusters.",
711
- confidence: "medium",
712
- };
713
- }
714
-
715
- if (topFriction === "plugin_distribution_unclear") {
716
- return {
717
- ...base,
718
- recommendedNextPr: "Plugin / Adapter Technical Readiness",
719
- whyNow: "Plugin distribution friction dominates feedback intelligence clusters.",
720
- confidence: "medium",
721
- };
722
- }
723
-
724
- if (topFriction === "install_confusion" || topFriction === "ai_prompt_unclear" || topFriction === "hook_approval_unclear") {
725
- return {
726
- ...base,
727
- recommendedNextPr: "Install / activation repair",
728
- whyNow: `Install confusion (${topFriction}) is the dominant cluster from feedback intelligence.`,
729
- confidence: "high",
730
- };
731
- }
732
-
733
- if (topFriction === "token_context_unknown" || tokenLevel === "not_available") {
734
- return {
735
- ...base,
736
- recommendedNextPr: "Token / cost evidence repair",
737
- whyNow: "Token/cost evidence missing or unclear per intelligence layer.",
738
- confidence: "medium",
739
- };
740
- }
741
-
742
- // If intelligence score is strong and journey is ready, recommend Full Readiness Gate
743
- if (prelaunchScore >= 85 && journeyStatus === "ready") {
744
- return {
745
- ...base,
746
- recommendedNextPr: "Full Readiness / Release Candidate Gate",
747
- whyNow: `Pre-launch intelligence score ${prelaunchScore}/100. Install journey ready. No dominant blocker.`,
748
- confidence: "medium",
749
- };
750
- }
751
-
752
- // If no intelligence override, use base recommendation
753
- return base;
754
- }
755
-
756
-
757
- function recommendNextPrWithFullReadiness(ledger, personaFindings, frictionClusters, intelligenceSignals, fullReadinessSignals) {
758
- const base = recommendNextPrWithIntelligence(ledger, personaFindings, frictionClusters, intelligenceSignals);
759
- if (!fullReadinessSignals) return base;
760
-
761
- const gateStatus = fullReadinessSignals.gateStatus;
762
- const rcStatus = fullReadinessSignals.releaseCandidateStatus;
763
- const blockerCount = fullReadinessSignals.blockerCount || 0;
764
- const safetyBlocker = fullReadinessSignals.safetyBlocker;
765
- const installDistributionDominates = fullReadinessSignals.installDistributionDominates;
766
- const browserProofDominates = fullReadinessSignals.browserProofDominates;
767
- const pluginAdapterDominates = fullReadinessSignals.pluginAdapterDominates;
768
- const feedbackInsufficient = fullReadinessSignals.feedbackInsufficient;
769
- const tokenEvidenceMissing = fullReadinessSignals.tokenEvidenceMissing;
770
- const proofOutcomeMissing = fullReadinessSignals.proofOutcomeMissing;
771
-
772
- if (safetyBlocker) {
773
- return { ...base, recommendedNextPr: "Repair: Safety / Support / MCP blocker", whyNow: "Full readiness gate has a safety/MCP hard blocker. Repair before launch.", confidence: "high", notRecommendedYet: [...(base.notRecommendedYet || []), "Website / pricing � deferred until gate passes with no safety blockers."] };
774
- }
775
- if (feedbackInsufficient) {
776
- return { ...base, recommendedNextPr: "Operational: Import real design-partner feedback", whyNow: "Full readiness still lacks qualified redacted feedback evidence.", confidence: "high" };
777
- }
778
- if (tokenEvidenceMissing) {
779
- return { ...base, recommendedNextPr: "Operational: Capture/import real token-cost evidence", whyNow: "Token/cost evidence is still heuristic-only or missing measured usage samples.", confidence: "high" };
780
- }
781
- if (proofOutcomeMissing) {
782
- return { ...base, recommendedNextPr: "Operational: Run proof after a real bounded task", whyNow: "A real proof/value summary artifact is still missing from readiness evidence.", confidence: "medium" };
783
- }
784
- if (rcStatus === "candidate_ready" && blockerCount === 0) {
785
- // If adapter readiness is already verified, move to alpha launch candidate prep
786
- if (fullReadinessSignals && fullReadinessSignals.adapterReadinessVerified) {
787
- return { ...base, recommendedNextPr: "Alpha Launch Candidate Prep", whyNow: "Full readiness gate and adapter technical readiness both passed. Ready for alpha launch candidate.", confidence: "high" };
788
- }
789
- return { ...base, recommendedNextPr: "Plugin/Adapter Technical Readiness", whyNow: "Full readiness gate passed. Distribution truth verified. Plugin/adapter readiness is next.", confidence: "high" };
790
- }
791
- if (rcStatus === "candidate_warn" && blockerCount === 0 && installDistributionDominates) {
792
- return { ...base, recommendedNextPr: "Repair: Distribution blockers before next PR", whyNow: "Gate warned with distribution blockers. Repair install claims or package content.", confidence: "high" };
793
- }
794
- if (browserProofDominates) {
795
- return { ...base, recommendedNextPr: "Browser Proof / Visual QA Bridge", whyNow: "Browser proof limitation is dominant in full readiness gate.", confidence: "medium" };
796
- }
797
- if (pluginAdapterDominates) {
798
- return { ...base, recommendedNextPr: "Plugin / Adapter Technical Readiness", whyNow: "Plugin/adapter limitation is dominant.", confidence: "medium" };
799
- }
800
- if (gateStatus === "blocked" && fullReadinessSignals.gateRecommendedNextPr) {
801
- return { ...base, recommendedNextPr: fullReadinessSignals.gateRecommendedNextPr, whyNow: "Full readiness gate blocked. Repair required.", confidence: "high" };
802
- }
803
- const notRecommendedYet = [...(base.notRecommendedYet || [])];
804
- if (rcStatus !== "candidate_ready" && !(rcStatus === "candidate_warn" && blockerCount === 0)) {
805
- if (!notRecommendedYet.includes("Website / pricing � deferred until full readiness gate passes.")) {
806
- notRecommendedYet.push("Website / pricing � deferred until full readiness gate passes.");
807
- }
808
- }
809
- return { ...base, notRecommendedYet };
810
- }
811
-
812
- function buildCompanyLoop(cwd, options = {}) {
813
- const { buildWorkLedger, writeWorkLedger } = require("./work-ledger");
814
- const ledger = buildWorkLedger(cwd, options);
815
-
816
- // Read alpha feedback into ledger friction signals (local only)
817
- try {
818
- const { readFeedbackSummary } = require("./alpha-feedback");
819
- const feedbackSummary = readFeedbackSummary(cwd);
820
- if (feedbackSummary && feedbackSummary.topFrictionType) {
821
- const rollupFriction = ledger.rollup?.friction;
822
- if (Array.isArray(rollupFriction)) {
823
- rollupFriction.push(`alpha_feedback:${feedbackSummary.topFrictionType}`);
824
- }
825
- }
826
- } catch {}
827
-
828
- // Consume pre-launch intelligence signals (PR #147)
829
- let intelligenceSignals = null;
830
- try {
831
- const { collectPrelaunchSignals, scorePrelaunchSignals } = require("./prelaunch-intelligence");
832
- const { buildFeedbackIntelligenceSurface } = require("./feedback-intelligence");
833
- const { buildTokenCostIntelligenceSurface } = require("./token-cost-intelligence");
834
- const { buildInstallJourneySurface } = require("./install-journey-intelligence");
835
-
836
- const signals = collectPrelaunchSignals(cwd, options);
837
- const scoreData = scorePrelaunchSignals(signals, options);
838
- const feedbackSurface = buildFeedbackIntelligenceSurface(cwd, options);
839
- const tokenSurface = buildTokenCostIntelligenceSurface(cwd, options);
840
- const journeySurface = buildInstallJourneySurface(cwd, options);
841
-
842
- intelligenceSignals = {
843
- prelaunchScore: scoreData.score,
844
- prelaunchStatus: scoreData.score >= 85 ? "strong" : scoreData.score >= 60 ? "moderate" : "weak",
845
- topFriction: feedbackSurface.topFriction,
846
- feedbackClusters: feedbackSurface.clustersFound,
847
- qualifiedFeedbackItemsCount: feedbackSurface.qualifiedFeedbackItemsCount || 0,
848
- tokenEvidenceLevel: tokenSurface.evidenceLevel,
849
- tokenRealUsageSamplesCount: tokenSurface.realUsageSamplesCount || 0,
850
- journeyStatus: journeySurface.status,
851
- manualStepsAvoided: journeySurface.manualStepsAvoided,
852
- aiInstallReady: signals.installPrompt?.status === "ready",
853
- prelaunchReadinessScore: signals.prelaunchReadiness?.score,
854
- };
855
-
856
- // Inject intelligence-based friction into ledger
857
- const rollupFriction = ledger.rollup?.friction;
858
- if (Array.isArray(rollupFriction)) {
859
- if (feedbackSurface.topFriction) {
860
- rollupFriction.push(`intelligence_friction:${feedbackSurface.topFriction}`);
861
- }
862
- if (tokenSurface.evidenceLevel === "not_available") {
863
- rollupFriction.push("intelligence_friction:token_context_unknown");
864
- }
865
- if (journeySurface.status !== "ready") {
866
- rollupFriction.push("intelligence_friction:install_journey_incomplete");
867
- }
868
- }
869
- } catch {}
870
-
871
- const personaFindings = runInternalPersonaReview(ledger);
872
- const frictionClusters = clusterFriction(ledger, personaFindings);
873
- const cogsRollup = buildCostCogsQualityRollup(ledger, personaFindings);
874
- // Consume full readiness gate signals (PR #148)
875
- let fullReadinessSignals = null;
876
- try {
877
- const { buildFullReadinessSurface } = require("./full-readiness-gate");
878
- const { buildKnownLimitationsSurface } = require("./known-limitations");
879
- const { buildProofOutcomeEvidenceSurface } = require("./proof-outcome-evidence");
880
- const gateSurface = buildFullReadinessSurface(cwd, options);
881
- const limitationsSurface = buildKnownLimitationsSurface(cwd, options);
882
- const proofOutcomeSurface = buildProofOutcomeEvidenceSurface(cwd, options);
883
- if (gateSurface.status !== "not_available") {
884
- const limitationsList = limitationsSurface?.limitations || [];
885
- fullReadinessSignals = {
886
- gateStatus: gateSurface.status,
887
- releaseCandidateStatus: gateSurface.releaseCandidateStatus,
888
- blockerCount: gateSurface.blockerCount,
889
- gateRecommendedNextPr: gateSurface.recommendedNextPr,
890
- safetyBlocker: (gateSurface.blockerCount || 0) > 0 &&
891
- ["mcp_tool_governance","hook_safety_boundaries","support_bundle_redaction","no_false_claims"].some(
892
- (id) => (gateSurface.blockers || []).find((b) => b.id === id)
893
- ),
894
- adapterReadinessVerified: false, // will be updated when adapterReadinessSignals is consumed
895
- installDistributionDominates:
896
- (limitationsList).some((l) => l.id === "install_distribution" && l.severity !== "info") &&
897
- (intelligenceSignals?.qualifiedFeedbackItemsCount || 0) > 0 &&
898
- (intelligenceSignals?.tokenRealUsageSamplesCount || 0) > 0,
899
- browserProofDominates:
900
- intelligenceSignals?.topFriction === "browser_proof_missing" ||
901
- (limitationsList).some((l) => l.id === "browser_proof_missing" && l.severity === "blocker"),
902
- pluginAdapterDominates:
903
- (limitationsList).some((l) => l.id === "plugin_adapter_pending" && l.severity === "blocker"),
904
- feedbackInsufficient:
905
- (intelligenceSignals?.qualifiedFeedbackItemsCount || 0) === 0,
906
- tokenEvidenceMissing:
907
- (intelligenceSignals?.tokenRealUsageSamplesCount || 0) === 0,
908
- proofOutcomeMissing:
909
- proofOutcomeSurface.latestProofAvailable !== true || (proofOutcomeSurface.realTaskProofCount || 0) === 0,
910
- };
911
- }
912
- } catch {}
913
-
914
- // Consume activation distribution readiness signals (PR #149)
915
- let activationDistributionSignals = null;
916
- try {
917
- const { buildActivationDistributionSurface } = require("./activation-distribution-readiness");
918
- const adrSurface = buildActivationDistributionSurface(cwd, options);
919
- if (adrSurface.status !== "not_available") {
920
- activationDistributionSignals = {
921
- status: adrSurface.status,
922
- score: adrSurface.score,
923
- blockerCount: adrSurface.blockerCount || 0,
924
- warningCount: adrSurface.warningCount || 0,
925
- isReady: adrSurface.status === "ready",
926
- safeNextAction: (adrSurface.safeNextActions || [])[0] || null,
927
- };
928
- if (fullReadinessSignals && activationDistributionSignals.blockerCount > 0) {
929
- fullReadinessSignals.installDistributionDominates = true;
930
- }
931
- }
932
- } catch {}
933
-
934
- // Consume public distribution gate signals (PR #161)
935
- let publicDistributionSignals = null;
936
- try {
937
- const pdGatePath = path.join(cwd, ".claude/cco/orchestration/public-distribution/latest-gate.json");
938
- if (fs.existsSync(pdGatePath)) {
939
- const pdGate = JSON.parse(fs.readFileSync(pdGatePath, "utf8"));
940
- if (pdGate && pdGate.status) {
941
- publicDistributionSignals = {
942
- status: pdGate.status,
943
- score: pdGate.score,
944
- blockerCount: (pdGate.blockers || []).length,
945
- warningCount: (pdGate.warnings || []).length,
946
- publicInstallStatus: pdGate.publicInstallStatus,
947
- claimSafetyStatus: pdGate.claimSafetyStatus,
948
- recommendedNextPr: pdGate.recommendedNextPr,
949
- isBlocked: pdGate.status === "blocked",
950
- isLocalOnly: pdGate.status === "local_only",
951
- };
952
- // If distribution is blocked (false claims, forbidden files), elevate to full readiness
953
- if (fullReadinessSignals && pdGate.status === "blocked") {
954
- fullReadinessSignals.installDistributionDominates = true;
955
- }
956
- }
957
- }
958
- } catch {}
959
-
960
- // Consume adapter technical readiness signals (PR #162)
961
- let adapterReadinessSignals = null;
962
- try {
963
- const adapterGatePath = path.join(cwd, ".claude/cco/orchestration/adapter-readiness/latest-technical-gate.json");
964
- if (fs.existsSync(adapterGatePath)) {
965
- const adapterGate = JSON.parse(fs.readFileSync(adapterGatePath, "utf8"));
966
- if (adapterGate && adapterGate.status) {
967
- adapterReadinessSignals = {
968
- status: adapterGate.status,
969
- score: adapterGate.score,
970
- verdict: adapterGate.verdict,
971
- blockerCount: adapterGate.blockerCount || 0,
972
- warningCount: adapterGate.warningCount || 0,
973
- browserRequired: false,
974
- noBrowserLaunch: true,
975
- isReady: adapterGate.verdict === "adapter_ready",
976
- isBlocked: adapterGate.status === "blocked",
977
- safeNextAction: adapterGate.safeNextAction || null,
978
- };
979
- // If adapter readiness is blocked, elevate to full readiness
980
- if (fullReadinessSignals && adapterGate.status === "blocked") {
981
- fullReadinessSignals.pluginAdapterDominates = true;
982
- }
983
- // If adapter readiness is ready, clear plugin/adapter friction and mark verified
984
- if (fullReadinessSignals && adapterGate.verdict === "adapter_ready") {
985
- fullReadinessSignals.pluginAdapterDominates = false;
986
- fullReadinessSignals.adapterReadinessVerified = true;
987
- }
988
- }
989
- }
990
- } catch {}
991
-
992
- const nextPrRecommendation = recommendNextPrWithFullReadiness(
993
- ledger, personaFindings, frictionClusters, intelligenceSignals, fullReadinessSignals
994
- );
995
-
996
- const warnCount = personaFindings.filter((p) => p.status === "warn").length;
997
- const failCount = personaFindings.filter((p) => p.status === "fail").length;
998
- const topFriction = frictionClusters[0]?.type || null;
999
-
1000
- const reportStatus =
1001
- failCount > 0 ? "fail" : warnCount > 2 ? "warn" : "pass";
1002
-
1003
- const report = {
1004
- contract: CONTRACT,
1005
- schemaVersion: SCHEMA_VERSION,
1006
- createdAt: new Date().toISOString(),
1007
- status: reportStatus,
1008
- ledger,
1009
- personaFindings,
1010
- frictionClusters,
1011
- cogsRollup,
1012
- nextPrRecommendation,
1013
- intelligenceSignals,
1014
- fullReadinessSignals,
1015
- activationDistributionSignals,
1016
- publicDistributionSignals,
1017
- adapterReadinessSignals,
1018
- surface: {
1019
- status: reportStatus,
1020
- latestReportPath: LATEST_REPORT_REL,
1021
- personaWarnCount: warnCount,
1022
- topFriction,
1023
- recommendedNextPr: nextPrRecommendation.recommendedNextPr,
1024
- confidence: nextPrRecommendation.confidence,
1025
- },
1026
- redacted: true,
1027
- };
1028
-
1029
- return report;
1030
- }
1031
-
1032
- function writeCompanyLoopReport(cwd, report) {
1033
- const dir = path.join(cwd, LOOP_DIR_REL);
1034
- fs.mkdirSync(dir, { recursive: true });
1035
- const filePath = path.join(cwd, LATEST_REPORT_REL);
1036
- fs.writeFileSync(filePath, JSON.stringify(report, null, 2), "utf8");
1037
- return filePath;
1038
- }
1039
-
1040
- function buildCompanyLoopSurface(cwd) {
1041
- const reportPath = path.join(cwd, LATEST_REPORT_REL);
1042
- if (!fs.existsSync(reportPath)) {
1043
- return {
1044
- status: "not_available",
1045
- latestReportPath: LATEST_REPORT_REL,
1046
- personaWarnCount: 0,
1047
- topFriction: null,
1048
- recommendedNextPr: null,
1049
- confidence: "low",
1050
- };
1051
- }
1052
- const data = safeReadJson(reportPath);
1053
- if (!data) return { status: "warn", latestReportPath: LATEST_REPORT_REL };
1054
- return data.surface || {
1055
- status: data.status,
1056
- latestReportPath: LATEST_REPORT_REL,
1057
- personaWarnCount: (data.personaFindings || []).filter((p) => p.status === "warn").length,
1058
- topFriction: (data.frictionClusters || [])[0]?.type || null,
1059
- recommendedNextPr: data.nextPrRecommendation?.recommendedNextPr || null,
1060
- confidence: data.nextPrRecommendation?.confidence || "low",
1061
- };
1062
- }
1063
-
1064
- function formatCompanyLoopText(report, options = {}) {
1065
- const debug = options.debug === true;
1066
- const lines = [];
1067
-
1068
- lines.push(`Avorelo Company Loop: ${report.status}`);
1069
- lines.push(`Created: ${report.createdAt}`);
1070
- lines.push("");
1071
-
1072
- const { nextPrRecommendation, frictionClusters, cogsRollup } = report;
1073
-
1074
- if (nextPrRecommendation) {
1075
- lines.push(`Recommended Next PR:`);
1076
- lines.push(` ${nextPrRecommendation.recommendedNextPr}`);
1077
- lines.push(` Why: ${nextPrRecommendation.whyNow}`);
1078
- lines.push(` Confidence: ${nextPrRecommendation.confidence}`);
1079
- lines.push("");
1080
- }
1081
-
1082
- if (frictionClusters?.length > 0) {
1083
- lines.push("Top Friction Clusters:");
1084
- for (const cluster of frictionClusters.slice(0, 5)) {
1085
- lines.push(
1086
- ` - ${cluster.type} (${cluster.severity}, count: ${cluster.count}): ${cluster.recommendedFix}`
1087
- );
1088
- }
1089
- lines.push("");
1090
- } else {
1091
- lines.push("Friction Clusters: none detected");
1092
- lines.push("");
1093
- }
1094
-
1095
- if (cogsRollup) {
1096
- lines.push("COGS / Quality Rollup:");
1097
- lines.push(` Local stages used (estimate): ${cogsRollup.estimatedLocalStagesUsed}`);
1098
- lines.push(` Context tokens saved (estimate): ${cogsRollup.estimatedContextTokensSaved}`);
1099
- lines.push(` Estimate method: ${cogsRollup.estimateMethod}`);
1100
- lines.push(` Quality checks verified: ${cogsRollup.qualityChecksVerified}`);
1101
- lines.push("");
1102
- }
1103
-
1104
- if (debug) {
1105
- lines.push("--- Debug: Persona Findings ---");
1106
- for (const pf of report.personaFindings || []) {
1107
- const label = PERSONA_LABELS[pf.persona] || pf.persona;
1108
- lines.push(`[${pf.status.toUpperCase()}] ${label}:`);
1109
- lines.push(` ${pf.finding}`);
1110
- if (pf.evidence) lines.push(` Evidence: ${pf.evidence}`);
1111
- if (pf.recommendedFix) lines.push(` Fix: ${pf.recommendedFix}`);
1112
- if (pf.reasonCodes?.length > 0) lines.push(` Codes: ${pf.reasonCodes.join(", ")}`);
1113
- }
1114
- lines.push("");
1115
-
1116
- lines.push("--- Debug: Not Recommended Yet ---");
1117
- for (const item of nextPrRecommendation?.notRecommendedYet || []) {
1118
- lines.push(` - ${item}`);
1119
- }
1120
- lines.push("");
1121
-
1122
- lines.push("--- Debug: COGS Caveats ---");
1123
- for (const caveat of cogsRollup?.caveats || []) {
1124
- lines.push(` ${caveat}`);
1125
- }
1126
- }
1127
-
1128
- return lines.join("\n");
1129
- }
1130
-
1131
- module.exports = {
1132
- CONTRACT,
1133
- SCHEMA_VERSION,
1134
- PERSONAS,
1135
- PERSONA_LABELS,
1136
- FRICTION_CLUSTER_TYPES,
1137
- ROADMAP_CANDIDATES,
1138
- LATEST_REPORT_REL,
1139
- runInternalPersonaReview,
1140
- clusterFriction,
1141
- buildCostCogsQualityRollup,
1142
- recommendNextPr,
1143
- recommendNextPrWithIntelligence,
1144
- recommendNextPrWithFullReadiness,
1145
- buildCompanyLoop,
1146
- writeCompanyLoopReport,
1147
- buildCompanyLoopSurface,
1148
- formatCompanyLoopText,
1149
- };