Skip to main content

homestead

The seat of Homestead · Affairsthe 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 layerkeep/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 L1L3 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); 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 L1L5 model), docs/homestead-affairs-face.md (the face), docs/die-rules.md.

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

homestead_affairs-0.2.1.tar.gz (418.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

homestead_affairs-0.2.1-py3-none-any.whl (100.5 kB view details)

Uploaded Python 3

File details

Details for the file homestead_affairs-0.2.1.tar.gz.

File metadata

  • Download URL: homestead_affairs-0.2.1.tar.gz
  • Upload date:
  • Size: 418.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for homestead_affairs-0.2.1.tar.gz
Algorithm Hash digest
SHA256 89477f9778add09640f0bb68158cfa9959a8f98eeea8076df5b09e4f29864e70
MD5 daf219f17297f6a79a950e8bf5a1a14c
BLAKE2b-256 39bf9fc48c50e83459058c0e0c98582bd4bd1df4b5f39a437d80984668d5b927

See more details on using hashes here.

Provenance

The following attestation bundles were made for homestead_affairs-0.2.1.tar.gz:

Publisher: release.yml on homestead-affairs/homestead

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file homestead_affairs-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for homestead_affairs-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 73f3b9418c783aed4271c6a65873eebffd36525bb81835d03f63f8c7e51af223
MD5 6662e937420684ac38e7ce9e6eafa012
BLAKE2b-256 7167bac1ae2842622c347ac48a7a2dc3402a1f9a5bfb83bdf4c0f370d69ede66

See more details on using hashes here.

Provenance

The following attestation bundles were made for homestead_affairs-0.2.1-py3-none-any.whl:

Publisher: release.yml on homestead-affairs/homestead

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.3

2 files

0.2.2

2 files

This release

0.2.1 This release

2 files

0.1.0

2 files

0.0.3

2 files

0.0.2

2 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