@konneal/engine 0.1.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 (285) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +13 -0
  3. package/dist/admin.d.ts +26 -0
  4. package/dist/ai.d.ts +6 -0
  5. package/dist/anchors.d.ts +6 -0
  6. package/dist/answercache.d.ts +22 -0
  7. package/dist/ask.d.ts +5 -0
  8. package/dist/auth.d.ts +12 -0
  9. package/dist/bubble.d.ts +14 -0
  10. package/dist/chunk-LLWPT2XV.js +49 -0
  11. package/dist/chunk-MB74PTRM.js +114 -0
  12. package/dist/chunk-WOGQM7DJ.js +197 -0
  13. package/dist/chunk-WWNCWKKC.js +42 -0
  14. package/dist/completion.d.ts +5 -0
  15. package/dist/config.d.ts +154 -0
  16. package/dist/config.js +37 -0
  17. package/dist/context.d.ts +115 -0
  18. package/dist/conversations.d.ts +5 -0
  19. package/dist/drafts.d.ts +129 -0
  20. package/dist/env.d.ts +57 -0
  21. package/dist/faithfulness.d.ts +5 -0
  22. package/dist/grader.d.ts +3 -0
  23. package/dist/graph.d.ts +13 -0
  24. package/dist/hybrid.d.ts +7 -0
  25. package/dist/index.d.ts +9 -0
  26. package/dist/index.js +5373 -0
  27. package/dist/internal_gateway.d.ts +14 -0
  28. package/dist/lexical.d.ts +7 -0
  29. package/dist/livedata.d.ts +77 -0
  30. package/dist/memories.d.ts +10 -0
  31. package/dist/modelplane.d.ts +61 -0
  32. package/dist/oidc.d.ts +73 -0
  33. package/dist/pipeline.d.ts +57 -0
  34. package/dist/profile.d.ts +2 -0
  35. package/dist/profile.gen.d.ts +70 -0
  36. package/dist/profile.js +8 -0
  37. package/dist/projects.d.ts +8 -0
  38. package/dist/prompts/conversational.md +8 -0
  39. package/dist/prompts/enrichment.md +3 -0
  40. package/dist/prompts/faithfulness.md +1 -0
  41. package/dist/prompts/grader.md +5 -0
  42. package/dist/prompts/listwise.md +3 -0
  43. package/dist/prompts/precision.md +1 -0
  44. package/dist/prompts/reflect.md +1 -0
  45. package/dist/prompts/relevancy.md +1 -0
  46. package/dist/prompts/research.md +10 -0
  47. package/dist/prompts/section-summary.md +5 -0
  48. package/dist/prompts/summarize.md +1 -0
  49. package/dist/prompts/system.md +18 -0
  50. package/dist/prompts/understanding.md +17 -0
  51. package/dist/quota.d.ts +13 -0
  52. package/dist/reflect.d.ts +5 -0
  53. package/dist/refs.d.ts +40 -0
  54. package/dist/refusal.d.ts +9 -0
  55. package/dist/refusal.js +9 -0
  56. package/dist/requestScope.d.ts +26 -0
  57. package/dist/requestScope.js +10 -0
  58. package/dist/research.d.ts +8 -0
  59. package/dist/search.d.ts +4 -0
  60. package/dist/selfquery.d.ts +7 -0
  61. package/dist/session.d.ts +1 -0
  62. package/dist/share.d.ts +2 -0
  63. package/dist/structural.d.ts +27 -0
  64. package/dist/tablecontext.d.ts +11 -0
  65. package/dist/understand.d.ts +11 -0
  66. package/dist/understandContract.d.ts +29 -0
  67. package/dist/verdict.d.ts +24 -0
  68. package/docs/API.md +451 -0
  69. package/docs/ARCHITECTURE.md +302 -0
  70. package/docs/AUDIT-2026-08-24.md +71 -0
  71. package/docs/CONTRIBUTOR-AUDIT-2026-08-25.md +147 -0
  72. package/docs/INGEST-ARCHITECTURE.md +158 -0
  73. package/docs/MCP.md +92 -0
  74. package/docs/METANORMA-AI-SERIALIZATION.md +247 -0
  75. package/docs/MKO-EXPORT-PIPELINE.md +147 -0
  76. package/docs/REDESIGN-NORMATIVE-RAG-ETSI.md +485 -0
  77. package/docs/RESEARCH-SOTA-2026.md +243 -0
  78. package/docs/ROADMAP-SOTA.md +130 -0
  79. package/docs/SOTA-STAGE-SPECS.md +509 -0
  80. package/docs/annealment/F1-verdict.md +27 -0
  81. package/docs/annealment/F10-notes.md +19 -0
  82. package/docs/annealment/F11-composition.md +17 -0
  83. package/docs/annealment/F12-passport.md +17 -0
  84. package/docs/annealment/F2-counterfactual.md +20 -0
  85. package/docs/annealment/F3-absence.md +21 -0
  86. package/docs/annealment/F4-instance.md +18 -0
  87. package/docs/annealment/F5-workflow.md +21 -0
  88. package/docs/annealment/F6-impact.md +21 -0
  89. package/docs/annealment/F7-editions.md +18 -0
  90. package/docs/annealment/F8-selfverify.md +19 -0
  91. package/docs/annealment/F9-projection-qa.md +17 -0
  92. package/docs/annealment/L0-locate.md +19 -0
  93. package/docs/annealment/L1-extract.md +18 -0
  94. package/docs/annealment/L2-nomenclature.md +22 -0
  95. package/docs/annealment/L3-geometry.md +23 -0
  96. package/docs/annealment/L4-composition.md +21 -0
  97. package/docs/annealment/L5-cross-standard.md +20 -0
  98. package/docs/annealment/L6-diachrony.md +21 -0
  99. package/docs/annealment/L7-perception.md +20 -0
  100. package/docs/annealment/L8-computation.md +22 -0
  101. package/docs/annealment/L9-instance-process.md +23 -0
  102. package/docs/annealment/README.md +10 -0
  103. package/docs/guidelines-metanorma-ai-programme.md +279 -0
  104. package/docs/identity-onboarding-rag.md +65 -0
  105. package/docs/identity-service.md +219 -0
  106. package/docs/knowledge-annealment.md +273 -0
  107. package/docs/konneal-extraction-plan.md +481 -0
  108. package/docs/metanorma-for-ai.md +270 -0
  109. package/docs/mirror-plan.md +36 -0
  110. package/docs/multi-sdo-architecture.md +191 -0
  111. package/docs/paper-annealment-comparison.md +259 -0
  112. package/docs/paper-assets/architecture.svg +94 -0
  113. package/docs/paper-assets/contract-v2.svg +94 -0
  114. package/docs/paper-assets/mko-ingest.svg +91 -0
  115. package/docs/paper-oiml-bulletin.md +402 -0
  116. package/docs/paper-oiml-bulletin.mdx +419 -0
  117. package/docs/product-branding-options.md +172 -0
  118. package/docs/projects-design.md +88 -0
  119. package/docs/sota-mechanisms.md +184 -0
  120. package/docs/spec-api.md +77 -0
  121. package/docs/spec-pipeline.md +126 -0
  122. package/docs/vector-adapter.md +88 -0
  123. package/package.json +70 -0
  124. package/profile/corpora.yaml +5 -0
  125. package/profile/datasets.yaml +14 -0
  126. package/profile/prompts.yaml +5 -0
  127. package/profile/publisher.yaml +17 -0
  128. package/profile/retrieval.yaml +1 -0
  129. package/profile/sources.yaml +5 -0
  130. package/profile/ui.yaml +7 -0
  131. package/scripts/gen_profile.mjs +33 -0
  132. package/workers/shared/ai.ts +21 -0
  133. package/workers/shared/auth.ts +16 -0
  134. package/workers/shared/chunk.ts +108 -0
  135. package/workers/shared/oidc.ts +312 -0
  136. package/workers/shared/router.ts +45 -0
  137. package/workers/shared/session.ts +104 -0
  138. package/workers/worker_internal/src/index.ts +157 -0
  139. package/workers/worker_internal/tsconfig.json +15 -0
  140. package/workers/worker_internal/wrangler.toml +32 -0
  141. package/workers/worker_mcp/src/index.ts +175 -0
  142. package/workers/worker_mcp/tsconfig.json +13 -0
  143. package/workers/worker_mcp/wrangler.toml +18 -0
  144. package/workers/worker_public/migrations/0002_conversations.sql +22 -0
  145. package/workers/worker_public/migrations/0003_shared_conversations.sql +9 -0
  146. package/workers/worker_public/migrations/0004_graph.sql +16 -0
  147. package/workers/worker_public/migrations/0005_documents.sql +19 -0
  148. package/workers/worker_public/migrations/0006_conversation_entities.sql +11 -0
  149. package/workers/worker_public/migrations/0007_chunks_fts.sql +43 -0
  150. package/workers/worker_public/migrations/0008_unit_payloads.sql +15 -0
  151. package/workers/worker_public/migrations/0009_chunks_unit.sql +8 -0
  152. package/workers/worker_public/migrations/0009_message_context.sql +7 -0
  153. package/workers/worker_public/migrations/0010_model_nodes.sql +33 -0
  154. package/workers/worker_public/migrations/0011_schema_union.sql +38 -0
  155. package/workers/worker_public/migrations/0012_memories.sql +15 -0
  156. package/workers/worker_public/migrations/0013_projects.sql +21 -0
  157. package/workers/worker_public/node_modules/@cloudflare/workers-types/2021-11-03/index.d.ts +16306 -0
  158. package/workers/worker_public/node_modules/@cloudflare/workers-types/2021-11-03/index.ts +16261 -0
  159. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-01-31/index.d.ts +16373 -0
  160. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-01-31/index.ts +16328 -0
  161. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-03-21/index.d.ts +16382 -0
  162. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-03-21/index.ts +16337 -0
  163. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-08-04/index.d.ts +16383 -0
  164. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-08-04/index.ts +16338 -0
  165. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-10-31/index.d.ts +16403 -0
  166. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-10-31/index.ts +16358 -0
  167. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-11-30/index.d.ts +16408 -0
  168. package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-11-30/index.ts +16363 -0
  169. package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-03-01/index.d.ts +16414 -0
  170. package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-03-01/index.ts +16369 -0
  171. package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-07-01/index.d.ts +16414 -0
  172. package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-07-01/index.ts +16369 -0
  173. package/workers/worker_public/node_modules/@cloudflare/workers-types/README.md +135 -0
  174. package/workers/worker_public/node_modules/@cloudflare/workers-types/entrypoints.svg +53 -0
  175. package/workers/worker_public/node_modules/@cloudflare/workers-types/experimental/index.d.ts +17095 -0
  176. package/workers/worker_public/node_modules/@cloudflare/workers-types/experimental/index.ts +17050 -0
  177. package/workers/worker_public/node_modules/@cloudflare/workers-types/index.d.ts +16306 -0
  178. package/workers/worker_public/node_modules/@cloudflare/workers-types/index.ts +16261 -0
  179. package/workers/worker_public/node_modules/@cloudflare/workers-types/latest/index.d.ts +16447 -0
  180. package/workers/worker_public/node_modules/@cloudflare/workers-types/latest/index.ts +16402 -0
  181. package/workers/worker_public/node_modules/@cloudflare/workers-types/oldest/index.d.ts +16306 -0
  182. package/workers/worker_public/node_modules/@cloudflare/workers-types/oldest/index.ts +16261 -0
  183. package/workers/worker_public/node_modules/@cloudflare/workers-types/package.json +11 -0
  184. package/workers/worker_public/package.json +13 -0
  185. package/workers/worker_public/prompts/conversational.md +8 -0
  186. package/workers/worker_public/prompts/enrichment.md +3 -0
  187. package/workers/worker_public/prompts/faithfulness.md +1 -0
  188. package/workers/worker_public/prompts/grader.md +5 -0
  189. package/workers/worker_public/prompts/listwise.md +3 -0
  190. package/workers/worker_public/prompts/precision.md +1 -0
  191. package/workers/worker_public/prompts/reflect.md +1 -0
  192. package/workers/worker_public/prompts/relevancy.md +1 -0
  193. package/workers/worker_public/prompts/research.md +10 -0
  194. package/workers/worker_public/prompts/section-summary.md +5 -0
  195. package/workers/worker_public/prompts/summarize.md +1 -0
  196. package/workers/worker_public/prompts/system.md +18 -0
  197. package/workers/worker_public/prompts/understanding.md +17 -0
  198. package/workers/worker_public/public/app.js +166 -0
  199. package/workers/worker_public/public/index.html +48 -0
  200. package/workers/worker_public/public/style.css +147 -0
  201. package/workers/worker_public/schema.sql +248 -0
  202. package/workers/worker_public/src/admin.ts +358 -0
  203. package/workers/worker_public/src/ai.ts +71 -0
  204. package/workers/worker_public/src/anchors.ts +41 -0
  205. package/workers/worker_public/src/answercache.ts +72 -0
  206. package/workers/worker_public/src/ask.ts +1094 -0
  207. package/workers/worker_public/src/auth.ts +252 -0
  208. package/workers/worker_public/src/bubble.ts +111 -0
  209. package/workers/worker_public/src/completion.ts +75 -0
  210. package/workers/worker_public/src/config.ts +238 -0
  211. package/workers/worker_public/src/context.ts +238 -0
  212. package/workers/worker_public/src/conversations.ts +162 -0
  213. package/workers/worker_public/src/drafts.ts +497 -0
  214. package/workers/worker_public/src/env.ts +90 -0
  215. package/workers/worker_public/src/faithfulness.ts +63 -0
  216. package/workers/worker_public/src/grader.ts +89 -0
  217. package/workers/worker_public/src/graph.ts +63 -0
  218. package/workers/worker_public/src/hybrid.ts +77 -0
  219. package/workers/worker_public/src/index.ts +441 -0
  220. package/workers/worker_public/src/internal_gateway.ts +41 -0
  221. package/workers/worker_public/src/lexical.ts +86 -0
  222. package/workers/worker_public/src/lib/hit.ts +4 -0
  223. package/workers/worker_public/src/lib/http.ts +83 -0
  224. package/workers/worker_public/src/lib/router.ts +4 -0
  225. package/workers/worker_public/src/livedata.ts +334 -0
  226. package/workers/worker_public/src/memories.ts +81 -0
  227. package/workers/worker_public/src/modelplane.ts +213 -0
  228. package/workers/worker_public/src/oidc.ts +333 -0
  229. package/workers/worker_public/src/pipeline.ts +377 -0
  230. package/workers/worker_public/src/ports/blobs.ts +7 -0
  231. package/workers/worker_public/src/ports/cloudflare/adapters.ts +177 -0
  232. package/workers/worker_public/src/ports/kv.ts +8 -0
  233. package/workers/worker_public/src/ports/model.ts +28 -0
  234. package/workers/worker_public/src/ports/runtime.ts +13 -0
  235. package/workers/worker_public/src/ports/store.ts +20 -0
  236. package/workers/worker_public/src/ports/vector.ts +26 -0
  237. package/workers/worker_public/src/profile.gen.ts +101 -0
  238. package/workers/worker_public/src/profile.ts +16 -0
  239. package/workers/worker_public/src/projects.ts +108 -0
  240. package/workers/worker_public/src/prompts.d.ts +6 -0
  241. package/workers/worker_public/src/quota.ts +54 -0
  242. package/workers/worker_public/src/reflect.ts +67 -0
  243. package/workers/worker_public/src/refs.ts +107 -0
  244. package/workers/worker_public/src/refusal.ts +65 -0
  245. package/workers/worker_public/src/requestScope.ts +71 -0
  246. package/workers/worker_public/src/research.ts +126 -0
  247. package/workers/worker_public/src/search.ts +56 -0
  248. package/workers/worker_public/src/selfquery.ts +25 -0
  249. package/workers/worker_public/src/session.ts +4 -0
  250. package/workers/worker_public/src/share.ts +53 -0
  251. package/workers/worker_public/src/stages/conceptGraph.ts +68 -0
  252. package/workers/worker_public/src/stages/conceptSteer.ts +39 -0
  253. package/workers/worker_public/src/stages/corpusScope.ts +25 -0
  254. package/workers/worker_public/src/stages/dedup.ts +10 -0
  255. package/workers/worker_public/src/stages/dense.ts +73 -0
  256. package/workers/worker_public/src/stages/diversity.ts +33 -0
  257. package/workers/worker_public/src/stages/editionCover.ts +63 -0
  258. package/workers/worker_public/src/stages/editionSteer.ts +88 -0
  259. package/workers/worker_public/src/stages/familyBoost.ts +22 -0
  260. package/workers/worker_public/src/stages/federate.ts +22 -0
  261. package/workers/worker_public/src/stages/glossary.ts +65 -0
  262. package/workers/worker_public/src/stages/graphLane.ts +31 -0
  263. package/workers/worker_public/src/stages/hyde.ts +29 -0
  264. package/workers/worker_public/src/stages/index.ts +69 -0
  265. package/workers/worker_public/src/stages/lexicalUnion.ts +21 -0
  266. package/workers/worker_public/src/stages/multiQuery.ts +57 -0
  267. package/workers/worker_public/src/stages/overviewDemote.ts +14 -0
  268. package/workers/worker_public/src/stages/poolOpen.ts +10 -0
  269. package/workers/worker_public/src/stages/propagate.ts +15 -0
  270. package/workers/worker_public/src/stages/rerank.ts +47 -0
  271. package/workers/worker_public/src/stages/seal.ts +16 -0
  272. package/workers/worker_public/src/stages/sectionDescent.ts +61 -0
  273. package/workers/worker_public/src/stages/stdRefNudge.ts +35 -0
  274. package/workers/worker_public/src/stages/subQuery.ts +42 -0
  275. package/workers/worker_public/src/stages/termNudge.ts +24 -0
  276. package/workers/worker_public/src/stages/typedPin.ts +131 -0
  277. package/workers/worker_public/src/stages/types.ts +112 -0
  278. package/workers/worker_public/src/stages/windowFloor.ts +23 -0
  279. package/workers/worker_public/src/structural.ts +171 -0
  280. package/workers/worker_public/src/tablecontext.ts +41 -0
  281. package/workers/worker_public/src/understand.ts +72 -0
  282. package/workers/worker_public/src/understandContract.ts +67 -0
  283. package/workers/worker_public/src/verdict.ts +255 -0
  284. package/workers/worker_public/tsconfig.json +18 -0
  285. package/workers/worker_public/wrangler.toml +104 -0
