fix: bake-answer messages stop asserting causes the classifier can't see

Rewords Cleared/Unanswered/ForeignRequest to name only observed facts and every live hypothesis instead of picking a winner; adds a guarded answeredOutcome accessor against a future unhandled BakeAnswerKind; folds an unreachable BakeScanKey/Context test state; fixes generation-stamp timing.
This commit is contained in:
2026-08-02 06:57:08 -04:00
parent 962ab64ef0
commit 7f3b00a646
6 changed files with 139 additions and 35 deletions
+13 -5
View File
@@ -127,6 +127,9 @@ std::optional<BakeOutcome> decodeBakeOutcome(const std::string& wire) {
BakeAnswer classifyBakeAnswer(const std::optional<std::string>& raw,
const BakeRequest& sent) {
BakeAnswer answer;
// `raw` folds three distinct bridge outcomes into one — absent, explicitly
// cleared, and an unreadable/oversized read — because the bridge cannot label
// which occurred. A caller's message for `Cleared` must not claim more than that.
if (!raw || raw->empty()) {
answer.kind = BakeAnswerKind::Cleared;
return answer;
@@ -150,6 +153,11 @@ BakeAnswer classifyBakeAnswer(const std::optional<std::string>& raw,
return answer;
}
const BakeOutcome* answeredOutcome(const BakeAnswer& answer) {
if (answer.kind != BakeAnswerKind::Answered || !answer.outcome) return nullptr;
return &*answer.outcome;
}
BakeScanVerdict classifyBakeScan(const BakeScanContext& session, const BakeScanKey& key,
std::int64_t nowSec) {
// Not a request: an outcome the writing instance has not collected yet, or a value
@@ -161,11 +169,11 @@ BakeScanVerdict classifyBakeScan(const BakeScanContext& session, const BakeScanK
if (age > kMaxRequestAgeSeconds || age < -kMaxRequestAgeSeconds)
return BakeScanVerdict::ClearStale;
// Three tabs have to agree before anything may land: the tab the request was found in,
// the tab the session's book/ledger last loaded, and the tab a persist will write into.
// Landing on a disagreement writes one tab's bake into another's bank.
const bool landable = session.sessionHasLoadedProject &&
session.loadedProjectIsActive && key.inLoadedProject;
// Two facts have to agree before anything may land: the loaded project is the one a
// persist would write into (loadedProjectIsActive), and this key's tab IS that loaded
// project (matchesLoadedProject — false by construction whenever no project is
// loaded, which is what folds the former three-way check into two).
const bool landable = session.loadedProjectIsActive && key.matchesLoadedProject;
return landable ? BakeScanVerdict::Land : BakeScanVerdict::RefuseWrongProject;
}