Inventories & holdings

Workshop stockpile

workshop-stockpile · an adoption of Container, version 1

Tests included

Use in your game

Opens the authoring tool with these answers and settings already filled in. You still add your game's own rules and tuning.

What is in the ZIP

The ZIP holds the adoption and its acceptance tests. In the authoring tool, choose Add contract and pick this ZIP. If you keep your design as files, put them in contracts/.

The contract behind it

A delivery is items arriving at a container, such as a bag or chest, that holds distinct items. This contract says when it is full and what happens when some items do not fit. It also says which items it accepts and which slot fills or empties first. It covers slots and size budgets. Version 1 excludes item footprints; counted amounts such as gold use the Ranged value contract.

Read the full Container contract →

Questions

The supplied answer is marked on each question. Pick other answers to see what changes. Nothing is saved here: the ZIP and the authoring tool use the supplied answers.

What makes this container full?

Choices for What makes this container full?
Supplied answer A fixed number of slots makes it full. A shop's twenty stock slots refuse a new kind of item when all twenty hold stacks. A matching stack with room can still accept it.
A size-budget container has no slots. A card deck with a thirty-point build budget may spend those points across cards of different costs.
A slot limit and a size budget both apply. A bag with three free slots can still refuse an anvil when its weight budget is full.
It never fills. A new item always has room, so nothing is refused because the container ran out of space.
Why this is asked

Capacity changes what the container can hold and how it fills. This contract supports one size measure. Containers where items occupy a width-and-height footprint are outside version 1.

A delivery reaches the container, but not all the items fit. What goes in?

Asked when
Capacity limit is Slot count or Size budget or Slots and size.
Choices for A delivery reaches the container, but not all the items fit. What goes in?
Supplied answer The whole delivery is refused. A ten-arrow pickup adds no arrows when the container has room for only five. Each offered type and amount is one delivery. A craft with several outputs makes several deliveries, so some outputs may enter before another is refused. The refused items stay with whatever offered them, and what that action does next is the game's own rule.
Everything that fits goes in. A ten-arrow pickup adds five when only five fit; the other five remain outside.
Why this is asked

Two containers with the same free space can act differently. One accepts what fits; the other refuses the whole delivery.

What happens to the items that do not fit?

Asked when
Partial acceptance is Fill what fits.
Choices for What happens to the items that do not fit?
The leftover goes back to its source. Arrows that do not fit return to the chest or pickup that offered them.
The leftover stays where the delivery arrived. Arrows that do not fit become a loose pickup beside the bag.
The leftover moves to another store named by your game. Arrows that do not fit may go to a stash.
The leftover is destroyed. Arrows that do not fit disappear instead of returning, dropping, or moving elsewhere.
Why this is asked

Items that stay outside still need a clear home. Otherwise one build may return them while another drops or destroys them.

Several slots could hold a new item. Which slot gets it?

Asked when
Capacity limit is Slot count or Slots and size or No limit.
Choices for Several slots could hold a new item. Which slot gets it?
Supplied answer Matching stacks fill before empty slots open. A potion tops up the first potion stack with room, then uses the first empty slot.
The first slot that can hold the item gets it. An empty first hotbar slot wins over a later matching stack with room.
New items go after everything already held. An empty slot in the middle stays unused until the items after it are gone. A bag with a slot limit can count as full while that gap remains.
Choose this only when each item has one reserved slot. If slots are unlimited, choose Append instead.
Why this is asked

Two teams building the same spec can fill the same container differently. That changes what players see and what the game removes later. Rules that score slots, rotate between containers, or use a custom sequence stay in your game's prose.

The game needs an item for one of its own rules. Which matching slot does it take from?

