Shared crypto packages get a 100% coverage floor
Scheduled8 min read By NT²
Specs bound scope. Security veto owns residual risk. Coverage floors own a narrower job: no uncovered line in the shared packages that seal, wrap, and describe vault facts—because agents will otherwise ship “done” with a hole.
Shared crypto packages get a 100% coverage floor
Claim: the foundation does not get “good enough” coverage
AI coding agents are fluent at green bars. Ask for a feature, and they will often add a unit test that exercises the happy path, assert a round-trip, and call the work finished. For a marketing page or a settings toggle, that may be enough. For the shared packages that encode ciphertext containers, wrap content keys, and carry typed vault events, it is not.
NT² Vault is a zero-knowledge, local-first vault. The product’s public promises—salt stays on the device, envelopes wrap a fresh content key per object, structured fields leave RAM as sealed blobs—rest on a small set of shared libraries every shell and every feature reuses. A missed branch there is not a local UI bug. It is a silent hole under every consumer.
So the claim for this installment is operational:
Shared crypto and event packages carry a hard coverage floor: 100% of statements, lines, and functions. Pre-push and CI fail closed. “Almost covered” is not a mergeable state for that foundation.
This is the fourth piece in Building with agents. Specs say what may ship (Specs before agents write code). The security veto says whether a secrets-touching change is allowed (Security veto is a role, not a vibe). Coverage floors say something colder: you may not leave an unexecuted line in the packages that define how ciphertext and events work—even when the agent is confident and the feature demo looks fine.
Constraint: agents optimize for a green path; foundations amplify misses
Three pressures make a soft coverage target fail when the product is a vault.
Happy-path tests are the default completion. Models have seen millions of “assert encrypt then decrypt” examples. They under-produce the awkward cases: wrong tag length, empty payload, malformed version byte, double-wrap, event parser refusal. Without a hard floor, “we have tests” means “we have the path that made the demo work.”
Shared packages multiply blast radius. A UI component that forgets a null check hurts one screen. A parser or wrap helper that forgets a check hurts every item, every attachment, every sync envelope that calls it. Agents do not feel that multiplication; they see a small diff in a small package and treat it like any other ticket.
Coverage theater looks like diligence. Raising a monorepo average from 62% to 71%, or posting a badge that says “high coverage,” does not prove the crypto path is exercised. Averages hide the packages that matter. Agents will happily improve the easy files and leave the hard ones “for later.” Later is how oracles and unwrap bugs ship.
The constraint is therefore sharp: you cannot treat coverage as a vibe or a portfolio average when the foundation is shared. The floor must sit on the packages whose bugs become every feature’s bugs.
Design: tiers, not one number for the whole tree
We do not demand 100% coverage on every line of the vault PWA. That would freeze product UI, punish exploratory shells, and train the team to game the metric. We tier instead.
| Tier | What it covers (plain language) | Floor |
|---|---|---|
| Shared foundation | Crypto containers, key-wrap helpers, typed event and sync shapes, and a few other pure packages every app imports | 100% statements, lines, and functions — fail closed on push and CI |
| Critical app seams | Vault-side crypto, deep-link, and share helpers that sit next to the UI but still encode security-sensitive pure logic | Also held to a 100% gate where we have drawn that line |
| Everything else | Routes, layout, long-running UI, platform glue | Unit tests where they earn their keep; integration and browser flows for behavior—not a blanket percentage theater |
The design rule is simple: percentage floors belong on small, pure, high-blast-radius packages. End-to-end flows still matter for unlock and backup walkthroughs; they do not replace line-level proof that every branch in a wrap helper ran.
flowchart LR
A[Agent changes shared package]
U[Unit tests]
C{100% floor?}
P[Push / CI]
M[Merge path]
A --> U --> C
C -->|fail| A
C -->|pass| P --> M
What the floor forces in practice:
- Every function has a caller in tests. An agent cannot leave a “helper for later” that never runs.
- Every statement has an execution. Refactor branches, error paths, and version switches cannot hide behind the happy round-trip.
- The gate is mechanical. Humans still own threat judgment (see the veto essay). The coverage gate owns a narrower refusal: uncovered foundation code does not leave the laptop.
This pairs with how we store secrets at rest. Essays like CBF is how structured fields leave RAM and envelope encryption with a CEK per object describe what those packages must get right. The coverage floor is how agent throughput stays honest about those packages: if you change the blob format or the wrap path, you inherit the obligation to keep the floor green—not a promise to “add tests in a follow-up.”
Why 100%, not 95%
A soft target invites negotiation. Ninety-five percent is where the awkward branch lives: the refusal path, the legacy version, the length check that only fails under malice. Agents are excellent at stopping one assertion short of that branch. A hard floor removes the negotiation. Either the statement ran under test, or the push fails.
We are not claiming that 100% coverage equals a correct threat model. Coverage does not prove the product should exist, that Non-Goals held, or that a human walked unlock after a key-path change. It proves something smaller and still necessary: there is no knowingly unexecuted line in the shared foundation the agent just touched.
Trade-off: slower shared-package diffs, fewer silent foundation holes
A 100% floor costs time. Shared packages become “expensive” tickets: every new export needs a test; every refactor must keep the floor; agents that paste a utility without a caller get bounced by CI before a human even opens the PR.
What we give up:
- Fast-and-loose foundation edits — “tiny helper, no tests, ship the feature above it.”
- Average-coverage theater — celebrating monorepo percentage while crypto packages lag.
- Follow-up-ticket culture on shared crypto — the follow-up rarely lands before the next agent builds on the hole.
- Treating green feature demos as proof that wrap and parse logic is exercised.
What we gain:
- A mechanical refusal that agents cannot sweet-talk — the floor does not care that the model is confident.
- Blast-radius containment — bugs still happen; uncovered known gaps in the foundation are no longer an accepted state.
- Compatible speed elsewhere — UI and product slices can move without dragging every route up to 100%.
- Honest pairing with veto and specs — specs bound inventiveness; veto owns residual risk; coverage owns unexecuted foundation lines.
The expensive failure mode is not “spent twenty minutes writing a parser refusal test.” It is “shipped an unwrap path an agent never ran, then taught every future change that the constitution is optional when demos look good.”
What we refuse
We refuse soft coverage targets on shared crypto and event packages. “High coverage” and “we’ll hit 100% next sprint” are not gates. The floor is 100%, and push fails without it.
We refuse averaging the monorepo into a single vanity number as proof that the foundation is safe. Tiers exist so the packages that multiply risk get a harder rule than marketing pages.
We refuse happy-path-only tests as done for wrap, parse, and event shape code. Round-trips are necessary. Refusal and malformation paths are part of the floor.
We refuse lowering the floor so agents can merge faster. Agent throughput is a tool. The product’s edge cases are not optional homework.
We refuse equating coverage with security sign-off. Green coverage is evidence for the mechanical gate. A human still owns unlock walkthroughs, dependency judgment, and veto on secrets-touching changes.
We refuse “debug-only” exports and untested helpers in those packages “just for the agent.” If it ships in the package, it runs under test—or it does not ship.
We refuse treating UI E2E as a substitute for foundation unit coverage. Browser flows prove sessions and screens. They do not prove every branch in a shared ciphertext helper.
These refusals keep the process stack coherent: specs stop wrong products, veto stops wrong risk acceptance, and the coverage floor stops wrong emptiness in the libraries everything else trusts.
Floors that outlast the model
A fluent agent will always be able to narrate why a missing test is fine. The 100% floor does not argue. It fails the push.
The authority model and release discipline live in How one person builds and operates NT² Vault with AI agents. The contract that keeps agents from inventing scope lives in Specs before agents write code. The role that keeps green CI from becoming merge authority for unlock paths lives in Security veto is a role, not a vibe. The product surfaces this floor protects are essays like CBF payload blobs at rest and envelope encryption with a CEK per object.
If you want a vault whose process refuses the same shortcuts its cryptography refuses—try NT² Vault or read more at nt2.me.
Last updated 2026-10-25
Related stories
- Security veto is a role, not a vibe
7 min read
- Specs before agents write code
7 min read
- How one person builds and operates NT² Vault with AI agents
10 min read