Merge Ε-W2: bank export and bank import, both verbs and both panel rows
Union of two parallel tracks. Both action rows, both menu rows, both link edges survive; the two package CLAUDE.md files now describe the post-merge reality rather than either side's pre-merge scope.
This commit is contained in:
@@ -5,12 +5,15 @@
|
||||
The filesystem and dialog acts behind bank-package export/import: streaming package
|
||||
file I/O plus the file-status and exclusive-create acts (`package_io`), the
|
||||
UTF-8 path conversion every one of them goes through (`package_path`), the landed-file
|
||||
journal and its rollback delete (`package_rollback`), the two file pickers
|
||||
(`package_pickers`), and the promptless export verb (`export_bank`) — the import verb
|
||||
does not live here yet. The package format itself (magic, manifest, entry layout)
|
||||
stays `core/package`'s business. No REAPER project state is touched in this directory:
|
||||
no ext-state read or write, no undo block, no generation bump — those belong to the
|
||||
prompting skin (`shell/actions/package_export_action`), not this seam.
|
||||
journal and its rollback delete (`package_rollback`), and the two file pickers
|
||||
(`package_pickers`). Those are bytes-only — the package format (magic, manifest, entry
|
||||
layout) is `core/package`'s business. Beside them sit both promptless verbs:
|
||||
`export_bank` whole, and the import split so its decisions stay testable —
|
||||
`import_landing` (REAPER-free) decides and writes, while `import_bank` owns the only
|
||||
REAPER project state this directory touches (the ext-state persist, the undo block,
|
||||
the generation bump). The export direction touches none of it: an export writes no ext
|
||||
state, opens no undo point and never bumps the generation, and what prompting it needs
|
||||
belongs to its skin (`shell/actions/package_export_action`), not this seam.
|
||||
|
||||
## Invariants
|
||||
|
||||
@@ -68,7 +71,14 @@ prompting skin (`shell/actions/package_export_action`), not this seam.
|
||||
landed files with no index entry and a journal that now refuses to roll them
|
||||
back — after which `rollback()` refuses and `writeLandedFile` refuses. (Destroying
|
||||
an armed journal without calling either does NOT roll it back — see
|
||||
`LandedFileJournal`'s own doc comment.)
|
||||
`LandedFileJournal`'s own doc comment.) `import_bank` honours it: it calls
|
||||
`markIndexCommitted()` only after `persistBankOp` has returned.
|
||||
- **Integrity is proven before the first byte lands, not undone after.**
|
||||
`landPackage` hashes every declared payload against the manifest and only then
|
||||
creates the bank folder, so a damaged package costs no rollback at all and cannot
|
||||
leave debris behind a rollback that itself failed. The second read of each payload
|
||||
is deliberate on a once-per-gesture path — do not fold it into one
|
||||
hash-and-write pass.
|
||||
- **Both pickers ride `GetUserFileName`** — mode 1 for import, mode 0 for export.
|
||||
There is no platform split and no fallback: `main.cpp` defines `REAPERAPI_IMPLEMENT`
|
||||
without `REAPERAPI_MINIMAL` and aborts the extension load if any single name fails
|
||||
@@ -79,8 +89,10 @@ prompting skin (`shell/actions/package_export_action`), not this seam.
|
||||
- `package_path` — header-only; the ONE UTF-8-narrow → `fs::path` conversion, so the encoding contract has a single enforcement point.
|
||||
- `package_io` — every filesystem act the verbs need: `PayloadBuffer` (move-only payload + the `alive()` seam counter), `PackageFileWriter` (append-only temp+atomic-rename writer), `PackageFileReader` (seek-and-read one range per call, range-checked against the real file size), `readFilePayload` (one source file as one entry's payload), `fileStatus` (Present/Absent/Unreadable — export's refusal message must distinguish the last two, and an empty payload cannot), `writeFileExclusive` (exclusive create + write, self-cleaning on a partial write), and `listFolderFileNames` (bare UTF-8 names, sorted, non-recursive, non-throwing). REAPER-free; tested without a DAW.
|
||||
- `package_rollback` — `LandedFileJournal`: `writeLandedFile` (exclusive-create land, path resolved absolute, recorded on success only), `markIndexCommitted` (disarms the journal), and `rollback` (deletes exactly the recorded set, hard unlink, tolerating a vanished file; refuses once disarmed). REAPER-free; tested without a DAW.
|
||||
- `package_pickers` — `pickPackageForImport` and `pickPackageSavePath`, both `GetUserFileName`; `pickPackageSavePath` also reports whether it appended `.rsbank` (`outAppended`), the signal `package_export_action` uses to skip a redundant overwrite confirm. `pickPackageForImport` stays compile-only until the import verb lands; neither picker can be exercised in a unit test.
|
||||
- `package_pickers` — `pickPackageForImport` and `pickPackageSavePath`, both `GetUserFileName`; `pickPackageSavePath` also reports whether it appended `.rsbank` (`outAppended`), the signal `package_export_action` uses to skip a redundant overwrite confirm. Neither picker can be exercised in a unit test.
|
||||
- `export_bank` — the promptless export verb, in three composable public steps: `surveyBankExport` (the read-only plan, report-before-acting), `digestSources` (measures each entry's length + `hashBytes` digest, one payload at a time), and `writePackageFile` (prefix, then each payload re-read and re-verified against that digest before it is appended, then commit). `exportBank` composes the three and gates on the plan verdict, the incomplete confirm and the destination confirm. The session arrives **const**: `saveToActiveProject`, `bumpBankGeneration` and `writeAssignmentRequest` are the session's only non-const acts, so a const session cannot reach them and "an export writes no ext state, opens no undo point and never bumps the generation" holds by the type rather than by memory (`pruneReclaim`, the sole file-deletion path, is const too and sits outside this claim). Reads the session through inline accessors only, which is why its tests link and run without a DAW.
|
||||
- `import_landing` — the import's two halves that decide anything: `landPackage` (decode, plan, verify EVERY payload's digest, then land through the journal) and `applyImportedBank` (the new bank's entries plus a birth record per landed file, in one straight-line block). REAPER-free deliberately — all-or-nothing, integrity and birth-record behaviour are assertable without a DAW.
|
||||
- `import_bank` — the promptless import verb over a live `ReaSamplerSession`: the project directory, the minted bank id, the `recordCreated` writer, and the one undo-batched persist. REAPER-facing, so it compiles into the extension module rather than into a library with a test target.
|
||||
|
||||
## Gotchas
|
||||
|
||||
|
||||
Reference in New Issue
Block a user