@@ -0,0 +1,302 @@
1
+ # OIML RAG Architecture — 2026-08-26
2
+
3
+ The complete serving pipeline, layer by layer. Every technique is
4
+ grounded in 2025/2026 research and running in production at
5
+ **ai.oimlsmart.org**. The layers below map 1:1 onto the stage registry
6
+ (`workers/worker_public/src/stages/` — per-stage contracts, guards and
7
+ failure modes in `docs/spec-pipeline.md`; the HTTP surface in
8
+ `docs/spec-api.md`).
9
+
10
+ ```
11
+ ┌─────────────────────────────────────────────────────────────────────┐
12
+ │ USER (browser / API) │
13
+ │ chat UI — Vue islands (Astro 7/Vite 8/Tailwind 4): sessions, │
14
+ │ fork, edit, export, markdown copy, globe spinner; suggestions + │
15
+ │ datasets panel render the API response verbatim (no hardcoded │
16
+ │ client content) │
17
+ │ ↓ SSE (stream:true, stop, prev, history[20]) │
18
+ ├─────────────────────────────────────────────────────────────────────┤
19
+ │ WORKER (rag-public) │
20
+ │ │
21
+ │ ┌─ 0. CONVERSATIONAL ROUTE (LLM-decided) ────────────────────────┐ │
22
+ │ │ understanding.intent: conversational | knowledge │ │
23
+ │ │ · greetings, identity, capability, small talk (ANY language) │ │
24
+ │ │ → answered directly from the DATASETS catalog facts │ │
25
+ │ │ (prompts/conversational.md), no retrieval, never refused │ │
26
+ │ │ · off-topic SUBJECT questions are knowledge (honest refusal │ │
27
+ │ │ + redirect) — "conversational" never means off-topic │ │
28
+ │ │ · asymmetric default: null/doubt → knowledge path │ │
29
+ │ └────────────────────────────────────────────────────────────────┘ │
30
+ │ ↓ │
31
+ │ ┌─ 1. QUERY UNDERSTANDING (LLM) ─────────────────────────────────┐ │
32
+ │ │ qwen3-30b-a3b → strict JSON (prompts/understanding.md): │ │
33
+ │ │ · intent (see layer 0) · docidentifier/docnumber │ │
34
+ │ │ · process_intent (certify/apply → B-series, not R-series) │ │
35
+ │ │ · term ("what is a load cell" → "load cell") │ │
36
+ │ │ · standalone_query (follow-ups folded with context) │ │
37
+ │ │ · complexity (simple vs complex → adaptive depth) │ │
38
+ │ │ · query_variants[2-3] (alternative phrasings for fusion) │ │
39
+ │ │ · sub_queries[2-4] (decomposition for complex questions) │ │
40
+ │ │ · hypothetical_answer (→ HyDE embedding) │ │
41
+ │ │ UNISON with deterministic regexes (union, not either-or) │ │
42
+ │ │ 1200 max_tokens (reasoning shares the budget), fresh call │ │
43
+ │ │ per retry, per-attempt timeouts 7s/4s; failure → vanilla │ │
44
+ │ └────────────────────────────────────────────────────────────────┘ │
45
+ │ │ Concurrently: the folded query is embedded while understanding │
46
+ │ │ runs (warm embedding) — reused whenever the final retrieval │
47
+ │ │ query is unchanged; understand→embed collapses to max() │ │
48
+ │ ↓ │
49
+ │ ┌─ 2. MULTI-QUERY RAG-FUSION ────────────────────────────────────┐ │
50
+ │ │ Primary query + each query_variant → own embedding │ │
51
+ │ │ Each → Vectorize query (topK=50, metadata-filtered) │ │
52
+ │ │ All rankings → Reciprocal Rank Fusion (k=60) │ │
53
+ │ │ Ref: RAG-Fusion paper; arXiv 2604.01733 (hybrid+RRF > alone) │ │
54
+ │ └────────────────────────────────────────────────────────────────┘ │
55
+ │ ↓ │
56
+ │ ┌─ 3. MULTI-HOP DECOMPOSITION (complex only) ────────────────────┐ │
57
+ │ │ Each sub_query → own embedding + Vectorize (topK=15) │ │
58
+ │ │ Results merged as complementary perspectives (union, 0.8×) │ │
59
+ │ │ Ref: Agent-Orchestrated Adaptive RAG (arXiv 2606.05658) │ │
60
+ │ └────────────────────────────────────────────────────────────────┘ │
61
+ │ ↓ │
62
+ │ ┌─ 4. OVERVIEW PENALTY + FAMILY BOOST ───────────────────────────┐ │
63
+ │ │ · Overview chunks ×0.85 (boilerplate drowns clause content) │ │
64
+ │ │ · Family chunks → top (multi-part structure: "R 60 = 3 │ │
65
+ │ │ parts + 1 annex") when doc-scoped query │ │
66
+ │ └────────────────────────────────────────────────────────────────┘ │
67
+ │ ↓ │
68
+ │ ┌─ 5. CROSS-ENCODER RERANKING ───────────────────────────────────┐ │
69
+ │ │ bge-reranker-base over all candidates │ │
70
+ │ │ Catches semantic relevance dense embeddings miss │ │
71
+ │ │ Retry ×2 on transient failure; vector order as fallback │ │
72
+ │ └────────────────────────────────────────────────────────────────┘ │
73
+ │ ↓ │
74
+ │ ┌─ 6. HYBRID SEARCH (BM25 + Dense + RRF) ────────────────────────┐ │
75
+ │ │ Keyword (lexical) scoring alongside rerank ranking │ │
76
+ │ │ RRF fusion (k=60) — catches exact terms ("n_LC", "R 60-3") │ │
77
+ │ │ Ref: arXiv 2604.01733; Denser.ai (RRF k=60 default) │ │
78
+ │ └────────────────────────────────────────────────────────────────┘ │
79
+ │ ↓ │
80
+ │ ┌─ 7. TERM BOOST + LANGUAGE NUDGE + EDITION RECENCY ─────────────┐ │
81
+ │ │ · Exact term match (clause_title/body starts with term) → │ │
82
+ │ │ decisive boost (definition questions) │ │
83
+ │ │ · Query language → prefer matching chunks (scaled to spread) │ │
84
+ │ │ · Edition recency → tie-break (newer > older, scaled) │ │
85
+ │ │ All boosts scaled to observed score spread │ │
86
+ │ └────────────────────────────────────────────────────────────────┘ │
87
+ │ ↓ │
88
+ │ ┌─ 8. DIVERSITY (per-publication caps) ──────────────────────────┐ │
89
+ │ │ · Overview: max 2 globally (6 for doc-scoped queries) │ │
90
+ │ │ · Clause: max 2 per docidentifier|language (3 for filtered) │ │
91
+ │ │ · Family chunks bypass (always included when relevant) │ │
92
+ │ └────────────────────────────────────────────────────────────────┘ │
93
+ │ ↓ │
94
+ │ ┌─ 9. CRAG GRADER ───────────────────────────────────────────────┐ │
95
+ │ │ deepseek-v4-flash grades passages good/weak/bad │ │
96
+ │ │ · good → generate │ │
97
+ │ │ · weak → ONE corrective re-retrieval (doc ident made │ │
98
+ │ │ explicit); accepted only on strictly better grade │ │
99
+ │ │ · bad → strict generation (refuses honestly) │ │
100
+ │ │ Ref: CRAG paper (arXiv 2401.15884) │ │
101
+ │ └────────────────────────────────────────────────────────────────┘ │
102
+ │ ↓ │
103
+ │ ┌─ 10. GENERATION ───────────────────────────────────────────────┐ │
104
+ │ │ Anon: qwen3-30b-a3b-fp8 | Member: qwen3.8-27b │ │
105
+ │ │ System prompt is DATA (prompts/system.md, {{PLACEHOLDERS}} │ │
106
+ │ │ filled from code; per-corpus notes travel with the DATASETS │ │
107
+ │ │ catalog entry) │ │
108
+ │ │ CONTEXT BUDGET (16k tokens est., CJK/Arabic-aware): │ │
109
+ │ │ · history 30% slice, newest-first, turns clipped 600 tok │ │
110
+ │ │ · overflow turns SUMMARIZED into a continuity block │ │
111
+ │ │ (prompts/summarize.md) — never silently dropped │ │
112
+ │ │ · passages fill the rest, best-ranked first, 900 tok/chunk │ │
113
+ │ │ · citations built from passages actually included │ │
114
+ │ │ Streaming SSE (3072 max_tokens, reasoning_effort: low) │ │
115
+ │ │ Strict grounding + mandatory process-answer rule; refusals │ │
116
+ │ │ canonicalized to the exact contract sentence (model │ │
117
+ │ │ paraphrases are normalized server-side) │ │
118
+ │ │ Citations sorted: in-force → unknown → superseded/withdrawn │ │
119
+ │ └────────────────────────────────────────────────────────────────┘ │
120
+ │ ↓ │
121
+ │ ┌─ 11. SELF-RAG REFLECTION ──────────────────────────────────────┐ │
122
+ │ │ Model critiques: is every claim grounded in the passages? │ │
123
+ │ │ If not → re-retrieve targeting missing info → regenerate │ │
124
+ │ │ (max one retry; better-grounded answer wins) │ │
125
+ │ │ Ref: selfrag.github.io; arXiv 2606.05658 (bounded reflection) │ │
126
+ │ └────────────────────────────────────────────────────────────────┘ │
127
+ │ ↓ │
128
+ │ ┌─ 12. ANSWER CACHE (KV) ────────────────────────────────────────┐ │
129
+ │ │ Keyed on INDEX_VERSION + query + lang │ │
130
+ │ │ · Cache hit → SSE stream (must speak SSE) │ │
131
+ │ │ · Regenerate (fresh=true) → skip cache read │ │
132
+ │ │ · Contextual follow-ups → skip cache entirely │ │
133
+ │ │ · Refusals are NEVER cached (they describe the moment, not │ │
134
+ │ │ the question — a cached refusal poisons retries) │ │
135
+ │ │ INDEX_VERSION bumped on any retrieval/logic change │ │
136
+ │ └────────────────────────────────────────────────────────────────┘ │
137
+ │ │
138
+ ├─────────────────────────────────────────────────────────────────────┤
139
+ │ INDEX PIPELINE (ingest) │
140
+ │ │
141
+ │ ┌─ Source Corpora ────────────────────────────────────────────────┐│
142
+ │ │ Clean: mn-samples-oiml (29 curated Metanorma collections) ││
143
+ │ │ Dirty: publications-private (880 OCR-derived docs) ││
144
+ │ │ ISO: smartcab-refs (16 ISO/IEC, internal-only, pending) ││
145
+ │ │ Precedence: clean wins over dirty on overlap ││
146
+ │ └────────────────────────────────────────────────────────────────┘│
147
+ │ ↓ │
148
+ │ ┌─ Extraction ────────────────────────────────────────────────────┐│
149
+ │ │ HTML-first: BeautifulSoup over compiled Metanorma HTML ││
150
+ │ │ · Rendered tables (caption + rows) ││
151
+ │ │ · Clause-number anchors from heading text ││
152
+ │ │ · Literal-tag stripping (OCR `<td>` artifacts) ││
153
+ │ │ · GUID anchor dropping (machine-generated ids) ││
154
+ │ │ · collection.yml manifest as identity authority ││
155
+ │ │ English-only (user directive; language detection from ││
156
+ │ │ slug suffixes + adoc attrs) ││
157
+ │ └────────────────────────────────────────────────────────────────┘│
158
+ │ ↓ │
159
+ │ ┌─ Family Chunks ─────────────────────────────────────────────────┐│
160
+ │ │ 47 synthetic chunks encoding multi-part structure ││
161
+ │ │ ("OIML R 60 comprises 3 parts and 1 annex") ││
162
+ │ │ Deterministic IDs (content-hashed for re-embedding on ││
163
+ │ │ text change) ││
164
+ │ └────────────────────────────────────────────────────────────────┘│
165
+ │ ↓ │
166
+ │ ┌─ Status Enrichment ─────────────────────────────────────────────┐│
167
+ │ │ relaton-data-oiml (5,707 YAML records) joined at ingest ││
168
+ │ │ · status: in-force / superseded / withdrawn / joint ││
169
+ │ │ · superseded_by: successor identifier ││
170
+ │ └────────────────────────────────────────────────────────────────┘│
171
+ │ ↓ │
172
+ │ ┌─ Contextual Enrichment (RUNNING over 31k chunks) ───────────────┐│
173
+ │ │ Anthropic contextual retrieval technique ││
174
+ │ │ POST /admin/enrich (Bearer ADMIN_TOKEN): deepseek-v4-pro ││
175
+ │ │ writes a 1-sentence situating context per chunk ││
176
+ │ │ (prompts/enrichment.md; 1600 max_tokens — reasoning ││
177
+ │ │ models starve below that), KV-cached 30d per chunk id; ││
178
+ │ │ context+text re-embedded and upserted in place (ctx flag) ││
179
+ │ │ Driver: ingest/enrich.py — paced (--rpm), rate-aware ││
180
+ │ │ backoff on Workers AI 3021s, resumable state file; ││
181
+ │ │ ~$0.0015/chunk → ≈$50 one-time (quality-first lane) ││
182
+ │ └────────────────────────────────────────────────────────────────┘│
183
+ │ ↓ │
184
+ │ ┌─ Embedding + Indexing ──────────────────────────────────────────┐│
185
+ │ │ @cf/qwen/qwen3-embedding-0.6b (1024-dim, 100+ languages) ││
186
+ │ │ → Vectorize idx_oiml_public_v2 (cosine, 31k English vectors) ││
187
+ │ │ Metadata indexes: doctype, doc_number, edition, language ││
188
+ │ │ Resumable embed (25/batch, per-item fallback) ││
189
+ │ │ Resumable upsert (batch cursor, idempotent) ││
190
+ │ │ Orphan deletion (stale IDs purged on re-index) ││
191
+ │ └────────────────────────────────────────────────────────────────┘│
192
+ │ │
193
+ ├─────────────────────────────────────────────────────────────────────┤
194
+ │ EVALUATION │
195
+ │ │
196
+ │ ┌─ Golden Set (19 cases) ────────────────────────────────────────┐│
197
+ │ │ Doc-level, definitions, table values, edition filters, ││
198
+ │ │ multilingual, refusals, leakage probes, process intent, ││
199
+ │ │ family structure, test report forms ││
200
+ │ │ npm run test:golden (90% threshold, exit 1 on regression) ││
201
+ │ └────────────────────────────────────────────────────────────────┘│
202
+ │ ┌─ Faithfulness (RAGAS-style) ────────────────────────────────────┐│
203
+ │ │ LLM-as-judge: every claim grounded in passages? (0-1) ││
204
+ │ │ Reported per case + averaged in eval-report.json ││
205
+ │ │ Ref: docs.ragas.io faithfulness metric ││
206
+ │ └────────────────────────────────────────────────────────────────┘│
207
+ │ ┌─ Live E2E (13 cases) ───────────────────────────────────────────┐│
208
+ │ │ Health, ask quality, citations, refusals + redirect, meta ││
209
+ │ │ turns (EN/FR/DE), 200-word questions, French, auth, quotas ││
210
+ │ │ tests/e2e.mjs ││
211
+ │ └────────────────────────────────────────────────────────────────┘│
212
+ │ ┌─ Retrieval eval (hit@5) ─────────────────────────────────────────┐│
213
+ │ │ Golden cases + 8 vocabulary-mismatch PARAPHRASE probes ││
214
+ │ │ (the contextual-enrichment failure mode) via /v1/search; ││
215
+ │ │ snapshots to artifacts/eval/ for before/after lift ││
216
+ │ │ tests/retrieval.mjs ││
217
+ │ └────────────────────────────────────────────────────────────────┘│
218
+ │ ┌─ UI (Playwright, 30 checks, runs in CI) ─────────────────────────┐│
219
+ │ │ Real Chromium over the built site with stubbed APIs (SSE ││
220
+ │ │ included): ask/stream/citations/superseded badges/sessions ││
221
+ │ │ CRUD/filter/persistence/XSS safety. tests/ui.mjs; CI also ││
222
+ │ │ builds the site for real (site-shell checked out) ││
223
+ │ └────────────────────────────────────────────────────────────────┘│
224
+ │ ┌─ Browser E2E ────────────────────────────────────────────────────┐│
225
+ │ │ Production layout + console-error probe. tests/browser.mjs ││
226
+ │ └────────────────────────────────────────────────────────────────┘│
227
+ │ │
228
+ ├─────────────────────────────────────────────────────────────────────┤
229
+ │ AUTH & TIERS │
230
+ │ │
231
+ │ · OIDC RP on id.oimlsmart.org (authorization code + PKCE, │
232
+ │ ES256 via JWKS, RFC 8414 discovery) │
233
+ │ · RAG-minted HMAC session cookie (7-day, sliding renewal) │
234
+ │ · Anon: 20/day per IP (KV counter) │
235
+ │ · Member: 300/day, qwen3.8-27b model │
236
+ │ · API key: per-key limits, D1-backed │
237
+ │ · Operator IP exemption (env + KV override) │
238
+ │ · Role-gated datasets panel (ISO corpus: mc_member, etc.) │
239
+ │ · Conversations D1 API (member-only, sub-keyed) │
240
+ │ │
241
+ ├─────────────────────────────────────────────────────────────────────┤
242
+ │ TECHNIQUE PROVENANCE │
243
+ │ │
244
+ │ ┌────────────────────────────┬───────────────────────────────────┐│
245
+ │ │ Technique │ Source ││
246
+ │ ├────────────────────────────┼───────────────────────────────────┤│
247
+ │ │ Query understanding (LLM) │ Agentic RAG survey (2501.09136) ││
248
+ │ │ Multi-query RAG-Fusion │ RAG-Fusion paper (Semantic ││
249
+ │ │ │ Scholar b4d1da74) ││
250
+ │ │ Hybrid search (BM25+RRF) │ arXiv 2604.01733; Denser.ai ││
251
+ │ │ Cross-encoder reranking │ Standard (bge-reranker-base) ││
252
+ │ │ CRAG corrective grading │ arXiv 2401.15884 ││
253
+ │ │ Self-RAG reflection │ selfrag.github.io ││
254
+ │ │ Adaptive decomposition │ arXiv 2606.05658 ││
255
+ │ │ Contextual enrichment │ anthropic.com/engineering/ ││
256
+ │ │ │ contextual-retrieval ││
257
+ │ │ Late chunking (alternative) │ arXiv 2409.04701 ││
258
+ │ │ RAGAS faithfulness │ docs.ragas.io ││
259
+ │ │ Family chunks │ novel (metanorma/metanorma#592) ││
260
+ │ │ Publication status marking │ novel (relaton join at ingest) ││
261
+ │ └────────────────────────────┴───────────────────────────────────┘│
262
+ │ │
263
+ │ NOT YET IMPLEMENTED │
264
+ │ │
265
+ │ · GraphRAG (knowledge graph over terms/documents) — vocab repo │
266
+ │ has 6,031 concepts; relaton has 5,707 relations │
267
+ │ · FLARE (forward-looking active retrieval) — predict next │
268
+ │ sentence to anticipate retrieval needs │
269
+ │ · Speculative RAG (parallel draft generation) │
270
+ │ · Turnstile/WAF (needs dashboard sitekey) │
271
+ │ │
272
+ │ Shipped since the 08-24 revision: HyDE (hypothetical-answer │
273
+ │ embedding via understanding), ISO internal tier + federated │
274
+ │ retrieval (worker_internal /retrieve + RRF), citation deep │
275
+ │ links (R2 renderings), shareable permalinks, contextual │
276
+ │ enrichment (running), conversational routing, context budget │
277
+ │ + compaction, prompts-as-data, CI with real site build + │
278
+ │ Playwright UI suite, retrieval eval harness │
279
+ └─────────────────────────────────────────────────────────────────────┘
280
+ ```
281
+
282
+
283
+ ## 2026-09 additions (delta over the 2026-08-26 map)
284
+
285
+ - **Multimodal generation**: figure units among the used passages attach
286
+ their R2 pixels to the glm-5.3-flash call (`attachFigureImages`) — the
287
+ model reads labels that exist only in the image. Users can attach a
288
+ photo (`image` data URL on /v1/ask, validated, 6MB) — text still drives
289
+ retrieval; image asks bypass both caches.
290
+ - **Edition steering**: family-relative demotion of superseded editions
291
+ (cross-publication recency kept); edition pins corroborated by the
292
+ corpus (<3 chunks → drop to doc-only). Fixed superseded-citation drift.
293
+ - **Citation labels**: model-facing passage headers and UI chips strip
294
+ OIML language markers, dedupe editions, never show UUID anchors.
295
+ - **Lexical lane carries unit identity** (chunks.unit_id/block) — typed
296
+ chunks arriving via BM25 keep their [[u:…]] contract.
297
+ - **Research loop**: keep-recent-10 context folding (older evidence as
298
+ digests) + per-round focus folding.
299
+ - **Witness-span eval**: a hit requires ≥75% containment of the golden
300
+ answer span (ETSI protocol); graph-lane probes.
301
+ - **Pipeline**: unit-level langid tags bilingual annexes; typed tables in
302
+ the lexical lane; `fts --incremental`; per-doc ingest resilience.
@@ -0,0 +1,71 @@
1
+ # Deep audit — 2026-08-24
2
+
3
+ Evidence-based review of code, architecture, UX, and results. Every finding
4
+ is grounded in this session's incidents, the live telemetry (642 asks, 7
5
+ failures, 0 feedback votes, 0 member conversations yet), and 2025/2026 RAG
6
+ literature. Fixed items are marked ✅ (this session); the rest are ranked.
7
+
8
+ ## 1. Results quality
9
+
10
+ | Finding | Status / Priority |
11
+ |---|---|
12
+ | Regex heuristics were the decision-maker between users and the model — the top defect source (E2-class hijack, glued `r60`, `de`-as-German, `forms`-drift). Replaced by an LLM query-understanding layer, **unioned** with the regexes (regex = tested floor, LLM = creative phrasings + context rewriting). Pure-LLM gating was tried and REJECTED with evidence: flaky JSON/latency lost the working expansions | ✅ shipped (understand.ts) |
13
+ | No corrective loop: weak retrieval went straight to generation | ✅ CRAG grader shipped (deepseek-v4-flash grades good/weak/bad; weak → one corrective re-retrieval, accepted only on a strictly better grade) |
14
+ | Exact-count/TOC questions ("how many forms") — honest partial answers; needs synopsis/TOC chunks or table extraction (see Metanorma-for-AI P1 tables) | Medium |
15
+ | Enrichment pass (contextual chunk prefixes, deepseek-v4-pro one-time) planned, never run — recall is the main retrieval ceiling | **High** |
16
+ | Terminology (vocab, 6,031 concepts) and relaton bibliography ingested only for status — exact definition lookup from Glossarist datasets unused | **High** (cheap, big quality win) |
17
+ | Doc-as-context mode (deepseek-v4-flash 1.31M ctx) for summarize-the-document questions — planned, not built | Medium |
18
+ | Graph-augmented retrieval (CLAUDE.md architecture) — not started | Low |
19
+ | Eval: 19 golden cases, manual runs, no trend history; no RAGAS-style faithfulness/relevancy metrics; 👍/👎 feedback never reviewed | **High** (nightly golden in CI + faithfulness scoring + feedback triage) |
20
+ | Multilingual: English-only corpus (user directive); French questions answered from EN sources — works; reversal requires interlinear alignment (mn-for-AI P2) | Recorded |
21
+
22
+ ## 2. Architecture
23
+
24
+ | Finding | Priority |
25
+ |---|---|
26
+ | worker_internal + ISO tier: datasets panel sells it, `idx_iso_internal` exists but is EMPTY — ingest smartcab-refs + federated internal worker | **Top gap** |
27
+ | KV quota counter is get→put (not atomic) — concurrent requests can exceed limits; Workers Rate Limiting binding is the proper primitive | Medium |
28
+ | No model fallback ladder (member qwen3.8-27b failure → 502; CLAUDE.md specifies a ladder ending at z.ai GLM) | Medium |
29
+ | D1 unbounded growth: queries/spend/feedback/conversations never pruned — retention cron + delete >90d | Medium |
30
+ | Session: 7d HMAC cookie, no OP revalidation mid-session; shorten members to 24h or re-check on /auth/me | Medium |
31
+ | Conversations API: member write path unrate-limited (ask quota doesn't cover message appends) | Medium |
32
+ | Deploy friction: INDEX_VERSION bumped 30+ times manually; stale-isolate poisoning twice → automate bump + 90s settle + smoke-test in a deploy script | **High** (scripts/deploy.sh) |
33
+ | Ingest is laptop-manual; weekly reindex cron in the architecture diagram isn't wired; scripts/ pile of one-offs → fold into ingest subcommands | Medium |
34
+ | Cloud sync is fire-and-forget (message loss on flaky networks); localStorage keeps last 100 convs only (silent guest loss) — outbox retry queue | Medium |
35
+ | Observability: telemetry exists but nobody looks — /v1/admin/stats + spend alerts (50/80/100) + error-rate dashboard | **High** |
36
+ | Turnstile absent (needs dashboard sitekey); hard cap 5000/day bounds worst case ≈ $2/day | Medium |
37
+
38
+ ## 3. Code quality
39
+
40
+ - `ui.ts` renderConversation duplicates beginAssistantMessage's done() — extract a shared renderAssistantBlock (Medium).
41
+ - Worker `any`-typing throughout (AI responses, env) — type the Workers AI result shapes (Low).
42
+ - `selfquery.ts` retained as the union's deterministic floor — now has tests via golden; keep frozen, no new heuristics without a golden case.
43
+ - linkifyCitations interpolates corpus identifiers into a title attribute — escape quotes (Low, hardening).
44
+ - No worker unit tests (vitest-pool-workers); ui.mjs is monolithic but effective.
45
+
46
+ ## 4. UX (remaining)
47
+
48
+ - **Citation deep links** — the biggest trust gap: citations show text but never link to the document. Link to oiml.org publication pages now; R2 clause-anchored renderings later (**High**).
49
+ - Share conversation permalinks (public read route + rate limit) — marketing value for a public service (Medium).
50
+ - Mobile: visualViewport handling for the composer above the keyboard; drawer focus-trap; aria-live is per-chat not per-message (Medium).
51
+ - /api page is stale — document /v1/ask+search, conversations, /auth/*, /api/datasets, keys (Medium).
52
+ - Feedback prompt is subtle — nudge after an answer settles; feedback is the eval flywheel and has 0 uses (Medium).
53
+ - UI strings are English-only; empty-state suggestions static (Low).
54
+
55
+ ## 5. What today's incidents taught (process)
56
+
57
+ 1. **Bugs clustered at heuristic boundaries** (regex layers) — the union architecture exists so no single layer gates silently.
58
+ 2. **Deploy propagation (~90s) + answer cache = poisoned cache** — twice. Automate the settle-and-smoke step.
59
+ 3. **Live verification beats type-checks** — every real bug today was caught by Playwright/D1 probes, none by tsc.
60
+
61
+ ## Sources (2025/2026 SOTA survey)
62
+
63
+ - [Engineering the RAG Stack: A Comprehensive Review (arXiv)](https://arxiv.org/html/2601.05264v1)
64
+ - [Agentic RAG with LangGraph — retrieval grading, rewriting, corrective loops](https://www.langchain.com/blog/agentic-rag-with-langgraph)
65
+ - [CRAG: Corrective Retrieval Augmented Generation (arXiv 2401.15884)](https://arxiv.org/html/2401.15884v3)
66
+ - [Corrective RAG workflow — Meilisearch](https://www.meilisearch.com/blog/corrective-rag)
67
+ - [GraphRAG vs CRAG vs Self-RAG — TowardsAI](https://pubs.towardsai.net/advanced-rag-comparing-graphrag-corrective-rag-and-self-rag-00491de494e4)
68
+ - [RAG best practices from 100+ teams — kapa.ai](https://www.kapa.ai/blog/rag-best-practices)
69
+ - [RAGAS metrics: faithfulness, answer relevancy](https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/faithfulness/)
70
+ - [RAGAS paper (arXiv 2309.15217)](https://arxiv.org/html/2309.15217v1)
71
+ - [From RAG to Context — 2025 review (RAGFlow)](https://ragflow.io/blog/rag-review-2025-from-rag-to-context)
@@ -0,0 +1,147 @@
1
+ # Contributor Audit — 2026-08-25
2
+
3
+ ## Verdict: REJECT the unstaged site/ changes
4
+
5
+ The contributor's changes convert the Astro site from **static output**
6
+ to **SSR on Cloudflare Workers** via `@astrojs/cloudflare`. This breaks
7
+ our architecture with zero functional benefit.
8
+
9
+ ### What the contributor did
10
+
11
+ | File | Change | Intent |
12
+ |------|--------|--------|
13
+ | `site/astro.config.mjs` | Added `adapter: cloudflare()` | Convert static → SSR |
14
+ | `site/package.json` | Added `@astrojs/cloudflare` dep | Enable SSR adapter |
15
+ | `site/tsconfig.json` | Added `worker-configuration.d.ts` include | Types for SSR runtime |
16
+ | `site/wrangler.jsonc` | NEW — second worker config | Deploy site as separate worker |
17
+ | `site/public/.assetsignore` | NEW — exclude `_worker.js` | Framework-fighting artifact |
18
+ | `site/public/spinning-globe-3d.js` | DELETED | We replaced with mini (intentional) |
19
+
20
+ ### Why this is wrong
21
+
22
+ **Our architecture** (documented in CLAUDE.md, docs/ARCHITECTURE.md):
23
+ ```
24
+ Browser → rag-public worker (ai.oimlsmart.org)
25
+ ├── / → static HTML from ASSETS binding
26
+ ├── /api/* → handler code
27
+ ├── /v1/* → handler code
28
+ └── /auth/* → handler code
29
+ ```
30
+ ONE worker. Static assets served through the worker's `[assets]` binding.
31
+ The chat app is a client-side SPA talking to the API via fetch.
32
+
33
+ **What the contributor's changes would produce:**
34
+ ```
35
+ Browser → which worker? (custom domain conflict)
36
+ ├── oimlsmart-rag-site (SSR worker)
37
+ │ └── / → server-rendered on every request
38
+ └── rag-public (API worker)
39
+ └── /api/* → handler code
40
+ ```
41
+ TWO workers. SSR compute on every page load. Custom domain routing
42
+ conflict. Cold starts for a page that was previously instant static HTML.
43
+
44
+ ### Specific violations
45
+
46
+ 1. **Breaks single-worker deployment** — `site/wrangler.jsonc` creates
47
+ a second deployment target (`oimlsmart-rag-site`) that conflicts with
48
+ `workers/worker_public/wrangler.toml` for the custom domain.
49
+
50
+ 2. **SSR is unnecessary** — the site has zero server-side rendering
51
+ needs. It's a chat UI that loads once and talks to the API via
52
+ fetch/SSE. Adding SSR adds compute cost and cold starts with no benefit.
53
+
54
+ 3. **Framework-fighting artifacts** — the `.assetsignore` file exists
55
+ solely to work around the adapter generating `_worker.js` in the
56
+ public directory. This is the framework telling you it doesn't fit.
57
+
58
+ 4. **Incomplete** — `@astrojs/cloudflare` is in package.json but
59
+ package-lock.json wasn't updated (0 new packages found). The
60
+ contributor didn't even install/test their own changes.
61
+
62
+ 5. **Violates CLAUDE.md ecosystem constraints** — "Deployment is purely
63
+ Cloudflare" is about the PLATFORM, not about adding more workers.
64
+ The minimal-infrastructure principle means one worker, not two.
65
+
66
+ ### What to do
67
+
68
+ Revert all unstaged changes in `site/`:
69
+ ```bash
70
+ git checkout -- site/astro.config.mjs site/package.json site/tsconfig.json
71
+ rm site/wrangler.jsonc site/public/.assetsignore
72
+ ```
73
+
74
+ If SSR is ever genuinely needed (e.g., for A/B testing, edge-side
75
+ personalization, or server components), it should be an explicit
76
+ architectural decision with a written proposal — not a drive-by adapter.
77
+
78
+ ---
79
+
80
+ ## Our code — quality audit
81
+
82
+ ### DRY violations (medium priority)
83
+
84
+ - `json()` and `err()` helpers duplicated in **3 files**: index.ts,
85
+ conversations.ts, share.ts. Extract to `src/lib/http.ts`.
86
+
87
+ - `Hit` construction (`matches.map((m) => ({ id: m.id, score: m.score,
88
+ metadata: m.metadata, text: ... }))`) duplicated **5 times** in
89
+ pipeline.ts (primary, fallback, RAG-Fusion variants, HyDE, multi-hop).
90
+ Extract to `toHit(m: any): Hit`.
91
+
92
+ ### OCP violations (medium priority)
93
+
94
+ - **Router**: 16-branch if-chain in a 636-line index.ts. Adding a route
95
+ requires editing the router AND creating a handler — the router should
96
+ be a declarative route table (Map of path patterns to handlers). New
97
+ route = new entry, no router modification.
98
+
99
+ - **Pipeline**: the `retrieve()` function at 377 lines contains all
100
+ retrieval techniques inline (embedding, vector search, HyDE, multi-query
101
+ fusion, multi-hop decomposition, overview penalty, family boost,
102
+ reranking, keyword ranking, RRF fusion, term boost, language nudge,
103
+ edition boost, diversity). Each new technique modifies the function.
104
+ Should be a composable pipeline: `const hits = pipe(query,
105
+ understanding, [embed, search, hyde, fuseVariants, decompose,
106
+ rerank, hybrid, boost, diversify])`.
107
+
108
+ ### `any` typing (low priority)
109
+
110
+ Worker code uses `any` for env bindings, AI responses, and metadata.
111
+ The Workers AI result shapes are known at each call site. Reduce by
112
+ defining interfaces for the response shapes we actually use.
113
+
114
+ ### MECE concerns
115
+
116
+ - `pipeline.ts` does retrieval + ranking + citation building + message
117
+ building — at least 4 responsibilities. Should be:
118
+ - `retrieval.ts` (embed, search, fuse)
119
+ - `ranking.ts` (rerank, boost, diversify)
120
+ - `citations.ts` (citation building)
121
+ - `messages.ts` (LLM message assembly)
122
+
123
+ - `ui.ts` at 506 lines duplicates assistant-message rendering between
124
+ `beginAssistantMessage.done()` and `renderConversation` — extract a
125
+ shared `renderAssistantContent(wrap, msg, handlers)`.
126
+
127
+ ### Missing tests
128
+
129
+ - No worker unit tests (vitest-pool-workers or miniflare). Route
130
+ handlers, retrieval pipeline stages, and auth logic are only tested
131
+ via live e2e. The retrieval pipeline especially would benefit from
132
+ deterministic unit tests (mock the AI bindings, verify ranking logic).
133
+
134
+ ### Recommended cleanup (prioritized)
135
+
136
+ 1. Reject contributor changes (above)
137
+ 2. Extract `lib/http.ts` (json/err helpers) — 30 minutes
138
+ 3. Extract `toHit()` helper — 15 minutes
139
+ 4. Route table replacing if-chain — 1 hour
140
+ 5. Pipeline middleware chain — 2 hours (careful: must preserve all
141
+ test behavior)
142
+ 6. Split pipeline.ts into retrieval/ranking/citations/messages — 1 hour
143
+ 7. Worker unit tests with miniflare — 2 hours
144
+ 8. Type Workers AI response shapes — 1 hour
145
+
146
+ Total: ~8 hours of cleanup. Can be done incrementally; each step is
147
+ independently valuable.