Repository navigation
ADR 003 Rule Based Classification
Accepted 2026-05-26. Not implemented in code (verified 2026-08-26). Replaces the earlier "Reuse EPIC.search Embedder" ADR.
DEMI has no classifier. There is no configs/ directory, and nothing in src/ reads
document-types.yaml, maps a document type to an ORCS code, or derives a retention class.
orcsClassification in src/seed/transform.js is copied verbatim from Eagle's document metadata.
The classify() function in src/text-quality.js scores text quality for chunking and is
unrelated to this decision. The approach below is the one to build when AICT needs it.
AICT needs suggested metadata for uploaded files: document type, topic tags, ORCS classification and retention class. The original DEMI brief assumed an LLM would produce them.
LLM classification is cheap. GPT-4.1-nano at May 2026 prices costs about $0.0001 per document — roughly $26 to classify the 65,000 existing Priority 1A documents, and about $7 a year at 50 uploads a day. Cost is therefore not the reason to avoid it.
The reason is the Metadata Verification Hold: a human reviews every classification before it takes effect. Suggestions only have to be helpful starting points, so 80% accuracy from rules is enough when a person confirms 100% of them.
Version 1 classifies by rules only. No LLM inference for metadata suggestions.
| Metadata | Method | Expected accuracy |
|---|---|---|
| Document type | Keyword scoring against a controlled vocabulary | 70-80% |
| Topic tags | Term frequency matched against tag definitions | 60-70% |
| ORCS code | Document type to ORCS mapping table | 90%, given the right type |
| Retention class | ORCS code to retention schedule lookup | 100%, given the right ORCS code |
| Title | PDF Title metadata, first heading, or filename |
50-70% |
| Creator | PDF Author metadata or email From header |
80% |
| Date | PDF CreationDate, email Date header, or filename pattern |
85% |
# configs/document-types.yaml
- name: "Environmental Assessment Certificate"
code: "EAC"
indicators:
high: ["environmental assessment certificate", "eac amendment"]
medium: ["certificate holder", "certified project"]
low: ["assessment", "certificate"]
orcs_code: "15400-30"Each high match scores 10, each medium 3, each low 1. The three highest-scoring entries with
a non-zero score are offered to the reviewer, each with its score and the keyword that earned it.
Not part of this decision and not built. The original plan used Typesense's similar_document_id,
which went with Typesense. Retrieval is lexical BM25 with no vector component, so there is no
embedding to compare — see Search-and-Retrieval.
Positive:
- No per-document cost, no API keys, no rate limits, and no external service to be down.
- Deterministic and explainable: a suggestion names the keyword that produced it.
- Fast enough to be free at this volume — string matching, under 100 ms per document.
- Tunable by editing YAML rather than code.
Negative:
- Lower accuracy than an LLM on ambiguous documents, roughly 70% against 90%.
- The keyword vocabularies have to be curated and maintained.
- Document types absent from the vocabulary get no suggestion at all.
- No use of context: rules cannot infer a subject that the text never names directly.
Move to LLM classification only if rule accuracy stays below 60% in use, reviewers report the suggestions are unhelpful, or volume grows enough to justify the API cost. The upgrade is an opt-in per project, using a small model only where rule confidence falls below a threshold; AI is already in the stack as a search-result summarizer, so this adds no first external dependency.
An embedding-similarity step is not an option: it would mean building the vector pipeline the project has deliberately not built.
- Environment Reality & Gotchas
- Architecture
- Seeding — filling Cosmos from Track and Eagle
- Sources and Status — every source, one state
- Search & Retrieval — overview
- Search Index Reference
- Search Query Construction
- Search Measurements
- Extraction Pipeline
- Extraction Quality — coverage, word-joining, tiling
- Identity Model — which id means what
- Attribute-Level Access — field-visibility levels, catalog
- Sync Architecture — how records get in
- Eagle Mirror Reference — mirrored kinds, refusals, drift classes
- ENGAGE Rows Reference — ENGAGE-owned comment periods, reconcile
- Public-Read Backfill — filling and repairing the mirror containers
-
Short Links —
/s/{code}redirect and/api/links -
Recent Uploads —
/api/documents/recent-uploads, eagle-public homepage panel - Reports — comment export and BCGW CSV reads
-
User Data — saved map areas, preferences,
/meroutes -
Bulk Download —
/api/bulk-downloads, zip jobs - Bulk Download: Operations — enable, poison-queue runbook
- Document Intake — upload link, malware scan, release
- Connecting an Application to DEMI
- Azure Environments
- Document Backup — archive copy of originals, run and check
- Document Backup: Revert and Drill — put documents back from the archive
- PDF Titles — public name written into stored PDFs, run, restore
- Secret Sync — Key Vault, secret-sync Function app, required names
-
Operating DEMI in Azure — deploy, verify
- Operating the DEMI Data Plane — devbox access, probes, audit and cost reads
- Edge ban detector — hourly timer, modes, kill switch, soak and promote
-
CI Workflows — every GitHub Actions workflow, trigger, identity, roles
- CI Deploy Workflows — eagle-demi staging and production deploys
- CI Admin Frontend Workflows — eagle-demi-admin checks and deploys
- Release Process — cutting, tagging, shipping and rolling back a version
- Runbook: Search Outage — index/app schema drift, diagnose, fix, roll back
- BC Gov Landing Zone
- Business Rules
- EPIC.search Business Rules — where DEMI differs from EPIC.search
- 001: Typesense for DFL Search — superseded
- 002: Async Processing (MongoDB Queue) — superseded
- 003: Rule-Based Classification
- 004: Read ACL Authorization Model
- 005: Cosmos Full-Text Search Ruled Out
- 006: AI Summarization over BM25
- 007: Service-to-Service Credentials
- 008: Audit and Usage Analytics Store
- 009: Track Feed — proposed
- 010: Attribute-Level Access Control
- 011: Public Read Surface
- 012: Public Config Surface
- 013: Stored Project Summaries — proposed
- 014: Sync-out to Eagle
- 015: Malware scanning on intake