import: remediate review findings — ledger gate, docs, message split

Delegates the refuse-gate to ledgerDegraded(), lifts its console message into a
pure testable fold, fixes stale doc line citations and an inaccurate outcome-enum
comment, and splits the rename counter into collision-vs-sanitize.
This commit is contained in:
2026-08-02 14:02:05 -04:00
parent a927dad2f4
commit f8dde16a7e
20 changed files with 299 additions and 92 deletions
+5 -2
View File
@@ -46,7 +46,8 @@ void fillPlanCounts(ImportBankResult& out, const package::ImportPlan& plan) {
out.seedBankName = plan.seedBankName;
out.bankNameAdjusted = plan.bankNameAdjusted;
out.landedCount = plan.landCount;
out.renamedCount = plan.renameCount;
out.collisionRenameCount = plan.collisionRenameCount;
out.sanitizeRenameCount = plan.sanitizeRenameCount;
out.collapsedCount = plan.collapseCount;
}
@@ -70,8 +71,9 @@ ImportBankResult importBankPackage(ReaSamplerSession& session,
fillPlanCounts(out, landing.plan);
if (landing.outcome != ImportOutcome::Landed) return out;
const std::string bankId = mintBankId();
const bool applied = applyImportedBank(
session.book(), mintBankId(), landing.plan,
session.book(), bankId, landing.plan,
[&session](const model::Sample& s) {
session.recordCreated(s, tracking::OriginKind::PackageImport);
});
@@ -80,6 +82,7 @@ ImportBankResult importBankPackage(ReaSamplerSession& session,
out.rollback = journal.rollback();
return out;
}
out.bankId = bankId;
// Generation bump + persist ride inside one undo block, so a Ctrl-Z takes the whole
// import back out of the index. It does NOT un-write the files — the summary says so.
+3 -1
View File
@@ -17,12 +17,14 @@ struct ImportBankResult {
ImportOutcome outcome = ImportOutcome::Unreadable;
package::PackageHeader header; // TooNew names the writer's build from here
std::string bankId; // the minted id — meaningful only when outcome == Landed
std::string bankDisplayName; // the bank actually created
std::string seedBankName; // what the package asked to be called
bool bankNameAdjusted = false;
int landedCount = 0;
int renamedCount = 0;
int collisionRenameCount = 0; // renamed: the package's own name was already taken
int sanitizeRenameCount = 0; // renamed: not spelled the way this tool spells a bank file
int collapsedCount = 0;
std::string failedEntryName;
+13 -1
View File
@@ -3,6 +3,7 @@
#include "shell/package/import_landing.h"
#include <cassert>
#include <cstdint>
#include <filesystem>
#include <system_error>
@@ -118,12 +119,23 @@ ImportLanding landPackage(const std::string& packageAbsPath,
bool applyImportedBank(BankBook& book, const std::string& bankId,
const package::ImportPlan& plan, const RecordBirth& recordBirth) {
// An empty std::function throws std::bad_function_call on invoke; every real caller
// supplies one, so an empty one here is a caller bug, not a runtime condition to
// recover from — enforce the contract rather than let it surface as an uncaught
// exception out of an extension action.
assert(recordBirth && "applyImportedBank: RecordBirth must not be empty");
if (!book.createBank(bankId, plan.bankDisplayName)) return false;
BankModel* index = book.index(bankId);
for (const package::PlannedEntry& e : plan.entries) {
if (e.action != EntryAction::Land) continue;
index->add(e.sample);
const AddResult added = index->add(e.sample);
// planImport already deduped Land entries by hash against an empty destination
// bank (this same freshly-created one), so a Collapsed add here would mean the
// plan and the book disagree — that would silently undercount reportSuccess's
// landedCount rather than fail loudly.
assert(added == AddResult::Added && "planImport's Land entries must not collapse");
(void)added;
// Unconditional on the add's outcome: the file exists either way, and an
// unrecorded file is permanently unreclaimable.
recordBirth(e.sample);
+10 -6
View File
@@ -15,18 +15,22 @@
namespace reasampler {
// How a landing ended. Every value but Landed means NOTHING is on disk and NO index
// was touched — the two refuse-whole failures (TooNew, Malformed) before a byte is
// written, the other two after a rollback.
// How a landing ended. Every value but Landed means NOTHING is on disk and NO index was
// touched. NoProject/Unreadable/Malformed/TooNew refuse before a byte is written.
// IntegrityFailed also refuses before any write — the full-package digest verification
// runs to completion first (landPackage) — so it needs no rollback either. WriteFailed
// is the only outcome that actually wrote and then rolled back. IndexRejected is never
// returned by landPackage/this struct — it is import_bank's own outcome, minted after a
// successful landing when the book itself refuses the create.
enum class ImportOutcome {
Landed,
NoProject, // unsaved project: there is no bank folder to land into
Unreadable, // the package file could not be opened
Malformed, // not a well-formed RSBK: corrupt, truncated, or trailing garbage
TooNew, // minReaderVersion above this build's ladder
IntegrityFailed, // an entry's payload did not match its recorded digest
IntegrityFailed, // an entry's payload did not match its recorded digest; pre-write refusal
WriteFailed, // a write failed partway; the landed files were rolled back
IndexRejected, // the book refused the bank the plan minted a free name for
IndexRejected, // never set here — see the comment above; import_bank's outcome only
};
struct ImportLanding {
@@ -36,7 +40,7 @@ struct ImportLanding {
package::PackageHeader header;
package::ImportPlan plan;
std::string failedEntryName; // IntegrityFailed / WriteFailed
RollbackResult rollback; // IntegrityFailed / WriteFailed
RollbackResult rollback; // WriteFailed only — IntegrityFailed leaves it default
};
// Streams `packageAbsPath` into the project's bank folder: decode, plan, verify EVERY