@echomem/mcp 1.4.43 → 1.4.44

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 (48) hide show
  1. package/README.md +25 -28
  2. package/dist/config-files.js +63 -0
  3. package/dist/context-analysis/claude-native-canonical.js +2 -2
  4. package/dist/context-analysis/vendored-canonical.js +2 -2
  5. package/dist/context-analysis/workspace-report.js +3 -3
  6. package/dist/hud/hooks.js +43 -31
  7. package/dist/index.js +15 -79
  8. package/dist/local-jsonl.js +87 -0
  9. package/dist/migrate.js +6 -4
  10. package/dist/onboarding-stats.js +16 -0
  11. package/dist/save-checkpoint-hook.js +1 -1
  12. package/dist/setup-page/client-core.js +18 -372
  13. package/dist/setup-page/client-extraction.js +33 -188
  14. package/dist/setup-page/client-lifecycle.js +31 -101
  15. package/dist/setup-page/client.js +0 -2
  16. package/dist/setup-page/styles-extraction.js +1 -31
  17. package/dist/setup-page/styles-foundation.js +0 -89
  18. package/dist/setup-page/styles-mvp.js +10 -155
  19. package/dist/setup-page/styles-website-alignment.js +0 -204
  20. package/dist/setup-page/styles.js +0 -4
  21. package/dist/setup-page.js +4 -4
  22. package/dist/setup-preview.js +4 -212
  23. package/dist/setup.js +314 -667
  24. package/dist/v1-contract.js +0 -8
  25. package/package.json +9 -7
  26. package/dist/city/README.md +0 -9
  27. package/dist/city/echo-ai-city-only.html +0 -2232
  28. package/dist/city/echo-extraction-plate.html +0 -330
  29. package/dist/city/echo-face-cutout.png +0 -0
  30. package/dist/city/personality_stickers/bossy.png +0 -0
  31. package/dist/city/personality_stickers/ghosty.png +0 -0
  32. package/dist/city/personality_stickers/loopy.png +0 -0
  33. package/dist/city/personality_stickers/lusty.png +0 -0
  34. package/dist/city/personality_stickers/maxxy.png +0 -0
  35. package/dist/city/personality_stickers/tabby.png +0 -0
  36. package/dist/city/vendor/OrbitControls.js +0 -1417
  37. package/dist/city/vendor/RoundedBoxGeometry.js +0 -155
  38. package/dist/city/vendor/echo_general-file-21.riv +0 -0
  39. package/dist/city/vendor/rive.js +0 -8139
  40. package/dist/city/vendor/rive.wasm +0 -0
  41. package/dist/city/vendor/three.module.min.js +0 -6
  42. package/dist/forensics.js +0 -1531
  43. package/dist/report.js +0 -721
  44. package/dist/setup-page/client-report-audit.js +0 -819
  45. package/dist/setup-page/client-report-city.js +0 -356
  46. package/dist/setup-page/client-report.js +0 -6
  47. package/dist/setup-page/styles-city-report.js +0 -880
  48. package/dist/setup-page/styles-context-audit.js +0 -470
