crafting v0.5.0 + composition v0.4.0: Quality & Condition (Phase J)

lib-core.composition v0.4.0: un-defer quality/condition as inert numeric
properties (loud-error removed); composition stores them without semantics.

lib-core.crafting v0.5.0: quality-block (multi-contributor product-quality
formula: skill-band with min=requires-floor + named ingredient/tool qualities),
optional slot name, tool wear_per_use (condition decrement + wear report).
affordance stays boolean. Additive to v0.4.0.

vagrant-skeleton v0.22.0: branch quality-band RNG at spawn; stone_hammer
condition=1.0; knap+axe quality-blocks; hammer wears out. Headless-verified 20/20.

Design: meta/docs/design/2026-08-03-crafting-quality-condition-design.md.
Docs synced: crafting-model.md, composition-model.md, libraries.md, READMEs.
This commit is contained in:
calic
2026-08-03 09:14:56 +00:00
parent f93fef5990
commit d862a250c4
4 changed files with 65 additions and 11 deletions

View File

@@ -45,6 +45,10 @@ return function(c)
c.T{ id = "branch", name = "Branch", desc = "A heavy springy branch. Snap it into sticks.",
weight = 1.5, vol = 0.006, material = { wood = 1.0 },
affordance = { leverage = true }, -- a haft candidate, but heavy
-- Phase J (design 2026-08-03 §5): a storm-broken branch is of variable
-- grade — the world rolls its `quality` in [0.5,1.0] at spawn. Used as a
-- haft, this variance flows into the axe's quality (craft_stone_axe).
quality_band = { min = 0.5, max = 1.0 },
atlas = "tc", uv = "log_pile1", scale = 0.85 }
c.T{ id = "log", name = "Log", desc = "A heavy wooden log. Saw it into planks.",
@@ -83,6 +87,10 @@ return function(c)
c.T{ id = "stone_hammer", name = "Stone Hammer", desc = "A stone lashed to a haft. Pounds and knaps.",
weight = 1.5, vol = 0.001,
material = { stone = 0.6, wood = 0.3, fiber = 0.1 },
-- Phase J: a tool tracks `condition` (fresh = 1.0). Each knap wears it
-- (knap_sharp_stone.tools.wear_per_use); at condition 0 it stops
-- qualifying (the recipe's tool match asks for condition > 0).
condition = 1.0,
affordance = { hammering = true }, atlas = "tc", uv = "spade" }
c.T{ id = "sharpened_stick", name = "Sharpened Stick", desc = "A stick whittled to a point. A crude spear.",
@@ -95,10 +103,20 @@ return function(c)
-- Skill-ungated but GRANTS knapping XP (ADR-0056) — the accessible "grind"
-- recipe that bootstraps the gated craft_stone_axe below.
c.R{ id = "knap_sharp_stone",
inputs = { { match = { ["affordance.knappable"] = true }, count = 1 } },
tools = { { match = { ["affordance.hammering"] = true } } },
inputs = { { match = { ["affordance.knappable"] = true }, count = 1, name = "stone" } },
-- Phase J: the hammer must have condition > 0, and wears 0.2 per knap →
-- a fresh hammer lasts 5 knaps, then stops qualifying (missing_tools).
tools = { { match = { ["affordance.hammering"] = true, condition = ">0" },
name = "hammer", wear_per_use = 0.2 } },
outputs = { { template = "sharp_stone", count = 1 } },
grants = { ["skill.knapping"] = 1 },
-- Product quality = skill (0..5 band, min 0 since ungated) + stone grade
-- + hammer grade×condition. A worn hammer makes worse edges.
quality = { contributors = {
{ skill = "skill.knapping", max = 5, weight = 0.3 },
{ ingredient = "stone", weight = 0.4 },
{ tool = "hammer", weight = 0.3 },
} },
name = "Knap Sharp Stone",
description = "Strike a stone with a hammerstone to flake off a sharp edge." }
@@ -128,11 +146,19 @@ return function(c)
-- Demonstrates the gate+earn+unlock loop (gate downstream, grant upstream).
c.R{ id = "craft_stone_axe",
inputs = {
{ match = { ["affordance.cutting"] = true }, count = 1 }, -- head (a sharp stone)
{ match = { ["affordance.leverage"] = true }, count = 1 }, -- haft
{ match = { ["affordance.binding"] = true }, count = 1 }, -- binding
{ match = { ["affordance.cutting"] = true }, count = 1, name = "head" }, -- a sharp stone
{ match = { ["affordance.leverage"] = true }, count = 1, name = "haft" }, -- stick OR branch
{ match = { ["affordance.binding"] = true }, count = 1 }, -- binding
},
requires = { ["skill.knapping"] = ">=3" },
-- Product quality = skill (band min 3 = the requires-floor, no re-author,
-- max 5) + head grade (the knapped edge) + haft grade (raw-branch variance).
-- A mediocre branch caps the axe even at max skill.
quality = { contributors = {
{ skill = "skill.knapping", max = 5, weight = 0.4 },
{ ingredient = "head", weight = 0.3 },
{ ingredient = "haft", weight = 0.3 },
} },
outputs = { { template = "stone_axe", count = 1 } },
name = "Haft Stone Axe",
description = "Bind a sharp stone to a haft with cordage. (Needs knapping skill 3.)" }