@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.
- package/LICENSE +29 -0
- package/README.md +13 -0
- package/dist/admin.d.ts +26 -0
- package/dist/ai.d.ts +6 -0
- package/dist/anchors.d.ts +6 -0
- package/dist/answercache.d.ts +22 -0
- package/dist/ask.d.ts +5 -0
- package/dist/auth.d.ts +12 -0
- package/dist/bubble.d.ts +14 -0
- package/dist/chunk-LLWPT2XV.js +49 -0
- package/dist/chunk-MB74PTRM.js +114 -0
- package/dist/chunk-WOGQM7DJ.js +197 -0
- package/dist/chunk-WWNCWKKC.js +42 -0
- package/dist/completion.d.ts +5 -0
- package/dist/config.d.ts +154 -0
- package/dist/config.js +37 -0
- package/dist/context.d.ts +115 -0
- package/dist/conversations.d.ts +5 -0
- package/dist/drafts.d.ts +129 -0
- package/dist/env.d.ts +57 -0
- package/dist/faithfulness.d.ts +5 -0
- package/dist/grader.d.ts +3 -0
- package/dist/graph.d.ts +13 -0
- package/dist/hybrid.d.ts +7 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +5373 -0
- package/dist/internal_gateway.d.ts +14 -0
- package/dist/lexical.d.ts +7 -0
- package/dist/livedata.d.ts +77 -0
- package/dist/memories.d.ts +10 -0
- package/dist/modelplane.d.ts +61 -0
- package/dist/oidc.d.ts +73 -0
- package/dist/pipeline.d.ts +57 -0
- package/dist/profile.d.ts +2 -0
- package/dist/profile.gen.d.ts +70 -0
- package/dist/profile.js +8 -0
- package/dist/projects.d.ts +8 -0
- package/dist/prompts/conversational.md +8 -0
- package/dist/prompts/enrichment.md +3 -0
- package/dist/prompts/faithfulness.md +1 -0
- package/dist/prompts/grader.md +5 -0
- package/dist/prompts/listwise.md +3 -0
- package/dist/prompts/precision.md +1 -0
- package/dist/prompts/reflect.md +1 -0
- package/dist/prompts/relevancy.md +1 -0
- package/dist/prompts/research.md +10 -0
- package/dist/prompts/section-summary.md +5 -0
- package/dist/prompts/summarize.md +1 -0
- package/dist/prompts/system.md +18 -0
- package/dist/prompts/understanding.md +17 -0
- package/dist/quota.d.ts +13 -0
- package/dist/reflect.d.ts +5 -0
- package/dist/refs.d.ts +40 -0
- package/dist/refusal.d.ts +9 -0
- package/dist/refusal.js +9 -0
- package/dist/requestScope.d.ts +26 -0
- package/dist/requestScope.js +10 -0
- package/dist/research.d.ts +8 -0
- package/dist/search.d.ts +4 -0
- package/dist/selfquery.d.ts +7 -0
- package/dist/session.d.ts +1 -0
- package/dist/share.d.ts +2 -0
- package/dist/structural.d.ts +27 -0
- package/dist/tablecontext.d.ts +11 -0
- package/dist/understand.d.ts +11 -0
- package/dist/understandContract.d.ts +29 -0
- package/dist/verdict.d.ts +24 -0
- package/docs/API.md +451 -0
- package/docs/ARCHITECTURE.md +302 -0
- package/docs/AUDIT-2026-08-24.md +71 -0
- package/docs/CONTRIBUTOR-AUDIT-2026-08-25.md +147 -0
- package/docs/INGEST-ARCHITECTURE.md +158 -0
- package/docs/MCP.md +92 -0
- package/docs/METANORMA-AI-SERIALIZATION.md +247 -0
- package/docs/MKO-EXPORT-PIPELINE.md +147 -0
- package/docs/REDESIGN-NORMATIVE-RAG-ETSI.md +485 -0
- package/docs/RESEARCH-SOTA-2026.md +243 -0
- package/docs/ROADMAP-SOTA.md +130 -0
- package/docs/SOTA-STAGE-SPECS.md +509 -0
- package/docs/annealment/F1-verdict.md +27 -0
- package/docs/annealment/F10-notes.md +19 -0
- package/docs/annealment/F11-composition.md +17 -0
- package/docs/annealment/F12-passport.md +17 -0
- package/docs/annealment/F2-counterfactual.md +20 -0
- package/docs/annealment/F3-absence.md +21 -0
- package/docs/annealment/F4-instance.md +18 -0
- package/docs/annealment/F5-workflow.md +21 -0
- package/docs/annealment/F6-impact.md +21 -0
- package/docs/annealment/F7-editions.md +18 -0
- package/docs/annealment/F8-selfverify.md +19 -0
- package/docs/annealment/F9-projection-qa.md +17 -0
- package/docs/annealment/L0-locate.md +19 -0
- package/docs/annealment/L1-extract.md +18 -0
- package/docs/annealment/L2-nomenclature.md +22 -0
- package/docs/annealment/L3-geometry.md +23 -0
- package/docs/annealment/L4-composition.md +21 -0
- package/docs/annealment/L5-cross-standard.md +20 -0
- package/docs/annealment/L6-diachrony.md +21 -0
- package/docs/annealment/L7-perception.md +20 -0
- package/docs/annealment/L8-computation.md +22 -0
- package/docs/annealment/L9-instance-process.md +23 -0
- package/docs/annealment/README.md +10 -0
- package/docs/guidelines-metanorma-ai-programme.md +279 -0
- package/docs/identity-onboarding-rag.md +65 -0
- package/docs/identity-service.md +219 -0
- package/docs/knowledge-annealment.md +273 -0
- package/docs/konneal-extraction-plan.md +481 -0
- package/docs/metanorma-for-ai.md +270 -0
- package/docs/mirror-plan.md +36 -0
- package/docs/multi-sdo-architecture.md +191 -0
- package/docs/paper-annealment-comparison.md +259 -0
- package/docs/paper-assets/architecture.svg +94 -0
- package/docs/paper-assets/contract-v2.svg +94 -0
- package/docs/paper-assets/mko-ingest.svg +91 -0
- package/docs/paper-oiml-bulletin.md +402 -0
- package/docs/paper-oiml-bulletin.mdx +419 -0
- package/docs/product-branding-options.md +172 -0
- package/docs/projects-design.md +88 -0
- package/docs/sota-mechanisms.md +184 -0
- package/docs/spec-api.md +77 -0
- package/docs/spec-pipeline.md +126 -0
- package/docs/vector-adapter.md +88 -0
- package/package.json +70 -0
- package/profile/corpora.yaml +5 -0
- package/profile/datasets.yaml +14 -0
- package/profile/prompts.yaml +5 -0
- package/profile/publisher.yaml +17 -0
- package/profile/retrieval.yaml +1 -0
- package/profile/sources.yaml +5 -0
- package/profile/ui.yaml +7 -0
- package/scripts/gen_profile.mjs +33 -0
- package/workers/shared/ai.ts +21 -0
- package/workers/shared/auth.ts +16 -0
- package/workers/shared/chunk.ts +108 -0
- package/workers/shared/oidc.ts +312 -0
- package/workers/shared/router.ts +45 -0
- package/workers/shared/session.ts +104 -0
- package/workers/worker_internal/src/index.ts +157 -0
- package/workers/worker_internal/tsconfig.json +15 -0
- package/workers/worker_internal/wrangler.toml +32 -0
- package/workers/worker_mcp/src/index.ts +175 -0
- package/workers/worker_mcp/tsconfig.json +13 -0
- package/workers/worker_mcp/wrangler.toml +18 -0
- package/workers/worker_public/migrations/0002_conversations.sql +22 -0
- package/workers/worker_public/migrations/0003_shared_conversations.sql +9 -0
- package/workers/worker_public/migrations/0004_graph.sql +16 -0
- package/workers/worker_public/migrations/0005_documents.sql +19 -0
- package/workers/worker_public/migrations/0006_conversation_entities.sql +11 -0
- package/workers/worker_public/migrations/0007_chunks_fts.sql +43 -0
- package/workers/worker_public/migrations/0008_unit_payloads.sql +15 -0
- package/workers/worker_public/migrations/0009_chunks_unit.sql +8 -0
- package/workers/worker_public/migrations/0009_message_context.sql +7 -0
- package/workers/worker_public/migrations/0010_model_nodes.sql +33 -0
- package/workers/worker_public/migrations/0011_schema_union.sql +38 -0
- package/workers/worker_public/migrations/0012_memories.sql +15 -0
- package/workers/worker_public/migrations/0013_projects.sql +21 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2021-11-03/index.d.ts +16306 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2021-11-03/index.ts +16261 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-01-31/index.d.ts +16373 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-01-31/index.ts +16328 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-03-21/index.d.ts +16382 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-03-21/index.ts +16337 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-08-04/index.d.ts +16383 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-08-04/index.ts +16338 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-10-31/index.d.ts +16403 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-10-31/index.ts +16358 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-11-30/index.d.ts +16408 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2022-11-30/index.ts +16363 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-03-01/index.d.ts +16414 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-03-01/index.ts +16369 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-07-01/index.d.ts +16414 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/2023-07-01/index.ts +16369 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/README.md +135 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/entrypoints.svg +53 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/experimental/index.d.ts +17095 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/experimental/index.ts +17050 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/index.d.ts +16306 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/index.ts +16261 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/latest/index.d.ts +16447 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/latest/index.ts +16402 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/oldest/index.d.ts +16306 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/oldest/index.ts +16261 -0
- package/workers/worker_public/node_modules/@cloudflare/workers-types/package.json +11 -0
- package/workers/worker_public/package.json +13 -0
- package/workers/worker_public/prompts/conversational.md +8 -0
- package/workers/worker_public/prompts/enrichment.md +3 -0
- package/workers/worker_public/prompts/faithfulness.md +1 -0
- package/workers/worker_public/prompts/grader.md +5 -0
- package/workers/worker_public/prompts/listwise.md +3 -0
- package/workers/worker_public/prompts/precision.md +1 -0
- package/workers/worker_public/prompts/reflect.md +1 -0
- package/workers/worker_public/prompts/relevancy.md +1 -0
- package/workers/worker_public/prompts/research.md +10 -0
- package/workers/worker_public/prompts/section-summary.md +5 -0
- package/workers/worker_public/prompts/summarize.md +1 -0
- package/workers/worker_public/prompts/system.md +18 -0
- package/workers/worker_public/prompts/understanding.md +17 -0
- package/workers/worker_public/public/app.js +166 -0
- package/workers/worker_public/public/index.html +48 -0
- package/workers/worker_public/public/style.css +147 -0
- package/workers/worker_public/schema.sql +248 -0
- package/workers/worker_public/src/admin.ts +358 -0
- package/workers/worker_public/src/ai.ts +71 -0
- package/workers/worker_public/src/anchors.ts +41 -0
- package/workers/worker_public/src/answercache.ts +72 -0
- package/workers/worker_public/src/ask.ts +1094 -0
- package/workers/worker_public/src/auth.ts +252 -0
- package/workers/worker_public/src/bubble.ts +111 -0
- package/workers/worker_public/src/completion.ts +75 -0
- package/workers/worker_public/src/config.ts +238 -0
- package/workers/worker_public/src/context.ts +238 -0
- package/workers/worker_public/src/conversations.ts +162 -0
- package/workers/worker_public/src/drafts.ts +497 -0
- package/workers/worker_public/src/env.ts +90 -0
- package/workers/worker_public/src/faithfulness.ts +63 -0
- package/workers/worker_public/src/grader.ts +89 -0
- package/workers/worker_public/src/graph.ts +63 -0
- package/workers/worker_public/src/hybrid.ts +77 -0
- package/workers/worker_public/src/index.ts +441 -0
- package/workers/worker_public/src/internal_gateway.ts +41 -0
- package/workers/worker_public/src/lexical.ts +86 -0
- package/workers/worker_public/src/lib/hit.ts +4 -0
- package/workers/worker_public/src/lib/http.ts +83 -0
- package/workers/worker_public/src/lib/router.ts +4 -0
- package/workers/worker_public/src/livedata.ts +334 -0
- package/workers/worker_public/src/memories.ts +81 -0
- package/workers/worker_public/src/modelplane.ts +213 -0
- package/workers/worker_public/src/oidc.ts +333 -0
- package/workers/worker_public/src/pipeline.ts +377 -0
- package/workers/worker_public/src/ports/blobs.ts +7 -0
- package/workers/worker_public/src/ports/cloudflare/adapters.ts +177 -0
- package/workers/worker_public/src/ports/kv.ts +8 -0
- package/workers/worker_public/src/ports/model.ts +28 -0
- package/workers/worker_public/src/ports/runtime.ts +13 -0
- package/workers/worker_public/src/ports/store.ts +20 -0
- package/workers/worker_public/src/ports/vector.ts +26 -0
- package/workers/worker_public/src/profile.gen.ts +101 -0
- package/workers/worker_public/src/profile.ts +16 -0
- package/workers/worker_public/src/projects.ts +108 -0
- package/workers/worker_public/src/prompts.d.ts +6 -0
- package/workers/worker_public/src/quota.ts +54 -0
- package/workers/worker_public/src/reflect.ts +67 -0
- package/workers/worker_public/src/refs.ts +107 -0
- package/workers/worker_public/src/refusal.ts +65 -0
- package/workers/worker_public/src/requestScope.ts +71 -0
- package/workers/worker_public/src/research.ts +126 -0
- package/workers/worker_public/src/search.ts +56 -0
- package/workers/worker_public/src/selfquery.ts +25 -0
- package/workers/worker_public/src/session.ts +4 -0
- package/workers/worker_public/src/share.ts +53 -0
- package/workers/worker_public/src/stages/conceptGraph.ts +68 -0
- package/workers/worker_public/src/stages/conceptSteer.ts +39 -0
- package/workers/worker_public/src/stages/corpusScope.ts +25 -0
- package/workers/worker_public/src/stages/dedup.ts +10 -0
- package/workers/worker_public/src/stages/dense.ts +73 -0
- package/workers/worker_public/src/stages/diversity.ts +33 -0
- package/workers/worker_public/src/stages/editionCover.ts +63 -0
- package/workers/worker_public/src/stages/editionSteer.ts +88 -0
- package/workers/worker_public/src/stages/familyBoost.ts +22 -0
- package/workers/worker_public/src/stages/federate.ts +22 -0
- package/workers/worker_public/src/stages/glossary.ts +65 -0
- package/workers/worker_public/src/stages/graphLane.ts +31 -0
- package/workers/worker_public/src/stages/hyde.ts +29 -0
- package/workers/worker_public/src/stages/index.ts +69 -0
- package/workers/worker_public/src/stages/lexicalUnion.ts +21 -0
- package/workers/worker_public/src/stages/multiQuery.ts +57 -0
- package/workers/worker_public/src/stages/overviewDemote.ts +14 -0
- package/workers/worker_public/src/stages/poolOpen.ts +10 -0
- package/workers/worker_public/src/stages/propagate.ts +15 -0
- package/workers/worker_public/src/stages/rerank.ts +47 -0
- package/workers/worker_public/src/stages/seal.ts +16 -0
- package/workers/worker_public/src/stages/sectionDescent.ts +61 -0
- package/workers/worker_public/src/stages/stdRefNudge.ts +35 -0
- package/workers/worker_public/src/stages/subQuery.ts +42 -0
- package/workers/worker_public/src/stages/termNudge.ts +24 -0
- package/workers/worker_public/src/stages/typedPin.ts +131 -0
- package/workers/worker_public/src/stages/types.ts +112 -0
- package/workers/worker_public/src/stages/windowFloor.ts +23 -0
- package/workers/worker_public/src/structural.ts +171 -0
- package/workers/worker_public/src/tablecontext.ts +41 -0
- package/workers/worker_public/src/understand.ts +72 -0
- package/workers/worker_public/src/understandContract.ts +67 -0
- package/workers/worker_public/src/verdict.ts +255 -0
- package/workers/worker_public/tsconfig.json +18 -0
- package/workers/worker_public/wrangler.toml +104 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Ingest Architecture — Object Input Interface → RAG Data Preprocessor → RAG Worker
|
|
2
|
+
|
|
3
|
+
*Formalizes the pipeline shape (2026-08-27). Companion pieces:
|
|
4
|
+
`SOTA-STAGE-SPECS.md` (schemas), `METANORMA-AI-SERIALIZATION.md` (upstream
|
|
5
|
+
serialization contract), `ROADMAP-SOTA.md` (phasing).*
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The principle: facts in source data, derivations in the preprocessor
|
|
10
|
+
|
|
11
|
+
The relaton audit made this concrete. Relaton's `status` FIELD lies in 58
|
|
12
|
+
records (claims in-force while carrying a successor edge) — because it is a
|
|
13
|
+
**derived fact stored as data**, the classic copy-drift bug. The
|
|
14
|
+
preprocessor therefore DERIVES status from successor edges and ignores the
|
|
15
|
+
field; nothing needed "fixing" for serving to be correct.
|
|
16
|
+
|
|
17
|
+
What derivation cannot invent: **missing edges**. 36 of 224 families have no
|
|
18
|
+
active edition because a successor edge was never recorded (e.g. `B 18:2016`
|
|
19
|
+
and `B 18:2017` both terminal). Those are genuine upstream gaps — they must
|
|
20
|
+
be fixed in relaton-data-oiml; the preprocessor's job is to SURFACE them
|
|
21
|
+
(the registry's no-active families are the worklist), not hide them.
|
|
22
|
+
|
|
23
|
+
| Data problem | Fix where | Mechanism |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Status field contradicts edges (58) | nowhere — derive | preprocessor: `derived_status` |
|
|
26
|
+
| Language instances carry primaries | nowhere — collapse | preprocessor: canonical-id dedup |
|
|
27
|
+
| Non-publication records (Bulletins) | nowhere — filter | preprocessor: series filter |
|
|
28
|
+
| Missing successor edges (36 families) | **relaton-data-oiml** | registry worklist → upstream PRs |
|
|
29
|
+
| Wrong/missing citation edges | **relaton-data-oiml** | graph build report → upstream PRs |
|
|
30
|
+
|
|
31
|
+
The loop: preprocessor emits a data-quality report every build; the report
|
|
32
|
+
drives upstream fixes; upstream fixes flow back on the next build. Data
|
|
33
|
+
gets better because serving keeps score, not because anyone audits YAML by
|
|
34
|
+
hand.
|
|
35
|
+
|
|
36
|
+
## The three layers
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
40
|
+
│ OBJECT INPUT INTERFACE (OII) │
|
|
41
|
+
│ The typed object contract. Four NATIVE object systems, each │
|
|
42
|
+
│ serialized from its own lutaml-model gem — never renderings: │
|
|
43
|
+
│ • Metanorma — document content model (metanorma-document) │
|
|
44
|
+
│ • Relaton — bibliographic records (relaton) │
|
|
45
|
+
│ • Glossarist — terminology concepts (glossarist) │
|
|
46
|
+
│ • PubID — canonical identifiers (pubid) │
|
|
47
|
+
│ Contract: the AI-serialization node projection (documents + │
|
|
48
|
+
│ typed nodes + edges), schema_versioned, validated at entry. │
|
|
49
|
+
└──────────────────────────┬───────────────────────────────────────┘
|
|
50
|
+
▼
|
|
51
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
52
|
+
│ RAG DATA PREPROCESSOR (RDP) — ingest/*, invariant-gated │
|
|
53
|
+
│ identity pubid-canonical DocumentRecord → D1 registry │
|
|
54
|
+
│ (derived status, active flags — the SSOT) │
|
|
55
|
+
│ structure typed nodes → ChunkRecordV2 (per block type) │
|
|
56
|
+
│ derivation registry + graph projection (relaton edges + │
|
|
57
|
+
│ glossarist defines edges) │
|
|
58
|
+
│ enrichment contextual contexts (quality-first lane, KV- │
|
|
59
|
+
│ cached, content-hash invalidated) │
|
|
60
|
+
│ embedding per-type embed_input → Vectorize (public/internal │
|
|
61
|
+
│ split — isolation is structural) │
|
|
62
|
+
│ verification invariants per stage + data-quality report → │
|
|
63
|
+
│ upstream worklist │
|
|
64
|
+
│ orchestration INDEX_VERSION bump → cache flush protocol │
|
|
65
|
+
└──────────────────────────┬───────────────────────────────────────┘
|
|
66
|
+
▼
|
|
67
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
68
|
+
│ RAG WORKERS — serving only, never parse source data │
|
|
69
|
+
│ rag-public ask/search pipeline + registry notes + graph lane │
|
|
70
|
+
│ rag-internal ISO federation (isolation-enforced) │
|
|
71
|
+
│ rag-mcp MCP tools for the agent ecosystem │
|
|
72
|
+
│ They consume: Vectorize + D1 (registry, graph) + KV (caches) │
|
|
73
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Current state vs the target
|
|
77
|
+
|
|
78
|
+
| Component | State |
|
|
79
|
+
|---|---|
|
|
80
|
+
| OII | de-facto: parse.py (HTML-first) + graph.py (relaton/glossarist). Target: consume the four native object serializations; the AI-serialization proposal (metanorma#592) is the upstream contract |
|
|
81
|
+
| Identity SSOT | ✅ documents registry in D1 (derived status, active flags, supersession chains) |
|
|
82
|
+
| Registry serving | ✅ edition notes injected into doc-scoped asks; `GET /api/documents?family=` public API |
|
|
83
|
+
| Graph projection | ✅ 7,128 nodes / 6,486 edges in D1; query lane live (defined_terms → defines → candidates) |
|
|
84
|
+
| Chunking | prose-only today; ChunkRecordV2 typed blocks = next build (tables/equations/requirements) |
|
|
85
|
+
| Enrichment | ✅ 98.7% corpus (the residual ~400 are persistent empty enrichments), KV-cached, replayed from the durable record after full restores |
|
|
86
|
+
| Verification | unit suites + contract tests in CI (`npm run test:units`, pydantic↔TS wire contract, schema-union drift); the data-quality report loop = next build |
|
|
87
|
+
| Orchestration | manual commands today; one-command pipeline (`ingest run --doc X`) when the above land |
|
|
88
|
+
|
|
89
|
+
## Corpus operations (the wire loop, as of 2026-09-08)
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
parse corpora → artifacts/chunks.jsonl (identifiers sanitized,
|
|
93
|
+
placeholders never win — language markers and :0000/:XXXX
|
|
94
|
+
fall to the slug-derived identity)
|
|
95
|
+
retrieval-plane primmel export → artifacts/model_retrieval_chunks.jsonl
|
|
96
|
+
(retrieval text/facets); the projection derives
|
|
97
|
+
artifacts/model_typed_chunks.jsonl (the ONLY unit_id/
|
|
98
|
+
block source) — separate files: one shared name had the
|
|
99
|
+
two derivations overwriting each other
|
|
100
|
+
embed content-aware resume: artifacts/embed_text_hashes.json
|
|
101
|
+
(id → text hash) — changed text re-embeds, untouched ids
|
|
102
|
+
never do (model chunk ids are content-independent hashes;
|
|
103
|
+
id-keyed resume alone would pair stale vectors with fresh
|
|
104
|
+
metadata)
|
|
105
|
+
upsert the internal worker's /admin/sync binding route
|
|
106
|
+
(rag-internal.<account>.workers.dev — no REST token
|
|
107
|
+
needed); the CLI's REST path defaults to the production
|
|
108
|
+
index idx_oiml_public_v2
|
|
109
|
+
restore scripts/restore_missing.py [sources...] [--batch N --pace S] —
|
|
110
|
+
reconcile's twin: reconcile deletes strays, restore fills
|
|
111
|
+
gaps (presence probe, then upsert only missing ids; paced
|
|
112
|
+
under the rolling Vectorize upsert quota — sustained
|
|
113
|
+
25-50-vector batches clamp after ~1k vectors; 10 × 25s
|
|
114
|
+
sustains; skips hard-failed batches, rerun to pick them
|
|
115
|
+
up)
|
|
116
|
+
enrich-replay scripts/replay_enrichment.py [--apply --pace S] — REQUIRED
|
|
117
|
+
after every full upsert OR raw restore: enrichment lives
|
|
118
|
+
only in the index (and the KV context cache), so both
|
|
119
|
+
overwrite it with raw text; the replay re-embeds
|
|
120
|
+
context+text from the durable record
|
|
121
|
+
(artifacts/enriched-contexts.jsonl) via the binding —
|
|
122
|
+
zero model generation, ≈$0.30
|
|
123
|
+
reconcile scripts/reconcile_index.py — enumerate the index (wrangler
|
|
124
|
+
list-vectors), diff against the canonical chunk set
|
|
125
|
+
declared ONCE in ingest/config.py
|
|
126
|
+
(CANONICAL_CHUNK_SOURCES — four derivations: prose parse,
|
|
127
|
+
retrieval plane, projection, MKO typed units), delete
|
|
128
|
+
strays (--apply). Upserts never delete; this closes the
|
|
129
|
+
loop.
|
|
130
|
+
cache scripts/invalidate_answer_cache.py (or wrangler kv put
|
|
131
|
+
sys:corpus_gen) after any corpus surgery
|
|
132
|
+
assets scripts/fix_figure_assets.py [--apply] — unit assets must
|
|
133
|
+
stay vision-readable (black-on-transparent rasters read
|
|
134
|
+
as solid black after alpha flattening); detects and
|
|
135
|
+
re-uploads white-flattened
|
|
136
|
+
documents scripts/upload_documents.py [--apply] — the rendered
|
|
137
|
+
publications for citation deep links (R2 docs/<slug>.html
|
|
138
|
+
+ clause-anchor maps, served at /docs/*); rerun when the
|
|
139
|
+
clean corpus's renderings change
|
|
140
|
+
graph ingest.cli graph (build) + graph --corpus apply (D1,
|
|
141
|
+
wrangler; absolute --file path)
|
|
142
|
+
gates scripts/gates.sh — golden ×N + annealment ×M
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The vector adapter (`ingest/vector_adapter.py`, contract in
|
|
146
|
+
`docs/vector-adapter.md`) remains the ONLY door from any producer to any
|
|
147
|
+
index: wire schema + target gating.
|
|
148
|
+
|
|
149
|
+
## PubID as the identity backbone
|
|
150
|
+
|
|
151
|
+
Node ids, registry keys, and chunk metadata all key on the canonical
|
|
152
|
+
identifier (`OIML R 60-1:2021`). Today graph.py normalizes identifiers with
|
|
153
|
+
its own regex; the target is the **pubid** gem's parser/generator as the
|
|
154
|
+
single authority (parse any spelling → canonical form → round-trip), so
|
|
155
|
+
`R60`, `OIML R60:2021 (E)`, and `r 60-1` all collapse to one identity
|
|
156
|
+
before they touch the registry. This is also an upstream piece of the
|
|
157
|
+
AI-serialization bundle: identifiers in the projection should BE pubid
|
|
158
|
+
objects serialized.
|
package/docs/MCP.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# OIML SMART AI — MCP Server
|
|
2
|
+
|
|
3
|
+
*Agent-native access to the OIML publications corpus via the Model
|
|
4
|
+
Context Protocol. For chat/API usage see [API.md](API.md); MCP is the
|
|
5
|
+
machine contract — including the publication registry, which is
|
|
6
|
+
deliberately NOT part of the chatbot API.*
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Connecting
|
|
11
|
+
|
|
12
|
+
**Endpoint:** `https://rag-mcp.oimlsmart-06c.workers.dev/mcp`
|
|
13
|
+
**Transport:** Streamable HTTP (MCP `2025-06-18`) — JSON-RPC 2.0 over
|
|
14
|
+
`POST /mcp`, stateless. `GET /` returns a service descriptor.
|
|
15
|
+
|
|
16
|
+
**Claude Desktop** (`claude_desktop_config.json`):
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"oiml": {
|
|
21
|
+
"type": "http",
|
|
22
|
+
"url": "https://rag-mcp.oimlsmart-06c.workers.dev/mcp"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
**Any MCP client:** point it at the URL above; no session handshake
|
|
28
|
+
state is required beyond the standard `initialize` call.
|
|
29
|
+
|
|
30
|
+
**Authorization:** the server is public-tier by default. Setting the
|
|
31
|
+
`RAG_API_KEY` secret (operator) raises its quota class; per-caller auth
|
|
32
|
+
is passed through the underlying API key if configured.
|
|
33
|
+
|
|
34
|
+
## 2. Tools
|
|
35
|
+
|
|
36
|
+
### `oiml_search` — ranked passage retrieval
|
|
37
|
+
```jsonc
|
|
38
|
+
// input
|
|
39
|
+
{ "query": "maximum permissible error load cell", "top_k": 3 } // top_k 1–10
|
|
40
|
+
```
|
|
41
|
+
Returns passages as text blocks:
|
|
42
|
+
```
|
|
43
|
+
OIML R 76-1:2006 §2.5.4 — 2.5.4 Maximum permissible error, mpe (T.5.4.4)
|
|
44
|
+
<snippet>
|
|
45
|
+
```
|
|
46
|
+
Use for: scanning the corpus, gathering context, cheap lookups (no
|
|
47
|
+
generation cost).
|
|
48
|
+
|
|
49
|
+
### `oiml_ask` — grounded, citation-linked answers
|
|
50
|
+
```jsonc
|
|
51
|
+
{ "query": "What does OIML R 60-1 require for verification intervals?" }
|
|
52
|
+
```
|
|
53
|
+
Returns the full answer plus a `Sources:` line of cited passages. Every
|
|
54
|
+
claim cites the exact publication and clause; normative values carry
|
|
55
|
+
verbatim quote anchors. Off-corpus questions return the canonical
|
|
56
|
+
refusal sentence.
|
|
57
|
+
|
|
58
|
+
### `oiml_documents` — publication registry (editions & status)
|
|
59
|
+
```jsonc
|
|
60
|
+
{ "family": "R-60" } // series letter + number, e.g. "R-60", "B-18", "D-11"
|
|
61
|
+
```
|
|
62
|
+
Returns every edition of the family with derived status:
|
|
63
|
+
```
|
|
64
|
+
OIML R 60:1991 — superseded → superseded by OIML R 60:2000
|
|
65
|
+
OIML R 60:2021 — in-force [ACTIVE]
|
|
66
|
+
OIML R 60-1:2017 — superseded → superseded by OIML R 60-1:2021
|
|
67
|
+
OIML R 60-1:2021 — in-force [ACTIVE]
|
|
68
|
+
…
|
|
69
|
+
```
|
|
70
|
+
`[ACTIVE]` is DERIVED from successor edges (terminal node of the
|
|
71
|
+
supersession chain), not from a status field — relaton's status field
|
|
72
|
+
contradicts its own edges in ~9% of records. Use for: "current/latest
|
|
73
|
+
edition", edition history, supersession questions. A family with no
|
|
74
|
+
`[ACTIVE]` line means the bibliographic data has a gap (missing
|
|
75
|
+
successor edge) — the registry surfaces it rather than guessing.
|
|
76
|
+
|
|
77
|
+
## 3. Protocol notes
|
|
78
|
+
|
|
79
|
+
- Notifications (no `id`) → `202`, no body
|
|
80
|
+
- Unknown method → `-32601`
|
|
81
|
+
- Tool failures → result with `isError: true` and the message (never a
|
|
82
|
+
dropped call)
|
|
83
|
+
- `initialize` responds with capabilities `{tools:{}}`; `tools/list`
|
|
84
|
+
returns the three tool definitions with JSON schemas
|
|
85
|
+
|
|
86
|
+
## 4. Implementation & isolation
|
|
87
|
+
|
|
88
|
+
The server (`workers/worker_mcp`, `rag-mcp`) holds **no corpus access
|
|
89
|
+
of its own**: `oiml_search`/`oiml_ask` proxy the rag-public API (so
|
|
90
|
+
audience isolation stays enforced in exactly one place), and
|
|
91
|
+
`oiml_documents` reads the derived D1 registry via a read-only binding
|
|
92
|
+
(public OIML metadata only — no ISO/IEC content).
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Metanorma AI Serialization — Adapter Format Proposal
|
|
2
|
+
|
|
3
|
+
*Proposed output flavor for `metanorma-document` (and the concrete answer to
|
|
4
|
+
[metanorma/metanorma#592](https://github.com/metanorma/metanorma/issues/592)):
|
|
5
|
+
a machine serialization of a Metanorma document designed for RAG ingestion
|
|
6
|
+
and AI training corpora. Draft v1.0.0-proposal, 2026-08-26.*
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Positioning
|
|
11
|
+
|
|
12
|
+
*Evidence alignment (2025–26): the projection's shape is exactly what the
|
|
13
|
+
normative-RAG literature converges on — [ETSI arXiv:2604.09868] recovers
|
|
14
|
+
InfoUnits + parthood/citation edges from PDFs by heuristic and shows
|
|
15
|
+
structure preservation is the retrieval win; [STC arXiv:2605.00318]
|
|
16
|
+
quantifies typed table rows (MRR 0.36→0.59); [RDR2 arXiv:2510.04293],
|
|
17
|
+
[SF-RAG arXiv:2602.13647], [SPIRE arXiv:2604.20849] all consume
|
|
18
|
+
structure trees/natively-hierarchical indexes; [MAHA arXiv:2510.14592]
|
|
19
|
+
indexes tables as structured objects and equations as LaTeX+description.
|
|
20
|
+
Metanorma can emit natively what all of them recover heuristically.*
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Metanorma already has the right substrate: `metanorma-document`
|
|
24
|
+
deserializes semantic XML into typed lutaml-model classes and serializes
|
|
25
|
+
them to XML/YAML/JSON natively. This proposal does NOT invent a new
|
|
26
|
+
document model — it defines a **projection flavor**: a stable, typed,
|
|
27
|
+
chunk-ready node graph derived from the existing model.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
adoc source ──compile──▶ semantic XML ──Root.from_xml──▶ metanorma-document MODEL
|
|
31
|
+
│
|
|
32
|
+
┌───────────────────────────────┤──▶ HTML / PDF (renderers)
|
|
33
|
+
└──▶ AiSerialization::Root.to_json / .to_yaml / .to_xml ◀── THIS PROPOSAL
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Properties:
|
|
37
|
+
|
|
38
|
+
- **Derived output** (like renderings): lossy by design, never a source
|
|
39
|
+
format; the model and semantic XML remain canonical.
|
|
40
|
+
- **Encoding-agnostic**: implemented as lutaml-model classes with
|
|
41
|
+
`mapping` blocks — JSON, YAML, and XML serializations of ONE schema.
|
|
42
|
+
No hand-rolled `to_h`/`to_json` anywhere (house rule).
|
|
43
|
+
- **Chunk-ready**: every node is self-contained (document identity +
|
|
44
|
+
breadcrumb + typed payload), so RAG consumers embed nodes without
|
|
45
|
+
re-deriving structure.
|
|
46
|
+
- **Graph-preserving**: a flat edge list exposes structure and semantics
|
|
47
|
+
(containment, requirements→conformance tests, term links, citations).
|
|
48
|
+
- **Training-corpus friendly**: provenance, license fields, and stable
|
|
49
|
+
node hashes make the same export usable as a curated AI-training
|
|
50
|
+
corpus (the #592 ask).
|
|
51
|
+
|
|
52
|
+
## 2. Envelope
|
|
53
|
+
|
|
54
|
+
```jsonc
|
|
55
|
+
{
|
|
56
|
+
"schema": "metanorma.ai-serialization", // const identifier
|
|
57
|
+
"schema_version": "1.0.0", // semver
|
|
58
|
+
"generated": {
|
|
59
|
+
"tool": "metanorma-document",
|
|
60
|
+
"model_version": "x.y.z", // gem version
|
|
61
|
+
"flavor": "oiml", // document flavor used
|
|
62
|
+
"timestamp": "2026-08-26T00:00:00Z"
|
|
63
|
+
},
|
|
64
|
+
"document": { /* DocumentIdentity, §3 */ },
|
|
65
|
+
"nodes": [ /* typed nodes, §4 */ ],
|
|
66
|
+
"edges": [ /* flat edge list, §5 */ ],
|
|
67
|
+
"datasets": { /* optional Glossarist/Relaton embeds, §6 */ },
|
|
68
|
+
"rights": { "license": "...", "copyright": "..." } // corpus-safe provenance
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 3. Document identity node
|
|
73
|
+
|
|
74
|
+
```jsonc
|
|
75
|
+
"document": {
|
|
76
|
+
"docidentifier": "OIML R 60-1", // authoritative, never slug-derived
|
|
77
|
+
"part": "1", // or "annex": "A"
|
|
78
|
+
"edition": "2017",
|
|
79
|
+
"language": "en",
|
|
80
|
+
"doctype": "R",
|
|
81
|
+
"status": "in-force", // in-force | superseded | withdrawn | joint
|
|
82
|
+
"superseded_by": null,
|
|
83
|
+
"title": "Metrological regulation for load cells — Part 1",
|
|
84
|
+
"family": "R-60", // series node for part graphs
|
|
85
|
+
"source": { "file": "document.xml", "hash": "sha256:…" },
|
|
86
|
+
"canonical_id": "OIML R 60-1:2017:en"
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 4. Typed nodes
|
|
91
|
+
|
|
92
|
+
Node classes map 1:1 onto existing model classes (right column = source in
|
|
93
|
+
`metanorma-document`):
|
|
94
|
+
|
|
95
|
+
| Node type | Source model class | Notes |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `clause` | `BasicDocument::Blocks::BasicBlock` (+subclasses) | carries `anchor`, `obligation`, breadcrumb |
|
|
98
|
+
| `table` | `BasicDocument::Tables::TableBlock` | columns/units/rows payload |
|
|
99
|
+
| `formula` | `BasicDocument::AncillaryBlocks::FormulaBlock` + `StemElement` | asciimath/latex/description |
|
|
100
|
+
| `figure` | `BasicDocument::Figure` | alt text, image ref |
|
|
101
|
+
| `term` | `StandardDocument` term entries | links to Glossarist concept |
|
|
102
|
+
| `requirement` | `Document::Components::Blocks::RequirementModel` | ModSpec projection |
|
|
103
|
+
| `permission` | `…/PermissionModel` | ModSpec projection |
|
|
104
|
+
| `recommendation` | requirement variants | ModSpec projection |
|
|
105
|
+
| `conformance_class` / `conformance_test` | ModSpec classes | `modspec-ruby` objects |
|
|
106
|
+
| `reference` | `BibData`/bibitem entries | Relaton key |
|
|
107
|
+
| `amendment`/`change` | `BasicDocument::Change` | editorial vs technical |
|
|
108
|
+
|
|
109
|
+
**Common fields (all nodes):**
|
|
110
|
+
```jsonc
|
|
111
|
+
{
|
|
112
|
+
"id": "n:tbl-4.1.2-1", // stable: "n:" + model anchor/id
|
|
113
|
+
"type": "table",
|
|
114
|
+
"parent": "n:cl-4.1.2", // containment (also in edges)
|
|
115
|
+
"anchor": "tbl-4.1.2-1",
|
|
116
|
+
"breadcrumb": ["4 Metrological requirements", "4.1 Classification"],
|
|
117
|
+
"obligation": "normative", // when the model carries it
|
|
118
|
+
"hash": "sha256:…", // content hash — enrichment invalidation
|
|
119
|
+
"text": "…" // human-readable display text
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Typed payloads:**
|
|
124
|
+
```jsonc
|
|
125
|
+
// table
|
|
126
|
+
{ "columns": [{ "label": "Load m", "unit": "e", "scope": "per verification interval" }],
|
|
127
|
+
"rows": [["0 ≤ m ≤ 5·10³", "0.5e"]],
|
|
128
|
+
"caption": "Maximum permissible errors",
|
|
129
|
+
"embed_text": "Table: Maximum permissible errors; columns: Load m [e], MPE; row: 0 ≤ m ≤ 5·10³ | 0.5e" }
|
|
130
|
+
|
|
131
|
+
// formula
|
|
132
|
+
{ "asciimath": "n_LC <= …", "latex": "n_{LC} \\leq …",
|
|
133
|
+
"described": "limit on the number of verification intervals" }
|
|
134
|
+
|
|
135
|
+
// term
|
|
136
|
+
{ "concept": "load-cell", "designation": "load cell",
|
|
137
|
+
"definition": "…", "vocab": "oiml-complete", "glossarist_id": "…" }
|
|
138
|
+
|
|
139
|
+
// requirement (ModSpec projection)
|
|
140
|
+
{ "identifier": "/req/oiml-r60-1/classification/nlc-limit",
|
|
141
|
+
"class": "/req/oiml-r60-1/classification",
|
|
142
|
+
"obligation": "requirement",
|
|
143
|
+
"statement": "The number of load cell verification intervals n_LC shall be within…",
|
|
144
|
+
"inherits": [], "subject": "load cell", "inherits:": [] }
|
|
145
|
+
|
|
146
|
+
// conformance_test
|
|
147
|
+
{ "identifier": "/conf/oiml-r60-1/classification/nlc-limit",
|
|
148
|
+
"class": "/conf/oiml-r60-1/classification",
|
|
149
|
+
"tests": "/req/oiml-r60-1/classification/nlc-limit",
|
|
150
|
+
"method": "Inspect the marking and the accompanying documents…" }
|
|
151
|
+
|
|
152
|
+
// reference
|
|
153
|
+
{ "key": "IEC61000-4-2", "cited": "IEC 61000-4-2:2008", "relaton_id": "…" }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`embed_text` is a PRODUCED convenience (deterministic serialization of the
|
|
157
|
+
payload for embedding); consumers may ignore it and serialize their own way.
|
|
158
|
+
|
|
159
|
+
## 5. Edges
|
|
160
|
+
|
|
161
|
+
```jsonc
|
|
162
|
+
{ "from": "n:tbl-4.1.2-1", "to": "n:cl-4.1.2", "kind": "part_of" }
|
|
163
|
+
```
|
|
164
|
+
Kinds: `part_of` (containment), `cites` (reference node → external docid),
|
|
165
|
+
`supersedes`, `defines` (term → concept), `tested_by` /
|
|
166
|
+
`requirement_of` (requirement ↔ conformance test), `class_of`,
|
|
167
|
+
`amends`, `variant_of` (language/edition variants).
|
|
168
|
+
|
|
169
|
+
## 6. Dataset embeds (optional)
|
|
170
|
+
|
|
171
|
+
```jsonc
|
|
172
|
+
"datasets": {
|
|
173
|
+
"glossarist": { "id": "oiml-complete", "concepts": 6031, "embedded": false, "ref": "…" },
|
|
174
|
+
"relaton": { "id": "relaton-data-oiml", "records": 5707, "embedded": false, "ref": "…" }
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
Embedding the full datasets inline is OPTIONAL (size); the fields declare
|
|
178
|
+
which datasets the document's edges/terms resolve against.
|
|
179
|
+
|
|
180
|
+
## 7. Serializations
|
|
181
|
+
|
|
182
|
+
One lutaml-model class set; three mappings (idiomatic examples):
|
|
183
|
+
|
|
184
|
+
- **JSON / YAML**: attribute names as above (`Metanorma::AiSerialization::Root.to_json`)
|
|
185
|
+
- **XML**: elements for complex parts, attributes for scalars —
|
|
186
|
+
`<node type="table" id="n:tbl-4.1.2-1" anchor="tbl-4.1.2-1"><caption>…</caption>…`
|
|
187
|
+
|
|
188
|
+
Consumers pick an encoding; the schema is the contract.
|
|
189
|
+
|
|
190
|
+
## 8. Conformance (producers MUST)
|
|
191
|
+
|
|
192
|
+
1. Emit `schema`, `schema_version`, full document identity, and node
|
|
193
|
+
`id`/`type`/`anchor` for every node.
|
|
194
|
+
2. Node ids stable across regenerations for unchanged content (anchor +
|
|
195
|
+
content hash basis).
|
|
196
|
+
3. Tables carry columns+rows (never linearized strings only); formulas
|
|
197
|
+
carry at least two of {asciimath, latex, described}.
|
|
198
|
+
4. Edges only reference present node ids or declared external keys.
|
|
199
|
+
5. `rights` present when the source declares license/copyright.
|
|
200
|
+
Consumers SHOULD treat unknown node types as opaque text nodes
|
|
201
|
+
(forward compatibility).
|
|
202
|
+
|
|
203
|
+
## 9. Our consumer mapping (rag ingest)
|
|
204
|
+
|
|
205
|
+
| AI Serialization | ChunkRecordV2 (Stage 2 spec) |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `document` | `DocumentRecord` |
|
|
208
|
+
| `nodes[type=clause]` | chunk `block: clause` |
|
|
209
|
+
| `nodes[type=table]` | chunk `block: table` + `table` payload |
|
|
210
|
+
| `nodes[type=formula]` | `block: equation` |
|
|
211
|
+
| `nodes[type=term]` | `block: definition` |
|
|
212
|
+
| `requirement`/`conformance_test` | `block: requirement` |
|
|
213
|
+
| `edges` (cites/supersedes/part_of/tested_by) | D1 graph projection |
|
|
214
|
+
|
|
215
|
+
## 10. Implementation sketch (upstream)
|
|
216
|
+
|
|
217
|
+
A `metanorma-document` flavor module — class set + a walk:
|
|
218
|
+
|
|
219
|
+
```ruby
|
|
220
|
+
module Metanorma
|
|
221
|
+
module AiSerialization
|
|
222
|
+
class Root < Lutaml::Model::Serializable
|
|
223
|
+
attribute :schema, :string
|
|
224
|
+
attribute :schema_version, :string
|
|
225
|
+
attribute :document, DocumentIdentity
|
|
226
|
+
attribute :nodes, Node, collection: true
|
|
227
|
+
attribute :edges, Edge, collection: true
|
|
228
|
+
json do |m| m.map "schema", to: :schema # … end
|
|
229
|
+
xml do |m| m.root "ai-serialization" # … end
|
|
230
|
+
end
|
|
231
|
+
module Project # the walk: model → nodes/edges
|
|
232
|
+
def self.call(doc_model) = … # visits typed model classes only
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
```
|
|
237
|
+
CLI: `metanorma compile doc.adoc -x ai-serialization,json` (a new output
|
|
238
|
+
format alongside html/pdf/… — the #592 ask reduced to one flavor entry).
|
|
239
|
+
|
|
240
|
+
## 11. Open questions for upstream
|
|
241
|
+
|
|
242
|
+
1. Version stability contract for the projection (semver gates?).
|
|
243
|
+
2. Whether `embed_text` serializations belong in the spec or a separate
|
|
244
|
+
"AI profile".
|
|
245
|
+
3. Multi-document collections (per-document envelopes vs collection
|
|
246
|
+
envelope with cross-doc edges).
|
|
247
|
+
4. License signaling for training-corpus redistribution.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# MKO export pipeline — mn-samples-oiml → RAG
|
|
2
|
+
|
|
3
|
+
**Status: producer + consumer validated end to end on the real corpus
|
|
4
|
+
(2026-08-28).** This is the producer-native path that replaces HTML
|
|
5
|
+
scraping for the clean corpus. Wire contract: MN 116 (metanorma/docs PR
|
|
6
|
+
#9, sources/116).
|
|
7
|
+
|
|
8
|
+
This pipeline is the first concrete realization of the ETSI-informed
|
|
9
|
+
redesign gaps ([REDESIGN-NORMATIVE-RAG-ETSI.md](REDESIGN-NORMATIVE-RAG-ETSI.md)):
|
|
10
|
+
native section `part_of` (G-ETSI-2), native `cites` edges (G-ETSI-3),
|
|
11
|
+
atomic typed tables (G-ETSI-5) — from the producer, with no recovery
|
|
12
|
+
heuristics.
|
|
13
|
+
|
|
14
|
+
## What MKO is
|
|
15
|
+
|
|
16
|
+
One Metanorma document → one `<short>.mko/` bundle of typed,
|
|
17
|
+
addressable knowledge objects:
|
|
18
|
+
|
|
19
|
+
| Component | Content |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `manifest.json` | schema id, per-component SHA-256 hashes (verified at ingest) |
|
|
22
|
+
| `document.json` | identity (parsed docids, doctype, edition, status, languages), relations, numbered structure tree |
|
|
23
|
+
| `units.jsonl` | typed units — clause/annex/term/table/figure/formula/note/example/sourcecode/requirement/reference — each with anchor, number, breadcrumb, plain text, typed payload, content hash |
|
|
24
|
+
| `edges.jsonl` | the graph: `part_of` containment, `cites` (reference **and** term units), `defines` (term→concept), `class_of`, document-level relations (`doc:<short> → ext:<id>`, Relaton type verbatim: obsoletes/hasPart/…) |
|
|
25
|
+
| `bibdata.json` | the document's own record as **native Relaton JSON** |
|
|
26
|
+
| `bibliography.jsonl` | every **cited document** as native objects: Relaton item + native pubid parse + pubid render |
|
|
27
|
+
| `glossary.json` | term entries as **native Glossarist concepts** |
|
|
28
|
+
| `identifiers.json` | the document's identifiers with **native pubid parses** |
|
|
29
|
+
|
|
30
|
+
Semantic anchors over GUIDs, content-hash-stable unit ids, byte-identical
|
|
31
|
+
determinism, zero flavor knowledge in the walk.
|
|
32
|
+
|
|
33
|
+
## Pipeline for mn-samples-oiml
|
|
34
|
+
|
|
35
|
+
The samples already carry compiled `document.xml` +
|
|
36
|
+
`document.presentation.xml` in-tree (OIML compiles through the iso
|
|
37
|
+
backend: `flavor="iso"`), so today the export is a one-liner per
|
|
38
|
+
document (from the metanorma-document checkout, branch
|
|
39
|
+
`feat/model-validation-l1-declarations`, PR #45):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# one command, gated (live since 2026-08-29):
|
|
43
|
+
.venv/bin/python -m ingest.cli mko # export → ingest → enrich → verify-gate → wire → fts → graph
|
|
44
|
+
.venv/bin/python -m ingest.cli mko --dry # counts + coverage check only
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The pipeline enforces the stage order this path proved matters: the
|
|
48
|
+
`verify` gate refuses to wire chunks that lack contextual preambles
|
|
49
|
+
(the 2026-08-28 regression — un-enriched upserts dropped retrieval
|
|
50
|
+
R@5 from 95% to 90%), and it stops before shipping (INDEX_VERSION
|
|
51
|
+
bump + deploy stay human). Stage 5 (wire) needs
|
|
52
|
+
`CLOUDFLARE_API_TOKEN` in the environment; enrichment upserts
|
|
53
|
+
enriched vectors live as it runs, so wiring is idempotent
|
|
54
|
+
bookkeeping afterwards. The underlying per-stage commands (for
|
|
55
|
+
reference / partial runs):
|
|
56
|
+
|
|
57
|
+
When the umbrella wiring lands (metanorma PR #591) this becomes
|
|
58
|
+
`metanorma compile document.adoc -x mko` and the Ruby step disappears —
|
|
59
|
+
the ingest side does not change.
|
|
60
|
+
|
|
61
|
+
## Worked example: OIML R 60-1 (load cells)
|
|
62
|
+
|
|
63
|
+
`oiml-r-60-1.mko` → ingest output (producer @e6918cb):
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
155 units (clause=72, term=59, table=6, figure=4, example=2, reference=12)
|
|
67
|
+
→ 136 chunks, 59 terms, 12 cited docs, 541 graph rows
|
|
68
|
+
canonical: OIML R 60-1 (edition 2)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Full-corpus run (2026-08-29, live):** 36 documents → 3,020 enriched
|
|
72
|
+
chunks (clause 1,913 / table 371 / term 113 / note 77 / formula 37 /
|
|
73
|
+
annex 32 / example 8), 113 glossary concepts, 342 cited docs, 3,561
|
|
74
|
+
section nodes + cites/defines edges in D1. Retrieval held at baseline
|
|
75
|
+
(R@5 95%, AP 0.875, MRR 0.893) after widening the rerank window to 10
|
|
76
|
+
for the enlarged clean lane.
|
|
77
|
+
## Full-corpus validation (2026-08-28)
|
|
78
|
+
|
|
79
|
+
All **37** compiled sample documents (R/D/B/G/E + OIML-CS admin + parts
|
|
80
|
+
+ amendments) export and ingest:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
37/37 bundles → 3053 chunks, 113 native Glossarist concepts,
|
|
84
|
+
342 cited documents (native Relaton + pubid), ~11k graph rows
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Includes the amendment cases: R 60/A1 keeps its 17 terms in an annex
|
|
88
|
+
(recovered into the glossary), and the OIML-CS admin documents keep
|
|
89
|
+
their whole body in `<preface>` (walked as clauses). Clause text now
|
|
90
|
+
carries list content in document order, not just paragraphs.
|
|
91
|
+
|
|
92
|
+
*Counting notes (verified against the artifacts): the 539 graph rows are
|
|
93
|
+
242 edges (147 `part_of`, 36 `cites`, 59 `defines`) + 297 node inserts;
|
|
94
|
+
figures and references become bibliography/graph objects, not chunks, so
|
|
95
|
+
135 chunks = clause 68 + term 59 + table 6 + example 2 (3 clause units
|
|
96
|
+
merge/empty; the source XML carries 63 raw `<term>` tags, 4 of them
|
|
97
|
+
nested/boilerplate).*
|
|
98
|
+
|
|
99
|
+
- 59 Glossarist-native concepts (designations, definition, sources,
|
|
100
|
+
`language_code: eng`) — the glossary-heavy load-cell vocabulary lands
|
|
101
|
+
directly in the terminology lane, no scraping.
|
|
102
|
+
- 6 tables as typed payloads (columns/rows), atomic — G-ETSI-5.
|
|
103
|
+
- 539 graph rows: 147 `part_of` (section parthood — G-ETSI-2), 36
|
|
104
|
+
`cites` (12 references + term sources — G-ETSI-3), 59 `defines`
|
|
105
|
+
(edges total 242; the remaining rows are node inserts).
|
|
106
|
+
- 12 cited documents (OIML V 1:2013, R 111, …) as native Relaton items —
|
|
107
|
+
the citation targets are addressable objects, not strings.
|
|
108
|
+
|
|
109
|
+
## Answer contract v2 stages (live)
|
|
110
|
+
|
|
111
|
+
- `to_payload_sql` → `artifacts/mko_unit_payloads.sql` → D1 `unit_payloads` (573 typed units; `mirror` stripped for serving size, 60KB cap)
|
|
112
|
+
- Figure assets → R2 `rag-public-assets` at unit-keyed keys, served at `/assets/u:<id>.<ext>` (immutable); `unit_payloads.payload.uri` updated to the canonical route (producer `uri` is null today — upstream asset-contract ask, metanorma-document#50)
|
|
113
|
+
|
|
114
|
+
## How the artifacts feed the existing stages
|
|
115
|
+
|
|
116
|
+
`artifacts/mko_chunks.jsonl` uses the **same chunk schema** the
|
|
117
|
+
parse/enrich/embed stages already consume (`chunk_text`, `doc_id`,
|
|
118
|
+
`docidentifier`, `clause_anchor`, `clause_title`, `tier`, `corpus`,
|
|
119
|
+
`status`, `superseded_by`, `text_ref`) plus new keys: `block` (unit
|
|
120
|
+
type), `unit_id`/`unit_hash` (incremental re-index keys), and typed
|
|
121
|
+
payloads (`metadata.table` with columns/rows, `metadata.formula` with
|
|
122
|
+
description/asciimath, `metadata.term`, `metadata.requirement`).
|
|
123
|
+
`artifacts/mko_graph.sql` targets the same D1 `graph_nodes`/`graph_edges`
|
|
124
|
+
tables as `ingest/graph.py`. `mko_glossary.json` and
|
|
125
|
+
`mko_bibliography.json` are new lanes (terminology exact-match; cited-doc
|
|
126
|
+
registry).
|
|
127
|
+
|
|
128
|
+
## Gaps / next steps
|
|
129
|
+
|
|
130
|
+
1. **CLI**: `-x mko` is wired in metanorma PR #591 (unreleased). Until
|
|
131
|
+
it ships, use the Ruby export above (works against the in-tree
|
|
132
|
+
compiled XML).
|
|
133
|
+
2. **pubid has no OIML flavor**: OIML identifiers ("OIML R 60-1:2017")
|
|
134
|
+
are not pubid-parsed → `pubid: null` in bibliography lines. Doc node
|
|
135
|
+
ids still normalize (`doc:OIML-R-60-1-2017` — same shape as
|
|
136
|
+
`graph.py#norm_id`, so the graphs join). Upstream ask filed:
|
|
137
|
+
pubid/pubid#342.
|
|
138
|
+
3. **Document-level relations**: the samples' semantic XML embeds no
|
|
139
|
+
relaton `<relation>` elements, so `doc:` edges are empty for them;
|
|
140
|
+
the relaton-data-oiml join stays authoritative for
|
|
141
|
+
status/supersession until flavors embed relations at compile time.
|
|
142
|
+
4. **Collections** (r060, r129, r138: parts + amendments via
|
|
143
|
+
`collection.yml`): export is per document today; a collection-level
|
|
144
|
+
manifest with cross-document edges is future MN 116 work.
|
|
145
|
+
5. **Multilingual editions** (FR/AR/…): units carry `lang`; interlinear
|
|
146
|
+
alignment (same unit id across languages) is specified in MN 116 but
|
|
147
|
+
needs producer work on translated sources.
|