Skip to main content

homestead-law

Homestead · Affairs — module one. The household handling its own deeds and disputes. Prose name: Law Gazelle.

A self-contained desktop module: it ships to a self-represented parent or a legal-aid clinic who double-clicks it, so its store is embedded SQLite — a linked library, not a server (the face's 2026-08-04 "no listening socket" decision holds; SQLite binds no port). The record layer is the engine's now: store.py is a thin binding — homestead.keep.store's adapter contract on a SQLite backing, in the law database. The invariants (I-6/I-7/I-9/I-11) are the engine's, tested there against every backing; this module only chooses the backing and the database. It pins the engine from PyPI — homestead-affairs>=0.1.0,<1.0 (the distribution name; import homestead is unchanged) — and shares the ~/.homestead root with the ledger, because a household's affairs are one thing.

The shared Postgres engine on the fleet side (the Willow side of the die) is a sync target, reached through the egress gate — never a runtime dependency of the shipped app. Sync is an S4 egress: an L5 record never crosses, and what lands in the shared store is only what the household chose to expose.

Status: bite 3 — runnable end to end on SQLite. The store (bite 1), the custody pack and registry (bite 2), and now the app — the two S1 surfaces (app/window, app/view), the cover's re-identification check (app/cover, I-31), the surfaced advisory matcher (app/advisories), and the citation extractor (patterns, I-18) — all reading the SQLite store. The chokepoint (I-16) guards the app: only the store reaches a payload, and no surface reflects. python -m homestead_law --demo prints the whole store→gate→surface pipeline headless. And the queue (queue) — what the season owes — deadlines across every matter, iterating all_matters() (the registry, not a hand-kept list — BUG-6's fix), computing urgency with homestead.keep.dates, surfacing an unparseable date as a gap (I-8), dropping a sealed deadline, and feeding the cover's re-identification check (I-31). The queue is wired into the app: the resting cover shows only counts that survive re-identification (nothing, over a single matter), a "What's due" view lists the queue, and --demo prints it headless. Suite: 85 passed. The "prove one app on SQLite end to end" milestone is met; the adapter seam and the gated Postgres sync generalize from here.

Entering your own information

The demo (--demo) is synthetic. A household's own records go into the household root — $HOMESTEAD_HOME, else ~/.homestead — and nothing below needs the optional entity extra:

pip install -e .

homestead-law ui                                   # entry forms, intake and dashboard, on localhost
homestead-law put custody courthouse "Dept 4, Second Judicial District Court, Bernalillo County"
homestead-law put custody child_name "A. Rivera"   # stored at the pack's rung (L4) — no rung is chosen here
homestead-law deadline custody hearing 2026-10-01 "Custody hearing"
homestead-law deadline custody evaluation 2026-08-12 --rung L4 "A submission is due"
homestead-law show custody                         # the list pane: L1–L3 shown, L4 derived, L5 absent
homestead-law show custody child_name              # the detail pane: L4 renders, L5 still refused
homestead-law queue                                # what's due
python -m homestead_law                            # the window, on these records (the demo only if empty)

Dates go through the engine's one strict parser on both doors: deadline takes 2026-10-01 or August 10, 2026, stores the ISO form, and refuses anything it cannot read in one line — a date the queue could not have read is a refusal where it can still be fixed, never a gap met weeks later.

The browser UI (ui) is the plain way in: a Records tab with a field form (matter, field, value — the rung and its reason shown beside the field), a deadline form, and the records on file composed through the gate; an Intake tab that extracts dates, parties, case numbers and courts from pasted text so each can be stored with one click. Entity resolution (resolve, propose), court orders (orders) and the ledger check (verify) need pip install 'homestead-law[entity]' and say so when it is missing.

Instances and jurisdiction

A matter can be more than one order in more than one forum — an NM custody order being registered in Oregon after a relocation is one matter, custody, with two instances: the original NM order and the OR registration. Nothing in the engine changed to say so (wave 3, decision 2): an item id is just a string, and this bite is the convention it now follows —

item_id(instance)        -> "<instance>"
item_id(instance, sub)   -> "<instance>.<sub>"

— stored exactly where it always was, (matter, item_type, item_id). An id matches ^[a-z0-9][a-z0-9-]{0,39}$ (homestead_law.instances.ID_PATTERN) — lowercase letters, digits and hyphens, never a dot — so split_item_id can always recover the two halves without guessing. --id defaults to primary everywhere, so a household with one instance of a matter sees no change at all.

An instance's jurisdiction — which forum's rules govern it — is a fact about the instance, not the matter: a pack declares a default (JURISDICTION) and the full set an instance may be filed under (JURISDICTIONS); an operator opens an instance by declaring which one it is actually in:

