Skip to content

Make check_source work on unbound rule templates#66

Merged
rmichaelthomas merged 1 commit into
mainfrom
feat/check-source-unbound-templates
Jul 21, 2026
Merged

Make check_source work on unbound rule templates#66
rmichaelthomas merged 1 commit into
mainfrom
feat/check-source-unbound-templates

Conversation

@rmichaelthomas

Copy link
Copy Markdown
Owner

Summary

check_source, as shipped in PR #65, calls run(source, enter_phase2=False, auto_confirm_amber=True) and passes contract_result.symbol_table straight to check_agreement. A contract source is very often an unbound rule template by design — it references evidence fields (amount, manager-approval, ...) that no remember binds. run() returns a symbol table with no entry for them, _build_constants allocates nothing, and encode_field raises UnencodableConstruct the first time a condition touches the field. Net effect: check_source returned encodable=False for every unbound template — every Translate draft, and every one of the six shipped templates in liminate-dev's app/agreement_templates.py.

This was verified against the real shipped vendor_invoice_review template, not just a synthetic case — it failed identically before this change. See Halverson dry run (PR #89), finding 1.

Changes

  • _condition_leaves, _literal_type, _predicate_subject_types, _infer_field_types — a type-inference pre-pass that synthesizes type-only placeholder SymbolEntry objects (value=None) for referenced-but-unbound fields, inferred from a literal comparison or a defined predicate's own body.
  • check_source now widens run()'s symbol table with these placeholders before calling check_agreement — a real remember/define binding always wins (only fills gaps, never overwrites).
  • A field typed by neither path stays unresolved and still correctly reports encodable=False — invariant 8 unchanged.
  • check_agreement, the encoder, and the seven checks are untouched.

Ported from case-studies/halverson/check-output/check_harness.py in liminate-dev — credit to that harness as the working prototype this stage productionizes.

Test plan

  • check_source on an unbound template with a numeric threshold returns encodable=True and finds the expected violation (regression test for the whole stage)
  • check_source on the real shipped vendor_invoice_review template (copied verbatim into the fixture) returns encodable=True
  • A field typed by a real remember is not overwritten by inference
  • A field typed only through a predicate application (<subject> is <defined-name>) resolves correctly
  • A field referenced but untypeable still yields encodable=False with a skipped_reason, never raises
  • Full suite green: pytest tests/ -q → 1787 passed (1782 prior + 5 new)

🤖 Generated with Claude Code

check_source (shipped in PR #65) passed run()'s symbol table straight
to check_agreement, so any referenced-but-unbound evidence field raised
UnencodableConstruct and every unbound rule template — every Translate
draft, and every shipped agreement template in liminate-dev's
app/agreement_templates.py — reported encodable=False (Halverson dry
run, PR #89, finding 1).

Adds a type-inference pre-pass inside check_source only: for each
referenced-but-unbound field, infer a scalar type from a literal
comparison or a defined predicate's own body, and synthesize a
type-only placeholder SymbolEntry (value=None) for it. A real
remember/define binding always wins. A field typed by neither path
stays unresolved and still correctly reports encodable=False —
invariant 8 unchanged. check_agreement, the encoder, and the seven
checks are untouched.

Ported from case-studies/halverson/check-output/check_harness.py in
liminate-dev, the working prototype this stage productionizes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@rmichaelthomas
rmichaelthomas merged commit c14eb38 into main Jul 21, 2026
2 checks passed
@rmichaelthomas
rmichaelthomas deleted the feat/check-source-unbound-templates branch July 21, 2026 19:07
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