Choices for The game needs an item for one of its own rules. Which matching slot does it take from?
Supplied answer The first matching slot supplies the item. Crafting uses the earliest stack in the bag before later stacks.
The last matching slot supplies the item. Crafting empties the last matching stack before earlier stacks.
The stack that received items most recently supplies them first. Topping up an older potion stack makes it the newest again.
The stack that began first supplies items first. Topping up an old potion stack does not make it newer.
The game never has to choose between matching slots. The player chooses a slot, only one can match, or the container has no slots.
Why this is asked

Automatic use needs a stable choice because it can change which stack remains for the player. A rotating choice over counted amounts belongs in the Ranged value contract.

Which kinds of item can this container hold?

Choices for Which kinds of item can this container hold?
Only listed item types can enter. A potion bag says no to a sword. The sword stays where it was; nothing is destroyed. An empty list means the container accepts nothing.
Supplied answer Every item type may enter once the contract knows how much room it needs. Where slots alone set the limit, an unlisted type — a quest letter no row names — uses one slot per item and cannot be forced out. Under a size budget, it is refused intact until a row names its size.
Each slot has its own item rule. An armour slot accepts a helmet but refuses a potion without destroying it. List every kind that needs a stacking or forced-out rule.

Each item row's slot-rules-declared-in citation is binding. It points to prose that lists every slot and every item kind that slot accepts; an item not accepted there is refused intact.

Why this is asked

A clear item rule prevents silent differences between what the game accepts and what the designer intended. Rules built from another list or a code callback stay in your game's prose.

Numbers2 numbers

Each value is either a number set here or a reference to one of your tuning keys.

Slot count = 24

fixed as written

slot-count

How many slots the container has. Use at least one when slots set capacity. Use zero when this container has no slot limit. If your game stores this number elsewhere, move it here so two copies cannot disagree.

Size budget = 0

fixed as written

size-budget

The largest total size the container holds. Your game chooses the unit, such as kilograms or bulk. Every item uses the same unit. Use zero when size does not limit the container.

Rules2 rules

A rule is a check between the numbers. Validation reports a rule that fails.

  • slot-count >= 0
  • size-budget >= 0
Lists1 list

Each list holds the rows this adoption supplies. A list can be empty.

Items

items

IdSlot rules declared inStack limitSizeWhen forced outForced out order
firewood40never
clay40never
ore-rock40never
charcoal40never
kiln-brick20never
kiln-lining4never
copper-ingot10never
glaze-slip10never
wardstone1never
Test inputsscope and seeds

Some tests need a scope or seeds from the adoption before they can run.

capacity-holds

Capacity holds

Scope
sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop
Seeds
["workshop-stockpile-audit-a","workshop-stockpile-audit-b"]

fill-order-holds

Fill order holds

Scope
02-mechanics.md#the-workshop

draw-order-by-position

Draw order by position

Scope
02-mechanics.md#the-workshop
Acceptance tests24 tests apply

The contract comes with 14 tests. A test that runs once per row is counted once for each row. Tests that do not apply to these answers are still listed, with the reason.

delivery-that-fits

a delivery that fits is accepted whole

scenarioonce

Applies to workshop-stockpile.

A delivery workshop-stockpile has room for is accepted whole: the container gains exactly what was offered, keeps everything it already held, and nothing is left over to account for. This is the ordinary case, written down so that every other test below reads as a departure from it.

Test steps and diagnostics
Given

the workshop-stockpile container with room for the whole of the delivery below

When
  • a delivery offers n items of a type workshop-stockpile accepts
Then
  • workshop-stockpile holds exactly n more items of that type than it did
  • nothing already in workshop-stockpile is removed, destroyed, or changed into another type
  • nothing is handed back, dropped, or destroyed
Diagnostics
  • workshop-stockpile-contents-before-after

refuses-whole

a delivery that does not fit is refused whole

scenarioonce

Applies to workshop-stockpile.

A delivery larger than the room available leaves workshop-stockpile untouched. Partial delivery is the failure this answer rules out: even the items that would have fitted stay out, and the delivery says so. Whether the action that offered them still occurs is decided in this game's own prose, not here.

Test steps and diagnostics
Given

