A saved block is entirely internal-name references. BlockData (db/schema.ts:283-293) stores target, extraGoals, recipes, dispositions, machines, fuels, modules, and beacons, plus the block's iconKind and iconName, all as internal-name strings. When the data changes (a mod updated, enabled, disabled, or removed, a Py version bump, or a TURD pick) those references can dangle, and the block should degrade gracefully instead of breaking or, worse, silently solving wrong.
Current behaviour is unsafe. The solve path resolves recipes with data.recipes.map(getRecipe).filter(Boolean) (factory-solve.ts:268-272), and getRecipe returns null for an unknown name (queries.ts:64-66), so a missing recipe is silently dropped and the block re-solves to different rates and flows with no error or warning. Detection already exists but only in a dry-run: blockChangeReportFn flags missingRecipes and marks a block "broken" (factory-solve.ts:1451-1462), but the normal load, edit, and solve path never calls it. Icons and display names already fall back gracefully (a grey placeholder and the internal name), so the gap is in the solve and in surfacing the problem.
This is one issue for now and can be broken down later. It should deliver:
- Stop silently dropping missing references. On load and solve, detect them and refuse to present a wrong solve; mark the block broken or degraded instead.
- Preserve the full
BlockData of a broken block rather than rewriting or deleting it, so re-enabling a mod or re-importing restores the block unchanged.
- Surface the problem in the block view: which recipe or item is missing, shown as a labelled placeholder row, with clear "no longer exists" messaging.
- Make staleness register per block.
data_fingerprint is currently a hash of enabled mod names only (dump.ts:236-243), so it misses in-place mod updates and TURD changes. Use a finer signal, such as a fingerprint over the specific prototypes a block references, so a block knows when its own inputs changed.
Pure renames are handled automatically by the migration capture in #26, so this issue is the fallback for references that genuinely changed meaning or disappeared. Mod-change detection that prompts a re-dump is #27.
A saved block is entirely internal-name references.
BlockData(db/schema.ts:283-293) storestarget,extraGoals,recipes,dispositions,machines,fuels,modules, andbeacons, plus the block'siconKindandiconName, all as internal-name strings. When the data changes (a mod updated, enabled, disabled, or removed, a Py version bump, or a TURD pick) those references can dangle, and the block should degrade gracefully instead of breaking or, worse, silently solving wrong.Current behaviour is unsafe. The solve path resolves recipes with
data.recipes.map(getRecipe).filter(Boolean)(factory-solve.ts:268-272), andgetRecipereturns null for an unknown name (queries.ts:64-66), so a missing recipe is silently dropped and the block re-solves to different rates and flows with no error or warning. Detection already exists but only in a dry-run:blockChangeReportFnflagsmissingRecipesand marks a block "broken" (factory-solve.ts:1451-1462), but the normal load, edit, and solve path never calls it. Icons and display names already fall back gracefully (a grey placeholder and the internal name), so the gap is in the solve and in surfacing the problem.This is one issue for now and can be broken down later. It should deliver:
BlockDataof a broken block rather than rewriting or deleting it, so re-enabling a mod or re-importing restores the block unchanged.data_fingerprintis currently a hash of enabled mod names only (dump.ts:236-243), so it misses in-place mod updates and TURD changes. Use a finer signal, such as a fingerprint over the specific prototypes a block references, so a block knows when its own inputs changed.Pure renames are handled automatically by the migration capture in #26, so this issue is the fallback for references that genuinely changed meaning or disappeared. Mod-change detection that prompts a re-dump is #27.