feat: a minted box records how it was minted, and box info reads it back #129

Merged
dan-claude-bot merged 3 commits from feat/mint-stamp into main 2026-07-21 11:24:40 +00:00
3 changed files with 63 additions and 2 deletions
Showing only changes of commit aed2f5bf1f - Show all commits

View file

@ -43,6 +43,17 @@ which records not just what changed but what each drill run proved.
records **one hop** — a clone of a clone names its parent and forgets its
grandparent, because the alternative is an unbounded chain in a config
value and the parent is the box an operator can go look at.
One key sits in **neither** column and is therefore *cleared*:
`user.box.mode.asked`. It records whether a container was asked for or
fallen back into, which makes it a mint-*event* fact — and the asker was
the **source's** operator. A clone refuses `--vm`/`--container` outright,
so nobody was asked anything about this instance, and there is no true
value to re-stamp it with; inheriting it made `box info` print
`MODE vm (asked: auto)` on a clone, describing a demand never made of it.
The clear lands with the re-stamp, before the start, and the read side
needs no special case: the `MODE` line is gated on `asked`, so absence
renders as silence while `TYPE` still reports VM or CT off the preserved
instance type.
- **`box info` grew a provenance block** (#103) — it printed
`NAME / STATE / TYPE / IPV4`, exposures and snapshots, and surfaced *none*
of the `user.box.*` keys, including the two that already existed. A stamp

16
bin/box
View file

@ -1079,6 +1079,17 @@ cmd_new() {
# that rig role — reading them off the source is the whole point of a clone.
# ('incus copy' preserves the instance type too, so mode stays true as well.)
#
# 'mode.asked' is the one key that sits in NEITHER column, and so it is
# CLEARED rather than re-stamped or inherited. It is a mint-event fact —
# only the mint knew whether a container was asked for or fallen back into
# for want of /dev/kvm — and the asker was the SOURCE's operator. A clone
# refuses --vm/--container outright (nobody was asked anything here), so an
# inherited 'asked' makes 'box info' print a demand that was never made of
# this instance. There is no true value to re-stamp it with: the honest
# answer is absence, and absence is already how the whole block renders
# what it does not know — the MODE line simply does not print, while TYPE
# above still says VM or CT off the preserved instance type.
#
# origin.from records ONE hop. A clone of a clone names its parent and
# forgets its grandparent: the alternative is an unbounded chain in a config
# value, and the parent is the box an operator can actually go look at.
@ -1088,6 +1099,11 @@ cmd_new() {
user.box.created="$(mint_time)" \
user.box.origin=clone \
user.box.origin.from="$srcref"
# Cleared, not set-to-empty: an empty value is still a key, and a reader
# that greps the config would find it. Tolerated failure because the source
# may predate the stamp and never have carried the key at all — a clone
# must not die over a key that was already absent.
incus config unset "$instance" user.box.mode.asked >/dev/null 2>&1 || true
incus start "$instance"
wait_agent "$instance"
reset_identity "$instance"

View file

@ -1256,6 +1256,17 @@ check "clone: does NOT re-stamp the image — the disk really came from it (#103
restamp_has "$CLONELOG" 'user\.box\.image'
check "clone: does NOT re-stamp the role — the source's rig converged it (#103)" 1 "" \
restamp_has "$CLONELOG" 'user\.box\.role'
# The third column, and the one review found: 'mode.asked' is neither lineage
# nor re-stampable. It is a mint-event fact whose asker was the SOURCE's
# operator, and a clone refuses --vm/--container, so nobody was asked anything
# here. It is CLEARED — there is no true value to give it.
check "clone: clears the inherited mode.asked — nobody asked THIS box (#103)" 0 "" \
grep -qF 'config unset w2 user.box.mode.asked' "$CLONELOG"
check "clone: ...and does not re-stamp it with a fabricated answer (#103)" 1 "" \
restamp_has "$CLONELOG" 'user\.box\.mode\.asked'
# Cleared, never set-to-empty: an empty value is still a key on the instance.
check "clone: clears it rather than setting it empty (#103)" 1 "" \
grep -qE 'config set .*user\.box\.mode\.asked=($|[[:space:]])' "$CLONELOG"
# Order: the re-stamp lands on the copied instance BEFORE it is started, so a
# clone is never observable wearing its source's provenance. Fail-closed — an
# absent line makes the arithmetic fail, not pass.
@ -1267,6 +1278,17 @@ restamp_precedes_start() {
}
check "clone: the re-stamp precedes the start (#103)" 0 "" \
restamp_precedes_start "$CLONELOG"
# The clear rides the same rule for the same reason: a clone must never be
# observable — not for one moment, not to 'box info' — wearing an 'asked' its
# operator never gave. Fail-closed the same way.
clear_precedes_start() {
local unset_ln start
unset_ln="$(grep -n 'config unset .* user.box.mode.asked' "$1" | head -1 | cut -d: -f1)"
start="$(grep -n '^incus start ' "$1" | head -1 | cut -d: -f1)"
[ -n "$unset_ln" ] && [ -n "$start" ] && [ "$unset_ln" -lt "$start" ]
}
check "clone: the mode.asked clear precedes the start too (#103)" 0 "" \
clear_precedes_start "$CLONELOG"
# --- the read half: 'box info' surfaces it ---------------------------------
# A stamp nothing can read is not done. cmd_info printed NAME/STATE/TYPE/IPV4
@ -1304,13 +1326,25 @@ check "info: surfaces the origin (#103)" 0 "ORIGIN mint" infobox "$STAMPED"
# Still the box it always was: the new block is additive, above the snapshots.
check "info: still prints the state block it always did" 0 "IPV4 10.1.2.3" infobox "$STAMPED"
# A clone reads back as a clone, naming its source.
# A clone reads back as a clone, naming its source. Modelled on what the
# --from branch actually leaves behind: origin re-stamped, mode.asked cleared.
CLONECFG="$MWORK/clone.cfg"
{ grep -v '^user.box.origin ' "$STAMPED"
{ grep -v -e '^user.box.origin ' -e '^user.box.mode.asked ' "$STAMPED"
echo 'user.box.origin clone'
echo 'user.box.origin.from work/authed'; } > "$CLONECFG"
check "info: a clone says so, and names the box it came from (#103)" \
0 "ORIGIN clone of work/authed" infobox "$CLONECFG"
# ...and stays silent about a demand nobody made of it. The MODE line is gated
# on 'asked' precisely so absence renders as silence rather than as a guess;
# TYPE above still reports VM off the instance type, so nothing is lost.
info_has_mode() { infobox "$1" | grep -q '^MODE'; }
check "info: a clone prints no MODE line — nobody asked IT anything (#103)" 1 "" \
info_has_mode "$CLONECFG"
check "info: ...while TYPE still reports what it actually is (#103)" \
0 "TYPE VM" infobox "$CLONECFG"
# The mint keeps its MODE line — there, the operator really was asked.
check "info: a MINT still surfaces what was asked for (#103)" \
0 "MODE vm (asked: auto)" infobox "$STAMPED"
# --- legacy boxes: the promise that they keep working under every verb ------
# A box carrying the boundary tag and NOTHING else — every box minted before