the workshop-stockpile container with room for fewer than n items of a type it accepts

When
  • a delivery offers n items of that type
Then
  • workshop-stockpile holds exactly what it held before
  • not one of the n items goes in — not even the ones that would have fitted
  • the delivery reports that it did not happen
Diagnostics
  • workshop-stockpile-contents-before-after
  • workshop-stockpile-delivery-report

takes-what-fits

a delivery that does not fit is split

scenarioonce

Does not apply to workshop-stockpile: partial acceptance is all or nothing, not fill what fits.

slots-are-the-limit

the container is full when its slots are full

scenarioonce

Applies to workshop-stockpile.

This container is full when every slot stated by the value at slot-count = 24 is in use and none of them can take more of what is being offered. This test cites that value and restates the number nowhere.

Test steps and diagnostics
Given

the workshop-stockpile container with all slot-count = 24 slots in use and no slot in use able to take more of the type below

When
  • a delivery offers one item of that type
Then
  • workshop-stockpile takes none of it
  • the number of slots in use is still the number stated by slot-count = 24
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

size-is-the-limit

the container is full when its size budget is spent

scenarioonce

Does not apply to workshop-stockpile: capacity limit is slot count, not size budget or slots and size.

never-refuses

nothing is ever refused for want of room

scenarioonce

Does not apply to workshop-stockpile: capacity limit is slot count, not no limit.

fill-order-holds

an accepted item lands in the declared slot

scenarioonce

Applies to workshop-stockpile.

An item workshop-stockpile accepts lands in a slot that already holds that type while any such slot can take more, and only then in the first empty slot. The rule is repeatable: the same delivery from the same starting contents lands in the same slot every time. Slot numbering is the numbering identified by this adoption's verification scope. Six externally authored games answer this question six different ways and none of them writes the answer down — this line is the whole reason the question is asked.

Test steps and diagnostics
Given

the workshop-stockpile container holding some of a type in one slot, with at least one other slot free and at least one slot freed by an earlier removal, its slots numbered as 02-mechanics.md#the-workshop sets out

When
  • a delivery offers one more item of that type
Then
  • the item lands in a slot that already holds that type while any such slot can take more, and only then in the first empty slot
  • the same delivery made again from the same starting contents lands in the same slot
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-fill-trace

draw-order-by-position

the game takes from the declared slot

scenarioonce

Applies to workshop-stockpile.

A take the game makes on its own comes from the first slot in the container's own order that holds the type, moving on only when that slot is empty, repeatably, against the slot numbering at 02-mechanics.md#the-workshop. Five externally authored games answer this question and answer it five different ways, no two alike; one of them has written its answer down, and only after its own users filed a bug about the silence. If workshop-stockpile adopts nothing else from this contract, it should adopt this line.

Test steps and diagnostics
Given

the workshop-stockpile container holding the same type in at least two slots, its slots numbered as 02-mechanics.md#the-workshop sets out

When
  • the game takes fewer of that type than workshop-stockpile holds, on its own rather than at a player's direction
Then
  • the items come from the first slot in the container's own order that holds the type, moving on only when that slot is empty
  • the same take made again from the same starting contents comes from the same slot
  • no slot other than the one the rule names is touched while that one can still supply the take
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-take-trace

draw-order-by-arrival

the game takes by when the stack arrived

scenarioonce

Does not apply to workshop-stockpile: draw order is first in order, not newest first or oldest first.

stack-limit-holds · firewood

firewood stacks no higher than its limit

scenarioper items row

Applies to the firewood row.

A stack of firewood never holds more than 40. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries firewood.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 40 of firewood

When
  • a delivery offers one more firewood
Then
  • that slot still holds exactly 40 of firewood
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · clay

clay stacks no higher than its limit

scenarioper items row

Applies to the clay row.

A stack of clay never holds more than 40. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries clay.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 40 of clay

When
  • a delivery offers one more clay
Then
  • that slot still holds exactly 40 of clay
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · ore-rock

