ADR 0001 — Rule set architecture: archetype as function, dimensions as kwargs¶
Status: Accepted Date: 2026-06-15 Deciders: Javier Marín Releases affected: 2026.6.13 (Phase 1 + 2)
Context¶
Groundlens ships rule sets in groundlens.agents for the three agent classes
in production AI pipelines (routing, RAG/informational, specialized/tool-using)
plus a decision-rationale set in groundlens.rules
(groundlens_banking_rules). The earlier naming convention encoded both the
agent archetype and the deployment dimension in the function name:
customer_support_rag_rules() # archetype + modality (RAG/no-RAG) baked in
groundlens_banking_rules() # archetype + domain (banking) baked in
rag_rules(domain=...) # dispatcher that returned the banking set by default
Two real cases (BBVA Blue RAG, Santander decision rationales — both in the cookbook) confirmed the current rule sets work, but they also surfaced three problems:
- Proliferation pressure. Adding insurance, healthcare, legal coverage under the current convention would require one new factory per domain.
- Confusing dispatch.
rag_rules(domain="banking")returned a decision-rationale set, not a RAG set. The name and the semantics disagreed. - Modality baked in.
customer_support_rag_rulescould not be reused for the no-RAG case (chat without retrieved context) without cloning.
Decision¶
Archetype is the function name. Dimensions are kwargs.
customer_support_rules(rag=True, domain="general", language="en")
decision_rationale_rules(domain="finance", regulations=("eu_ai_act",))
routing_rules(domain="general")
specialized_agent_rules(domain="finance", tools=())
- One factory per agent archetype (routing, customer support, decision rationale, specialized).
- Dimensions that the archetype legitimately varies over become keyword arguments on that factory.
- Heuristic for adding a new factory: only when the new agent class has a structurally distinct sub-score taxonomy. Same sub-scores with a different vocabulary is a kwarg, not a function.
Heuristic table¶
| Change | Action | Why |
|---|---|---|
| New agent archetype (different sub-scores) | New factory | Structurally distinct |
| New domain (banking → insurance → healthcare) | domain= kwarg |
Sub-scores stable; vocabulary changes |
| New regulation (EU AI Act → SR 26-2 → HIPAA) | regulations= filter on audit_explanation |
Rules unchanged; only citation provenance changes |
| New language (en → es → multi) | language= kwarg |
Stopword / speculative-marker surface only |
| RAG present vs absent | rag= kwarg |
Same archetype, different evidence available |
Alternatives considered¶
Approach 1 — Single generic factory¶
Rejected: less discoverable. IDE autocomplete on a function name gives the deployer the archetype catalogue immediately; autocomplete on a kwarg of a generic factory doesn't.
Approach 2 — Functional composition¶
Rejected: more verbose at the call site. The 95% path should be one line, not three. Composition is Pythonic but punishes the deployer reading a notebook at 11 PM. Could be reintroduced as a power-user API later.
Approach 4 — Minimal kwargs, keep current names¶
Rejected by the maintainer on UX grounds: keeping both
customer_support_rag_rules and a hypothetical customer_support_rules
factory side by side is worse than collapsing them into one with rag= as a
parameter. The cost of the refactor is justified by the UX win.
Consequences¶
Phase 1 (release 2026.6.13)¶
customer_support_rag_rules()→customer_support_rules(rag=True, domain="general", language="en").- Old name preserved as a
DeprecationWarningalias for at least three releases. rag=Falseshrinks the produced sub-scores:groundednessis omitted (no context to verify against); the result carriescompletenessandno_overreachonly. The flag predicate adapts.domainandlanguageextend stopwords / speculative markers; they do not add rules.
Phase 2 (same release 2026.6.13)¶
groundlens_banking_rules()→decision_rationale_rules(domain="finance", regulations=("eu_ai_act", "sr_26_2")).- Old name preserved as a
DeprecationWarningalias. regulations=filters the citation lines that appear inaudit_explanation; it does not add or remove rules.rag_rules()(the old dispatcher) is preserved as a deprecated alias that redirects tocustomer_support_rules(rag=True)for thecustomer_supportcase anddecision_rationale_rules(domain="finance")for thebankingcase.routing_rules()gains adomain="general"kwarg for symmetry; no behavioural change yet.specialized_agent_rules()gainsdomain="general"andtools=()kwargs.
Cookbook¶
Both notebooks (customer_support_rag_eval_clean.ipynb,
decision_rationale_eval.ipynb) are updated to use the new factory names.
The deprecated calls would still work but emit a warning.
Phase 3 (future)¶
Removal of deprecated aliases is deferred to a future release. No date set; will follow an explicit notice on the changelog.
Non-decisions (left for later)¶
template=parameter forcompute_sgi/compute_dgiis orthogonal to this refactor. It belongs to the geometric layer, not the rule layer. Tracked separately.- Power-user composition API (
.extend()) is not introduced here. Reconsider only if a real case requires it. register_domain()extension hook is not introduced here. Reconsider if community contributions start arriving.
References¶
- Cookbook notebook 1 (BBVA RAG Blue replication):
customer_support_rag_eval_clean.ipynb - Cookbook notebook 2 (Santander decision rationale replication):
decision_rationale_eval.ipynb - Marin (2025). Semantic Grounding Index for LLM Hallucination Detection. arXiv:2512.13771.
- Marin (2026). A Geometric Taxonomy of Hallucinations in Large Language Models. arXiv:2602.13224.
- Marin (2026). Defendable Rules for LLM Rationale Evaluation in Banking Governance: A Multi-Source Provenance Framework.