Reuse and dependencies
Task and place
Section titled “Task and place”Real canons borrow: calendars, tariff schedules, shared definitions, readings of neighboring acts. This stage decides what the package imports, what it restates in its own words, and what it merely cites — then writes the boundary down so later change arrives as a named event, not silent drift. It sits at both ends of the pipeline: scope names candidate sources up front, and release freezes the chosen versions; review checks the boundary between.
Inputs
Section titled “Inputs”- The candidate source: package name, version, and the exact content to borrow.
- Its provenance: which act, which edition, which materialization the content was pinned to.
- Its assumptions: the readings, policies, and limits its own decision records state.
- The review record template and the filled EAI review record, which carries finding EAI-R1 and shows the record shape borrowings are checked against.
Actions
Section titled “Actions”- Check semantic identity before borrowing: same act, same edition window, same reading of the shared passage. A matching title is not identity; read the pinned bytes and the source’s decision records.
- Restate rather than import when the reading differs: a borrowed rule you would amend is a fork wearing an import’s clothes — copy the content, cite the origin, and own the divergence in a decision record.
- Pin versions exactly: the manifest names each source with the version reviewed, and an upstream amendment reopens the boundary instead of flowing in silently.
- Record provenance per borrowed item: origin package and version, edition, and the assumption the borrower relies on.
- Keep local imports explicit: every name used across files in the package is listed where it is used, so the boundary reader sees the full surface without guessing.
Decisions
Section titled “Decisions”- Import, restate, or cite: import when identity holds and the source is maintained; restate when the reading differs or the source may lapse; cite without borrowing when the act merely points outward.
- Pin or track: released canon pins; only a live draft tracks a moving source, and it says so in the boundary record.
Artifact
Section titled “Artifact”The artifact is the dependency boundary: one entry per borrowed item with source, pinned version, borrowed content, provenance, relied-upon assumptions, and the revisit trigger. An empty boundary is a valid artifact — it states the package stands alone — but it must be written, not assumed: an unwritten boundary cannot distinguish “no dependencies” from “never checked.”
EAI example
Section titled “EAI example”The running example stands alone: package kz.corpus.employee_accident_insurance, version 0.1.0, language 0.2, carries no dependency entries in its manifest, so the boundary record is an explicit empty list with the check run as evidence. Local names cross files through explicit imports, so the boundary reader sees the full internal surface.
Runnable shape of the boundary record for a package with no outside sources; the check below is the evidence.
dependency boundary for kz.corpus.employee_accident_insurance 0.1.0: outside sources: none (manifest carries no dependency entries) local imports: explicit, listed at each use site revisit trigger: any future manifest entry reopens this recordThe running example proves the empty boundary; it cannot prove that borrowing works. The executable half of this stage is the payroll drill: borrower demo.handbook.payroll computes a premium from a rate schedule borrowed from demo.handbook.rates, pinned to 1.0.0, with a file registry publishing both 1.0.0 and 1.0.1. Its boundary record, with values taken from the shipped lock:
borrowed item: class rates class_rate/2 with inputs risk_class/2 source: demo.handbook.rates, pinned version 1.0.0, contentHash sha256:51f4da7c9ee041e09244ea33449af619ba0b8aa3e9515dd48e2dfa2c572b521c content: two rate rules over the synthetic RATE_SCHEDULE source provenance: synthetic schedule authored for this drill; identity by exact version plus content hash, not by title assumption relied upon: class-2 rate is 0.012 per unit of payroll transfer mode: import of pub declarations (Employer, risk_class, class_rate) revisit trigger: any new published version reopens this entryPitfall
Section titled “Pitfall”Silent drift: an unpinned source amends, the borrower’s suite stays green, and answers change meaning without any test noticing — because the suite pins behavior, not the source bytes. The twin failure is borrowing a reading sight unseen: importing a rule without reading its decision records inherits someone else’s close calls as your silent premises. Both are cured the same way: pins plus per-item provenance, checked at review.
Verify
Section titled “Verify”The stage is done when the manifest and the boundary record agree item by item and the check passes. Observed with tool version law 0.1.0, semantics law.core/0.2:
$ law engine check corpus/laws/kz/laws/employee-accident-insurancecheck OK: corpus/laws/kz/laws/employee-accident-insuranceCriterion: compare the manifest’s dependency entries against the boundary record line by line — for the running example both are empty — and confirm the check passes on that closed content. Any entry on one side missing from the other fails the stage.
The drill’s own criterion is stricter: the pin must hold while a new version exists, and the update must fail loudly. Observed with the same tool version:
$ law test docs/handbook/files/fixtures/reuse-payroll/payrolllaw test demo.handbook.payroll: world demo.handbook.payroll, demo.handbook.rates ok [demo.handbook.payroll#authored] tests/premium.lawtest / premium uses the borrowed class-2 ratetotal: 1 checked, 1 passed, 0 failed, 0 not run; code 0Version 1.0.1 sits in the shipped registry and changes the borrowed class-2 rate from 0.012 to 0.015, yet the borrower above stays green: the import line, the manifest entry, the lock’s contentHash, and the vendored deps/ IR all name 1.0.0, and nothing flows in silently. Moving the pin on a scratch copy of the borrower is a named event across five artifacts — and the suite trips on the changed assumption:
$ law update 'demo.handbook.rates@1.0.1' --registry file=../registry~ demo.handbook.rates 1.0.0 -> 1.0.1changed: .law/transport.jsonchanged: deps/demo.handbook.rates.lawir.jsonchanged: law.lockchanged: law.tomlchanged: package.law$ law test . FAIL [demo.handbook.payroll#authored] tests/premium.lawtest / premium uses the borrowed class-2 rate truth_status == TRUE_ONLY: in the document NEITHERtotal: 1 checked, 0 passed, 1 failed, 0 not run; code 1The 12000 KZT expectation pins the relied-upon 0.012 behaviorally: after the update it no longer derives, which is the boundary working as designed — the borrower meets the upstream change as a failing check, not as drift. (Observed on a scratch copy; the shipped borrower stays pinned to 1.0.0.)
Limits
Section titled “Limits”The running example has no cross-act borrowing: no calendar, no shared schedule, no reading inherited from a neighbor package. Multi-act bridges — one package’s conclusions feeding another’s premises — are maintainer work beyond the solo lane: they need aligned law dates, matched versions, and a joint review the single-package boundary record only points to. A boundary record proves the borrower looked, not that the source is right; criticism of the source stays with the source’s own review.
Next step
Section titled “Next step”Continue with Writing scenarios, which turns the model and its decisions into planned checks with fixed expectations.
Sources
Section titled “Sources”- Language — packages, versions, and imports.
- Tutorials — the drill track behind this handbook.
- Command line — the check command used above.
- Recording decisions — where divergences from borrowed readings earn records.
For a collection of packages, continue with shared vocabularies and dependency contracts.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.