package: one bank leaves the project as one .rsbank, or the export refuses and says why

Pure planner classifies missing/unreadable/unrepresentable and repairs transport
names; the verb digests, streams and commits atomically over a const session.
This commit is contained in:
2026-08-02 13:21:43 -04:00
parent 33ea95078d
commit 081b6f1028
16 changed files with 1426 additions and 2 deletions
+14
View File
@@ -73,6 +73,12 @@ landing after the format.
here, computed where payloads are streamed (shell). The bank's `slot_map`
rides along. Unknown keys skip at every level; duplicate entry names are
rejected both ways.
- `export_plan` — the pure export decision over value inputs (the bank's members
plus the shell's per-file probe result): the verdict (`Ready` / `Incomplete` /
`Refused`), the transport name per shipping entry, and what is excluded and why
(missing / unreadable / an index record the format cannot represent). Owns the
name repair the codec's refusal backstops, and normalizes each shipping record's
`relativePath` to the bare package name — see the transport-name gotcha below.
- `bank_package` — framing and arithmetic composing the two above:
`encodePackage` (prefix bytes + layout + total size, stamping this build's
ladder pair and `version::stampVersion()`), `decodePackage` (prefix + observed
@@ -115,6 +121,14 @@ landing after the format.
`minReaderVersion` bump, not additive: an old reader would otherwise compare
a stored digest against bytes hashed the new way and silently misjudge
corruption.
- **A written package carries no path in ANY field.** `isValidNestedSamplePath`
permits a relative `relativePath` because a *record* may hold one, but
`export_plan` writes each shipping entry's `relativePath` as its bare package
name, so an emitted manifest has no separator anywhere and the entry name is the
single naming authority on both sides. The directory component it drops carries
no information — the bank subfolder is a fixed `capture_paths` constant the
importer re-spells. The nested-path rule stays as the decode-side backstop for a
package this build did not write.
- **Obligation on the export track: sanitize, don't relay the refusal.**
`serializeManifest` returns one indistinguishable `nullopt` for every rejection
— an unrepresentable name, a case-folded collision, a traversing nested path, a