ore-rock stacks no higher than its limit

scenarioper items row

Applies to the ore-rock row.

A stack of ore-rock never holds more than 40. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries ore-rock.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 40 of ore-rock

When
  • a delivery offers one more ore-rock
Then
  • that slot still holds exactly 40 of ore-rock
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · charcoal

charcoal stacks no higher than its limit

scenarioper items row

Applies to the charcoal row.

A stack of charcoal never holds more than 40. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries charcoal.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 40 of charcoal

When
  • a delivery offers one more charcoal
Then
  • that slot still holds exactly 40 of charcoal
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · kiln-brick

kiln-brick stacks no higher than its limit

scenarioper items row

Applies to the kiln-brick row.

A stack of kiln-brick never holds more than 20. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries kiln-brick.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 20 of kiln-brick

When
  • a delivery offers one more kiln-brick
Then
  • that slot still holds exactly 20 of kiln-brick
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · kiln-lining

kiln-lining stacks no higher than its limit

scenarioper items row

Applies to the kiln-lining row.

A stack of kiln-lining never holds more than 4. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries kiln-lining.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 4 of kiln-lining

When
  • a delivery offers one more kiln-lining
Then
  • that slot still holds exactly 4 of kiln-lining
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · copper-ingot

copper-ingot stacks no higher than its limit

scenarioper items row

Applies to the copper-ingot row.

A stack of copper-ingot never holds more than 10. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries copper-ingot.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 10 of copper-ingot

When
  • a delivery offers one more copper-ingot
Then
  • that slot still holds exactly 10 of copper-ingot
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · glaze-slip

glaze-slip stacks no higher than its limit

scenarioper items row

Applies to the glaze-slip row.

A stack of glaze-slip never holds more than 10. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries glaze-slip.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 10 of glaze-slip

When
  • a delivery offers one more glaze-slip
Then
  • that slot still holds exactly 10 of glaze-slip
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

stack-limit-holds · wardstone

wardstone stacks no higher than its limit

scenarioper items row

Applies to the wardstone row.

A stack of wardstone never holds more than 1. The limit belongs to the item type rather than to workshop-stockpile, which is how every surveyed game that stacks at all does it, so the same number holds in every container that carries wardstone.

Test steps and diagnostics
Given

the workshop-stockpile container with one slot holding 1 of wardstone

When
  • a delivery offers one more wardstone
Then
  • that slot still holds exactly 1 of wardstone
  • the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting and is settled by the partial-acceptance answer
Diagnostics
  • workshop-stockpile-slot-occupancy
  • workshop-stockpile-delivery-report

unlisted-type-refused

a type the list does not name is refused

scenarioonce

Does not apply to workshop-stockpile: type restriction is any item, not only these.

forced-out-holds

Row.id leaves workshop-stockpile in the declared way

scenarioper items row

Does not apply to workshop-stockpile: no row in items matches when-forced-out dropped nearby or moved to another store or destroyed.

never-forced-out · firewood

firewood is never given up by workshop-stockpile itself

scenarioper items row

Applies to the firewood row.

Nothing this container does on its own removes firewood from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy firewood is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding firewood at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no firewood leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no firewood is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · clay

clay is never given up by workshop-stockpile itself

scenarioper items row

Applies to the clay row.

Nothing this container does on its own removes clay from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy clay is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding clay at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no clay leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no clay is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · ore-rock

ore-rock is never given up by workshop-stockpile itself

scenarioper items row

Applies to the ore-rock row.

Nothing this container does on its own removes ore-rock from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy ore-rock is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding ore-rock at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no ore-rock leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no ore-rock is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · charcoal

charcoal is never given up by workshop-stockpile itself

scenarioper items row

Applies to the charcoal row.

Nothing this container does on its own removes charcoal from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy charcoal is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding charcoal at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no charcoal leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no charcoal is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · kiln-brick

