Package garden is Gnotchi's Phase 1 on-chain slice, v2: everything v1's garden realm does (Adopt, GnomeByAddress, Render, soulbound, one gnome per address, the validated name/hat/coat rules, the OriginSend refusal -- every fix from v1's three audit rounds, carried over rather than rewritten from memory, see below for exactly which lines are unchanged from realms/garden/garden.gno) plus the new thing Phase 1 actually needs: SaveDay, the "one signature saves the whole day" call the brief's section 5.2 and the build brief's own paragraph 2 promise and that the deployed v1 realm does not have.
v1 (realms/garden/garden.gno) is deployed to the onyx testnet at gno.land/r/g1r4aw43kagaaquhegxw6xr346h9f2qu2ezf0jar/garden/v1 and, per DECISIONS.md, cannot be edited -- this file is deliberately a sibling, not a modification. v1 is left completely untouched as the deployed record.
THIS FILE IS NOT DEPLOYED. Authored and tested locally only, per this assignment's own brief: no gnokey, no key material, no deploy.
Everything below this comment that is unchanged from v1 (the soulboundExtension, Adopt's validation chain, the name-charset allowlist/denylist, Render's path validation, GnomeByAddress) is carried over with its original comments intact, because those comments are the audit trail for *why* each check exists -- deleting them to make this file shorter would silently discard that trail. New material (the care-state fields on gnome, SaveDay and its helpers, CareState) is clearly marked "v2:" in its own comments.
SECURITY: the same warning v1 carries applies here unchanged and is reprinted in full, because it is load-bearing and not something a reader should have to go find in a different file to understand this one: no code in this realm, now or later, may ever recover() around a call into ledger or token (grc721's PrivateLedger/Token). The soulbound guarantee below is real, but it is NOT that the ledger write never happens -- it does, before the panic -- it is that an *uncaught* panic aborts the whole enclosing transaction, so that write (and everything else the transaction did) is discarded and never committed on chain. p/nt/grc721/v0/types.gno says this outright, about extension hooks like soulboundExtension below: "Hooks run after the ledger write so they observe the post-movement state; only a caller that recovers from the panic keeps that write." A recover() anywhere between a ledger call and the transaction boundary -- even one added for an unrelated reason, even one several call-frames away -- would silently convert every refused transfer into a permanent, successful one. Don't add one. This is not limited to code textually inside this file: a pure `p/` package this realm calls runs in garden's own call frame too, so a helper as innocuous as `Try(func(){ ledger.TransferFrom(...) })` imported from some future `p/` dependency would break the same guarantee just as surely as a recover() written here directly. The same rule now also applies to SaveDay's own validate-then-commit pattern below: SaveDay never recovers from its own internal panics either, by design -- see that function's comment.