Skip to content

Add an authoritative variable definition tool - #257

Open
vahid-ahmadi wants to merge 1 commit into
mainfrom
feat/variable-definition-tool
Open

Add an authoritative variable definition tool#257
vahid-ahmadi wants to merge 1 commit into
mainfrom
feat/variable-definition-tool

Conversation

@vahid-ahmadi

Copy link
Copy Markdown
Collaborator

Part of #250 (§2, the formula-definition tool). Advances #140.

Why

The runtime can tell the model where a variable lives (get_variable, search_variables) but not what it means or how the model defines it. Questions like "what does household_net_income measure" or "how is Universal Credit calculated" had no grounded path, which is the class of failure behind the wrong LHA-vs-UC answer in the 8/17 session.

The tool

get_variable_definition(query, limit=5) — accepts an exact variable name or a short description, and has exactly four deterministic outcomes:

Outcome When Returns
success exact name, or one variable alone in the best matching tier one definition + source
needs_confirmation several variables tie at the best tier ranked options, no definition
error nothing matches ranked close variable names + a hint
error query has no word characters the reason

Matching walks fixed tiers — exact name, exact label, phrase, all tokens, description — and breaks ties on shorter canonical name then alphabetical order, so a result never depends on registry iteration order. Observed behaviour against policyengine-uk 2.89.2:

  • household_net_incomesuccess / exact_name
  • child benefitsuccess / exact_label
  • net incomeneeds_confirmation, 15 tied options
  • what does universal credit includeerror, suggestions led by universal_credit
  • universl credt (misspelt) → error, suggestions led by universal_credit

Suggestions rank by how many query words a variable covers, then by how little padding the variable carries. Recall alone ties universal_credit with is_uc_eligible; that precision term is what puts the variable the query actually names first.

Formula honesty

#140 warns against sourcing formulas from a package other than the one doing the calculation. Definitions here are read from the compiled model version that runs the simulations, so they cannot diverge, and source.model carries that version.

formula is authoritative only when formula.available is true. It is then the model's own adds/subtracts composition rendered as an exact statement:

household_net_income = household_market_income + household_benefits - household_tax - pension_contributions

89 of 869 UK variables expose one. The remaining 780 — including universal_credit — return available: false with a note saying the label and description are documentation, not a formula. The system prompt rule and an answer eval both pin that the model must say the exact formula is unavailable rather than describe one.

Files

  • backend/engine/definitions.py (new) — matching, ranking, formula and source reporting. Kept separate from engine/discovery.py, which answers only existence and location.
  • backend/tools/definitions.py, backend/tools/dispatch.py — strict schema (additionalProperties: false, limit clamped to 1–10) and registration.
  • backend/prompts/system.py — how to read each status and when formula may be trusted.
  • docs/engineering/skills/uk-chat-runtime.md — the boundary, per the AGENTS.md canonical-docs-first rule.

Verification

  • backend/tests/test_variable_definitions.py — 17 tests. Ranking rules run against a stub model so they stay pinned where policyengine.py is unavailable; the compiled-model cases are gated with requires_policyengine_py.
  • 8 new eval cases covering all four suites Plan UK Chat beta launch readiness scope #250 asks for: 4 tool_contract (each outcome), 1 trajectory (tool selection), 2 answer (no formula over-claim; composition stated exactly), 1 tool_loop (disambiguate, then define).
  • make eval-ai-offline: 124 passed, 0 failed (116 on main).
  • Backend suite: 477 passed, 12 skipped.

Not in scope

Parameter source metadata. get_parameter already returns values and labels; whether parameters need the same definition/provenance treatment is worth deciding separately rather than widening this tool.

🤖 Generated with Claude Code

https://claude.ai/code/session_01W5Zsotd2SND15F9efcePoP

The runtime could report where a variable lives but not what it means or how
the model defines it, so questions about a variable's meaning were answered
from memory or inferred from a simulation.

Add get_variable_definition, backed by engine/definitions.py. Resolution is
deterministic with four outcomes: one definition, ranked options when several
variables tie at the best matching tier, ranked suggestions when nothing
matches, and an error for a query with no word characters. Matching walks fixed
tiers and breaks ties on name length then alphabetical order, so the result
never depends on registry iteration order.

Formulas come from the model's own adds/subtracts composition and are reported
as exact statements. Variables without a machine-readable formula report
available: false with a note, so a description cannot be presented as a
formula. Definitions are read from the compiled model version that runs the
simulations, which is the divergence constraint in #140.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W5Zsotd2SND15F9efcePoP
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
policyengine-uk-chat Ready Ready Preview Aug 24, 2026 1:38pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant