You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(solver): byproduct consumers no longer let the plan import-and-restructure
The block-27 failure: adding a consumer for an exported byproduct could
REWRITE the plan. grade-2-crush (a reprocessor) let the LP import
15.4/s grade-2-iron and shut the mine off entirely — cheaper by
machine-seconds, absurd by intent — because the byproduct was a free
good (importable). And a pyvoid did nothing at all: it produces
nothing the objective wants, so it idled at 0 with the export intact.
Three-part fix:
1. The consume-gesture (adding a consumer via a byproduct's chip) now
marks the good MADE — imports forbidden, so a reprocessor can only
eat the in-block surplus. On the real block 27: mining trims 58→39
(recycling legitimately reduces ore demand) instead of dying.
2. New DRAIN pin (net = 0 on the item): the byproduct-disposal
primitive. Set automatically when the added consumer is a pure sink
(no products, or only returning less of the same good — the pyvoid
shape, classified from data). Forces the sink to absorb exactly the
surplus; coexisting demand-driven consumers are unaffected. Flows
through temp expansion, diagnosis provenance (with a one-click
'allow export instead'), snapshot diffs, rename migrations, the pin
dialog, and the row badge.
3. importedProducible: the solve reports imports of goods an enabled
in-block recipe produces — the tell-tale of the trap arising any
other way (search-adds, manual unmarks) — and the import chip
offers one click to claim the good in-block.
Also hardens e2e: the deps spec scoped its clicks to the sidebar (its
page-wide button match could hit the nav's Undo button, whose
accessible name embeds the last-edited block's name — a mutating
control on the user's real DB; luckily the click never fired) and
waits for hydration before typing.
Refs #91
// pin members: name the recipe + offer one-click removal
151
172
constlabel=
152
173
prov.type==="pin-share"
@@ -290,6 +311,21 @@ export function BalanceCard({
290
311
{/* Locked-as-block-driver state (set via right-click → "Size block by this
291
312
input"): edit its rate inline + an unlock control. The toggle itself
292
313
lives in the context menu, so non-locked rows stay uncluttered. */}
314
+
{/* the block imports this while an in-block recipe
315
+
produces it — usually the import-instead-of-make
316
+
trap (block 27); one click claims it in-block */}
317
+
{res.importedProducible?.includes(f.name)&&(
318
+
<button
319
+
title="an enabled recipe in this block produces this good, but the plan imports it. Click to mark it made in-block (production must cover consumption)."
320
+
onClick={()=>{
321
+
doc.markMade(f.name);
322
+
doc.note(`Mark "${res.display?.[f.name]??f.name}" made in-block`);
0 commit comments