# K3 validation

Continuing WIP 68a51d7 against offline-kit spec 6049830 (discussion #5).
The inherited implementations were explicitly no-op stubs, not working code.

2026-09-24: ran the inherited tests against those stubs before implementation.
`swift test` failed on missing enqueues, sends, replacement ordering, status
mapping and store writes. One inherited outbox test indexed an empty result
and terminated the process. A separate filtered run of `SyncStringsTests`,
`SyncStatusTests`, `FaultingBlobStoreTests`, and `SealedStoreTests` executed 24
tests with 78 failures (including missing sealed files). Local transcripts:
`/tmp/k3-kit-red.log`, `/tmp/k3-kit-red-rest.log`.

After implementation, the storage/status/fault suite passed 32 tests and the
drainer/catalog suite passed 18. `make ci` passed, including macOS and iOS
companion builds, Go race tests, and Python bundle tests; transcript:
`/tmp/k3-kit-ci-1.log`. This is intermediate evidence, not final K3 approval.

The continuation evidence below supersedes the intermediate status. Nothing
has been merged or deployed.

## Disk stop, 2026-09-24

Work stopped when `df` reported 1.2 GiB free (user's stop threshold: 1.5 GiB).
Only session-created Docs build outputs and companion DerivedData were removed.
The inherited `.build` directory in this worktree was preserved.

Additional focused evidence before the stop:

- Seal-count rotation and interrupted-rotation tests: both failed with the
  rotation call stubbed (`/tmp/k3-rotation-red.log`); all 14 sealed-store tests
  passed after restoring/fixing rotation (`/tmp/k3-rotation-green-2.log`).
- Independent-lane retry regression: failed with the first retry starving the
  next lane (`/tmp/k3-lane-retry-red.log`); all 15 drainer tests then passed
  (`/tmp/k3-lane-retry-green.log`).
- Fixed an inherited undeclared AppleTests → RastrilloTestSupport dependency:
  incremental builds could compile tests against a stale support module.
- Fixed an inherited test's unchecked empty-array indexing so stub failures
  produce an assertion instead of terminating the test process.

At that disk stop, the latest changes had not had another full make ci.
The resumed local gate and later focused checks are recorded below.

Docs adoption is saved on oficina/docs `feat/k3-outbox-lane`, discussion #69.
Its evidence file lists unresolved title/lifecycle issues and remaining gates.

## Resume: status priority and concurrent close-save

Spec §3.4 gives session-ended priority 2 and empty priority 3. Pending entries
already produced needsSignIn(n); the empty-session exception is now removed too.
A concurrent drain now awaits the reserved batch's result, so close-save cannot
mistake an in-flight batch for idle. New checks failed on the previous behavior
(2 assertions, /tmp/k3-status-drain-red.log); all 20 status/drainer tests then
passed (/tmp/k3-status-drain-green.log).

Reservation API rationale: load surfaces unavailable storage rather than an
empty queue; entries includes held entries for offline replay; beginSend makes
selection and reservation one actor operation so compaction cannot delete a
batch in flight; endSend releases a retry/cancelled reservation without ack.
No update or retarget API was added.

## Final continuation evidence

- Full local `make ci` passed at 3e93ef916f2bb5469fd09375e0f6253938da8650,
  including Swift, macOS/iOS companion builds, Go race and Python bundle checks
  (`/tmp/k3-kit-final-ci.log`).
- A locked store must preserve its last known status. The new regression failed
  against the previous behavior (`/tmp/k3-unavailable-status-red.log`); all 21
  drainer/status tests passed after the fix (`/tmp/k3-unavailable-status-green.log`).
  Explicit app enqueue failures still show cannotSaveOnDevice; unknown storage
  never masquerades as a known empty queue.
- The final-head `make ci` rerun is logged at `/tmp/k3-kit-release-ci.log` and
  its result/head is recorded on [discussion #9](https://amadan.net/rastrillo/native/discuss/9).
- Hub CI at 3e93ef9 failed before compilation: Sparkle archive extraction could
  not find unzip. There is no macOS runner; the local macOS gate is authoritative
  for this task, as directed by the user.
- Docs now has real SIGKILL red/green proof and the parked-update port. Its
  replica/metadata/Home adoption and crash tests are on oficina/docs #69.

The only deliberate ordering difference is app-side discard removing the replica
before its lane; exhaustive crash tests prove this prevents stranded unsent text.
The prior empty-session status exception is removed. No merge or deployment.

## Fable review follow-up (2026-09-24)

- `testSealBlocksCacheStateAndSkipUnusedQuotaAfterCrash`: failed against the inherited per-seal implementation (38 high-water assertions and two cache assertions); passes with 1024-slot reservations. Two process lifetimes consume 19 seals each, observe durable marks 1024/2048, and produce 38 distinct 96-bit nonces. A restart abandons 1005 unused slots; key rotation still counts reseals and keeps its previous key until completion. Complete file protection remains in every atomic write.
- `testThrowingLaneDoesNotStarveOtherLanesAndEventuallyHolds`: failed against the inherited drainer (only lane a called, three lanes remained, no hold, fourth throw); passes with b/c draining on the first attempt and a held after its third consecutive untyped throw. Returning a disposition or a typed transport error resets the throw streak.
- Full Swift suite: 119 tests passed. Red/green logs: `/tmp/k3-native-review-{red,green}.log` (ephemeral); observed assertions above are the durable record.
- Reservation API addition: `entries(lane:excludingInFlight:)` adds a filter to the existing snapshot, needed to deduplicate held metadata markers without suppressing a successor to a marker already being sent. No new mutation or reservation operation.
- Snapshot invariant is now documented: entries/summary can retain stale display/deduplication hints on unavailable storage; summary flags this, sendable fails closed, and load/beginSend/all mutations enforce availability before replay or changes.
- Corrected unavailable-send and Retry-After comments. The latter remains a deadline that neither connectivity nor Try again bypasses.
