Skip to main content

homestead

The seat of Homestead · Affairs — the affairs you handle yourself.

This repository holds homestead.keep: the shared record, deadline, evidence and log core that every module on the face pins. It is the base repo, and on this face the base repo is not optional — a module cannot pin an engine that does not exist.

Phase 0 was audited, and the findings are fixed. Suite: 30 passed / 13 xfailed. The path scans now catch the Desktop leak that walked through the first version, IntegrityLog.append() takes a lock, ensure() resolves before it checks, and CI builds and smoke-runs the artifact on three platforms. Encryption of the integrity log is a named Phase 4 item. History below, kept rather than edited away.

Phase 0 did not meet its exit criteria. Two independent audits (docs/audits/) found the implementations roughly right and the enforcement theatre — the path scans miss the Desktop leak they were written to prevent, SealedLog.append() has no lock and breaks its own chain under concurrent use, ensure()'s containment check is lexical, and the packaged artifact crashes on startup. Nothing below should be trusted as enforced until docs/PHASE0-REMEDIATION.md is worked. The list is written down; the fixes are not made.

Status: Phase 0, audited and remediated. The resolver, the two logs, the rung type, a window that opens and shows nothing, and the invariant suite. Deadline arithmetic is built (keep/dates), and so now is the record layer — keep/record, bite 1 of docs/PLAN-first-runnable.md: a read-only canonical handle and the sidecar the app writes to, keyed once (I-7), refusing silent overwrites (I-9), and failing closed to L5 when a stored rung is missing or unreadable (I-11 at the storage boundary). The first matter pack — custody (packs/custody, bite 2) — is authored and classified at import: a closed schema whose every field declares a rung, its matter and its jurisdiction, so an unclassified field fails the build naming itself (I-11), on a real schema rather than a synthetic one. The authorization chokepoint is wired ahead of the surfaces that will use it (bite 3): a payload may be reached only in the gate (keep/rungs) and the store (keep/record), and a reach past serve() on any surface is a build failure (I-16). The two S1 surfaces now render through that gate (bite 4, app/window): a Window that rests on the cover until a human asks (I-21), a list that shows L1–L3 payloads, the derived form for L4, and drops L5 without a trace, and a detail pane that shows the L4 payload and still refuses L5 — the surface calculating nothing itself (I-29), only asking serve. Bite 4 is now wired end to end: the store enumerates a matter's records (Sidecar.records, each with its key as a reference), a Window composes them into the list and opens one by reference into the detail, and a thin tkinter view (app/view) draws it — with python -m homestead.app --demo printing the whole pipeline headless. A row carries a reference, never a payload, so the list is interactive without a datum living on the surface. And the logs now have a writer (bite 5, keep/export): an export — the operator taking their own record out, gated through serve(…, S4_EGRESS, purpose=…), since nothing here dials — writes the content to exports/, one IntegrityLog entry naming the declared purpose, and one VisibleLog EXPORTED act, both carrying references and never content (I-15). Event.EXPORTED had a name and no writer; it has one now. The head that vouches for the ledger is held off the log's own tree in anchors/ (the willow-mcp #280 separation), and export_record returns it so the operator can record it off the machine — the only closure against someone who edits both.

Bites 1–3 were then audited adversarially and remediated (docs/audits/bites-1-3-remediation.md). The audit earned its keep: the chokepoint was theatre — getattr(record, "payload") in a surface reached a sealed L5 payload and passed the suite, because the scan matched the spelling .payload rather than the property. It now bans reflection in the surface layer outright, and its regression runs the real scan over every bypass the audit found. The store's put was made race-safe (I-9) and corruption-safe (a corrupt row reads L5, not a crash), the canonical tree closed to every module but the store, and two custody rungs aligned to the spec.

The audit's one deferred residual — that notes, kept at L4, could hold L5-worthy content — now has its guard: the advisory content matcher (keep/advise). It flags declared L1, content shaped like an SSN — the half classify_schema cannot do — and is built to three conditions each held by a test: it may only argue a rung up, never down; it is advisory and gates nothing (put never consults it); and its silence is never a clean bill. Its patterns are anchored and tested against the benign strings they must not fire on (I-18, F-3's discipline: an address, a ZIP+4, a hearing date), and it never echoes what it matched (I-15). It is now surfaced: opening a record in the detail pane draws any advisory as a muted line beneath it (app/advisories over Sidecar.advise, drawn by app/view), so a wrong-declared rung is caught where the operator is already looking — advisory still, never a block, never the datum, and silence draws nothing.

