@encore-os/eos-spec 0.3.1

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 (256) hide show
  1. package/LICENSE +17 -0
  2. package/bin/check-dist-fresh.js +51 -0
  3. package/bin/eos-spec.js +7 -0
  4. package/dist/commands/ac-backfill.d.ts +31 -0
  5. package/dist/commands/ac-backfill.js +198 -0
  6. package/dist/commands/ac-backfill.js.map +1 -0
  7. package/dist/commands/archive.d.ts +2 -0
  8. package/dist/commands/archive.js +101 -0
  9. package/dist/commands/archive.js.map +1 -0
  10. package/dist/commands/audit.d.ts +30 -0
  11. package/dist/commands/audit.js +107 -0
  12. package/dist/commands/audit.js.map +1 -0
  13. package/dist/commands/backfill.d.ts +41 -0
  14. package/dist/commands/backfill.js +239 -0
  15. package/dist/commands/backfill.js.map +1 -0
  16. package/dist/commands/checkArtifacts.d.ts +2 -0
  17. package/dist/commands/checkArtifacts.js +48 -0
  18. package/dist/commands/checkArtifacts.js.map +1 -0
  19. package/dist/commands/checkPlacement.d.ts +2 -0
  20. package/dist/commands/checkPlacement.js +31 -0
  21. package/dist/commands/checkPlacement.js.map +1 -0
  22. package/dist/commands/claim.d.ts +4 -0
  23. package/dist/commands/claim.js +46 -0
  24. package/dist/commands/claim.js.map +1 -0
  25. package/dist/commands/complete.d.ts +2 -0
  26. package/dist/commands/complete.js +138 -0
  27. package/dist/commands/complete.js.map +1 -0
  28. package/dist/commands/conformance.d.ts +23 -0
  29. package/dist/commands/conformance.js +124 -0
  30. package/dist/commands/conformance.js.map +1 -0
  31. package/dist/commands/create.d.ts +6 -0
  32. package/dist/commands/create.js +277 -0
  33. package/dist/commands/create.js.map +1 -0
  34. package/dist/commands/deferred.d.ts +2 -0
  35. package/dist/commands/deferred.js +85 -0
  36. package/dist/commands/deferred.js.map +1 -0
  37. package/dist/commands/delta.d.ts +17 -0
  38. package/dist/commands/delta.js +292 -0
  39. package/dist/commands/delta.js.map +1 -0
  40. package/dist/commands/freshness.d.ts +13 -0
  41. package/dist/commands/freshness.js +72 -0
  42. package/dist/commands/freshness.js.map +1 -0
  43. package/dist/commands/funnel.d.ts +2 -0
  44. package/dist/commands/funnel.js +61 -0
  45. package/dist/commands/funnel.js.map +1 -0
  46. package/dist/commands/gen-tests.d.ts +2 -0
  47. package/dist/commands/gen-tests.js +53 -0
  48. package/dist/commands/gen-tests.js.map +1 -0
  49. package/dist/commands/init.d.ts +2 -0
  50. package/dist/commands/init.js +64 -0
  51. package/dist/commands/init.js.map +1 -0
  52. package/dist/commands/list.d.ts +9 -0
  53. package/dist/commands/list.js +61 -0
  54. package/dist/commands/list.js.map +1 -0
  55. package/dist/commands/metrics.d.ts +2 -0
  56. package/dist/commands/metrics.js +66 -0
  57. package/dist/commands/metrics.js.map +1 -0
  58. package/dist/commands/next.d.ts +48 -0
  59. package/dist/commands/next.js +344 -0
  60. package/dist/commands/next.js.map +1 -0
  61. package/dist/commands/precedent.d.ts +66 -0
  62. package/dist/commands/precedent.js +343 -0
  63. package/dist/commands/precedent.js.map +1 -0
  64. package/dist/commands/ready.d.ts +28 -0
  65. package/dist/commands/ready.js +147 -0
  66. package/dist/commands/ready.js.map +1 -0
  67. package/dist/commands/reconcile.d.ts +44 -0
  68. package/dist/commands/reconcile.js +187 -0
  69. package/dist/commands/reconcile.js.map +1 -0
  70. package/dist/commands/rollup.d.ts +2 -0
  71. package/dist/commands/rollup.js +43 -0
  72. package/dist/commands/rollup.js.map +1 -0
  73. package/dist/commands/scorecard.d.ts +11 -0
  74. package/dist/commands/scorecard.js +55 -0
  75. package/dist/commands/scorecard.js.map +1 -0
  76. package/dist/commands/signoff.d.ts +2 -0
  77. package/dist/commands/signoff.js +114 -0
  78. package/dist/commands/signoff.js.map +1 -0
  79. package/dist/commands/status.d.ts +2 -0
  80. package/dist/commands/status.js +100 -0
  81. package/dist/commands/status.js.map +1 -0
  82. package/dist/commands/tasks.d.ts +13 -0
  83. package/dist/commands/tasks.js +81 -0
  84. package/dist/commands/tasks.js.map +1 -0
  85. package/dist/commands/validate.d.ts +16 -0
  86. package/dist/commands/validate.js +89 -0
  87. package/dist/commands/validate.js.map +1 -0
  88. package/dist/commands/verify-acs.d.ts +15 -0
  89. package/dist/commands/verify-acs.js +196 -0
  90. package/dist/commands/verify-acs.js.map +1 -0
  91. package/dist/commands/verifyRollout.d.ts +2 -0
  92. package/dist/commands/verifyRollout.js +125 -0
  93. package/dist/commands/verifyRollout.js.map +1 -0
  94. package/dist/index.d.ts +21 -0
  95. package/dist/index.js +138 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/lib/ac-draft-prompt.d.ts +18 -0
  98. package/dist/lib/ac-draft-prompt.js +38 -0
  99. package/dist/lib/ac-draft-prompt.js.map +1 -0
  100. package/dist/lib/ac-response-parser.d.ts +18 -0
  101. package/dist/lib/ac-response-parser.js +57 -0
  102. package/dist/lib/ac-response-parser.js.map +1 -0
  103. package/dist/lib/ai-call.d.ts +13 -0
  104. package/dist/lib/ai-call.js +17 -0
  105. package/dist/lib/ai-call.js.map +1 -0
  106. package/dist/lib/archive.d.ts +21 -0
  107. package/dist/lib/archive.js +136 -0
  108. package/dist/lib/archive.js.map +1 -0
  109. package/dist/lib/artifact-integrity.d.ts +5 -0
  110. package/dist/lib/artifact-integrity.js +65 -0
  111. package/dist/lib/artifact-integrity.js.map +1 -0
  112. package/dist/lib/backfill-queue.d.ts +11 -0
  113. package/dist/lib/backfill-queue.js +14 -0
  114. package/dist/lib/backfill-queue.js.map +1 -0
  115. package/dist/lib/blockers.d.ts +66 -0
  116. package/dist/lib/blockers.js +103 -0
  117. package/dist/lib/blockers.js.map +1 -0
  118. package/dist/lib/claims.d.ts +39 -0
  119. package/dist/lib/claims.js +133 -0
  120. package/dist/lib/claims.js.map +1 -0
  121. package/dist/lib/classify-debt.d.ts +17 -0
  122. package/dist/lib/classify-debt.js +13 -0
  123. package/dist/lib/classify-debt.js.map +1 -0
  124. package/dist/lib/code-evidence.d.ts +35 -0
  125. package/dist/lib/code-evidence.js +171 -0
  126. package/dist/lib/code-evidence.js.map +1 -0
  127. package/dist/lib/coherence.d.ts +14 -0
  128. package/dist/lib/coherence.js +188 -0
  129. package/dist/lib/coherence.js.map +1 -0
  130. package/dist/lib/completion-gate.d.ts +17 -0
  131. package/dist/lib/completion-gate.js +28 -0
  132. package/dist/lib/completion-gate.js.map +1 -0
  133. package/dist/lib/compliance-signoff.d.ts +39 -0
  134. package/dist/lib/compliance-signoff.js +81 -0
  135. package/dist/lib/compliance-signoff.js.map +1 -0
  136. package/dist/lib/config.d.ts +63 -0
  137. package/dist/lib/config.js +40 -0
  138. package/dist/lib/config.js.map +1 -0
  139. package/dist/lib/cost.d.ts +12 -0
  140. package/dist/lib/cost.js +12 -0
  141. package/dist/lib/cost.js.map +1 -0
  142. package/dist/lib/debt-dashboard.d.ts +25 -0
  143. package/dist/lib/debt-dashboard.js +36 -0
  144. package/dist/lib/debt-dashboard.js.map +1 -0
  145. package/dist/lib/embedding-store.d.ts +103 -0
  146. package/dist/lib/embedding-store.js +133 -0
  147. package/dist/lib/embedding-store.js.map +1 -0
  148. package/dist/lib/embeddings-source.d.ts +36 -0
  149. package/dist/lib/embeddings-source.js +62 -0
  150. package/dist/lib/embeddings-source.js.map +1 -0
  151. package/dist/lib/enforcement-allowlist.d.ts +12 -0
  152. package/dist/lib/enforcement-allowlist.js +25 -0
  153. package/dist/lib/enforcement-allowlist.js.map +1 -0
  154. package/dist/lib/events.d.ts +47 -0
  155. package/dist/lib/events.js +75 -0
  156. package/dist/lib/events.js.map +1 -0
  157. package/dist/lib/exec.d.ts +8 -0
  158. package/dist/lib/exec.js +25 -0
  159. package/dist/lib/exec.js.map +1 -0
  160. package/dist/lib/frontmatter.d.ts +112 -0
  161. package/dist/lib/frontmatter.js +261 -0
  162. package/dist/lib/frontmatter.js.map +1 -0
  163. package/dist/lib/funnel.d.ts +22 -0
  164. package/dist/lib/funnel.js +41 -0
  165. package/dist/lib/funnel.js.map +1 -0
  166. package/dist/lib/git-mtime.d.ts +4 -0
  167. package/dist/lib/git-mtime.js +23 -0
  168. package/dist/lib/git-mtime.js.map +1 -0
  169. package/dist/lib/metrics.d.ts +42 -0
  170. package/dist/lib/metrics.js +92 -0
  171. package/dist/lib/metrics.js.map +1 -0
  172. package/dist/lib/migration-collision.d.ts +20 -0
  173. package/dist/lib/migration-collision.js +61 -0
  174. package/dist/lib/migration-collision.js.map +1 -0
  175. package/dist/lib/next-action.d.ts +44 -0
  176. package/dist/lib/next-action.js +138 -0
  177. package/dist/lib/next-action.js.map +1 -0
  178. package/dist/lib/ollama-embed.d.ts +21 -0
  179. package/dist/lib/ollama-embed.js +65 -0
  180. package/dist/lib/ollama-embed.js.map +1 -0
  181. package/dist/lib/output.d.ts +35 -0
  182. package/dist/lib/output.js +46 -0
  183. package/dist/lib/output.js.map +1 -0
  184. package/dist/lib/pipeline-config.d.ts +20 -0
  185. package/dist/lib/pipeline-config.js +208 -0
  186. package/dist/lib/pipeline-config.js.map +1 -0
  187. package/dist/lib/pipeline-map.d.ts +68 -0
  188. package/dist/lib/pipeline-map.js +256 -0
  189. package/dist/lib/pipeline-map.js.map +1 -0
  190. package/dist/lib/pipeline-schema.d.ts +48 -0
  191. package/dist/lib/pipeline-schema.js +22 -0
  192. package/dist/lib/pipeline-schema.js.map +1 -0
  193. package/dist/lib/placement.d.ts +6 -0
  194. package/dist/lib/placement.js +40 -0
  195. package/dist/lib/placement.js.map +1 -0
  196. package/dist/lib/precedent-search.d.ts +18 -0
  197. package/dist/lib/precedent-search.js +160 -0
  198. package/dist/lib/precedent-search.js.map +1 -0
  199. package/dist/lib/predicate-registry.d.ts +6 -0
  200. package/dist/lib/predicate-registry.js +40 -0
  201. package/dist/lib/predicate-registry.js.map +1 -0
  202. package/dist/lib/recall-cases.d.ts +15 -0
  203. package/dist/lib/recall-cases.js +39 -0
  204. package/dist/lib/recall-cases.js.map +1 -0
  205. package/dist/lib/repo.d.ts +20 -0
  206. package/dist/lib/repo.js +82 -0
  207. package/dist/lib/repo.js.map +1 -0
  208. package/dist/lib/requirements.d.ts +91 -0
  209. package/dist/lib/requirements.js +179 -0
  210. package/dist/lib/requirements.js.map +1 -0
  211. package/dist/lib/rollup.d.ts +24 -0
  212. package/dist/lib/rollup.js +34 -0
  213. package/dist/lib/rollup.js.map +1 -0
  214. package/dist/lib/scorecard-run.d.ts +6 -0
  215. package/dist/lib/scorecard-run.js +48 -0
  216. package/dist/lib/scorecard-run.js.map +1 -0
  217. package/dist/lib/scorecard.d.ts +69 -0
  218. package/dist/lib/scorecard.js +113 -0
  219. package/dist/lib/scorecard.js.map +1 -0
  220. package/dist/lib/semantic-search.d.ts +36 -0
  221. package/dist/lib/semantic-search.js +56 -0
  222. package/dist/lib/semantic-search.js.map +1 -0
  223. package/dist/lib/session-state.d.ts +8 -0
  224. package/dist/lib/session-state.js +25 -0
  225. package/dist/lib/session-state.js.map +1 -0
  226. package/dist/lib/spec-debt.d.ts +8 -0
  227. package/dist/lib/spec-debt.js +17 -0
  228. package/dist/lib/spec-debt.js.map +1 -0
  229. package/dist/lib/spec-pure.d.ts +59 -0
  230. package/dist/lib/spec-pure.js +215 -0
  231. package/dist/lib/spec-pure.js.map +1 -0
  232. package/dist/lib/specs.d.ts +148 -0
  233. package/dist/lib/specs.js +373 -0
  234. package/dist/lib/specs.js.map +1 -0
  235. package/dist/lib/test-generator.d.ts +5 -0
  236. package/dist/lib/test-generator.js +72 -0
  237. package/dist/lib/test-generator.js.map +1 -0
  238. package/dist/lib/user-stories.d.ts +6 -0
  239. package/dist/lib/user-stories.js +56 -0
  240. package/dist/lib/user-stories.js.map +1 -0
  241. package/dist/lib/verifies-scan.d.ts +9 -0
  242. package/dist/lib/verifies-scan.js +73 -0
  243. package/dist/lib/verifies-scan.js.map +1 -0
  244. package/dist/lib/verify-core.d.ts +23 -0
  245. package/dist/lib/verify-core.js +48 -0
  246. package/dist/lib/verify-core.js.map +1 -0
  247. package/dist/lib/with-event-log.d.ts +12 -0
  248. package/dist/lib/with-event-log.js +65 -0
  249. package/dist/lib/with-event-log.js.map +1 -0
  250. package/dist/lib/wizard-specs.d.ts +17 -0
  251. package/dist/lib/wizard-specs.js +34 -0
  252. package/dist/lib/wizard-specs.js.map +1 -0
  253. package/dist/pure.d.ts +19 -0
  254. package/dist/pure.js +31 -0
  255. package/dist/pure.js.map +1 -0
  256. package/package.json +69 -0