@@ -88,171 +88,6 @@ export const SETUP_PAGE_STYLES_WEBSITE_ALIGNMENT = String.raw `
88
88
  box-shadow: none;
89
89
  }
90
90
 
91
- /* Local scan -------------------------------------------------------------- */
92
- body.scanMode {
93
- background:
94
- radial-gradient(circle, rgba(26,58,143,0.075) 0 1px, transparent 1.35px) 0 0 / 18px 18px,
95
- radial-gradient(circle, rgba(78,205,196,0.07) 0 1px, transparent 1.35px) 9px 9px / 22px 22px,
96
- var(--echo-paper-canvas);
97
- }
98
- body.scanMode main {
99
- padding: clamp(32px, 6vw, 72px) clamp(18px, 5vw, 58px);
100
- }
101
- body.scanMode #app {
102
- width: min(860px, 100%);
103
- min-height: min(72vh, 680px);
104
- }
105
- .scanLoader {
106
- position: relative;
107
- overflow: visible;
108
- width: min(760px, 100%);
109
- border: 1.5px solid rgba(26,58,143,0.20);
110
- border-radius: var(--echo-radius-panel);
111
- background: rgba(255,255,255,0.92);
112
- padding: clamp(26px, 5vw, 48px);
113
- box-shadow: var(--echo-shadow-pop);
114
- }
115
- .scanLoader::before {
116
- content: "";
117
- position: absolute;
118
- top: -11px;
119
- left: 50%;
120
- z-index: 2;
121
- width: 88px;
122
- height: 25px;
123
- border: 1px solid rgba(43,42,38,0.07);
124
- background: color-mix(in srgb, var(--echo-note-cream) 72%, white 28%);
125
- box-shadow: 0 1px 2px rgba(43,42,38,0.07);
126
- opacity: 0.82;
127
- transform: translateX(-50%) rotate(-1deg);
128
- }
129
- .scanLoaderLead {
130
- display: grid;
131
- grid-template-columns: auto minmax(0, 1fr);
132
- align-items: center;
133
- gap: clamp(20px, 4vw, 34px);
134
- }
135
- .scanMascot {
136
- display: grid;
137
- place-items: center;
138
- width: clamp(108px, 14vw, 132px);
139
- aspect-ratio: 1;
140
- flex: 0 0 auto;
141
- border: 1px solid rgba(26,58,143,0.11);
142
- border-radius: 20px;
143
- background: color-mix(in srgb, var(--echo-paper-white) 64%, var(--echo-note-cream) 36%);
144
- box-shadow: var(--echo-shadow-paper);
145
- overflow: hidden;
146
- transform: rotate(-1.5deg);
147
- }
148
- .scanMascotFrames {
149
- position: relative;
150
- display: block;
151
- width: 100%;
152
- height: 100%;
153
- }
154
- .scanMascotFrame {
155
- position: absolute;
156
- inset: 0;
157
- display: block;
158
- width: 100%;
159
- height: 100%;
160
- object-fit: contain;
161
- opacity: 0;
162
- filter: drop-shadow(0 12px 14px rgba(26,58,143,0.16));
163
- animation: scanMascotFrame 4.2s linear infinite;
164
- }
165
- /* Keep the ready pose mounted underneath every animated frame. This prevents
166
- a transparent flash at loop boundaries or while a later PNG is decoding. */
167
- .scanMascotFrame:nth-child(1) {
168
- opacity: 1;
169
- animation: none;
170
- }
171
- .scanMascotFrame:nth-child(2) { animation-delay: 0.6s; }
172
- .scanMascotFrame:nth-child(3) { animation-delay: 1.2s; }
173
- .scanMascotFrame:nth-child(4) { animation-delay: 1.8s; }
174
- .scanMascotFrame:nth-child(5) { animation-delay: 2.4s; }
175
- .scanMascotFrame:nth-child(6) { animation-delay: 3s; }
176
- .scanMascotFrame:nth-child(7) { animation-delay: 3.6s; }
177
- @keyframes scanMascotFrame {
178
- 0%, 14.4% { opacity: 1; }
179
- 14.5%, 100% { opacity: 0; }
180
- }
181
- .scanLoaderCopy { min-width: 0; }
182
- .scanEyebrow {
183
- width: fit-content;
184
- margin: 0 0 15px;
185
- border: 1px solid rgba(26,58,143,0.13);
186
- border-radius: 999px;
187
- background: rgba(255,255,255,0.72);
188
- padding: 6px 11px;
189
- box-shadow: var(--echo-shadow-glass);
190
- color: color-mix(in srgb, var(--echo-ink-primary) 70%, var(--echo-ink-accent) 30%);
191
- font-size: 11px;
192
- letter-spacing: 0.11em;
193
- }
194
- .scanLoader h2.siteHeadline {
195
- max-width: 560px;
196
- font-size: clamp(40px, 6vw, 64px);
197
- line-height: 0.98;
198
- }
199
- .scanIntro {
200
- max-width: 520px;
201
- margin: 18px 0 0;
202
- color: var(--echo-ink-mute);
203
- font-size: 15px;
204
- font-weight: 500;
205
- line-height: 1.55;
206
- }
207
- .scanProgressCard {
208
- margin-top: clamp(26px, 5vw, 38px);
209
- border: 1px solid rgba(26,58,143,0.10);
210
- border-radius: var(--echo-radius-card);
211
- background: color-mix(in srgb, var(--echo-paper-white) 68%, var(--echo-note-blue) 32%);
212
- padding: 17px 18px 15px;
213
- box-shadow: var(--echo-shadow-paper);
214
- }
215
- .scanProgress {
216
- width: 100%;
217
- height: 10px;
218
- margin: 0;
219
- border-radius: 999px;
220
- background: rgba(255,255,255,0.78);
221
- box-shadow: inset 0 1px 3px rgba(20,24,34,0.10);
222
- }
223
- .scanProgressFill {
224
- min-width: 10px;
225
- border-radius: 999px;
226
- background: linear-gradient(90deg, var(--echo-ink-primary), color-mix(in srgb, var(--echo-ink-primary) 72%, var(--echo-ink-accent) 28%));
227
- box-shadow: 0 0 0 1px rgba(26,58,143,0.08), 0 3px 9px rgba(26,58,143,0.20);
228
- }
229
- .scanCaption {
230
- margin: 12px 0 0;
231
- color: var(--echo-ink-mute);
232
- font-size: 12px;
233
- font-weight: 700;
234
- line-height: 1.5;
235
- }
236
- .scanPrivacy {
237
- display: flex;
238
- align-items: center;
239
- gap: 8px;
240
- margin: 15px 2px 0;
241
- color: var(--echo-ink-faint);
242
- font-family: var(--echo-font-mono);
243
- font-size: 11px;
244
- font-weight: 600;
245
- line-height: 1.45;
246
- }
247
- .scanPrivacy > span {
248
- width: 8px;
249
- height: 8px;
250
- flex: 0 0 auto;
251
- border-radius: 50%;
252
- background: var(--echo-ink-accent-deep);
253
- box-shadow: 0 0 0 4px rgba(78,205,196,0.13);
254
- }
255
-
256
91
  /* Permission and skip states ------------------------------------------------ */
257
92
  .localConsent {
258
93
  overflow: visible;
@@ -954,38 +789,6 @@ export const SETUP_PAGE_STYLES_WEBSITE_ALIGNMENT = String.raw `
954
789
  .skipStage {
955
790
  border-radius: 18px;
956
791
  }