Network egress is refused by default (keep/egress, I-17): nothing on this self-contained face dials on its own, and send raises unless the caller performs an explicit per-call act — it is shown exactly what will be sent (the confirmation and the transport are handed the same Wire, so the bytes approved are the bytes that leave — BUG-5's answer at the wire) and says yes. The default transport lazy-imports urllib inside itself, so the core imports no network (I-26/I-30).

The cover now survives re-identification (app/cover, I-31): the resting screen may show a count only where the number reveals nothing about which matter it came from — a count of one, and a household of one matter, each withhold every count (k ≥ 2 on both the count and the matters), and a dropped count is an absent key, never a rendered zero. The rule is proposed for ratification in docs/DECISION-cover-re-identification.md (verified_by ≠ author).

The matter registry now stands (keep/registry, I-23): one enumeration — all_matters() over REGISTRY — that ties each matter name to its pack and reads that pack's fields live rather than copying them, so navigation, the queue and the briefing iterate it instead of keeping lists of their own. Only custody is registered (bankruptcy and workers' comp are Phase 5) (struck 2026-09-11: bankruptcy landed and is registered too) — custody and bankruptcy are registered; workers' comp remains Phase 5, not built. A pack that exists but is unregistered fails the build, and a matter name hand-kept as an enumeration anywhere but the registry is a build failure too — BUG-6 was three such lists drifting until workers' comp fell out of the urgent queue.

And the citation extractor is closed (keep/patterns, I-18): a legal citation is volume reporter page, and the reporter is one of a closed set of published abbreviations, not any capitalized word — so 1420 Maple 87501 cannot wear a citation's shape and be POSTed as one (F-3), and 347 F.3d 1120, which the loose regex missed, is caught. An unknown reporter misses a cite; it never matches an address — the safe direction. With it, every invariant this project's pending file ever held red is built and green (UNBUILT is empty). Nothing here is installable by anyone who is not building it.

The method

Every invariant is written as a test before the code that satisfies it, and each one is traceable to a failure that actually happened in the predecessor. tests/test_invariants_pending.py holds the invariants for phases not yet built, as xfail(strict=True) — so the suite stays green while a phase is unbuilt, and fails the moment an implementation quietly satisfies one, forcing the test to be promoted rather than forgotten.

pip install pytest && pip install -e .
pytest -q          # bare, from a cold checkout. No out-of-band install step.

What is enforced here today

Each row was audited and, where it fell short, fixed. docs/audits/ holds the findings; docs/PHASE0-REMEDIATION.md holds what changed.

I-19 / I-20 One resolver, one spelling. keep/paths.py is the only module that may reach a home directory, and expanduser() is banned outright — it is invisible to the store's vault-leak linter, so the identical path in that spelling vanishes from the report.
I-22 / I-15 Two logs, and a writer for them. VisibleLog takes a closed Event enum and a reference tuple — there is no free-text parameter in any position. IntegrityLog is hash-chained, locked against concurrent appends, and anchored: truncation and tail rewrites are caught. An export (keep/export) is the first thing to write either — one integrity entry and one visible act per export, both references, never content. The head anchor is held off the log's own tree (anchors/) and returned to the operator to record off the machine. It is not encrypted and does not withstand someone who edits both the log and its anchor; the docstring says so and a test asserts it.
I-30 / I-26 Nothing imports the network and nothing listens. The self-contained shape removes the problem rather than managing it.
I-14 A rung is a string. L3, never 3 — trust runs the other direction, and if level >= 3 reads perfectly either way while being right on one scale and catastrophic on the other.
I-27 / I-28 Declared dependencies are true (there are none), and bare pytest -q works.

Design

Lives in the safe-app-store: docs/homestead-law-build-plan.md (the 36 invariants and the phase order), docs/homestead-rungs.md (the L1–L5 model), docs/homestead-affairs-face.md (the face), docs/die-rules.md.

Apache-2.0.

Metadata

Release files for homestead-affairs 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-affairs 0.3.0
File Size Uploaded
homestead_affairs-0.3.0.tar.gz 438.8 kB Details

Built distribution (wheel)

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

Total release size: 543.7 kB

Release files / homestead_affairs-0.3.0.tar.gz

Download URL homestead_affairs-0.3.0.tar.gz
Size 438.8 kB
Tags Source
SHA-256 checksum
How to use checksums
355ba538ef8e6ba187bb543c3cbaac4346f2e6fff66f1c818b7d825c426d2670
BLAKE2b-256 checksum
How to use checksums
d441c8e6ae4a4ea265d76d2b7003fefd2ae4a7e25ae1b308361a143f5e3133d3
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_affairs-0.3.0-py3-none-any.whl

Download URL homestead_affairs-0.3.0-py3-none-any.whl
Size 104.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
745146c22702916d73ad9b2f74bbf32a51577779f4e0c3bc084d51031f39d518
BLAKE2b-256 checksum
How to use checksums
2568453a0e90477427708e9948ae7440c5e90c7a35fd4a607bc1cf019fb0b36c
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.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

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.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.1.0

2 release files

0.0.3

2 release files

0.0.2

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