Skip to content

Releases: kjpatel/duly

v0.4.0 — M4: standards, authoring, and static assurance

Choose a tag to compare

@kjpatel kjpatel released this 31 Jul 01:15
caf0eb2

M4 complete: the interchange contract now speaks standards, rule authors have a second surface and a solver, and the toolkit is demonstrably consumable from outside.

Ten capabilities across twenty-five pull requests (#6#30), and the golden corpus was never regenerated once. All 351 receipts replay byte-for-byte from before any of it. Every track's acceptance test was that git diff -- golden/ came back empty, and every one held.

Standards alignment

  • PROV-O JSON-LD export (#9#14) — facts, receipts, and run envelopes expand to W3C PROV triples under external contexts, stored bytes unchanged. The mapping is deliberately partial: bitemporal effective time, confidence, and abstentions have no faithful PROV equivalent. An earlier "lossless mapping" claim was corrected in the process.
  • Ontology conformance gate (#16) — a fact's schemaRef resolves against versioned, immutable LinkML artifacts; a misspelled attribute that previously surfaced only as a rule silently failing to bind now fails ingestion loudly. The hot-path validator interprets a documented LinkML subset rather than importing linkml-runtime, which would drag RDF tooling into the runtime.
  • Pack-embedded calendars (#17) — add_business_days walks a calendar the pack carries, with a coverage window that raises rather than guessing past its edge. "Last Monday in May" became legal content, versioned and receipt-pinned with the rules that use it. The TILA pack now computes the rescission deadline it could previously only certify.

Authoring

  • DMN decision-table compiler (#20) — DMN 1.3+ tables compile to the rule IR; the kernel cannot tell the result from a hand-written pack. It refuses rather than approximates: an uncited row is a compile error, not an invented TODO(verify).
  • Pack-owned decision phrasing (#28) — verdict wording moved from demo/app.py into the pack. Every determination the demo can render is byte-identical before and after; the wording moved without a word of it changing.
  • Rule-ID convention, ids grandfathered (#28) — nothing renamed, because NY-NR-45 sits in 76 golden receipts and a receipt is not editable. A rule id is a handle, not a claim.

Static assurance

  • Z3 static pack verifier (#21) — PROVED-DISJOINT / NOT-PROVED with a witness / OUT-OF-FRAGMENT naming what it declined to encode, plus uncovered input regions. Across six packs: 25 proved disjoint, one genuine overlap (correct — a registered eNote is a promissory note), nine uncovered regions, all intended and now witnessed. validate_pack is deliberately not relaxed.
  • What-if queries (#26) — solve a pack backwards for one freed input. The solver proposes; the kernel disposes: every answer is re-adjudicated, extremals are boundary-verified, and a disagreement raises with both artifacts rather than returning an answer.
  • Marker-gated suites now run in CI (#22) — linkml, z3, and docling had never executed there. The linkml one mattered most: its whole job is checking the ontologies against real tooling, and the pure-Python gate would have gone on passing while the files drifted out of spec.

Reference wiring

  • OR-Tools closing scheduler (#29), first resident of examples/ — CP-SAT plans sign → fund → record, where every hard constraint is a table of days an adjudication permitted and each chosen date cites the receipt ids that constrained it. Compliance opens Saturday 2026-02-21 (Saturdays are business days under the precise § 1026.2(a)(6) calendar); the wire desk is closed Saturdays, so the plan says Monday, and the output names which one bound the date.

Three claims the work corrected

  • The DMN acceptance criterion demanded "the same decision and receipt", which is unachievable: a receipt pins its pack's name and version, so two packs are two identities.
  • That equivalence proof turned out fixture-bounded — a >>= perturbation leaves the whole suite green because no fixture reaches the boundary. This is what motivated pack equivalence in the verifier.
  • "Keep actions outside the kernel" is only half a boundary. An integration can respect it perfectly at the API level and still hold a second copy of the rule ten lines away, invisible at the seam. Detectable only by mutation — which the scheduler now demonstrates rather than asserts.

Numbers at this tag

704 tests passing; 351 golden receipts replaying byte-for-byte; six rule packs across two domains; 1,478 committed facts conforming to their pinned ontologies; 25 same-priority rule pairs proved disjoint.

This tag marks a milestone, not a package release. pyproject.toml deliberately stays at 0.0.1 — nothing is published, and installable distribution is M5 work. The contracts remain v0 and may break until v1.0.

Full notes: CHANGELOG.md
Full diff: v0.3.0...v0.4.0

v0.3.0 — M3: extraction and review

Choose a tag to compare

@kjpatel kjpatel released this 30 Jul 15:50
d10b138

M3 complete: the probabilistic edge of the seam is now real, and the correction loop closes.

M3 (#3)

  • Extraction adapters — a protocol derived from two implementations (the honest scripted stub and live Docling), emitting renditions per spec D4 with every span verified against the rendition text on emission
  • Run envelopes — content-addressed manifests so a whole extraction run can be verified before ingestion and revoked at once (resolves the batch-envelope question deferred from M0)
  • Abstention policy — pack-versioned confidence floors enforced by the kernel: below-floor machine facts are excluded at binding with low_confidence receipt entries carrying score, threshold, and provenance; packs without a policy remain byte-identical (pinned-hash proven)
  • Calibration module — temperature, Platt, and split-conformal math with an ECE/Brier/coverage validation harness; deliberately unfitted until real review labels exist, and explicit that the conformal guarantee is marginal, not error-among-accepted
  • Review queue — abstentions become dedup'd queue items; human corrections enter the store as first-class superseding facts, flip decisions on re-adjudication, export (score, correct) calibration pairs, and freeze as replayable review-* golden cases
  • The demo arc — extract → abstain → inline human correction → flipped verdict → golden-case export, end to end in the browser

The commercial extraction adapter (Azure DI / Google Document AI) moved to v1.1 by decision: Docling proved the interface against a real converter, and a second provider is a contribution the seam exists to invite.

Also in this tag's tree (#4, #5)

Four statutorily-researched mortgage-closing rule packs — RON eligibility on real state authorization dates (including California's not-until-2030 statute), eSign/eNote routing, TILA rescission with its documented MODELING BOUNDARY, county recording readiness with its own abstention arc — plus a domain-grouped demo (seven scenarios, two domains) and the roadmap restructure that declared M3 complete (M4 reordered by consumer readiness, the alternate Datalog backend split to M5).

Numbers at this tag: 378 tests passing; 251 golden receipts replaying byte-for-byte; six rule packs across two domains; every citation verified against primary sources or marked TODO(verify).

Full diff: v0.2.0...v0.3.0

v0.2.0 — M2: replay and regression

Choose a tag to compare

@kjpatel kjpatel released this 29 Jul 17:32

Decisions were already deterministic in v0.1.0. This milestone makes that property continuously provable, adds the time dimension the architecture was designed around, and turns rule changes into a reviewable event.

What is new

Bitemporal fact store (store/) — append-only event log on SQLite with a Postgres-portable schema. Facts are never mutated; corrections supersede. Projections take both dials: as_of(case, knowledge, effective). The query the architecture exists to answer now runs: what would we have concluded in March, knowing what we knew in March? Ingest a correction recorded later and the old knowledge horizon still replays the original decision byte-for-byte, while the new horizon reflects the correction. Correction-of-a-correction chains are walkable in either direction. The store never reads the wall clock — knowledge time always comes from the facts themselves.

Golden corpus (golden/) — 250 committed synthetic cases with their adjudicated receipts, generated from a seeded deterministic generator (python -m duly_assurance generate). Coverage is deliberate: notice margins crossing each state threshold in both directions, 60+ cases evaluating under superseded rule versions, nonpayment grounds that exercise exception-and-defeat chains, and TRID amounts above, at, and below baseline. Regeneration from the same seed is byte-identical.

Replay verification (python -m duly_assurance verify) — re-adjudicates all 250 cases and asserts byte-identical receipts, catching both body edits and hash edits. Runs in CI on every push, so determinism is proven continuously rather than asserted in a README.

Rule-change impact analysis (python -m duly_assurance impact) — re-adjudicates the corpus under working-tree rule packs and reports every decision that changes. PRs touching rulepacks/ now get a sticky comment: "N of M decisions flip" with before/after receipts, plus reasoning-only changes (same verdict, different rules fired) tracked separately — the distinction an auditor cares about. Rule maintenance becomes a reviewed event with a visible blast radius.

Florida and California rule packs — verified against official statute text, not model recall:

State Nonrenewal minimum Nonpayment Source
New York 45 days 15 days N.Y. Ins. Law § 3425
Florida 120 days 10 days Fla. Stat. § 627.4133(2)(b)
California 75 days 10 days Cal. Ins. Code § 678(c), § 677.4

Three jurisdictions, three thresholds, one generic deficiency rule — the long-tail argument made concrete. Sub-cases outside the fact vocabulary carry explicit # SCOPE: comments; unconfirmed enactment dates carry # TODO(verify): markers rather than guesses.

Pack validator: provable disjointness — equal-priority rules are permitted when the validator can prove they never co-apply, via disjoint effective windows (rule versioning) or contradictory equality guards (jurisdiction scoping). It earned its keep immediately: it caught that the NY nonpayment rule lacked a state guard and would have applied its 15-day figure to Florida and California cases.

Verify it yourself

uv sync
uv run pytest kernel/tests demo/tests assurance/tests store/tests
uv run python -m duly_assurance verify

124 tests. CI runs the full suite plus replay verification on every push.

Honest labels

Corpus cases are synthetic and use attestation grounding rather than fabricated documents. Extraction remains a scripted stub pending real adapters (M3). One pre-2026 NY rule version is marked DEMO-SYNTHETIC and exists only to demonstrate effective-dated replay. Breaking changes expected until v1.0.

Full changelog: v0.1.0...v0.2.0

🤖 Generated with Claude Code

v0.1.0 — M1: end-to-end vertical slice

Choose a tag to compare

@kjpatel kjpatel released this 29 Jul 17:01

First working milestone: the complete perception-proposes-logic-disposes loop, running deterministically end to end.

What works

  • Grounded fact contract (spec + JSON Schemas): typed facts with clause-level provenance, calibrated confidence, and content-addressed ids; decision receipts with full derivation trees.
  • Defeasible rule IR: YAML rule packs with priority, overrides, legal citations, and effective windows; a typed expression language with decimal-only money.
  • Reference kernel: stratified deterministic evaluation with defeat semantics, effective-dated rule selection, human-outranks-machine conflict resolution, and receipt emission. No wall clock, no floats, no randomness.
  • Two rule packs: New York termination-notice compliance (N.Y. Ins. Law § 3425) and federal TRID fee tolerance (12 CFR 1026.19(e)), each with declared expected outcomes run in CI.
  • Two starters: synthetic documents with span-verified extracted facts for both verticals.
  • Interactive demo (uv run uvicorn demo.app:app --port 8788): grounding-span highlighting, derivation tree, citations, defeated-rule badges, receipt download, and as-of replay — change the evaluation date and watch the outcome flip under the rules then in force.
  • Deterministic audit reports: layered Markdown + PDF rendered purely from the receipt (byte-identical on re-render), with PII quote redaction. Example report.

80 tests. Breaking changes expected until v1.0.

Honest labels

Demo documents are synthetic; extraction is a scripted stub pending real adapters (M3); one pre-2026 historical rule version is marked DEMO-SYNTHETIC and exists only to demonstrate effective-dated replay.

🤖 Generated with Claude Code