@@ -0,0 +1,188 @@
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { join, relative } from 'node:path';
3
+ import { runScript } from './exec.js';
4
+ import { readFrontmatter, stripFrontmatter } from './frontmatter.js';
5
+ /**
6
+ * Find `{core}_*` / `pf_*` table names referenced by a spec that ALREADY EXIST
7
+ * in a committed migration. This is the complement of the `missing-table-migration`
8
+ * coherence warning: instead of "spec proposes a table with no migration", it
9
+ * surfaces "spec references a table that is already implemented" — the signal
10
+ * that a new spec may be duplicating an existing feature rather than extending it.
11
+ * Advisory only; the human confirms extend-vs-duplicate.
12
+ */
13
+ /** A status value that indicates the spec has already shipped — for these, references
14
+ * to existing tables are the spec's OWN production migrations, not a
15
+ * duplicate-vs-extend signal. */
16
+ const COMPLETE_STATUS_VALUE_RE = /^(?:✅|complete|implemented)/i;
17
+ const COMPLETE_STATUS_PROSE_RE = /^\*\*Status:\*\*\s*(?:✅|complete|implemented)/im;
18
+ /** Lifecycle-complete check: frontmatter `status:` wins when present and non-empty;
19
+ * the body `**Status:**` prose line is fallback only (mirrors listSpecs in specs.ts). */
20
+ function isLifecycleComplete(specText) {
21
+ const fm = readFrontmatter(specText);
22
+ const fmStatus = typeof fm.status === 'string' && fm.status.trim() !== '' ? fm.status.trim() : undefined;
23
+ if (fmStatus !== undefined)
24
+ return COMPLETE_STATUS_VALUE_RE.test(fmStatus);
25
+ return COMPLETE_STATUS_PROSE_RE.test(stripFrontmatter(specText));
26
+ }
27
+ export function findExistingTableReferences(repoRoot, specId, core) {
28
+ const specPath = resolveSpecPath(repoRoot, core, specId);
29
+ if (!specPath)
30
+ return [];
31
+ const specText = readSafe(specPath);
32
+ // Lifecycle-aware: an implemented spec referencing existing tables is by definition
33
+ // pointing at its own production migrations. Skip the advisory in that case.
34
+ if (isLifecycleComplete(specText))
35
+ return [];
36
+ const migrationsDir = join(repoRoot, 'supabase', 'migrations');
37
+ if (!existsSync(migrationsDir))
38
+ return [];
39
+ const tables = extractTableNames(specText, core);
40
+ const files = readdirSync(migrationsDir)
41
+ .filter((f) => f.endsWith('.sql'))
42
+ .sort();
43
+ const out = [];
44
+ for (const table of tables) {
45
+ const tableRegex = new RegExp(`\\bcreate\\s+table\\b[\\s\\S]{0,200}\\b${escapeRegex(table)}\\b`, 'i');
46
+ for (const file of files) {
47
+ if (tableRegex.test(readSafe(join(migrationsDir, file)))) {
48
+ out.push({ table, migration: file });
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+ export function evaluateCoherence(repoRoot, specId, core) {
56
+ const warnings = [];
57
+ const specPath = resolveSpecPath(repoRoot, core, specId);
58
+ if (!specPath)
59
+ return { warnings };
60
+ const specText = readSafe(specPath);
61
+ const taskPath = join(repoRoot, 'specs', core, 'tasks', `${specId}-TASKS.md`);
62
+ const tasksText = readSafe(taskPath);
63
+ const migrationText = readMigrationText(repoRoot);
64
+ for (const table of extractTableNames(specText, core)) {
65
+ const tableRegex = new RegExp(`\\bcreate\\s+table\\b[\\s\\S]{0,200}\\b${escapeRegex(table)}\\b`, 'i');
66
+ if (!tableRegex.test(migrationText)) {
67
+ warnings.push({
68
+ type: 'missing-table-migration',
69
+ message: `No migration CREATE TABLE reference found for ${table}`,
70
+ });
71
+ }
72
+ }
73
+ const taskPaths = extractTaskPaths(tasksText);
74
+ for (const taskFile of taskPaths.files) {
75
+ const absolute = join(repoRoot, taskFile);
76
+ if (!existsSync(absolute)) {
77
+ warnings.push({
78
+ type: 'missing-task-path',
79
+ message: `Task references missing path: ${taskFile}`,
80
+ });
81
+ }
82
+ }
83
+ const allFiles = listAllFiles(repoRoot);
84
+ for (const pattern of taskPaths.testPatterns) {
85
+ if (!matchesAnyFile(allFiles, pattern)) {
86
+ warnings.push({
87
+ type: 'missing-test-pattern',
88
+ message: `Task test pattern has no matching files: ${pattern}`,
89
+ });
90
+ }
91
+ }
92
+ return { warnings };
93
+ }
94
+ function resolveSpecPath(repoRoot, core, specId) {
95
+ // Wizard/UX specs live in `ux/`, base specs in `specs/` — scan both (mirrors listSpecs).
96
+ for (const sub of ['specs', 'ux']) {
97
+ const dir = join(repoRoot, 'specs', core, sub);
98
+ if (!existsSync(dir))
99
+ continue;
100
+ for (const file of readdirSync(dir)) {
101
+ if (!file.endsWith('.md'))
102
+ continue;
103
+ if (file.startsWith(`${specId}-`)) {
104
+ return join(dir, file);
105
+ }
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+ function readSafe(path) {
111
+ if (!existsSync(path))
112
+ return '';
113
+ return readFileSync(path, 'utf8');
114
+ }
115
+ function readMigrationText(repoRoot) {
116
+ const migrationsDir = join(repoRoot, 'supabase', 'migrations');
117
+ if (!existsSync(migrationsDir))
118
+ return '';
119
+ let combined = '';
120
+ for (const file of readdirSync(migrationsDir)) {
121
+ if (!file.endsWith('.sql'))
122
+ continue;
123
+ combined += `\n${readSafe(join(migrationsDir, file))}`;
124
+ }
125
+ return combined;
126
+ }
127
+ function extractTableNames(specText, core) {
128
+ const matches = specText.match(/\b[a-z]{2,3}_[a-z0-9_]+\b/g) ?? [];
129
+ const allowedPrefixes = new Set([`${core.toLowerCase()}_`, 'pf_']);
130
+ const out = new Set();
131
+ for (const table of matches) {
132
+ if ([...allowedPrefixes].some((prefix) => table.startsWith(prefix))) {
133
+ out.add(table);
134
+ }
135
+ }
136
+ return [...out];
137
+ }
138
+ function extractTaskPaths(tasksText) {
139
+ const files = new Set();
140
+ const testPatterns = new Set();
141
+ const backticks = [...tasksText.matchAll(/`([^`\n]+)`/g)].map((m) => m[1] ?? '');
142
+ for (const token of backticks) {
143
+ if (token.includes('*') && (token.includes('.test.') || token.includes('.spec.') || token.includes('.rls.'))) {
144
+ testPatterns.add(token);
145
+ continue;
146
+ }
147
+ if (token.includes('/') && !token.startsWith('npm ') && !token.startsWith('node ')) {
148
+ files.add(token);
149
+ }
150
+ }
151
+ return { files: [...files], testPatterns: [...testPatterns] };
152
+ }
153
+ function listAllFiles(repoRoot) {
154
+ const gitFiles = runScript(['git', 'ls-files'], repoRoot);
155
+ if (gitFiles.exitCode === 0 && gitFiles.stdout.trim()) {
156
+ return gitFiles.stdout
157
+ .split('\n')
158
+ .map((line) => line.trim())
159
+ .filter(Boolean);
160
+ }
161
+ const out = [];
162
+ walk(repoRoot, repoRoot, out);
163
+ return out;
164
+ }
165
+ function walk(root, dir, out) {
166
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
167
+ if (entry.name === '.git' || entry.name === 'node_modules')
168
+ continue;
169
+ const abs = join(dir, entry.name);
170
+ if (entry.isDirectory()) {
171
+ walk(root, abs, out);
172
+ continue;
173
+ }
174
+ out.push(relative(root, abs));
175
+ }
176
+ }
177
+ function matchesAnyFile(files, pattern) {
178
+ const regex = globToRegex(pattern);
179
+ return files.some((f) => regex.test(f));
180
+ }
181
+ function globToRegex(pattern) {
182
+ const escaped = escapeRegex(pattern).replace(/\\\*/g, '.*');
183
+ return new RegExp(`^${escaped}$`);
184
+ }
185
+ function escapeRegex(value) {
186
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
187
+ }
188
+ //# sourceMappingURL=coherence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coherence.js","sourceRoot":"","sources":["../../src/lib/coherence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SpecFile } from './specs.js';
2
+ export type GateVerdict = {
3
+ ok: true;
4
+ } | {
5
+ ok: false;
6
+ reason: string;
7
+ };
8
+ /**
9
+ * UI-evidence completion gate (Epic C1). A UI-bearing spec must carry both
10
+ * docshot evidence and a browser auto-heal sign-off before it can claim
11
+ * `status: complete` — the exact predicates the navigator enforces in its
12
+ * mark-complete tail (next.ts implementOrComplete). A `ui-gate-waived` marker
13
+ * is an explicit, dated escape. Pure: reads only the precomputed signals so the
14
+ * inline (complete.ts) and corpus (check-ui-completion-evidence.ts) call sites
15
+ * cannot diverge.
16
+ */
17
+ export declare function uiEvidenceGate(spec: SpecFile): GateVerdict;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * UI-evidence completion gate (Epic C1). A UI-bearing spec must carry both
3
+ * docshot evidence and a browser auto-heal sign-off before it can claim
4
+ * `status: complete` — the exact predicates the navigator enforces in its
5
+ * mark-complete tail (next.ts implementOrComplete). A `ui-gate-waived` marker
6
+ * is an explicit, dated escape. Pure: reads only the precomputed signals so the
7
+ * inline (complete.ts) and corpus (check-ui-completion-evidence.ts) call sites
8
+ * cannot diverge.
9
+ */
10
+ export function uiEvidenceGate(spec) {
11
+ const s = spec.signals;
12
+ if (!s.isUiBearing)
13
+ return { ok: true };
14
+ if (s.hasUiGateWaiver)
15
+ return { ok: true };
16
+ if (s.hasDocshots && s.hasHealSignoff)
17
+ return { ok: true };
18
+ const missing = [];
19
+ if (!s.hasDocshots)
20
+ missing.push('docshots');
21
+ if (!s.hasHealSignoff)
22
+ missing.push('heal-verified sign-off');
23
+ return {
24
+ ok: false,
25
+ reason: `UI-bearing spec missing ${missing.join(' + ')} — complete the verification tail or waive with \`eos-spec signoff --type ui-gate-waived --spec ${spec.id}\``,
26
+ };
27
+ }
28
+ //# sourceMappingURL=completion-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-gate.js","sourceRoot":"","sources":["../../src/lib/completion-gate.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IACvB,IAAI,CAAC,CAAC,CAAC,WAAW;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,CAAC,eAAe;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,cAAc;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,CAAC,CAAC,WAAW;QAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC,CAAC,cAAc;QAAE,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC9D,OAAO;QACL,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,2BAA2B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,mGAAmG,IAAI,CAAC,EAAE,IAAI;KACrK,CAAC;AACJ,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Compliance regimes the per-spec sign-off can record a determination against.
3
+ * Derived from the existing trackers under `docs/compliance/*_TRACKING.md` (and
4
+ * `docs/compliance/ONC_*`), NOT invented:
5
+ * - 42-cfr-part-2 (SUD — RH/CE trackers)
6
+ * - hipaa-164 (45 CFR 164 — RH/CE trackers)
7
+ * - onc-170.315 (ONC certification criteria — ONC_CERTIFICATION_*)
8
+ * - fcra / tcpa (FCRA_TCPA_COMPLIANCE_TRACKING.md)
9
+ * - ahcccs (AZ Medicaid)
10
+ * - carf (GR accreditation — GR_GOVERNANCE_COMPLIANCE_TRACKING.md)
11
+ * - samhsa (FA/GR federal-award reporting)
12
+ * - dhs-licensure (RH_RECOVERY_HOUSING_COMPLIANCE_TRACKING.md)
13
+ * - can-spam (CE_COMMUNICATIONS_COMPLIANCE_TRACKING.md)
14
+ */
15
+ export declare const COMPLIANCE_REGIMES: readonly ["42-cfr-part-2", "hipaa-164", "onc-170.315", "fcra", "tcpa", "ahcccs", "carf", "samhsa", "dhs-licensure", "can-spam"];
16
+ export type ComplianceRegime = (typeof COMPLIANCE_REGIMES)[number];
17
+ /** Per-regime determination status. */
18
+ export declare const DETERMINATION_STATUSES: readonly ["reviewed", "not-applicable", "deferred"];
19
+ export type DeterminationStatus = (typeof DETERMINATION_STATUSES)[number];
20
+ export interface Determination {
21
+ regime: ComplianceRegime;
22
+ status: DeterminationStatus;
23
+ note?: string;
24
+ }
25
+ export interface ComplianceSignoffParse {
26
+ valid: boolean;
27
+ errors: string[];
28
+ reviewer?: string;
29
+ date?: string;
30
+ determinations: Determination[];
31
+ }
32
+ /**
33
+ * Parse + validate a `{ID}-COMPLIANCE-SIGNOFF.md` body. Never throws — a missing
34
+ * or malformed frontmatter block returns `{ valid: false, errors: [...] }` so the
35
+ * gate can warn rather than crash. `valid` requires: a matching `spec_id`, a
36
+ * non-empty `reviewer`, an ISO `date`, and at least one determination whose
37
+ * `regime` is a known regime and `status` is a known status.
38
+ */
39
+ export declare function parseComplianceSignoff(text: string, expectedSpecId: string): ComplianceSignoffParse;
@@ -0,0 +1,81 @@
1
+ import { readFrontmatter } from './frontmatter.js';
2
+ /**
3
+ * Compliance regimes the per-spec sign-off can record a determination against.
4
+ * Derived from the existing trackers under `docs/compliance/*_TRACKING.md` (and
5
+ * `docs/compliance/ONC_*`), NOT invented:
6
+ * - 42-cfr-part-2 (SUD — RH/CE trackers)
7
+ * - hipaa-164 (45 CFR 164 — RH/CE trackers)
8
+ * - onc-170.315 (ONC certification criteria — ONC_CERTIFICATION_*)
9
+ * - fcra / tcpa (FCRA_TCPA_COMPLIANCE_TRACKING.md)
10
+ * - ahcccs (AZ Medicaid)
11
+ * - carf (GR accreditation — GR_GOVERNANCE_COMPLIANCE_TRACKING.md)
12
+ * - samhsa (FA/GR federal-award reporting)
13
+ * - dhs-licensure (RH_RECOVERY_HOUSING_COMPLIANCE_TRACKING.md)
14
+ * - can-spam (CE_COMMUNICATIONS_COMPLIANCE_TRACKING.md)
15
+ */
16
+ export const COMPLIANCE_REGIMES = [
17
+ '42-cfr-part-2',
18
+ 'hipaa-164',
19
+ 'onc-170.315',
20
+ 'fcra',
21
+ 'tcpa',
22
+ 'ahcccs',
23
+ 'carf',
24
+ 'samhsa',
25
+ 'dhs-licensure',
26
+ 'can-spam',
27
+ ];
28
+ /** Per-regime determination status. */
29
+ export const DETERMINATION_STATUSES = ['reviewed', 'not-applicable', 'deferred'];
30
+ const REGIME_SET = new Set(COMPLIANCE_REGIMES);
31
+ const STATUS_SET = new Set(DETERMINATION_STATUSES);
32
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
33
+ /**
34
+ * Parse + validate a `{ID}-COMPLIANCE-SIGNOFF.md` body. Never throws — a missing
35
+ * or malformed frontmatter block returns `{ valid: false, errors: [...] }` so the
36
+ * gate can warn rather than crash. `valid` requires: a matching `spec_id`, a
37
+ * non-empty `reviewer`, an ISO `date`, and at least one determination whose
38
+ * `regime` is a known regime and `status` is a known status.
39
+ */
40
+ export function parseComplianceSignoff(text, expectedSpecId) {
41
+ const fm = readFrontmatter(text);
42
+ const errors = [];
43
+ const specId = typeof fm.spec_id === 'string' ? fm.spec_id.trim() : '';
44
+ if (!specId) {
45
+ errors.push('missing spec_id');
46
+ }
47
+ else if (specId.toUpperCase() !== expectedSpecId.toUpperCase()) {
48
+ errors.push(`spec_id "${specId}" does not match expected "${expectedSpecId}"`);
49
+ }
50
+ const reviewer = typeof fm.reviewer === 'string' && fm.reviewer.trim() !== '' ? fm.reviewer.trim() : undefined;
51
+ if (!reviewer)
52
+ errors.push('missing reviewer');
53
+ const date = typeof fm.date === 'string' && DATE_RE.test(fm.date.trim()) ? fm.date.trim() : undefined;
54
+ if (!date)
55
+ errors.push('missing or malformed date (expected YYYY-MM-DD)');
56
+ const rawDet = Array.isArray(fm.determinations) ? fm.determinations : [];
57
+ const determinations = [];
58
+ if (rawDet.length === 0) {
59
+ errors.push('determinations: at least one determination is required');
60
+ }
61
+ for (let i = 0; i < rawDet.length; i++) {
62
+ const d = rawDet[i];
63
+ const regime = d && typeof d.regime === 'string' ? d.regime.trim() : '';
64
+ const status = d && typeof d.status === 'string' ? d.status.trim() : '';
65
+ const regimeOk = REGIME_SET.has(regime);
66
+ const statusOk = STATUS_SET.has(status);
67
+ if (!regimeOk) {
68
+ errors.push(`determinations[${i}]: unknown regime "${regime}"`);
69
+ }
70
+ if (!statusOk) {
71
+ errors.push(`determinations[${i}]: invalid status "${status}" (expected reviewed | not-applicable | deferred)`);
72
+ }
73
+ if (!regimeOk || !statusOk) {
74
+ continue;
75
+ }
76
+ const note = d && typeof d.note === 'string' && d.note.trim() !== '' ? d.note.trim() : undefined;
77
+ determinations.push({ regime: regime, status: status, note });
78
+ }
79
+ return { valid: errors.length === 0, errors, reviewer, date, determinations };
80
+ }
81
+ //# sourceMappingURL=compliance-signoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compliance-signoff.js","sourceRoot":"","sources":["../../src/lib/compliance-signoff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export type CoreDef = {
2
+ id: string;
3
+ name: string;
4
+ architectural_role?: string;
5
+ };
6
+ export type StatusDef = {
7
+ id: string;
8
+ label: string;
9
+ description: string;
10
+ };
11
+ export type ArchivePolicy = {
12
+ enabled: boolean;
13
+ trigger: string;
14
+ threshold_days: number;
15
+ destination: string;
16
+ preserves: string[];
17
+ removes_from: string[];
18
+ };
19
+ export type SpecConfig = {
20
+ version: number;
21
+ last_updated: string;
22
+ cores: CoreDef[];
23
+ statuses: StatusDef[];
24
+ paths: {
25
+ specs: string;
26
+ plans: string;
27
+ tasks: string;
28
+ archive: string;
29
+ };
30
+ templates: Record<string, string | Record<string, string>>;
31
+ hard_gates: Array<{
32
+ rule: string;
33
+ description: string;
34
+ enforced_in: string[];
35
+ applies_to_cores?: string[];
36
+ tags: string[];
37
+ }>;
38
+ commands: {
39
+ unified: Record<string, string>;
40
+ legacy: Record<string, string>;
41
+ };
42
+ archive: ArchivePolicy;
43
+ delta_types: string[];
44
+ defaults: Record<string, unknown>;
45
+ per_core_phase_reference?: string;
46
+ /** Per-consumer embedding-index location, consumed via the EmbeddingsSource seam
47
+ * (lib/embeddings-source.ts). Absent ⇒ the legacy fork-layout defaults. The
48
+ * package carries NO corpus data; each consumer points at its own. */
49
+ embeddings?: {
50
+ /** Dir holding the committed index (manifest + matrix + recall vectors), relative to repo root. */
51
+ data_dir?: string;
52
+ /** Path to the generated spec-index.json (freshness corpus), relative to repo root. */
53
+ spec_index_path?: string;
54
+ };
55
+ };
56
+ export declare function loadConfig(repoRoot: string, configOverride?: string): SpecConfig;
57
+ export declare function resetConfigCache(): void;
58
+ export declare function coresFromConfig(config: SpecConfig): string[];
59
+ export declare function isKnownCoreFromConfig(config: SpecConfig, core: string): boolean;
60
+ /** Resolve a flat template key (e.g. 'full_spec', 'plan') to its path relative to repo root. */
61
+ export declare function resolveTemplatePath(config: SpecConfig, key: string): string | null;
62
+ /** Get the archive directory path pattern from config. */
63
+ export declare function archiveDestination(config: SpecConfig): string;
@@ -0,0 +1,40 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ let cached = null;
5
+ let cachedPath = null;
6
+ export function loadConfig(repoRoot, configOverride) {
7
+ const configPath = configOverride ?? join(repoRoot, 'specs', 'config.yaml');
8
+ if (cached && cachedPath === configPath)
9
+ return cached;
10
+ if (!existsSync(configPath)) {
11
+ throw new Error(`Spec config not found: ${configPath}`);
12
+ }
13
+ const raw = readFileSync(configPath, 'utf8');
14
+ const parsed = parseYaml(raw);
15
+ cached = parsed;
16
+ cachedPath = configPath;
17
+ return parsed;
18
+ }
19
+ export function resetConfigCache() {
20
+ cached = null;
21
+ cachedPath = null;
22
+ }
23
+ export function coresFromConfig(config) {
24
+ return config.cores.map((c) => c.id);
25
+ }
26
+ export function isKnownCoreFromConfig(config, core) {
27
+ return coresFromConfig(config).includes(core.toLowerCase());
28
+ }
29
+ /** Resolve a flat template key (e.g. 'full_spec', 'plan') to its path relative to repo root. */
30
+ export function resolveTemplatePath(config, key) {
31
+ const val = config.templates[key];
32
+ if (typeof val === 'string')
33
+ return val;
34
+ return null;
35
+ }
36
+ /** Get the archive directory path pattern from config. */
37
+ export function archiveDestination(config) {
38
+ return config.archive.destination;
39
+ }
40
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAwD1C,IAAI,MAAM,GAAsB,IAAI,CAAC;AACrC,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,cAAuB;IAClE,MAAM,UAAU,GAAG,cAAc,IAAI,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAE5E,IAAI,MAAM,IAAI,UAAU,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC;IAEvD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAe,CAAC;IAC5C,MAAM,GAAG,MAAM,CAAC;IAChB,UAAU,GAAG,UAAU,CAAC;IACxB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,IAAI,CAAC;IACd,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAkB;IAChD,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAkB,EAAE,IAAY;IACpE,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,MAAkB,EAAE,GAAW;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,kBAAkB,CAAC,MAAkB;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;AACpC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /** Per-1M-token rates in USD. Kept in sync with automation/_platform/ai-call.ts MODEL_RATES.
2
+ * Cross-package import is blocked by tools/eos-spec's tsconfig rootDir; tests assert parity. */
3
+ export declare const MODEL_RATES: Record<string, {
4
+ promptPer1m: number;
5
+ completionPer1m: number;
6
+ }>;
7
+ export type AiTokens = {
8
+ prompt: number;
9
+ completion: number;
10
+ total: number;
11
+ };
12
+ export declare function computeCostUsd(model: string, tokens: AiTokens): number | null;
@@ -0,0 +1,12 @@
1
+ /** Per-1M-token rates in USD. Kept in sync with automation/_platform/ai-call.ts MODEL_RATES.
2
+ * Cross-package import is blocked by tools/eos-spec's tsconfig rootDir; tests assert parity. */
3
+ export const MODEL_RATES = {
4
+ 'anthropic/claude-sonnet-4': { promptPer1m: 3, completionPer1m: 15 },
5
+ };
6
+ export function computeCostUsd(model, tokens) {
7
+ const rate = MODEL_RATES[model];
8
+ if (!rate)
9
+ return null;
10
+ return (tokens.prompt * rate.promptPer1m + tokens.completion * rate.completionPer1m) / 1_000_000;
11
+ }
12
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/lib/cost.ts"],"names":[],"mappings":"AAAA;iGACiG;AACjG,MAAM,CAAC,MAAM,WAAW,GAAqE;IAC3F,2BAA2B,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE;CACrE,CAAC;AAIF,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,MAAgB;IAC5D,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;AACnG,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface DebtRow {
2
+ id: string;
3
+ claimed: string;
4
+ tier: string;
5
+ honestStatus: string;
6
+ missing: string[];
7
+ effort: 'S' | 'M' | 'L';
8
+ /** Optional per-row evidence note surfaced in a trailing Notes column for human review. */
9
+ reason?: string;
10
+ }
11
+ export interface RelinkEntry {
12
+ id: string;
13
+ reason: string;
14
+ }
15
+ export interface DashboardOptions {
16
+ /** T1 rows whose tests exist but whose @verifies linkage is broken — listed for hand-relinking, not downgrade. */
17
+ relinkQueue?: RelinkEntry[];
18
+ }
19
+ /**
20
+ * Render a per-core verification-debt dashboard as Markdown. One row per claimed-complete spec with
21
+ * its computed tier, honest status, missing artifacts, and effort. A trailing Notes column carries
22
+ * the code-evidence reason when present (purely for human review). Optionally appends a Relink queue
23
+ * section for T1 specs (tests exist, linkage broken) — these are NOT downgraded by `--apply`.
24
+ */
25
+ export declare function renderDebtDashboard(core: string, rows: DebtRow[], options?: DashboardOptions): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Render a per-core verification-debt dashboard as Markdown. One row per claimed-complete spec with
3
+ * its computed tier, honest status, missing artifacts, and effort. A trailing Notes column carries
4
+ * the code-evidence reason when present (purely for human review). Optionally appends a Relink queue
5
+ * section for T1 specs (tests exist, linkage broken) — these are NOT downgraded by `--apply`.
6
+ */
7
+ export function renderDebtDashboard(core, rows, options = {}) {
8
+ const hasNotes = rows.some((r) => r.reason && r.reason.trim() !== '');
9
+ const head = hasNotes
10
+ ? '| Spec | Claimed | Tier | Real status | Missing artifacts | Effort | Notes |\n' +
11
+ '|------|---------|------|-------------|-------------------|--------|-------|\n'
12
+ : '| Spec | Claimed | Tier | Real status | Missing artifacts | Effort |\n' +
13
+ '|------|---------|------|-------------|-------------------|--------|\n';
14
+ const header = `# Verification Debt — ${core.toUpperCase()}\n\n` +
15
+ `> Generated by \`eos-spec backfill --core ${core}\`. Do not hand-edit.\n\n` +
16
+ head;
17
+ const body = rows
18
+ .map((r) => {
19
+ const cells = [r.id, r.claimed, r.tier, r.honestStatus, r.missing.join(', ') || '—', r.effort];
20
+ if (hasNotes)
21
+ cells.push((r.reason ?? '').replace(/\|/g, '\\|'));
22
+ return `| ${cells.join(' | ')} |`;
23
+ })
24
+ .join('\n');
25
+ let out = `${header}${body}\n`;
26
+ const relink = options.relinkQueue ?? [];
27
+ if (relink.length > 0) {
28
+ const lines = relink.map((e) => `- **${e.id}** — ${e.reason}`).join('\n');
29
+ out +=
30
+ `\n## Relink queue\n\n` +
31
+ `> Tests exist but \`@verifies\` linkage is broken (undeclared/typo'd ids). ` +
32
+ `Status is NOT downgraded; re-link the backlinks instead.\n\n${lines}\n`;
33
+ }
34
+ return out;
35
+ }
36
+ //# sourceMappingURL=debt-dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debt-dashboard.js","sourceRoot":"","sources":["../../src/lib/debt-dashboard.ts"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,IAAe,EAAE,UAA4B,EAAE;IAC/F,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,QAAQ;QACnB,CAAC,CAAC,gFAAgF;YAChF,gFAAgF;QAClF,CAAC,CAAC,wEAAwE;YACxE,wEAAwE,CAAC;IAE7E,MAAM,MAAM,GACV,yBAAyB,IAAI,CAAC,WAAW,EAAE,MAAM;QACjD,6CAA6C,IAAI,2BAA2B;QAC5E,IAAI,CAAC;IAEP,MAAM,IAAI,GAAG,IAAI;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/F,IAAI,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QACjE,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACpC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,IAAI,GAAG,GAAG,GAAG,MAAM,GAAG,IAAI,IAAI,CAAC;IAE/B,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IACzC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1E,GAAG;YACD,uBAAuB;gBACvB,6EAA6E;gBAC7E,+DAA+D,KAAK,IAAI,CAAC;IAC7E,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}