Adds 6 new TAP assertions (13-18) covering the new Multi-Source /
Single-Sink locale API and the bare-handle bw-compat shim:
13. Bw-Compat: craft(recipe, entity_handle, ctx) still accepts a
bare container-entity-handle; post-state matches the v0.1
single-container behavior (inputs consumed, output added back
to the same container).
14. Form-2 happy-path: sources={c1,c2}, sink=c1, recipe needs one
rock + one stick (c1 has rock, c2 has stick) → c1 ends with the
rock_pick + zero rocks, c2 ends empty.
15. Greedy-drain-order: source1 has 2 rocks, source2 has 5 rocks,
recipe needs 3 rocks → source1 fully drained, source2 has 4 left
(proves left-to-right priority is stable).
16. Aggregate missing-count: source1 has 1 rock, source2 has 1 rock,
recipe needs 3 → can_craft returns missing entry with have=2
(proves cross-source counting in can_craft).
17. Loud-Error empty sources: locale={sources={}, sink=c1} →
error string mentions "crafting", "sources", "non-empty".
18. Loud-Error nil sink: locale={sources={c1}, sink=nil} →
error string mentions "crafting", "sink", "nil".
Adds a sibling fixture helper `extra_container(items)` that creates
a populated container WITHOUT resetting the recipe registry. Needed
for the multi-source cases (14-18): the existing `setup_container`
calls `crafting._test_clear_all()` on every invocation, so it can
only be used once per test; the second-and-later containers come
from `extra_container`. This keeps test isolation per-case while
allowing N>1 containers in a single case.
Manifest bumped 0.1.0 → 0.2.0; dep on lib-core.crafting bumped to
0.2.0 to match the producer. inventory-list 0.1.0 and composition
0.3.0 deps unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Test suite for lib-core.crafting v0.1.0. Covers:
1. define_recipe + list_recipes round-trip; shallow-copy isolation
(mutating the returned list does not affect the registry).
2. define_recipe missing id → Loud-Error.
3. define_recipe duplicate id → Loud-Error.
4. define_recipe empty inputs → Loud-Error.
5. get_recipe known/unknown.
6. is_known propagates ctx-identity to recipe.is_known(ctx).
7. can_craft happy-path → ok=true.
8. can_craft missing inputs → error='missing_inputs' +
missing-array with {template, needed, have}.
9. craft happy-path: consumes 2, crafts 1, container has only output.
10. craft unknown recipe → ok=false, error='unknown_recipe',
container untouched.
11. craft is_known=false → ok=false, error='unknown_recipe',
container untouched.
12. count-form: 2-of-3 reports missing={template, needed=3, have=2}.
Uses engine.test.assert with string.find for pattern matching
loud-error messages (engine.test has no assert_match helper).
Per-test isolation via crafting._test_clear_all; composition templates
are defined once at module-scope (composition has no clear-all hook).
Depends on lib-core.crafting 0.1.0, lib-core.inventory-list 0.1.0,
lib-core.composition 0.3.0 (all three direct, per non-transitive
engine resolver).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>