Repository navigation
upgrade updates the record: it refreshes the stale copies only, and its receipt stacks on the current lifetime #928
Description
Epic: #451 · Feature: #762 The writ lifecycle surface · Schedule: #916, lane 11, PR E · Waits on: #971 (lane 17)
The ruling (#913; this lane ruled 2026-09-23)
Upgrade updates the record. The same deployment, refreshed: its receipt stacks on the current lifetime (#922)
and never opens a new one. Upgrade acts on what is stale only (ruled 2026-09-23): the copies -- templates,
secrets, copies -- whose source content no longer matches the source digest the record holds (RecordedSourceDigest,
#923). A copy whose source is unchanged is left alone, and the receipt says exactly what was refreshed.
Today
cmd/writ/writ/upgrade regenerates every copied file from its current source, whether or not the source moved,
and writes a receipt that the unbounded fold treats like any other.
The change
- Upgrade reads the current lifetime's record and selects the
staleentries, by the same comparisonreconcile
makes for that word. - It re-renders those, and only those, and its receipt records the new target and source digests for them.
- The receipt stacks on the current lifetime: identity fields unchanged, observation fields refreshed for what was
rewritten, nothing else touched. A secondupgradefinds nothing stale and writes a receipt that says so. - Links are never upgrade's: a link's referent is the checkout, and a link whose referent moved between layers is
deploy's (writ deploy calls its own dangling symlinks foreign: a file that moved between layers cannot be re-pointed without --conflict=replace #883).
Acceptance
- after a deploy, an upgrade with no source change refreshes nothing and says so; the record's observation
fields are unchanged - edit one template's source;
reconcilereports onestale;upgraderefreshes that one file and no other;
reconcileexits 0 - the upgrade's receipt folds onto the deploy's record (deploy replaces the record: readback.Fold is bounded to the current lifetime, one writ deploy invocation across scopes #922): one lifetime, the identity fields the deploy's,
the refreshed entry's digests the upgrade's -
10-command-line-interface.md§3.1's mechanics row forupgradesays "the stale copies, from their sources" - both VMs: the edit-one-source sequence above
Plan and design documents
| Kind | Document |
|---|---|
| Plan | a lane plan arrives with the branch |
| Design | 5.1-reconciliation.md, 10-command-line-interface.md §3.1 |
Revised 2026-09-28: upgrade pins and moves links (#847, ruling 5)
Under kept snapshots, upgrade pins its own ref and moves a layer's links to the new snapshot along with re-rendering its copies, so one lifetime shows one commit per layer. "The stale copies only" is superseded. A file new in the new commit waits for deploy; a file gone keeps its link on the old snapshot and is reported for deploy. Closes #844 (upgrade pins and records origin).
Activity
doc(writ): the maintainer owns every merge; upgrade moves links; writ…
doc(writ): kept snapshots -- reconcile against the ref that produced …
David-Noble-at-work commentedon Oct 2, 2026
Amended by the owner's ruling of 2026-10-02, lifetimes are generations: writ follows git and Nix. It is stated in
docs/architecture/5.1-reconciliation.md§ Lifetimes are generations, recorded on #916, and its finding is open question 5 of lane 7's plan,docs/plans/task/926-scope-flag.md(#926). The lane's plan takes this up when the schedule reaches it.Upgrade writes a new lifetime from the current one's runs, by reference, with its own runs on top, and makes it current, rather than stacking its receipt on the current lifetime. Each run records its scope and, for each layer, the commit it deployed from.