wicked-crew 0.5.0 → 0.7.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 (167) hide show
  1. package/dist/api/audit.d.ts +70 -0
  2. package/dist/api/audit.d.ts.map +1 -0
  3. package/dist/api/audit.js +131 -0
  4. package/dist/api/audit.js.map +1 -0
  5. package/dist/api/auth.d.ts +192 -0
  6. package/dist/api/auth.d.ts.map +1 -0
  7. package/dist/api/auth.js +515 -0
  8. package/dist/api/auth.js.map +1 -0
  9. package/dist/api/gate-cache.d.ts +8 -0
  10. package/dist/api/gate-cache.d.ts.map +1 -1
  11. package/dist/api/gate-cache.js +10 -0
  12. package/dist/api/gate-cache.js.map +1 -1
  13. package/dist/api/guidance-index.d.ts +39 -0
  14. package/dist/api/guidance-index.d.ts.map +1 -0
  15. package/dist/api/guidance-index.js +67 -0
  16. package/dist/api/guidance-index.js.map +1 -0
  17. package/dist/api/open-path.d.ts +34 -0
  18. package/dist/api/open-path.d.ts.map +1 -0
  19. package/dist/api/open-path.js +101 -0
  20. package/dist/api/open-path.js.map +1 -0
  21. package/dist/api/retry-index.d.ts +30 -0
  22. package/dist/api/retry-index.d.ts.map +1 -0
  23. package/dist/api/retry-index.js +45 -0
  24. package/dist/api/retry-index.js.map +1 -0
  25. package/dist/api/routes.d.ts +164 -1
  26. package/dist/api/routes.d.ts.map +1 -1
  27. package/dist/api/routes.js +769 -21
  28. package/dist/api/routes.js.map +1 -1
  29. package/dist/api/run-files.d.ts +63 -0
  30. package/dist/api/run-files.d.ts.map +1 -0
  31. package/dist/api/run-files.js +271 -0
  32. package/dist/api/run-files.js.map +1 -0
  33. package/dist/api/seat-health.d.ts +55 -0
  34. package/dist/api/seat-health.d.ts.map +1 -0
  35. package/dist/api/seat-health.js +273 -0
  36. package/dist/api/seat-health.js.map +1 -0
  37. package/dist/api/seat-signin.d.ts +27 -0
  38. package/dist/api/seat-signin.d.ts.map +1 -0
  39. package/dist/api/seat-signin.js +143 -0
  40. package/dist/api/seat-signin.js.map +1 -0
  41. package/dist/api/server.d.ts +190 -3
  42. package/dist/api/server.d.ts.map +1 -1
  43. package/dist/api/server.js +365 -11
  44. package/dist/api/server.js.map +1 -1
  45. package/dist/api/stall-watchdog.d.ts +62 -0
  46. package/dist/api/stall-watchdog.d.ts.map +1 -0
  47. package/dist/api/stall-watchdog.js +138 -0
  48. package/dist/api/stall-watchdog.js.map +1 -0
  49. package/dist/cli/index.js +171 -12
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/cli/mcp.d.ts +14 -0
  52. package/dist/cli/mcp.d.ts.map +1 -0
  53. package/dist/cli/mcp.js +119 -0
  54. package/dist/cli/mcp.js.map +1 -0
  55. package/dist/core/adapter.d.ts +87 -10
  56. package/dist/core/adapter.d.ts.map +1 -1
  57. package/dist/core/adapter.js +347 -28
  58. package/dist/core/adapter.js.map +1 -1
  59. package/dist/core/bridge-reaper.d.ts +134 -0
  60. package/dist/core/bridge-reaper.d.ts.map +1 -0
  61. package/dist/core/bridge-reaper.js +286 -0
  62. package/dist/core/bridge-reaper.js.map +1 -0
  63. package/dist/core/deliver.d.ts +118 -0
  64. package/dist/core/deliver.d.ts.map +1 -0
  65. package/dist/core/deliver.js +241 -0
  66. package/dist/core/deliver.js.map +1 -0
  67. package/dist/core/deliverable-floor.d.ts +103 -0
  68. package/dist/core/deliverable-floor.d.ts.map +1 -0
  69. package/dist/core/deliverable-floor.js +173 -0
  70. package/dist/core/deliverable-floor.js.map +1 -0
  71. package/dist/core/exec.d.ts +2 -0
  72. package/dist/core/exec.d.ts.map +1 -1
  73. package/dist/core/exec.js.map +1 -1
  74. package/dist/core/types.d.ts +92 -352
  75. package/dist/core/types.d.ts.map +1 -1
  76. package/dist/core/types.js +14 -4
  77. package/dist/core/types.js.map +1 -1
  78. package/dist/interactive/bridge-pool.d.ts +99 -0
  79. package/dist/interactive/bridge-pool.d.ts.map +1 -0
  80. package/dist/interactive/bridge-pool.js +244 -0
  81. package/dist/interactive/bridge-pool.js.map +1 -0
  82. package/dist/interactive/bridge-root.d.ts +36 -0
  83. package/dist/interactive/bridge-root.d.ts.map +1 -0
  84. package/dist/interactive/bridge-root.js +48 -0
  85. package/dist/interactive/bridge-root.js.map +1 -0
  86. package/dist/interactive/chat-events.d.ts +207 -0
  87. package/dist/interactive/chat-events.d.ts.map +1 -0
  88. package/dist/interactive/chat-events.js +769 -0
  89. package/dist/interactive/chat-events.js.map +1 -0
  90. package/dist/interactive/demo-events.d.ts +283 -0
  91. package/dist/interactive/demo-events.d.ts.map +1 -0
  92. package/dist/interactive/demo-events.js +889 -0
  93. package/dist/interactive/demo-events.js.map +1 -0
  94. package/dist/interactive/draft-events.d.ts +224 -0
  95. package/dist/interactive/draft-events.d.ts.map +1 -0
  96. package/dist/interactive/draft-events.js +793 -0
  97. package/dist/interactive/draft-events.js.map +1 -0
  98. package/dist/interactive/edit-events.d.ts +194 -0
  99. package/dist/interactive/edit-events.d.ts.map +1 -0
  100. package/dist/interactive/edit-events.js +601 -0
  101. package/dist/interactive/edit-events.js.map +1 -0
  102. package/dist/interactive/ledger.d.ts +39 -0
  103. package/dist/interactive/ledger.d.ts.map +1 -0
  104. package/dist/interactive/ledger.js +93 -0
  105. package/dist/interactive/ledger.js.map +1 -0
  106. package/dist/interactive/proxy-routes.d.ts +39 -0
  107. package/dist/interactive/proxy-routes.d.ts.map +1 -0
  108. package/dist/interactive/proxy-routes.js +189 -0
  109. package/dist/interactive/proxy-routes.js.map +1 -0
  110. package/dist/interactive/repo-snapshot.d.ts +100 -0
  111. package/dist/interactive/repo-snapshot.d.ts.map +1 -0
  112. package/dist/interactive/repo-snapshot.js +289 -0
  113. package/dist/interactive/repo-snapshot.js.map +1 -0
  114. package/dist/interactive/ws-relay.d.ts +85 -0
  115. package/dist/interactive/ws-relay.d.ts.map +1 -0
  116. package/dist/interactive/ws-relay.js +191 -0
  117. package/dist/interactive/ws-relay.js.map +1 -0
  118. package/dist/projects/activity.d.ts +29 -0
  119. package/dist/projects/activity.d.ts.map +1 -0
  120. package/dist/projects/activity.js +172 -0
  121. package/dist/projects/activity.js.map +1 -0
  122. package/dist/projects/charter.d.ts +28 -0
  123. package/dist/projects/charter.d.ts.map +1 -0
  124. package/dist/projects/charter.js +53 -0
  125. package/dist/projects/charter.js.map +1 -0
  126. package/dist/projects/events.d.ts +55 -0
  127. package/dist/projects/events.d.ts.map +1 -0
  128. package/dist/projects/events.js +141 -0
  129. package/dist/projects/events.js.map +1 -0
  130. package/dist/projects/graph-paths.d.ts +92 -0
  131. package/dist/projects/graph-paths.d.ts.map +1 -0
  132. package/dist/projects/graph-paths.js +130 -0
  133. package/dist/projects/graph-paths.js.map +1 -0
  134. package/dist/projects/graph.d.ts +179 -0
  135. package/dist/projects/graph.d.ts.map +1 -0
  136. package/dist/projects/graph.js +775 -0
  137. package/dist/projects/graph.js.map +1 -0
  138. package/dist/projects/membership-index.d.ts +25 -0
  139. package/dist/projects/membership-index.d.ts.map +1 -0
  140. package/dist/projects/membership-index.js +46 -0
  141. package/dist/projects/membership-index.js.map +1 -0
  142. package/dist/projects/routes.d.ts +97 -0
  143. package/dist/projects/routes.d.ts.map +1 -0
  144. package/dist/projects/routes.js +510 -0
  145. package/dist/projects/routes.js.map +1 -0
  146. package/dist/projects/settings.d.ts +32 -0
  147. package/dist/projects/settings.d.ts.map +1 -0
  148. package/dist/projects/settings.js +64 -0
  149. package/dist/projects/settings.js.map +1 -0
  150. package/dist/qe/acceptance.d.ts +137 -0
  151. package/dist/qe/acceptance.d.ts.map +1 -0
  152. package/dist/qe/acceptance.js +249 -0
  153. package/dist/qe/acceptance.js.map +1 -0
  154. package/dist/qe/gate-events.d.ts +111 -0
  155. package/dist/qe/gate-events.d.ts.map +1 -0
  156. package/dist/qe/gate-events.js +168 -0
  157. package/dist/qe/gate-events.js.map +1 -0
  158. package/dist/qe/ledger.d.ts +100 -0
  159. package/dist/qe/ledger.d.ts.map +1 -0
  160. package/dist/qe/ledger.js +154 -0
  161. package/dist/qe/ledger.js.map +1 -0
  162. package/dist/studio/assets/index-8p8uwCxG.js +530 -0
  163. package/dist/studio/assets/index-D6S9zUtO.css +32 -0
  164. package/dist/studio/index.html +5 -3
  165. package/package.json +10 -4
  166. package/dist/studio/assets/index-DaaUU8Ep.css +0 -32
  167. package/dist/studio/assets/index-Fu5DRC00.js +0 -423
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Opt-in consumption of the QE gate's wicked-bus events.
3
+ *
4
+ * The QE pipeline announces gate results on the bus — the wire contract the
5
+ * retired wicked-testing package's `lib/gate.mjs` established and garden's qe
6
+ * skills now emit (Phase 6c kept these event names and payload fields STABLE
7
+ * by decision — only the emitters' `domain` stamp rebranded to `qe`):
8
+ *
9
+ * wicked.qe.gate.passed | wicked.qe.gate.failed | wicked.qe.gate.conditional
10
+ * payload (8 canonical fields): run_id, context, gate_verdict, exit_code,
11
+ * verdict_summary, mode, completed_at, scenario_count
12
+ * idempotency key: `qe:gate.result:{context}:{sha256(run_id)[0:16]}:0`
13
+ * wicked.qe.deploy.completed
14
+ * payload: run_id, project_id (emitted alongside a PASS)
15
+ *
16
+ * Consumption is OPT-IN behind crew's existing bus seam (like `--bus-db` /
17
+ * `WICKED_BUS_EXEC`): when armed, a durable wicked-bus subscriber folds each
18
+ * event into this in-memory cache so acceptance reads see gate results the
19
+ * moment they happen; when the bus is absent, nothing here runs and the
20
+ * acceptance route's lazy ledger read is the (always-correct) fallback. The
21
+ * cache is a freshness signal — the ledger stays the system of record for the
22
+ * gate decision, so a lost or replayed event can never flip a verdict.
23
+ */
24
+ /** The gate-result event types (the old gate.mjs wire contract, verbatim). */
25
+ export const QE_GATE_EVENT_TYPES = [
26
+ 'wicked.qe.gate.passed',
27
+ 'wicked.qe.gate.failed',
28
+ 'wicked.qe.gate.conditional',
29
+ ];
30
+ /** The cross-product deploy signal emitted alongside a PASS. */
31
+ export const QE_DEPLOY_EVENT_TYPE = 'wicked.qe.deploy.completed';
32
+ /**
33
+ * One durable-subscription filter covering both families above
34
+ * (`prefix.**` = one or more remaining segments in wicked-bus filter grammar).
35
+ */
36
+ export const QE_BUS_FILTER = 'wicked.qe.**';
37
+ /** Subscriber identity on the bus (registration + cursor resume key). */
38
+ export const QE_BUS_PLUGIN = 'wicked-crew';
39
+ function str(v) {
40
+ return typeof v === 'string' ? v : null;
41
+ }
42
+ function num(v) {
43
+ return typeof v === 'number' && Number.isFinite(v) ? v : null;
44
+ }
45
+ /**
46
+ * Latest-gate-result cache, keyed by QE run id and by context.
47
+ *
48
+ * At-least-once delivery means the same logical event may arrive more than
49
+ * once; folding is idempotent by construction (same event ⇒ same entry). No
50
+ * eviction: entries are one small record per QE run/context and the daemon is
51
+ * local-first — a restart simply starts empty and the ledger read covers it.
52
+ */
53
+ export class QeGateCache {
54
+ byRun = new Map();
55
+ byContext = new Map();
56
+ latestEntry;
57
+ /**
58
+ * Fold one bus event. Returns `true` when the event was a recognized
59
+ * `wicked.qe.*` gate/deploy frame and was cached; unknown types are ignored
60
+ * (the durable filter is a prefix, so future qe events pass through here).
61
+ */
62
+ ingest(eventType, payload, observedAt = new Date().toISOString()) {
63
+ const isGate = QE_GATE_EVENT_TYPES.includes(eventType);
64
+ const isDeploy = eventType === QE_DEPLOY_EVENT_TYPE;
65
+ if (!isGate && !isDeploy)
66
+ return false;
67
+ if (typeof payload !== 'object' || payload === null)
68
+ return false;
69
+ const p = payload;
70
+ const runId = str(p['run_id']);
71
+ if (runId === null)
72
+ return false; // both contracts require run_id
73
+ const entry = {
74
+ eventType,
75
+ runId,
76
+ // Gate events carry `context`; the deploy signal spells it `project_id`.
77
+ context: str(p['context']) ?? str(p['project_id']),
78
+ gateVerdict: isGate ? str(p['gate_verdict']) : null,
79
+ exitCode: isGate ? num(p['exit_code']) : null,
80
+ verdictSummary: isGate ? str(p['verdict_summary']) : null,
81
+ mode: isGate ? str(p['mode']) : null,
82
+ completedAt: isGate ? str(p['completed_at']) : null,
83
+ scenarioCount: isGate ? num(p['scenario_count']) : null,
84
+ observedAt,
85
+ };
86
+ // The deploy signal must not shadow the gate result it accompanies: for the
87
+ // same run, a gate event always wins the byRun/byContext slots; the deploy
88
+ // frame only fills them when no gate result was seen (e.g. cursor_init
89
+ // 'latest' catching the tail of an emission pair).
90
+ const existing = this.byRun.get(runId);
91
+ if (!(isDeploy && existing !== undefined && existing.gateVerdict !== null)) {
92
+ this.byRun.set(runId, entry);
93
+ if (entry.context !== null)
94
+ this.byContext.set(entry.context, entry);
95
+ }
96
+ this.latestEntry = entry;
97
+ return true;
98
+ }
99
+ /** The latest cached result for a QE run id. */
100
+ forRun(runId) {
101
+ return this.byRun.get(runId);
102
+ }
103
+ /** The latest cached result for a context (QE project id). */
104
+ forContext(context) {
105
+ return this.byContext.get(context);
106
+ }
107
+ /** The most recently observed event, whatever it was keyed by. */
108
+ latest() {
109
+ return this.latestEntry;
110
+ }
111
+ /** Number of distinct QE runs with a cached result (diagnostics / tests). */
112
+ size() {
113
+ return this.byRun.size;
114
+ }
115
+ }
116
+ /**
117
+ * Start the durable `wicked.qe.**` subscriber and fold events into `cache`.
118
+ *
119
+ * Graceful degradation, matching how other wicked consumers subscribe
120
+ * (wicked-brain's memory subscriber): wicked-bus is dynamically imported, and
121
+ * a missing package / unopenable db returns `null` instead of throwing — the
122
+ * caller opted in, so the degradation is LOGGED, but a daemon must still boot
123
+ * on a machine whose bus is broken (acceptance falls back to lazy ledger
124
+ * reads, which never needed the bus).
125
+ *
126
+ * `cursor_init: 'latest'`: the cache is a live freshness signal, not history —
127
+ * replaying an old bus backlog into it would let a stale event masquerade as
128
+ * fresh. History belongs to the ledger.
129
+ */
130
+ export async function startQeGateSubscriber(cache, opts = {}) {
131
+ const log = opts.log ?? ((m) => console.error(m));
132
+ let bus;
133
+ try {
134
+ bus = await import('wicked-bus');
135
+ }
136
+ catch (err) {
137
+ log(`[qe-gate-events] wicked-bus is not importable — gate events disabled, acceptance stays on lazy ledger reads: ${err instanceof Error ? err.message : String(err)}`);
138
+ return null;
139
+ }
140
+ let db;
141
+ try {
142
+ db = bus.openDb(opts.dbPath !== undefined ? { db_path: opts.dbPath } : {});
143
+ }
144
+ catch (err) {
145
+ log(`[qe-gate-events] could not open the bus db${opts.dbPath !== undefined ? ` at ${opts.dbPath}` : ''} — gate events disabled: ${err instanceof Error ? err.message : String(err)}`);
146
+ return null;
147
+ }
148
+ const sub = bus.subscribe({
149
+ db,
150
+ plugin: QE_BUS_PLUGIN,
151
+ filter: QE_BUS_FILTER,
152
+ cursor_init: 'latest',
153
+ pollIntervalMs: opts.pollIntervalMs ?? 5000,
154
+ // The handler only folds into an in-memory map; a retry loop or DLQ entry
155
+ // for it would be noise. It never throws by construction.
156
+ maxRetries: 0,
157
+ handler: (event) => {
158
+ cache.ingest(event.event_type, event.payload);
159
+ },
160
+ onError: (err, event) => {
161
+ log(`[qe-gate-events] handler error on event ${String(event?.event_id ?? '?')}: ${err.message}`);
162
+ },
163
+ });
164
+ return {
165
+ stop: () => sub.stop(),
166
+ };
167
+ }
168
+ //# sourceMappingURL=gate-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-events.js","sourceRoot":"","sources":["../../src/qe/gate-events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Read-only view over a repo's QE evidence ledger (wicked-ledger).
3
+ *
4
+ * The ledger is the data contract between the QE pipeline (wicked-garden's qe
5
+ * skills, formerly the retired wicked-testing package) and the acceptance gate
6
+ * this daemon owns: a DomainStore rooted at `<repo>/.wicked-qe/` (legacy
7
+ * `<repo>/.wicked-testing/` — see qeLedgerRoot) holding `runs` and
8
+ * `verdicts`, plus the public evidence manifest at
9
+ * `<root>/evidence/<run-id>/manifest.json`. This module reads that state
10
+ * through the wicked-ledger package API (public entry, no deep imports) and
11
+ * never writes a domain record — the QE pipeline is the only writer.
12
+ *
13
+ * ONE deliberate mutation is allowed: `rebuildIndex()`, which regenerates the
14
+ * store's DERIVED SQLite index from the canonical JSON files when the two
15
+ * disagree (see `readAcceptanceState`). Canonical JSON is authoritative by the
16
+ * ledger's own schema contract; the index is a cache, and rebuilding a cache
17
+ * is not a write to the ledger's record of what happened.
18
+ */
19
+ import type { EvidenceManifest, RunRecord, VerdictRecord } from 'wicked-ledger';
20
+ /**
21
+ * The ledger root directory name under a repo root.
22
+ *
23
+ * Phase 6c (the wicked-testing retirement) renamed the wire contract to
24
+ * `.wicked-qe`; `.wicked-testing` is the legacy dirname repos written by the
25
+ * retired package (and pre-6c garden qe skills) still carry. Resolution is
26
+ * dual-read and mirrors wicked-ledger's `resolveLedgerRoot`: the new name
27
+ * wins, an existing legacy root is honored, fresh repos get the new name.
28
+ */
29
+ export declare const DEFAULT_QE_LEDGER_DIRNAME = ".wicked-qe";
30
+ export declare const LEGACY_QE_LEDGER_DIRNAME = ".wicked-testing";
31
+ /** The configured ledger dir name: `WICKED_QE_LEDGER_DIR` env override, else the default. */
32
+ export declare function qeLedgerDirName(): string;
33
+ /**
34
+ * Absolute ledger root for a repo (dual-read, Phase 6c).
35
+ *
36
+ * An explicit `WICKED_QE_LEDGER_DIR` pins the dirname exactly — the operator
37
+ * is driving, no fallback probing. Otherwise: `<repo>/.wicked-qe` when it
38
+ * exists; else an existing legacy `<repo>/.wicked-testing` (that ledger keeps
39
+ * its root — a store must never split across two dirs); else `.wicked-qe`.
40
+ */
41
+ export declare function qeLedgerRoot(repoRoot: string): string;
42
+ /**
43
+ * The acceptance-relevant slice of a repo's ledger.
44
+ *
45
+ * `found: false` means the repo has no ledger at all (the dir is absent) —
46
+ * a distinct fact from "a ledger with no verdicts", and the gate treats both
47
+ * as a deny with different reasons. `error` carries a read-layer failure
48
+ * (store threw); it is never set on an ordinary empty ledger.
49
+ */
50
+ export interface QeAcceptanceState {
51
+ /** Absolute ledger root that was read (or probed). */
52
+ root: string;
53
+ /** Whether the ledger root exists on disk. */
54
+ found: boolean;
55
+ /** The QE run the verdict belongs to, when resolvable. */
56
+ run: RunRecord | null;
57
+ /** The governing verdict row — newest first, the ledger's system of record. */
58
+ verdict: VerdictRecord | null;
59
+ /** The public evidence manifest for that run, when present and parseable. */
60
+ manifest: EvidenceManifest | null;
61
+ /** Absolute path the manifest was read from (null when absent). */
62
+ manifestPath: string | null;
63
+ /** Read-layer failure detail (store open/read threw). */
64
+ error?: string;
65
+ }
66
+ /**
67
+ * Read the ledger's current acceptance state for a repo.
68
+ *
69
+ * The newest verdict row governs (`opts.qeRunId` narrows to one QE run's
70
+ * newest verdict instead). The verdicts TABLE is the system of record — the
71
+ * manifest is the public artifact built from it at run finalization, returned
72
+ * here as display evidence, never as a gate input: a run can legitimately be
73
+ * re-reviewed after its manifest was built, and the newer verdict row wins.
74
+ *
75
+ * Index-drift healing: the store is dual-write (canonical JSON + a derived
76
+ * SQLite index) and a writer that degraded to JSON-only leaves the index
77
+ * behind. When the index answers "no verdicts" but canonical verdict files
78
+ * exist, the index is provably stale, so it is rebuilt from JSON once and
79
+ * re-read — otherwise a ledger full of evidence would read as "missing
80
+ * evidence ⇒ deny", a wrong answer in the honest direction but still wrong.
81
+ */
82
+ export declare function readAcceptanceState(repoRoot: string, opts?: {
83
+ qeRunId?: string;
84
+ }): Promise<QeAcceptanceState>;
85
+ /** The summary of a manifest the acceptance route serves (never the full artifact list). */
86
+ export interface QeManifestSummary {
87
+ manifestVersion: string;
88
+ runId: string;
89
+ scenarioName: string | null;
90
+ status: string;
91
+ artifactCount: number;
92
+ verdict: {
93
+ value: string;
94
+ reviewer: string;
95
+ recordedAt: string | null;
96
+ };
97
+ }
98
+ /** Reduce a manifest to the route's summary shape. */
99
+ export declare function summarizeManifest(manifest: EvidenceManifest): QeManifestSummary;
100
+ //# sourceMappingURL=ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/qe/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEhF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,eAAe,CAAC;AACtD,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAE1D,6FAA6F;AAC7F,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQrD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IACtB,+EAA+E;IAC/E,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,mEAAmE;IACnE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAaD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAqC5B;AAgBD,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACzE;AAED,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,iBAAiB,CAa/E"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Read-only view over a repo's QE evidence ledger (wicked-ledger).
3
+ *
4
+ * The ledger is the data contract between the QE pipeline (wicked-garden's qe
5
+ * skills, formerly the retired wicked-testing package) and the acceptance gate
6
+ * this daemon owns: a DomainStore rooted at `<repo>/.wicked-qe/` (legacy
7
+ * `<repo>/.wicked-testing/` — see qeLedgerRoot) holding `runs` and
8
+ * `verdicts`, plus the public evidence manifest at
9
+ * `<root>/evidence/<run-id>/manifest.json`. This module reads that state
10
+ * through the wicked-ledger package API (public entry, no deep imports) and
11
+ * never writes a domain record — the QE pipeline is the only writer.
12
+ *
13
+ * ONE deliberate mutation is allowed: `rebuildIndex()`, which regenerates the
14
+ * store's DERIVED SQLite index from the canonical JSON files when the two
15
+ * disagree (see `readAcceptanceState`). Canonical JSON is authoritative by the
16
+ * ledger's own schema contract; the index is a cache, and rebuilding a cache
17
+ * is not a write to the ledger's record of what happened.
18
+ */
19
+ import { existsSync, readdirSync } from 'node:fs';
20
+ import { readFile } from 'node:fs/promises';
21
+ import { join } from 'node:path';
22
+ import { createDomainStore } from 'wicked-ledger';
23
+ /**
24
+ * The ledger root directory name under a repo root.
25
+ *
26
+ * Phase 6c (the wicked-testing retirement) renamed the wire contract to
27
+ * `.wicked-qe`; `.wicked-testing` is the legacy dirname repos written by the
28
+ * retired package (and pre-6c garden qe skills) still carry. Resolution is
29
+ * dual-read and mirrors wicked-ledger's `resolveLedgerRoot`: the new name
30
+ * wins, an existing legacy root is honored, fresh repos get the new name.
31
+ */
32
+ export const DEFAULT_QE_LEDGER_DIRNAME = '.wicked-qe';
33
+ export const LEGACY_QE_LEDGER_DIRNAME = '.wicked-testing';
34
+ /** The configured ledger dir name: `WICKED_QE_LEDGER_DIR` env override, else the default. */
35
+ export function qeLedgerDirName() {
36
+ const env = process.env['WICKED_QE_LEDGER_DIR']?.trim();
37
+ return env !== undefined && env !== '' ? env : DEFAULT_QE_LEDGER_DIRNAME;
38
+ }
39
+ /**
40
+ * Absolute ledger root for a repo (dual-read, Phase 6c).
41
+ *
42
+ * An explicit `WICKED_QE_LEDGER_DIR` pins the dirname exactly — the operator
43
+ * is driving, no fallback probing. Otherwise: `<repo>/.wicked-qe` when it
44
+ * exists; else an existing legacy `<repo>/.wicked-testing` (that ledger keeps
45
+ * its root — a store must never split across two dirs); else `.wicked-qe`.
46
+ */
47
+ export function qeLedgerRoot(repoRoot) {
48
+ const env = process.env['WICKED_QE_LEDGER_DIR']?.trim();
49
+ if (env !== undefined && env !== '')
50
+ return join(repoRoot, env);
51
+ const current = join(repoRoot, DEFAULT_QE_LEDGER_DIRNAME);
52
+ if (existsSync(current))
53
+ return current;
54
+ const legacy = join(repoRoot, LEGACY_QE_LEDGER_DIRNAME);
55
+ if (existsSync(legacy))
56
+ return legacy;
57
+ return current;
58
+ }
59
+ /** True when the canonical JSON dir for a table has at least one record file. */
60
+ function hasCanonicalRows(root, table) {
61
+ try {
62
+ return readdirSync(join(root, table)).some((f) => f.endsWith('.json') && !f.includes('.tmp.'));
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ /**
69
+ * Read the ledger's current acceptance state for a repo.
70
+ *
71
+ * The newest verdict row governs (`opts.qeRunId` narrows to one QE run's
72
+ * newest verdict instead). The verdicts TABLE is the system of record — the
73
+ * manifest is the public artifact built from it at run finalization, returned
74
+ * here as display evidence, never as a gate input: a run can legitimately be
75
+ * re-reviewed after its manifest was built, and the newer verdict row wins.
76
+ *
77
+ * Index-drift healing: the store is dual-write (canonical JSON + a derived
78
+ * SQLite index) and a writer that degraded to JSON-only leaves the index
79
+ * behind. When the index answers "no verdicts" but canonical verdict files
80
+ * exist, the index is provably stale, so it is rebuilt from JSON once and
81
+ * re-read — otherwise a ledger full of evidence would read as "missing
82
+ * evidence ⇒ deny", a wrong answer in the honest direction but still wrong.
83
+ */
84
+ export async function readAcceptanceState(repoRoot, opts) {
85
+ const root = qeLedgerRoot(repoRoot);
86
+ const state = {
87
+ root,
88
+ found: false,
89
+ run: null,
90
+ verdict: null,
91
+ manifest: null,
92
+ manifestPath: null,
93
+ };
94
+ // Probe before opening: createDomainStore CREATES its root when absent, and
95
+ // a read must not install an empty ledger into a repo that never had one.
96
+ if (!existsSync(root))
97
+ return state;
98
+ state.found = true;
99
+ try {
100
+ const store = createDomainStore({ root });
101
+ const filter = opts?.qeRunId !== undefined ? { run_id: opts.qeRunId } : undefined;
102
+ let verdicts = store.list('verdicts', filter);
103
+ if (verdicts.length === 0 && store.mode === 'sqlite+json' && hasCanonicalRows(root, 'verdicts')) {
104
+ store.rebuildIndex();
105
+ verdicts = store.list('verdicts', filter);
106
+ }
107
+ const verdict = verdicts[0] ?? null;
108
+ state.verdict = verdict;
109
+ if (verdict !== null) {
110
+ state.run = store.get('runs', verdict.run_id);
111
+ state.manifestPath = join(root, 'evidence', verdict.run_id, 'manifest.json');
112
+ state.manifest = await readManifest(state.manifestPath);
113
+ }
114
+ }
115
+ catch (err) {
116
+ // A ledger that exists but cannot be read is NOT "no evidence" — the gate
117
+ // still denies (deny-dominates), but the reason must name the read failure
118
+ // so an operator fixes the store instead of hunting for a missing run.
119
+ state.error = err instanceof Error ? err.message : String(err);
120
+ }
121
+ return state;
122
+ }
123
+ /** Parse the public manifest, or null when absent/malformed (display evidence only). */
124
+ async function readManifest(path) {
125
+ try {
126
+ const raw = await readFile(path, 'utf8');
127
+ const parsed = JSON.parse(raw);
128
+ // Minimal shape check — enough to know this is a manifest and not stray JSON.
129
+ if (typeof parsed !== 'object' || parsed === null)
130
+ return null;
131
+ if (typeof parsed.run_id !== 'string' || typeof parsed.manifest_version !== 'string')
132
+ return null;
133
+ return parsed;
134
+ }
135
+ catch {
136
+ return null;
137
+ }
138
+ }
139
+ /** Reduce a manifest to the route's summary shape. */
140
+ export function summarizeManifest(manifest) {
141
+ return {
142
+ manifestVersion: manifest.manifest_version,
143
+ runId: manifest.run_id,
144
+ scenarioName: typeof manifest.scenario_name === 'string' ? manifest.scenario_name : null,
145
+ status: manifest.status,
146
+ artifactCount: Array.isArray(manifest.artifacts) ? manifest.artifacts.length : 0,
147
+ verdict: {
148
+ value: manifest.verdict?.value ?? 'INCONCLUSIVE',
149
+ reviewer: manifest.verdict?.reviewer ?? '',
150
+ recordedAt: manifest.verdict?.recorded_at ?? null,
151
+ },
152
+ };
153
+ }
154
+ //# sourceMappingURL=ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/qe/ledger.ts"],"names":[],"mappings":"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"}