homestead-law matter open custody --id nm-order --jurisdiction US-NM
homestead-law matter open custody --id or-order --jurisdiction US-OR
homestead-law put custody courthouse "Second Judicial District Court" --id nm-order
homestead-law deadline custody nm-order 2026-11-01 --sub hearing
homestead-law deadline custody hearing 2026-11-01     # the default instance: primary.hearing
homestead-law show custody                    # lists instances: nm-order, or-order
homestead-law show custody --id nm-order      # that instance's records

Every deadline is addressed to an instance. What is stored is always "<instance>.<name>": with no --sub the positional id is the deadline's name inside the default instance (so the command line an operator already knows is unchanged and deadline custody hearing … files primary.hearing), and with --sub the positional id is the instance and --sub the deadline within it. A free-form id is refused by name, not stored — an id that cannot be split is a deadline no instance can own, and the instance list, the queue's matter+instance naming and the computed-deadline keys a later bite writes ((matter, "deadline", "<inst>.<template>")) all rest on the shape. See docs/DECISION-deadline-ids-are-instance-addressed.md; there is no migration (the store is v1 synthetic-only), and a deadline written before this convention still opens by its own id through show <matter> deadline <id>.

A code outside the pack's own JURISDICTIONS is refused by name, and nothing is stored; opening an already-open instance again is refused unless --replace is given (the store's own I-9, not a new rule). Reading a jurisdiction back (homestead_law.jurisdiction.jurisdiction_of) goes through the same gate every other record does — serve(), never .payload — and refuses (provisional I-42: "jurisdiction absent → refuse") whenever nothing was actually rendered, whether because no jurisdiction was ever set or because what is on file does not read back as itself (a jurisdiction planted by hand at L5, say, or a code the pack's own tuple does not contain — checked on the way out as well as on the way in, since L1 renders whatever is on disk). Anything that will one day do date arithmetic on a deadline in an instance must call jurisdiction_of first — an anchor date counted under an assumed forum is a guess about which rules to count under, and this module refuses that guess before the counting rules themselves exist to make it (they are a later bite).

A pack may also declare REPEATABLE — field names that accept a --sub (a repeatable sub-record, e.g. a child of a custody matter). Custody declares none yet; --sub on any of its fields is refused by name.

GET /api/instances?matter= and POST /api/matter/open are the browser UI's doors onto the same two functions; /api/store and /api/deadline accept id/sub alongside the existing fields. The page's own forms do not yet offer an instance picker — that UI wiring is left to a later (surfaces) bite; today they always write the primary instance, exactly as before this one.

What is enforced here today

The record invariants, carried from homestead.keep.record and held more tightly by the database.

I-6 The canonical record is read-only, enforced by type. Canonical reads the canonical table and has no put/update/delete; Sidecar writes its own. The Postgres sync target is the shared canonical on the fleet side.
I-7 One key. (matter, item_type, item_id) is the composite primary key, computed once by key(), shared by read and write. Two call sites cannot derive it two ways (BUG-11).
I-9 Writes never silently overwrite. A first write is an INSERT; the primary key makes a racing second write an IntegrityError, refused — race-safe by the database, no lock. An explicit overwrite reports what it replaced.
I-11 Absence fails closed to L5 at the storage boundary. A row whose rung is missing, unreadable, or whose payload will not decode reads L5 on the way out — never L1 — using the same rungs._read_rung the gate uses.

The method

Test-first, as in homestead: every claim is a check somebody can run. From a cold checkout — the engine (homestead.keep) resolves from PyPI as homestead-affairs, no sibling checkout needed:

pip install -e .    # pulls homestead-affairs (homestead.keep) from PyPI
pytest -q

Apache-2.0.

Metadata

Release files for homestead-law 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for homestead-law 0.3.0
File Size Uploaded
homestead_law-0.3.0.tar.gz 227.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for homestead-law 0.3.0
File Interpreter ABI Platform
homestead_law-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 310.1 kB

Release files / homestead_law-0.3.0.tar.gz

Download URL homestead_law-0.3.0.tar.gz
Size 227.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a731dfe7789243fc68763a9b065c1deeb924826e0c3088ef64906824c92758e1
BLAKE2b-256 checksum
How to use checksums
e10020783d995ab42b45953795a0204cfd05433674a6e5d369a55d9b7d82bb81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / homestead_law-0.3.0-py3-none-any.whl

Download URL homestead_law-0.3.0-py3-none-any.whl
Size 83.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
63ba104d704b61a4904bf60cd7af33192ee18a90c1d887f7e620d173c58378ea
BLAKE2b-256 checksum
How to use checksums
e5a1e62c5da25be58b32cf87a5c002d92a8394c3d1a4ba9a5c551847ee753db7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page