kiln-brick is never given up by workshop-stockpile itself

scenarioper items row

Applies to the kiln-brick row.

Nothing this container does on its own removes kiln-brick from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy kiln-brick is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding kiln-brick at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no kiln-brick leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no kiln-brick is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · kiln-lining

kiln-lining is never given up by workshop-stockpile itself

scenarioper items row

Applies to the kiln-lining row.

Nothing this container does on its own removes kiln-lining from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy kiln-lining is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding kiln-lining at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no kiln-lining leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no kiln-lining is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · copper-ingot

copper-ingot is never given up by workshop-stockpile itself

scenarioper items row

Applies to the copper-ingot row.

Nothing this container does on its own removes copper-ingot from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy copper-ingot is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding copper-ingot at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no copper-ingot leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no copper-ingot is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · glaze-slip

glaze-slip is never given up by workshop-stockpile itself

scenarioper items row

Applies to the glaze-slip row.

Nothing this container does on its own removes glaze-slip from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy glaze-slip is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding glaze-slip at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no glaze-slip leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no glaze-slip is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

never-forced-out · wardstone

wardstone is never given up by workshop-stockpile itself

scenarioper items row

Applies to the wardstone row.

Nothing this container does on its own removes wardstone from it: when workshop-stockpile has to shed items, this type is passed over, and only when shedding everything that can go is still not enough does workshop-stockpile refuse the change outright. A player choosing to drop, sell, or destroy wardstone is a different thing entirely and is governed by this game's own rules, not by this line. Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.

Test steps and diagnostics
Given

the workshop-stockpile container holding wardstone at a moment when something would leave it holding more than it can — its slots shrank, or its rules changed

When
  • that change is attempted
Then
  • no wardstone leaves workshop-stockpile: the type is passed over while types that can go are given up in their declared order
  • if giving up every type that can go is still not enough, workshop-stockpile refuses the change
  • no wardstone is dropped, moved to another store, or destroyed by workshop-stockpile itself
Diagnostics
  • workshop-stockpile-forced-removal-log
  • workshop-stockpile-contents-before-after

capacity-holds

the limit holds after every delivery and take

generalonce

Applies to workshop-stockpile.

For every delivery and take in this adoption's verification scope — sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop — the number of slots in use never goes above the container's declared slot count. The scope and seeds are supplied by this adoption through its verification inputs; the rule being checked is the one this container's own capacity answer entitles it to assert.

Test steps and diagnostics
Diagnostics
  • workshop-stockpile-contents-trace
  • first-violating-delivery-or-take
Holds

after every delivery and every take, the number of slots in use never goes above the container's declared slot count

Seeds

["workshop-stockpile-audit-a","workshop-stockpile-audit-b"]

Scope

sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop

JSONthe adoption as one file

The adoption file as supplied. Answers you try on this page are not written into it; to change an adoption, open it in the authoring tool.

