@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,65 @@
1
+ # The RAG service's identity onboarding — what to fix now
2
+
3
+ The companion to docs/identity-service.md (the general guide): the
4
+ RAG-specific fix-and-verify list. The OP side is done — the
5
+ `oiml-rag` client is registered and ACTIVE (public PKCE client;
6
+ `claims_policy: { "claims": ["roles"] }`); the authorize path answers
7
+ 302→sign-in for it (verified 2026-08-24).
8
+
9
+ ## Turn it on
10
+
11
+ 1. Set `OIDC_CLIENT_ID=oiml-rag` + `OIDC_ISSUER=https://id.oimlsmart.org`
12
+ and flip the feature flag. No OP-side act remains.
13
+
14
+ ## The sign-in flow (your half — verify each)
15
+
16
+ 2. The authorize URL carries `scope=openid profile email roles`,
17
+ `state` AND `nonce` (both unguessable, both one-time), PKCE S256.
18
+ (Your state handling is confirmed one-time; add the nonce check if
19
+ absent — the ID token's `nonce` must match what you issued.)
20
+ 3. The callback validates the ID token against the OP's JWKS — iss
21
+ exact, aud = oiml-rag, exp with ≤ 60 s leeway, the nonce — and the
22
+ JWKS is cached briefly with NO hard-pinned kid (the OP rotates with
23
+ overlap; a pinned kid breaks on rotation day).
24
+ 4. Map the OP's error taxonomy (`access_denied` and friends) to plain
25
+ language; fail closed, never a stack trace.
26
+ 5. Your session cookie: `Secure`, `HttpOnly`, `SameSite=Lax` — Strict
27
+ breaks the callback's top-level navigation back from the OP. State
28
+ the lifetime; renew sliding; logout clears it.
29
+ 6. Logout today is LOCAL-ONLY by necessity: the OP does not yet declare
30
+ `end_session_endpoint` (it lands with the identity-service cutover
31
+ wave — TODO.identity-sso wave A). When the discovery document gains
32
+ it, add the OP-side call so sign-out also ends the OP session (the
33
+ reference implementation in oimlsmart/smart
34
+ `browser/server/auth/oidc.ts` already implements RP-initiated
35
+ logout; copy it).
36
+ 7. The OP's sign-in page today renders in the platform's shell on the
37
+ identity host (works, and your users see it). After the
38
+ identity-service cutover it becomes the identity-native sign-in page
39
+ — you change NOTHING: the authorize URL is frozen by the OP's
40
+ contract gate.
41
+ 8. Your edge (Turnstile/WAF/rate limits): the `/auth/login` start and
42
+ `/auth/callback` must not be challenged, or the challenge must
43
+ survive the redirect chain — verify the round-trip under your edge
44
+ rules before announcing.
45
+ 9. `/auth/me` serves the session's cached claims — the ID token never
46
+ reaches the browser (your HMAC-cookie pattern already does this;
47
+ keep it).
48
+
49
+ ## The claims policy (the joint decision)
50
+
51
+ 10. The token may carry the estate role vocabulary: `applicant`,
52
+ `ia_officer`, `tl_operator`, `biml_officer`, `cs_admin`,
53
+ `mc_member`, `rc_member`, `executive_secretary`, `admin`, `viewer`,
54
+ plus `case_officer`, `certification_officer`, `signatory`,
55
+ `org_admin`.
56
+ 11. DECIDE NOW: which estate roles map to your member tier — every
57
+ signed-in user, or a bounded set? And which roles map to the
58
+ INTERNAL audience (the ISO corpus)? Once you declare the sets, the
59
+ OP bounds the policy's role allowlist to exactly them (one console
60
+ act — least privilege). Until then the policy is unbounded by
61
+ design; treat an absent/empty roles claim as the anonymous tier,
62
+ honestly.
63
+ 12. Key your users by `sub` (stable), never by email. Honor
64
+ `email_verified` before any email-keyed behavior. Erasure: a
65
+ deleted account's `sub` stops resolving — treat that as anonymous.
@@ -0,0 +1,219 @@
1
+ # Integrating with the OIML SMART identity service
2
+
3
+ **Audience:** an agent or engineer building a service that authenticates
4
+ users via the OIML SMART identity service. This file is self-contained;
5
+ nothing outside it is required reading. The canonical copy lives at
6
+ `docs/integration/identity-service.md` in the `oimlsmart/smart`
7
+ repository — copies into consumer repos are welcome; the canonical copy
8
+ wins on any drift.
9
+
10
+ > **Repo note (2026-08):** the identity service's code is moving from
11
+ > the smart monorepo to its own repository (`oimlsmart/identity`) — the
12
+ > extraction changes where the code lives, NEVER the public surface:
13
+ > the issuer `https://id.oimlsmart.org`, every endpoint, and the claims
14
+ > contract below are stable across the move. The source paths cited in
15
+ > §6 and §11 are the pre-extraction locations in `oimlsmart/smart`;
16
+ > after the cutover they read as the same relative paths inside
17
+ > `oimlsmart/identity`.
18
+
19
+ ## 1. The cast
20
+
21
+ - **The OP (OpenID Provider)** — the identity service at
22
+ `https://id.oimlsmart.org`. It authenticates users and issues OIDC ID
23
+ tokens (JWT, ES256). It is the ONLY account registry in the estate.
24
+ - **Your service is an RP (Relying Party)** — it trusts the OP. It runs
25
+ NO login form and holds NO account list of its own.
26
+ - **Upstream IdPs** (GitHub today; member-body providers such as
27
+ Microsoft Entra next) sit BEHIND the OP as linked login methods. Your
28
+ service never talks to them; the OP's account links them.
29
+
30
+ The OP speaks OIDC Core 1.0 (authorization code + PKCE), RFC 8414
31
+ discovery, and OIDC RP-Initiated Logout 1.0.
32
+
33
+ ## 2. The endpoint cheat sheet
34
+
35
+ Issuer: `https://id.oimlsmart.org`
36
+
37
+ | What | Where |
38
+ |---|---|
39
+ | Discovery (RFC 8414) | `GET {issuer}/.well-known/openid-configuration` |
40
+ | JWKS (the signing keys) | `GET {issuer}/jwks.json` (the discovery document's `jwks_uri` is authoritative) |
41
+ | Authorization endpoint | `{issuer}/op/authorize` |
42
+ | Token endpoint | `{issuer}/op/token` (authorization_code ONLY) |
43
+ | UserInfo | `{issuer}/op/userinfo` |
44
+ | Account console (your users manage their own profile, linked identities, password, avatar there) | `{issuer}/op/account` |
45
+
46
+ ## 3. Onboarding your service (the client registry)
47
+
48
+ Your service needs a client registration on the OP. One entry:
49
+
50
+ ```json
51
+ {
52
+ "client_id": "your-service-name",
53
+ "name": "Your Service",
54
+ "secret": "… (confidential clients only)",
55
+ "redirect_uris": ["https://your-service.example/auth/callback"],
56
+ "claims_policy": {
57
+ "claims": ["roles", "groups", "org"],
58
+ "roles": ["viewer", "mc_member"]
59
+ }
60
+ }
61
+ ```
62
+
63
+ - **Public client** (no `secret`): browser/SPA/native apps — PKCE is
64
+ the whole credential. **Confidential client** (with `secret`):
65
+ server-side apps that can keep a secret.
66
+ - `redirect_uris` are **exact-match**. No wildcards, ever.
67
+ - `claims_policy` (the per-client privilege): `claims` names the claim
68
+ FAMILIES the ID token may carry for your service (absent = profile +
69
+ email only); `roles` bounds WHICH roles those claims may carry
70
+ (absent = unbounded by the policy — declare it). **Least claims by
71
+ default**: if you need only identity, ask for no claims policy.
72
+ - How to get registered: ask an OP administrator (the admin console at
73
+ `{issuer}/op/admin` manages clients), or the registry API
74
+ (`POST /api/op/clients`, admin-held), or — for a self-hosted OP — the
75
+ `OP_CLIENT_SEED` bootstrap env.
76
+ - Rotation and disable: a client can be disabled without deleting its
77
+ audit trail; a disabled client's tokens stop at issuance (existing
78
+ sessions at your service die at YOUR session lifetime — see §8).
79
+
80
+ ## 4. The claims contract (what the ID token carries)
81
+
82
+ Standard: `iss` (exactly the issuer URL), `sub` (the stable account id —
83
+ THIS is your user key, never the email), `aud` (your client_id), `exp`
84
+ (validate with ≤ 60 s leeway), `email`, `name`, plus the policy-gated
85
+ families:
86
+
87
+ - `roles` — the account's estate role codes (see §6 for the vocabulary).
88
+ - `groups` — the account's group memberships.
89
+ - `org` — the account's registered organization affiliation.
90
+
91
+ Claims beyond profile+email arrive ONLY when your client's policy
92
+ allows them. The same user signing into two services can therefore
93
+ carry different claim sets — by design.
94
+
95
+ **`picture` rides userinfo, not the ID token** — the ID token carries
96
+ the profile contract (name/email + policy families); the avatar URL
97
+ arrives at the userinfo endpoint (declared in discovery). Relying
98
+ parties that want the photo fetch userinfo with the access token,
99
+ sub-checked against the ID token's `sub`.
100
+
101
+ ## 5. The sign-in flow (authorization code + PKCE)
102
+
103
+ 1. Discover: `GET {issuer}/.well-known/openid-configuration`; the
104
+ `issuer` value in the metadata MUST match the issuer URL exactly.
105
+ 2. Build the authorization request: `GET {issuer}/op/authorize` with
106
+ `response_type=code`, `client_id`, `redirect_uri` (exact), `scope`
107
+ (`openid profile email` + your policy's families), `state`
108
+ (unguessable, stored), `nonce` (unguessable, stored), and PKCE
109
+ (`code_challenge`, S256 — never plain).
110
+ 3. The user authenticates at the OP (password and/or a linked upstream
111
+ IdP) and consents; the OP redirects to your `redirect_uri` with
112
+ `code` + `state`. Verify `state` before anything else.
113
+ 4. Exchange: `POST {issuer}/op/token` with `grant_type=
114
+ authorization_code`, the code, the same `redirect_uri`, and the PKCE
115
+ `code_verifier` (plus HTTP-Basic client auth for confidential
116
+ clients). No other grant type is served today (machine callers: §9).
117
+ 5. Validate the ID token (§6), then build YOUR OWN session (your cookie,
118
+ your lifetime). The ID token is evidence of the sign-in event, not a
119
+ session.
120
+ 6. Logout: end your session; if the metadata declares
121
+ `end_session_endpoint`, redirect there for the OP-side sign-out.
122
+
123
+ ## 6. Validating tokens (the must-dos)
124
+
125
+ - Verify the signature against the JWKS (`jwks.json`, cached briefly —
126
+ the OP rotates keys with JWKS overlap, so never hard-pin a `kid`).
127
+ - Check `iss` (exact), `aud` (your client_id; `azp` when several
128
+ audiences), `exp` (≤ 60 s leeway), and the `nonce` you issued.
129
+ - Do the validation INSIDE your service. A check at an edge/WAF is UX,
130
+ never the gate.
131
+ - On any failure: fail closed, in plain language, never a stack trace.
132
+
133
+ The reference implementation (copy it; ~300 lines, zero dependencies,
134
+ WebCrypto + fetch only, runs on Node ≥ 18 and edge runtimes):
135
+ `browser/server/auth/oidc.ts` in `oimlsmart/smart` — discovery, PKCE,
136
+ the exchange, the validation, the logout URL, and the error taxonomy.
137
+
138
+ ## 7. Who declares what actions are allowed (the authorization division)
139
+
140
+ This is the question every integrator asks. The division:
141
+
142
+ - **The OP declares WHO the user is** — identity plus the coarse estate
143
+ role claims your client's policy allows. The OP's administrator
144
+ controls which roles exist and which accounts hold them; the OP's
145
+ per-client claims policy bounds what your service may SEE.
146
+ - **Your service declares WHAT those roles may do** — your action
147
+ vocabulary, your role→permission map, your enforcement at your own
148
+ routes. Never invert this (the OP is not a fine-grained policy
149
+ engine, by design).
150
+
151
+ The platform's own RBAC is the reference shape (`oimlsmart/smart`):
152
+ `browser/src/auth/permissions.ts` declares the action vocabulary;
153
+ `browser/src/auth/rbac.ts` holds the default role→permission map;
154
+ `browser/server/rbac.ts` resolves the EFFECTIVE map per instance
155
+ (an installed profile map, then the `INSTANCE_RBAC_JSON` env, then the
156
+ shipped default) and the entity routes enforce the write gates. The
157
+ estate role vocabulary today: `applicant`, `ia_officer`, `tl_operator`,
158
+ `biml_officer`, `cs_admin`, `mc_member`, `rc_member`,
159
+ `executive_secretary`, `admin`, `viewer`, plus the NMI split roles
160
+ (`case_officer`, `certification_officer`, `signatory`) and `org_admin`
161
+ (delegated organization administration). Map your service's actions to
162
+ the roles your claims policy receives — or keep your own roles internal
163
+ and map the estate roles into them at your boundary.
164
+
165
+ ## 8. Centralized management or multiple services — both, deliberately
166
+
167
+ - **Centralized (the estate's shape):** ONE OP, many registered
168
+ clients. Every service onboards per §3. Users have one account with
169
+ linked login methods; the admin surface is one console. This is the
170
+ recommended shape for anything in the oimlsmart.org estate.
171
+ - **Multiple SERVICES on one OP** is the normal case (one client
172
+ registration each) — nothing extra to do.
173
+ - **Multiple identity PROVIDERS** (a sovereign deployment): a
174
+ self-hosted platform instance can point its RP side at a DIFFERENT
175
+ issuer entirely (the instance's `OIDC_ISSUER` configuration) — e.g. a
176
+ national body's own provider. Supported, with the trade named: that
177
+ deployment leaves the estate's shared account registry and role
178
+ coherence. The softer shape for most members: keep trusting the
179
+ estate OP and link the member's provider as an UPSTREAM login method
180
+ (users sign in with their national IdP; the account stays the
181
+ estate's).
182
+ - The OP itself is deployable outside the hosted Cloudflare shape
183
+ (Node + SQLite / a container image — see
184
+ `docs/deployment/identity-operations.md` §"Deployment portability"),
185
+ so a sovereign operator can run the whole OP too.
186
+
187
+ ## 9. Machine callers (today's honest gap)
188
+
189
+ The OP serves authorization code + PKCE ONLY. There is no
190
+ `client_credentials` grant today: non-human callers (agent pipelines,
191
+ MCP servers) are NOT served yet. The gap is recorded and sized in
192
+ `TODO.identity-ops/07` (service accounts as confidential clients with
193
+ no redirect URIs, audience-bound tokens, scoped claims). If your
194
+ integration needs machine tokens, say so — that is the trigger that
195
+ schedules it. Do NOT work around it by embedding a human's credentials.
196
+
197
+ ## 10. What your service inherits
198
+
199
+ - **Degraded mode**: when the OP is unreachable, existing sessions at
200
+ your service ride their own cookies; new sign-ins fail honestly.
201
+ State your behavior and cache JWKS briefly so validation survives
202
+ short OP outages.
203
+ - **Offboarding**: an account disabled at the OP stops issuing
204
+ immediately; its existing session at YOUR service dies at YOUR
205
+ session lifetime. Re-check the OP on sensitive acts.
206
+ - **Erasure**: a deleted account's `sub` stops resolving; keep your own
207
+ records keyed by `sub` and treat an unresolvable `sub` as anonymous.
208
+
209
+ ## 11. Development and test posture
210
+
211
+ - A local OP for development: the platform's node dev stack boots the OP
212
+ profile locally (see `docs/deployment/identity-operations.md`); point
213
+ your service's issuer config at it. The demo accounts exist for
214
+ development only — never a production login path.
215
+ - The test pattern to copy: the identity e2e legs in
216
+ `oimlsmart/smart` (`browser/e2e/`, the identity-arc legs) boot the OP
217
+ and an RP in one harness.
218
+ - The OP's failures answer a machine `reason` — map them to plain
219
+ language; never leak internals to your users.
@@ -0,0 +1,273 @@
1
+ # The knowledge-annealment ladder v2 — defined by system primitives
2
+
3
+ **The instrument for the four-corpus comparison** (Bulletin paper #2).
4
+ Annealment = the degree to which knowledge is bound into structure a
5
+ machine can traverse and compute. Each rung is defined by WHICH PRIMITIVES
6
+ it requires; each corpus lane is characterized by the primitives its
7
+ representation carries. A lane's **capability ceiling** = the highest
8
+ consecutive rung at ≥60% witness-checked pass; its **annealment index** =
9
+ the fraction of primitive tiers it materializes. Pass is always
10
+ witness-checked; L8/L9 witnesses are COMPUTED, never judged.
11
+
12
+ Fixed corpus across lanes: the OIML R 60 family (2021 p1–3 + annexes;
13
+ the 2017 edition package for diachrony).
14
+
15
+ ## The primitive taxonomy (P1–P10) and who carries what
16
+
17
+ | Tier | Primitive | Metanorma/MKO realizes | Primmel realizes |
18
+ |---|---|---|---|
19
+ | P1 | surface text | adoc prose | prl descriptions |
20
+ | P2 | editorial anchoring | clause/unit/number/title/breadcrumb/cite_as | section + `source: urn#clause` on everything |
21
+ | P3 | object geometry | table payload (cols/rows), figure, formula display | tables with TYPED columns (name/type/unit) |
22
+ | P4 | nomenclature | glossary concepts, designations | terms with vocabulary registers (VIML), multilingual spellings, form types; aspects & behaviors registries |
23
+ | P5 | relation | part_of/cites/defines edges | curated clause-level references; `uses:` package composition (CASCO); requirement↔aspect binding; type↔instance references |
24
+ | P6 | temporality | editions + derived status | edition lifecycle (status/supersedes/validity.from) + FULL edition packages (diffable) |
25
+ | P7 | perception | figure units + assets + captions | figure references (fig-2/fig-3 in sequences) |
26
+ | P8 | quantitative typing | UnitsML in stems — flattened to string suffixes by the export (metanorma-document#55) | **unit register**: stable ids, quantity_kind, dimension vector, SI coherent unit, conversion factor; coherence on KINDS |
27
+ | P9 | computation | formula asciimath+mathml (display-only; no evaluation semantics — metanorma-document#55 GAP-3) | formulas-as-operations (lookup with params); calculations (typed IO); **OCL constraints with violation meaning + on_violation** |
28
+ | P10 | instance & process | — | entity schemas (type vs instance, obligation/cardinality); ordered test sequences (roles, contamination semantics); workflows; execution forms |
29
+
30
+ Meta-primitive (P★, Primmel only): **self-verification** — the model-linker
31
+ rules (quantity-coherence, requirement-binding-targets) and the
32
+ burned-to-empty allowlist ledger: the model is machine-checked consistent.
33
+
34
+ **Lane inventories:** A `exp_plain` = P1(+P2 as text) · B `exp_adoc` =
35
+ P1, P2-textual, P3-degraded · C `exp_mko` = P1–P7 (P8 weak strings) ·
36
+ D `exp_primmel` = P1–P10 · **E `exp_primmel_flat`** (diagnostic ablation:
37
+ D's projected prose WITHOUT payloads/edges/typing) — separates "better
38
+ text" from "better structure" inside D; the causal control the paper
39
+ needs.
40
+
41
+ ## The ladder (L0–L9, sub-probes where the systems diverge)
42
+
43
+ **L0 LOCATE** (P1–P2). *"Where does R 60 address creep?"* Witness: clause
44
+ anchor. All lanes pass — the sanity floor.
45
+
46
+ **L1 EXTRACT** (P1–P2). Verbatim value from prose. Witness: exact
47
+ string. All lanes pass; small separation.
48
+
49
+ **L2 NOMENCLATURE** (P4). Colloquial → defined term.
50
+ a) corpus-local ("drift"→durability) b) **cross-register**: the VIML
51
+ clause via vocab_ref c) multilingual spelling resolution (Primmel only).
52
+ Witness: term + register anchor. Expected: C strong at (a), D strong
53
+ (a–c), A/B luck.
54
+
55
+ **L3 GEOMETRY** (P3+P8). a) cell lookup by row×column (typed block
56
+ required) b) **unit-aware cell**: the value AND its quantity kind (P8:
57
+ is n_LC dimensionless? loads in `v` units?) c) derived cell (needs a
58
+ lookup formula — transitional to L8). Witness: value + row/col keys +
59
+ unit kind. Expected: A ≤40%, B partial, C strong (a), D strong (a–c).
60
+
61
+ **L4 COMPOSITION** (P2+P5). a) intra-document join (MPE table + doubling
62
+ clause + load bands) b) **cross-part** join (R 60-1 requirement ↔ R 60-2
63
+ test ↔ R 60-3 form). Witness: both anchors + derived relation. Expected:
64
+ C/D strong at both; A/B partial (b near-zero).
65
+
66
+ **L5 CROSS-STANDARD** (P5). a) cites-edge ("which ISO/IEC test method
67
+ does R 60-2 invoke for humidity?") b) **composition + binding** ("which
68
+ CASCO vocabulary governs the certification activities; which aspects do
69
+ requirements bind?"). Witness: the linked id/clause. **ISOLATION: links
70
+ only in public lanes — ISO/IEC text never appears** (structural rule).
71
+ Expected: D strong, C partial (a), A/B near-zero.
72
+
73
+ **L6 DIACHRONY** (P6). a) current-edition selection b) **delta
74
+ extraction** 2017→2021 (the 2017 edition PACKAGE makes real diffs
75
+ computable) c) validity windows. Witness: edition pair + delta fact.
76
+ Expected: D strong, C partial (alignment, no diffs), A/B near-zero.
77
+
78
+ **L7 PERCEPTION** (P7). a) caption/asset b) pixel-only content (labels
79
+ readable only from the drawing) c) user-image grounding (nameplate
80
+ photo). Witness: pixel-only label / classification. Expected: C strong,
81
+ D via figure references, A/B zero. **The visible demo separator — and
82
+ live in production:** the pinned figure's pixels ride the generation
83
+ call (asset readability + message shape are measured invariants; see
84
+ the mechanism reference #12), so pixel-only labels are read from the
85
+ drawing itself, not disclaimed against the caption.
86
+
87
+ **L8 COMPUTATION** (P9+P8). a) pure calculation (conversion factor f
88
+ from inputs) b) **constraint/conformance verdict with the violation
89
+ meaning** ("is D_max=0.8·E_max acceptable?" → the OCL answer AND the
90
+ recorded violation semantics) c) **unit-coherence judgment** (compare
91
+ 3000 kgf vs 30 kN via the register — P8). Witnesses: COMPUTED offline
92
+ from the model (deterministic, no judge). Expected: **D only, by
93
+ construction.**
94
+
95
+ **L9 INSTANCE & PROCESS** (P10). a) **process order & consequence**
96
+ ("what is contaminated if creep runs before MDLO?" — encoded as sequence
97
+ semantics, not prose) b) instance-grounded facts (a specific recorded
98
+ type/instance profile — sample data only) c) execution-form knowledge
99
+ (test report structure). Witnesses: order verdict / instance fact
100
+ (deterministic from entities). Expected: **D only.**
101
+
102
+ ## Rigor rules (v2 additions)
103
+
104
+ 1. **Containment filtering**: every L8/L9 question is checked against
105
+ the corpus text — if the specific answer string exists in prose, the
106
+ question cannot separate lanes and is replaced. The instrument must
107
+ probe structure, not memory of printed answers.
108
+ 2. **Ablation lane E** (primmel-flat) is mandatory: without it, D's win
109
+ is confounded by projection prose quality.
110
+ 3. **Deterministic graders** for L8/L9 (computed ground truth); judge
111
+ only at L4 (synthesis) — the instrument's upper rungs are its most
112
+ objective.
113
+ 4. Sequential measurement windows per lane; ×3 repeats; ranges reported.
114
+
115
+ ## Golden set v2
116
+
117
+ ~66 primary questions (6–7/rung incl. sub-probes) + 2 paraphrases for
118
+ L0–L6; R 60 primary, R 76-1 generality probes at L1/L3/L4 (A/B/C only).
119
+ Headline outputs: the **lane × rung matrix**, per-lane **primitive
120
+ activation radar** (P1–P10), **capability ceiling**, **annealment
121
+ index**, and **cost per correct answer**.
122
+
123
+
124
+ ---
125
+
126
+ # The three eras — and the Primmel frontier (F1–F12)
127
+
128
+ ## The era framing
129
+
130
+ | Era | Representation | Primitives | What the assistant IS | Ceiling |
131
+ |---|---|---|---|---|
132
+ | **1 · LEGACY** | plain text / raw adoc | P1–P2 | an index: find and restate | L1–L3 |
133
+ | **2 · NOW** | MKO (P1–P7) · Primmel-KO (P1–P10) | structure, typing, execution | a grounded instrument: cite, render, verify, compute | MKO L7 · Primmel L9 |
134
+ | **3 · FRONTIER** | Primmel objects (F1–F12 below) | closed world + executability + instances | an OPERATOR: verdict, simulate, prove, personalize, walk processes, verify publications | beyond L9 |
135
+
136
+ The comparison programme (TODO 15–20) measures Era 2's value per primitive.
137
+ The FRONTIER is Era 3 — capabilities that exist because the corpus is a
138
+ model with a closed world, executable semantics, and recorded instances.
139
+ **No document representation can follow** — these are the special wins
140
+ for D that make Primmel the destination, not just the winner of a test.
141
+
142
+ ## F1 — Verdict as data (conformance-as-a-service)
143
+ `Verdict` data class ("the canonical verdict chain"), OCL constraints
144
+ with `violation_meaning` + `on_violation`, examination reports. Answers
145
+ return a **VERDICT BLOCK**: pass/fail/void + the reason in the
146
+ standard's own words + the full clause chain — produced by EXECUTION,
147
+ verified by execution. The answer contract's strongest artifact class.
148
+
149
+ ## F2 — Counterfactual simulation
150
+ Constraints and table-lookup formulas run on HYPOTHETICAL parameters:
151
+ *"what if D_max were 0.8·E_max?"* → the OCL verdict + violation meaning;
152
+ *"which accuracy class for n_LC = 3000?"* → the lookup INVERTED.
153
+ Documents state facts; models evaluate hypotheses.
154
+
155
+ ## F3 — Exhaustiveness and provable absence
156
+ The closed world (audited: all 60 requirements, 62 tests; forAll
157
+ semantics) → *"list ALL requirements binding marking"* is COMPLETE, and
158
+ *"does R 60 require X? — no, provably"* is a proof, not a refusal.
159
+ Retrieval corpora can only fail to find; the model can show the absence.
160
+
161
+ ## F4 — Instance-grounded, parameterized answers
162
+ Attributes scoped family/instance + load-cell-instance entities + sample
163
+ data → the MPE table becomes a FUNCTION evaluated at the user's
164
+ instrument (Max, e, class): the answer is computed for YOUR device.
165
+ (Member/internal tier.) Input annealment: the unit register normalizes
166
+ any input units first.
167
+
168
+ ## F5 — Certification workflow statefulness
169
+ `evaluation/processes` (layer-composed, `validate_provision` URN
170
+ anchors), gateways, execution forms + checklist → a procedural assistant
171
+ that knows where the evaluation stands, what gates what, what runs next —
172
+ and can advance checklist state. Agentic, not just informative.
173
+
174
+ ## F6 — Impact analysis (committee tooling)
175
+ Requirement↔test↔formula↔table bindings (`formulas-used`, aspect
176
+ bindings) → *"if limit_factor for class C changes, which requirements,
177
+ tests, verdicts and forms change?"* — change impact over the dependency
178
+ graph. Drafting-committee superpower.
179
+
180
+ ## F7 — Semantic edition diffs + temporal jurisdiction
181
+ Full 2017 edition PACKAGES + `validity.from` → edition deltas COMPUTED at
182
+ model level ("what changed in the creep requirement") and retro-jurisdiction
183
+ questions ("which edition governed a 2019 evaluation?").
184
+
185
+ ## F8 — Self-verification as a query (meta-grounding)
186
+ The model-linker rules and the burned-empty allowlist: the corpus is
187
+ machine-checked consistent — so the assistant can VERIFY ITS OWN
188
+ model-grounded claims by execution. The faithfulness judge's successor
189
+ for the D lane.
190
+
191
+ ## F9 — Document-as-projection verification
192
+ `documents/*/presentation.xml`: the model carries its own renders →
193
+ *"does the published Table 4 match the model?"* — QA of PUBLISHING
194
+ itself; the inverse direction (model → document generation) later.
195
+
196
+ ## F10 — Normative notes as overrides
197
+ First-class NOTE/EXAMPLE objects with override semantics ("the MPE for
198
+ creep shall ALWAYS use p_LC = 0.7 regardless of the manufacturer's
199
+ declaration") → notes become queryable RULES that feed computation, not
200
+ buried prose that computation ignores.
201
+
202
+ ## F11 — Composition-aware answers
203
+ `uses:` package composition (ISO/IEC 17000/17065) with layer-overlay
204
+ semantics → questions spanning the composition carry per-layer
205
+ provenance: "core says X; R 60 overlays Y" — co-location is not
206
+ composition, and only the model composes.
207
+
208
+ ## F12 — The machine passport (r60-to-dpp.prm)
209
+ The `.prm` artifact: answers exportable as structured passport DATA, not
210
+ prose — the answer contract's ultimate block type. The Q&A becomes a
211
+ data source for downstream systems.
212
+
213
+ ## Frontier sequencing
214
+
215
+ **LIVE** (serving the public today): F1 verdicts, F2 counterfactuals, F3
216
+ provable absence, F8 answer verification. **Within reach of the current
217
+ model plane** (deterministic witnesses, no producer dependency): F7
218
+ edition diffs, F10 note overrides. **Programme scale** (instance
219
+ execution and estate data): F4, F5, F6, F9, F11, F12.
220
+
221
+ ## Structural retrieval (the clause tree, adapted from FABLE/BEAR, arXiv:2601.18116)
222
+
223
+ FABLE/BEAR (arXiv:2601.18116) retrieves over LLM-built semantic forests;
224
+ we adapt its serving techniques to a corpus that already IS a tree —
225
+ Metanorma clause anchors chain parent→child natively, so no index-time
226
+ tree-builder runs at all (the paper's entire offline cost collapses to
227
+ ~1,400 synthetic depth-1 summary nodes, ≈$3 one-time). Three techniques
228
+ ship in the serving path (`src/structural.ts`), each gated by the golden
229
+ suite:
230
+
231
+ 1. **Structural propagation** (their TreeExpansion, Eq. 7): a hit's
232
+ score blends with its ancestors' (topic continuity) and descendants'
233
+ (subtopic heat) — a section whose clauses are collectively hot rises;
234
+ a hot section lifts its clauses. Spread-scaled like edition steering,
235
+ so the cross-encoder's own signal always dominates.
236
+ 2. **Position-preserving evidence order** (their NodeFusion): passages
237
+ are presented in document reading order per publication (publications
238
+ by best rank) — synthesis quality depends on arrangement, not just
239
+ set membership. Applied in `buildMessages`, so every consumer (ask,
240
+ research, lanes) inherits it.
241
+ 3. **Ancestor-descendant dedup**: near-duplicate chunks of one clause
242
+ chain (parent §3.1 vs child §3.1.2 repeating its text) collapse to
243
+ the stronger one before the window is cut.
244
+
245
+ Plus the **multi-granularity index** (their internal-node indexing): the
246
+ corpus's chunks start at depth 2 ("3.1") — depth-1 nodes ("§3") did not
247
+ exist as retrievable objects. `/admin/section` (admin-token gated,
248
+ mirrors `/admin/enrich`) generates, embeds (toc-path ⊕ summary style)
249
+ and upserts them; the pipeline descends from a ranked section unit to
250
+ its quotable child clauses and retires the synthetic summary (citations
251
+ must quote source clauses, never our own summaries). Driver:
252
+ `ingest/cli.py sections` (resumable — KV-cached per unit id). And the
253
+ eval harness reports **EIR** (context utilization: cited/retrieved at
254
+ the answer) — the precision-side counterpart to witness recall, after
255
+ their EIR metric.
256
+
257
+ ## Era 3: execution (the frontier is live)
258
+
259
+ Beyond the ladder, the machine objects are EXECUTED, not retrieved:
260
+
261
+ - **Verdicts** (`src/verdict.ts`): a question naming a constraint or
262
+ machine limit gets the check evaluated against its stated values —
263
+ pass / the standard's own violation word / void naming what is
264
+ missing — attached as data the answer must present faithfully.
265
+ Counterfactuals are free (values are values).
266
+ - **Provable absence** (`/v1/absence`): an enumeration certificate
267
+ over the standard's model plane — absent means "N nodes enumerated,
268
+ 0 matches", never a bare refusal.
269
+ - **Answer verification** (`/v1/verify`): the deterministic contract
270
+ battery plus a judged faithfulness score, exposed for any answer.
271
+
272
+ The full mechanism reference — every serving layer with its staircase
273
+ (what the layer below cannot do) — is `docs/sota-mechanisms.md`.