957
- body.scanMode main {
958
- padding: 34px 14px 52px;
959
- }
960
- body.scanMode #app {
961
- min-height: calc(100vh - 86px);
962
- }
963
- .scanLoader {
964
- border-radius: 18px;
965
- padding: 28px 20px 22px;
966
- }
967
- .scanLoaderLead {
968
- grid-template-columns: 1fr;
969
- gap: 18px;
970
- }
971
- .scanMascot {
972
- width: 88px;
973
- border-radius: 16px;
974
- }
975
- .scanLoader h2.siteHeadline {
976
- font-size: clamp(38px, 12vw, 52px);
977
- }
978
- .scanIntro {
979
- margin-top: 14px;
980
- font-size: 14px;
981
- }
982
- .scanProgressCard {
983
- margin-top: 24px;
984
- padding: 15px 14px 13px;
985
- }
986
- .scanPrivacy {
987
- align-items: flex-start;
988
- }
989
792
  .consentLead,
990
793
  .skippedEcho {
991
794
  border-radius: 16px 16px 0 0;
@@ -1044,12 +847,5 @@ export const SETUP_PAGE_STYLES_WEBSITE_ALIGNMENT = String.raw `
1044
847
  transition: none;
1045
848
  transform: none;
1046
849
  }
1047
- .scanMascotFrame {
1048
- animation: none;
1049
- opacity: 0;
1050
- }
1051
- .scanMascotFrame:first-child {
1052
- opacity: 1;
1053
- }
1054
850
  }
1055
851
  `;
@@ -1,15 +1,11 @@
1
1
  import { SETUP_PAGE_STYLES_FOUNDATION } from "./styles-foundation.js";
2
- import { SETUP_PAGE_STYLES_CITY_REPORT } from "./styles-city-report.js";
3
2
  import { SETUP_PAGE_STYLES_EXTRACTION } from "./styles-extraction.js";
4
- import { SETUP_PAGE_STYLES_CONTEXT_AUDIT } from "./styles-context-audit.js";
5
3
  import { SETUP_PAGE_STYLES_WEBSITE_ALIGNMENT } from "./styles-website-alignment.js";
6
4
  import { SETUP_PAGE_STYLES_MVP } from "./styles-mvp.js";
7
5
  // Kept as one emitted style tag so the local HTML page remains self-contained.
8
6
  export const SETUP_PAGE_STYLES = [
9
7
  SETUP_PAGE_STYLES_FOUNDATION,
10
- SETUP_PAGE_STYLES_CITY_REPORT,
11
8
  SETUP_PAGE_STYLES_EXTRACTION,
12
- SETUP_PAGE_STYLES_CONTEXT_AUDIT,
13
9
  SETUP_PAGE_STYLES_WEBSITE_ALIGNMENT,
14
10
  SETUP_PAGE_STYLES_MVP,
15
11
  ].join("\n");
@@ -1,17 +1,17 @@
1
1
  import { renderSetupPageDocument } from "./setup-page/document.js";
2
2
  import { renderSetupPreviewBootstrap } from "./setup-preview.js";
3
- export { SETUP_PREVIEW_REPORT, SETUP_PREVIEW_STATES } from "./setup-preview.js";
3
+ export { SETUP_PREVIEW_STATES } from "./setup-preview.js";
4
4
  /**
5
5
  * Setup page entry point. The implementation is split by product phase under ./setup-page/:
6
- * core utilities, local report, post-auth extraction, and lifecycle polling.
6
+ * core utilities, post-auth extraction, and lifecycle polling.
7
7
  */
8
8
  export function renderSetupPage(options = {}) {
9
9
  const previewState = options.previewState ?? null;
10
10
  const startupScript = previewState
11
11
  ? renderSetupPreviewBootstrap(previewState)
12
12
  : `
13
- init().catch(function () {
14
- renderReportIssue("SETUP_INITIALIZATION_FAILED", "The local setup page could not start. Close this tab and run echomem-mcp init again.");
13
+ init().catch(function (error) {
14
+ renderDiscoveryCheckIssue(error && error.message ? error.message : "The local setup page could not start.");
15
15
  });`;
16
16
  return renderSetupPageDocument({ previewState, startupScript });
17
17
  }
@@ -1,10 +1,6 @@
1
1
  export const SETUP_PREVIEW_STATES = [
2
2
  "consent",
3
3
  "consent-required",
4
- "scan",
5
- "scan-error",
6
- "bridge-error",
7
- "report",
8
4
  "extract-counting",
9
5
  "extract-degraded",
10
6
  "extract-degraded-exact",
@@ -38,189 +34,12 @@ export const SETUP_PREVIEW_STATES = [
38
34
  export function parseSetupPreviewState(value) {
39
35
  return SETUP_PREVIEW_STATES.includes(value) ? value : null;
40
36
  }
41
- export const SETUP_PREVIEW_REPORT = {
42
- schemaVersion: 1,
43
- dataOrigin: "design-preview",
44
- generatedFrom: [],
45
- llmCallsUsed: 0,
46
- transcriptsUploaded: false,
47
- scanStartDate: "2026-05-01",
48
- scanEndDate: "2026-07-09",
49
- firstSession: {
50
- date: "2026-05-01T16:14:00.000Z",
51
- source: "codex",
52
- repo: "Preview Workspace",
53
- },
54
- activeSessionCoverage: { codex: 82, claudeCode: 54, total: 136 },
55
- scale: {
56
- sessionCount: 136,
57
- repoCount: 4,
58
- totalTokens: 140_400_000,
59
- totalInputTokens: 138_000_000,
60
- totalCommits: 312,
61
- },
62
- cost: { total: 428, byModel: { "preview-model": { total: 140_400_000, cost: 428 } } },
63
- modelUsage: { topModel: "preview-model", topModelShare: 62, identityLabel: "Design preview" },
64
- userWorkingHours: { userAttentionHours: 184.5, averageDailyAttentionHours: 3.8 },
65
- rhythm: { lateNightShare: 18, hourHistogram: [0, 0, 0, 0, 0, 0, 1, 2, 5, 8, 10, 11, 9, 8, 7, 8, 10, 12, 11, 8, 5, 3, 1, 0] },
66
- cleanliness: { staleReadSharePct: 42 },
67
- contextWindow: { sampleCount: 0, metrics: {} },
68
- rereadForensics: {
69
- topFiles: [
70
- { file: "src/preview-alpha.ts", repo: "Preview Workspace", totalReads: 37, sessionsTouched: 12, daysTouched: 9, everChanged: true },
71
- { file: "src/preview-beta.ts", repo: "Sample Service", totalReads: 21, sessionsTouched: 7, daysTouched: 5, everChanged: true },
72
- ],
73
- },
74
- avoidableWait: {},
75
- counterfactual: { targetScore: 86, daysGained: 20.3, counterfactualDate: "2026-06-19" },
76
- repos: [
77
- { name: "Preview Workspace", sessions: 62, tokens: 78_000_000, totalTokens: 78_000_000, attentionHours: 72, assistantMessages: 740 },
78
- { name: "Sample Service", sessions: 31, tokens: 41_000_000, totalTokens: 41_000_000, attentionHours: 39, assistantMessages: 360 },
79
- { name: "Example CLI", sessions: 27, tokens: 12_000_000, totalTokens: 12_000_000, attentionHours: 28, assistantMessages: 250 },
80
- { name: "Demo Library", sessions: 16, tokens: 7_000_000, totalTokens: 7_000_000, attentionHours: 22, assistantMessages: 180 },
81
- ],
82
- canonicalGoldenStandard: {
83
- summary: {
84
- sessionsAnalyzed: 136,
85
- reposAnalyzed: 4,
86
- turnsAnalyzed: 1_840,
87
- officialInputTokens: 18_400_000,
88
- usefulTokens: 10_672_000,
89
- wasteTokens: 7_728_000,
90
- usefulPct: 58,
91
- wastePct: 42,
92
- attributedWasteTokens: 7_140_000,
93
- unattributedWasteTokens: 588_000,
94
- },
95
- diagnostics: { skippedSessions: 0 },
96
- buckets: { duplicate: 1_280_000, refind: 1_750_000, dead: 4_110_000, unattributed: 588_000 },
97
- problems: [
98
- {
99
- id: "P13",
100
- label: "Agent's Reasoning Notes",
101
- bucket: "dead",
102
- category: "Context Hygiene",
103
- count: 96,
104
- sessions: 32,
105
- allocatedWasteTokens: 2_180_000,
106
- examples: [{
107
- repo: "Preview Workspace",
108
- session: "preview-session-1",
109
- agentSource: "codex",
110
- turn: 30,
111
- sessionTitle: "Preview context report",
112
- sessionOrdinal: 82,
113
- sourceSessionCount: 82,
114
- sessionTurns: 41,
115
- timestampMs: Date.UTC(2026, 6, 6),
116
- tokens: 82_000,
117
- turnInputTokens: 212_400,
118
- turnUsefulTokens: 61_000,
119
- turnWasteTokens: 151_400,
120
- prompt: "Preview prompt. This is not local user data.",
121
- evidence: "Preview evidence used only in an explicitly authorized design state.",
122
- }],
123
- },
124
- {
125
- id: "P01",
126
- label: "Outdated Images & Screenshots",
127
- bucket: "dead",
128
- category: "Runtime Bug",
129
- count: 70,
130
- sessions: 18,
131
- allocatedWasteTokens: 1_930_000,
132
- examples: [{
133
- repo: "Sample Service",
134
- session: "preview-session-2",
135
- agentSource: "codex",
136
- turn: 67,
137
- sessionTitle: "Preview visual verification",
138
- sessionOrdinal: 79,
139
- sourceSessionCount: 82,
140
- sessionTurns: 88,
141
- timestampMs: Date.UTC(2026, 6, 3),
142
- tokens: 118_000,
143
- turnInputTokens: 224_300,
144
- turnUsefulTokens: 52_300,
145
- turnWasteTokens: 172_000,
146
- prompt: "Preview prompt. This is not local user data.",
147
- evidence: "Preview evidence used only in an explicitly authorized design state.",
148
- }],
149
- },
150
- {
151
- id: "P12",
152
- label: "Tool Call Logs",
153
- bucket: "refind",
154
- category: "Structural Accumulation",
155
- count: 428,
156
- sessions: 41,
157
- allocatedWasteTokens: 1_750_000,
158
- examples: [{
159
- repo: "Example CLI",
160
- session: "preview-session-3",
161
- agentSource: "claude-code",
162
- turn: 44,
163
- sessionTitle: "Preview build repair",
164
- sessionOrdinal: 51,
165
- sourceSessionCount: 54,
166
- sessionTurns: 63,
167
- timestampMs: Date.UTC(2026, 6, 7),
168
- tokens: 96_000,
169
- turnInputTokens: 198_600,
170
- turnUsefulTokens: 74_700,
171
- turnWasteTokens: 123_900,
172
- prompt: "Preview prompt. This is not local user data.",
173
- command: "npm run build",
174
- evidence: "Preview evidence used only in an explicitly authorized design state.",
175
- }],
176
- },
177
- {
178
- id: "P07",
179
- label: "Failed Turn Leftovers",
180
- bucket: "dead",
181
- category: "Model Behavior",
182
- count: 54,
183
- sessions: 27,
184
- allocatedWasteTokens: 1_280_000,
185
- examples: [{
186
- repo: "Demo Library",
187
- session: "preview-session-4",
188
- agentSource: "codex",
189
- turn: 23,
190
- sessionTitle: "Preview onboarding flow",
191
- sessionOrdinal: 74,
192
- sourceSessionCount: 82,
193
- sessionTurns: 35,
194
- timestampMs: Date.UTC(2026, 5, 30),
195
- tokens: 74_000,
196
- turnInputTokens: 176_800,
197
- turnUsefulTokens: 68_900,
198
- turnWasteTokens: 107_900,
199
- prompt: "Preview prompt. This is not local user data.",
200
- evidence: "Preview evidence used only in an explicitly authorized design state.",
201
- }],
202
- },
203
- ],
204
- },
205
- billedWasteProjection: {
206
- method: "canonical-window-share-over-provider-input",
207
- billedInputTokens: 138_000_000,
208
- canonicalInputTokens: 18_400_000,
209
- canonicalUsefulTokens: 10_672_000,
210
- canonicalWasteTokens: 7_728_000,
211
- billingMultiplier: 7.5,
212
- projectedUsefulTokens: 80_040_000,
213
- projectedWasteTokens: 57_960_000,
214
- usefulPct: 58,
215
- wastePct: 42,
216
- },
217
- };
218
37
  function previewWatermarkScript() {
219
38
  return `
220
39
  document.body.setAttribute("data-preview", "true");
221
40
  var previewWatermark = document.createElement("div");
222
41
  previewWatermark.setAttribute("role", "status");
223
- previewWatermark.textContent = "DESIGN PREVIEW · SAMPLE DATA · NOT YOUR LOCAL REPORT";
42
+ previewWatermark.textContent = "DESIGN PREVIEW · SAMPLE DATA · NOT YOUR LOCAL DATA";
224
43
  previewWatermark.style.cssText = "position:fixed;z-index:99999;left:50%;top:10px;transform:translateX(-50%);padding:7px 12px;border:1px solid #8b2c26;border-radius:999px;background:#fff4e8;color:#8b2c26;font:700 11px/1.2 ui-monospace,monospace;letter-spacing:.05em;box-shadow:0 4px 16px rgba(0,0,0,.12)";
225
44
  document.body.appendChild(previewWatermark);
226
45
  `;
@@ -288,40 +107,13 @@ export function renderSetupPreviewBootstrap(state) {
288
107
  const watermark = previewWatermarkScript();
289
108
  if (state === "consent") {
290
109
  return `${watermark}
291
- renderLocalScanConsent();`;
110
+ renderLocalHistoryConsent();`;
292
111
  }
293
112
  if (state === "consent-required") {
294
113
  return `${watermark}
295
- renderLocalScanConsent();
114
+ renderLocalHistoryConsent();
296
115
  setConsentStatus("Local history access is required to continue setup. Nothing will be scanned or uploaded unless you allow it.", "required");`;
297
116
  }
298
- if (state === "scan") {
299
- return `${watermark}
300
- reportEnvelope = {
301
- schemaVersion: 1,
302
- kind: "scanning",
303
- mode: "preview",
304
- scanId: "design-preview",
305
- progress: { stage: "reading-transcripts", label: "Reading transcript files", scanned: 116, total: 180, overall: 0.451, stageElapsedMs: 3000 }
306
- };
307
- renderLoading();`;
308
- }
309
- if (state === "scan-error") {
310
- return `${watermark}
311
- renderReportIssue("REPORT_CANONICAL_INVALID", "Preview-only canonical reconciliation failure.");`;
312
- }
313
- if (state === "bridge-error") {
314
- return `${watermark}
315
- renderBridgeIssue();`;
316
- }
317
- if (state === "report") {
318
- const reportJson = JSON.stringify(SETUP_PREVIEW_REPORT);
319
- return `${watermark}
320
- localHistoryConsentGranted = true;
321
- report = ${reportJson};
322
- reportEnvelope = { schemaVersion: 1, kind: "ready", mode: "preview", scanId: "design-preview", report: report };
323
- renderForensicReport();`;
324
- }
325
117
  if (state === "extract-counting") {
326
118
  return `${watermark}
327
119
  stats = null;
@@ -341,7 +133,7 @@ export function renderSetupPreviewBootstrap(state) {
341
133
  quotaLimit: 100, quotaRemaining: 100, candidateCount: 7, selectFree: true,
342
134
  })}
343
135
  stats.discovery = { phase: "exact", exact: true };
344
- stats.optionalDiagnostics = { degraded: true, reason: "FULL_STATS_FAILED", countsTrusted: true };
136
+ stats.optionalDiagnostics = { degraded: true, reason: "ACCOUNT_RECONCILIATION_FAILED", countsTrusted: true };
345
137
  renderDashboard();`;
346
138
  if (state === "extract-ready")
347
139
  return `${watermark}${extractionPreviewBootstrap({