{
  "contract": "container",
  "version": 1,
  "origin": "https://opengdd.org/contracts/container-1",
  "summary": "A delivery is items arriving at a container, such as a bag or chest, that holds distinct items. This contract says when it is full and what happens when some items do not fit. It also says which items it accepts and which slot fills or empties first. It covers slots and size budgets. Version 1 excludes item footprints; counted amounts such as gold use the Ranged value contract.",
  "mechanism": [
    "One container holds items. Two items of one type are interchangeable; items differing within a type — wear, charges — are separate types here, or this game's prose. A slot holds one stack: items of one type together.",
    "The container's own order is the order the game's material numbers or lists its slots; first and last below mean first and last in it. A container with no slots has none. Containers where an item occupies a width-and-height footprint, including attaché cases and grid inventories, are outside version 1.",
    "A put offers a type and an amount — a delivery. A take asks for a type and an amount; one larger than the holdings yields what is held and reports the shortfall.",
    "A delivery that fits is accepted whole; one that does not is settled by partial-acceptance, and anything left over by leftover-destination.",
    "A stack never holds more than the stack limit on its type's row. Past it, an amount starts a new stack in a free slot, or counts as not fitting if there is none. Under type-restriction any-item, where slots alone set the limit, a type with no row stacks one item per slot and is unmovable in a forced removal, as though when-forced-out were never; under a size budget an unlisted type has no size, so it is refused intact until a row names its size.",
    "A forced removal is an item leaving without a take: the container shrank, its rules changed, or its owner is gone. Each item row says what becomes of its type and when its turn comes. In a container with slots, the last occupied slot within one type goes first.",
    "One adoption file describes one container; two are two files with their own rows. Moving an item between them is a take then a delivery, and nothing binds them. Rearranging by hand is input. In a container with slots, a sort re-delivers the contents in the order the sort names; each delivery then lands by the fill-order answer. A slotless container's sort changes nothing observable.",
    "The same delivery from the same contents lands the same way; the same take comes from the same slot."
  ],
  "questions": {
    "capacity-limit": {
      "asks": "What makes this container full?",
      "rationale": "Capacity changes what the container can hold and how it fills. This contract supports one size measure. Containers where items occupy a width-and-height footprint are outside version 1.",
      "options": {
        "slot-count": {
          "meaning": "A fixed number of slots makes it full. A shop's twenty stock slots refuse a new kind of item when all twenty hold stacks. A matching stack with room can still accept it."
        },
        "size-budget": {
          "meaning": "A size-budget container has no slots. A card deck with a thirty-point build budget may spend those points across cards of different costs."
        },
        "slots-and-size": {
          "meaning": "A slot limit and a size budget both apply. A bag with three free slots can still refuse an anvil when its weight budget is full."
        },
        "no-limit": {
          "meaning": "It never fills. A new item always has room, so nothing is refused because the container ran out of space.",
          "rationale": "Use this when room can never run out. It avoids a fake large limit that readers may mistake for a real cap."
        }
      }
    },
    "partial-acceptance": {
      "asks": "A delivery reaches the container, but not all the items fit. What goes in?",
      "rationale": "Two containers with the same free space can act differently. One accepts what fits; the other refuses the whole delivery.",
      "when": {
        "flag": {
          "capacity-limit": [
            "slot-count",
            "size-budget",
            "slots-and-size"
          ]
        }
      },
      "options": {
        "all-or-nothing": {
          "meaning": "The whole delivery is refused. A ten-arrow pickup adds no arrows when the container has room for only five. Each offered type and amount is one delivery. A craft with several outputs makes several deliveries, so some outputs may enter before another is refused. The refused items stay with whatever offered them, and what that action does next is the game's own rule."
        },
        "fill-what-fits": {
          "meaning": "Everything that fits goes in. A ten-arrow pickup adds five when only five fit; the other five remain outside."
        }
      }
    },
    "leftover-destination": {
      "asks": "What happens to the items that do not fit?",
      "rationale": "Items that stay outside still need a clear home. Otherwise one build may return them while another drops or destroys them.",
      "when": {
        "flag": {
          "partial-acceptance": [
            "fill-what-fits"
          ]
        }
      },
      "options": {
        "back-to-the-sender": {
          "meaning": "The leftover goes back to its source. Arrows that do not fit return to the chest or pickup that offered them."
        },
        "left-where-it-is": {
          "meaning": "The leftover stays where the delivery arrived. Arrows that do not fit become a loose pickup beside the bag."
        },
        "another-store": {
          "meaning": "The leftover moves to another store named by your game. Arrows that do not fit may go to a stash."
        },
        "destroyed": {
          "meaning": "The leftover is destroyed. Arrows that do not fit disappear instead of returning, dropping, or moving elsewhere."
        }
      }
    },
    "fill-order": {
      "asks": "Several slots could hold a new item. Which slot gets it?",
      "rationale": "Two teams building the same spec can fill the same container differently. That changes what players see and what the game removes later. Rules that score slots, rotate between containers, or use a custom sequence stay in your game's prose.",
      "when": {
        "flag": {
          "capacity-limit": [
            "slot-count",
            "slots-and-size",
            "no-limit"
          ]
        }
      },
      "options": {
        "top-up-then-first-empty": {
          "meaning": "Matching stacks fill before empty slots open. A potion tops up the first potion stack with room, then uses the first empty slot."
        },
        "first-slot-that-fits": {
          "meaning": "The first slot that can hold the item gets it. An empty first hotbar slot wins over a later matching stack with room."
        },
        "append": {
          "meaning": "New items go after everything already held. An empty slot in the middle stays unused until the items after it are gone. A bag with a slot limit can count as full while that gap remains."
        },
        "not-applicable": {
          "meaning": "Choose this only when each item has one reserved slot. If slots are unlimited, choose Append instead."
        }
      }
    },
    "draw-order": {
      "asks": "The game needs an item for one of its own rules. Which matching slot does it take from?",
      "rationale": "Automatic use needs a stable choice because it can change which stack remains for the player. A rotating choice over counted amounts belongs in the Ranged value contract.",
      "options": {
        "first-in-order": {
          "meaning": "The first matching slot supplies the item. Crafting uses the earliest stack in the bag before later stacks."
        },
        "last-in-order": {
          "meaning": "The last matching slot supplies the item. Crafting empties the last matching stack before earlier stacks."
        },
        "newest-first": {
          "meaning": "The stack that received items most recently supplies them first. Topping up an older potion stack makes it the newest again."
        },
        "oldest-first": {
          "meaning": "The stack that began first supplies items first. Topping up an old potion stack does not make it newer.",
          "rationale": "Use this when the longest-held stack must leave first, such as a magazine or queue."
        },
        "not-applicable": {
          "meaning": "The game never has to choose between matching slots. The player chooses a slot, only one can match, or the container has no slots."
        }
      }
    },
    "type-restriction": {
      "asks": "Which kinds of item can this container hold?",
      "rationale": "A clear item rule prevents silent differences between what the game accepts and what the designer intended. Rules built from another list or a code callback stay in your game's prose.",
      "options": {
        "only-these": {
          "meaning": "Only listed item types can enter. A potion bag says no to a sword. The sword stays where it was; nothing is destroyed. An empty list means the container accepts nothing."
        },
        "any-item": {
          "meaning": "Every item type may enter once the contract knows how much room it needs. Where slots alone set the limit, an unlisted type — a quest letter no row names — uses one slot per item and cannot be forced out. Under a size budget, it is refused intact until a row names its size."
        },
        "by-slot": {
          "meaning": "Each slot has its own item rule. An armour slot accepts a helmet but refuses a potion without destroying it. List every kind that needs a stacking or forced-out rule.",
          "semantics": "Each item row's slot-rules-declared-in citation is binding. It points to prose that lists every slot and every item kind that slot accepts; an item not accepted there is refused intact."
        }
      }
    }
  },
  "declares": {
    "values": {
      "slot-count": {
        "description": "How many slots the container has. Use at least one when slots set capacity. Use zero when this container has no slot limit. If your game stores this number elsewhere, move it here so two copies cannot disagree."
      },
      "size-budget": {
        "description": "The largest total size the container holds. Your game chooses the unit, such as kilograms or bulk. Every item uses the same unit. Use zero when size does not limit the container."
      }
    },
    "rows": {
      "items": {
        "description": "The item types whose rules this contract records. Use one row for each type. For a restricted container, the rows are also the allowed list. An empty list means no listed types. For any-item, the rows plus the unlisted-type defaults fully decide entry, stacking, and forced removal for every type. The validator checks each row's fields; a reviewer checks that the game's own prose does not give unlisted types a rule different from the defaults.",
        "record": {
          "id": {
            "type": "string",
            "required": true,
            "pattern": "kebab-case",
            "unique": true,
            "description": "The item type's name, written as your game names it."
          },
          "slot-rules-declared-in": {
            "type": "citation",
            "when": {
              "flag": {
                "type-restriction": [
                  "by-slot"
                ]
              }
            },
            "description": "The place in this game's prose that lists every slot and every item kind it accepts. This citation is the binding rule for the slots. Use the same citation on every row when one section holds the whole list."
          },
          "stack-limit": {
            "type": "integer",
            "when": {
              "flag": {
                "capacity-limit": [
                  "slot-count",
                  "slots-and-size",
                  "no-limit"
                ]
              }
            },
            "description": "How many items of this type fit in one slot. It is required whenever the container has slots, including when it never fills. Use one for an item that does not stack, or another positive whole number."
          },
          "size": {
            "type": "number",
            "when": {
              "flag": {
                "capacity-limit": [
                  "size-budget",
                  "slots-and-size"
                ]
              }
            },
            "description": "How much of the size budget one item uses. Use the same unit as the container's budget. Use zero or more."
          },
          "when-forced-out": {
            "type": "string",
            "required": true,
            "options": [
              "never",
              "dropped-nearby",
              "moved-to-another-store",
              "destroyed"
            ],
            "description": "What happens to this item when the container must give items up. It may stay, drop nearby, move to another store, or be destroyed. An item marked to stay is skipped. The container tries other types in their chosen order. It refuses the forced removal if too few items can leave. If destroying an item could make the game impossible to finish, say so and test it in your own rules."
          },
          "forced-out-order": {
            "type": "integer",
            "unique": true,
            "when": {
              "row": {
                "when-forced-out": [
                  "dropped-nearby",
                  "moved-to-another-store",
                  "destroyed"
                ]
              }
            },
            "description": "The order in which item types leave, lowest number first. Give each movable type a different number. Items of one type leave from its last occupied slot first. The size of the gaps between numbers does not matter."
          }
        }
      }
    }
  },
  "pack": "sha256:8f40a54e650b683136852e7a5b47976ebe709f810057f847424d6d8ab3b41b20",
  "rules": {
    "slot-count-not-negative": "slot-count >= 0",
    "size-budget-not-negative": "size-budget >= 0"
  },
  "answers": {
    "capacity-limit": "slot-count",
    "partial-acceptance": "all-or-nothing",
    "fill-order": "top-up-then-first-empty",
    "draw-order": "first-in-order",
    "type-restriction": "any-item"
  },
  "values": {
    "slot-count": 24,
    "size-budget": 0
  },
  "rows": {
    "items": [
      {
        "id": "firewood",
        "stack-limit": 40,
        "when-forced-out": "never"
      },
      {
        "id": "clay",
        "stack-limit": 40,
        "when-forced-out": "never"
      },
      {
        "id": "ore-rock",
        "stack-limit": 40,
        "when-forced-out": "never"
      },
      {
        "id": "charcoal",
        "stack-limit": 40,
        "when-forced-out": "never"
      },
      {
        "id": "kiln-brick",
        "stack-limit": 20,
        "when-forced-out": "never"
      },
      {
        "id": "kiln-lining",
        "stack-limit": 4,
        "when-forced-out": "never"
      },
      {
        "id": "copper-ingot",
        "stack-limit": 10,
        "when-forced-out": "never"
      },
      {
        "id": "glaze-slip",
        "stack-limit": 10,
        "when-forced-out": "never"
      },
      {
        "id": "wardstone",
        "stack-limit": 1,
        "when-forced-out": "never"
      }
    ]
  },
  "verification": {
    "capacity-holds": {
      "scope": "sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop",
      "seeds": [
        "workshop-stockpile-audit-a",
        "workshop-stockpile-audit-b"
      ]
    },
    "fill-order-holds": {
      "scope": "02-mechanics.md#the-workshop"
    },
    "draw-order-by-position": {
      "scope": "02-mechanics.md#the-workshop"
    }
  }
}