0c98080964
Befund 2 aus dem getraceten 5.0.0-auf-6.0.0-Upgrade-Lauf. Eine ausgelieferte Instanz bekommt CHANGES.md als Stub und dist upgrade ueberschreibt sie nie, der Befehl konnte dort also nie antworten - an genau der Stelle, an der Breaking Change und Migration gelesen werden muessen. Fehlt der Eintrag lokal, wird der Feed aus update_url gefragt. Nur mit Release-Stamp, damit Ursprungs-Repo und CI den Pfad nicht betreten koennen; stdout traegt nur die Notes, Herkunft nach stderr; --offline verweigert den Aufruf und nennt die release_url, so wie jeder Feed-Fehlerfall auch. Dazu zwei seit ihrer Umsetzung falsche Eintraege aus tools/CONTRACT.md "Future considerations" entfernt: MCP-Server-Wrapper und dist upgrade. Files changed: - CHANGES.md - INSTALL.md - VERSION - instructions/upgrade-instance.md - tools/CONTRACT.md - tools/chemenu/commands/version_cmd.py - tools/chemenu/tests/test_version_cmd.py - tools/chemenu/version.py
232 lines
12 KiB
Markdown
232 lines
12 KiB
Markdown
---
|
|
type: types/instruction.md
|
|
name: upgrade-instance
|
|
description: Carry out a stack release upgrade on an instance built from a tarball - read this release's notes, swap the machinery with dist upgrade, work the migration chain, verify, publish, and restart the session at the point where the new control plane starts to matter.
|
|
manual: true
|
|
---
|
|
# Upgrade this instance to a new stack release
|
|
|
|
An instance built from a `dist export` tarball takes stack updates by copying a newer release
|
|
over its machinery. This is the order in which that happens, what each step decides, and where
|
|
the two known rough edges are. It ends with the instance on the new `VERSION`, its content
|
|
version recorded, every check green, and the change published.
|
|
|
|
**This is the tarball path.** An instance that is a *clone* of the origin repo, sharing git
|
|
history, takes updates by three-way merge (`tools/wikitool upstream merge`) and follows
|
|
[private-instance.md](private-instance.md) instead. `git remote -v` answers which one this is:
|
|
a clone carries an `upstream` remote pointing at the origin.
|
|
|
|
**One thing this file deliberately does not know.** The copy you are reading shipped with the
|
|
release this instance is *leaving*, not the one it is going to - so nothing specific to a
|
|
particular jump is written here. That belongs to the release notes (step 2) and to the migration
|
|
documents that arrive inside the tarball.
|
|
|
|
<!-- wikitool:toc -->
|
|
## Contents
|
|
|
|
- [When to run](#when-to-run)
|
|
- [Steps](#steps)
|
|
- [Decision points](#decision-points)
|
|
- [Scope](#scope)
|
|
<!-- /wikitool:toc -->
|
|
|
|
## When to run
|
|
|
|
- `tools/wikitool version check` reports `state: update` or `state: migration`, and the operator
|
|
wants the new release installed.
|
|
- An operator asks for the stack, the tooling or "the wiki software" to be brought up to date.
|
|
- An interrupted upgrade is being resumed. Do not restart from step 1: `migrate status` and
|
|
`dist upgrade --dry-run` both report the true state, and the step that matches what they say
|
|
is where this run continues.
|
|
|
|
Not for setting up a new instance ([setup-instance.md](setup-instance.md)), not for preparing a
|
|
fresh clone ([bootstrap.md](bootstrap.md)), and not for the clone-with-upstream path above.
|
|
|
|
## Steps
|
|
|
|
1. **Take a session id and pass it on every call for the whole upgrade** - the form and the
|
|
reason are in [session-setup.md](session-setup.md). An upgrade is one of the longest runs
|
|
this stack has, and the iteration budget only sees it as one run if every call carries the
|
|
same id:
|
|
|
|
```bash
|
|
WIKITOOL_SESSION_ID=upgrade-<target-version> tools/wikitool version check
|
|
```
|
|
|
|
2. **Read this release's notes before touching anything.** Two lines decide the rest of the run:
|
|
**Breaking Change:** says what stops working and what this instance must do about it, and
|
|
**Migration:** says whether the corpus has to be rewritten (`none required` when it does not).
|
|
|
|
```bash
|
|
tools/wikitool version notes
|
|
```
|
|
|
|
On an instance this answers out of the release feed, not out of the local `CHANGES.md` - that
|
|
file arrives as a stub with no version entries and `dist upgrade` never overwrites it, so the
|
|
command reads the notes off the release the feed publishes instead. Two things follow that are
|
|
worth knowing before reading the output. It can only ask for the feed's *latest* release, so
|
|
while `VERSION` still names the release being left, the version it answers with is **not** the
|
|
one this tree declares - it says so on stderr, and that is the normal shape here rather than a
|
|
fault. And if the feed cannot be reached, the error names the release page from
|
|
`.wikitool-release.json`'s `release_url`; read it there and continue.
|
|
|
|
3. **Ask what is already outstanding, while `VERSION` is still the old one:**
|
|
|
|
```bash
|
|
tools/wikitool migrate status
|
|
```
|
|
|
|
Anything in the outstanding chain is finished **before** the swap - `dist upgrade` refuses
|
|
otherwise, and a chain that was already owed is not this release's business. The procedure is
|
|
step 12's, run against the migration documents this instance already has. An `offered` upgrade
|
|
listed separately blocks nothing and is decided later, in step 12.
|
|
|
|
4. **Fetch the tarball and verify it.** `dist upgrade` downloads nothing; the file has to be
|
|
there already. Take the `.tar.gz` and its `.sha256` from the release page found in step 2 and
|
|
check them before unpacking. A tarball must unpack to exactly one top-level directory.
|
|
|
|
5. **Dry-run the swap and read all four counts:**
|
|
|
|
```bash
|
|
tools/wikitool dist upgrade <tarball> --dry-run
|
|
```
|
|
|
|
`unchanged` / `new` / `locally changed` / `removed from the release`. The first two need no
|
|
decision. `locally changed` is step 6. `removed` matters only if `--prune` is wanted, which is
|
|
optional and never required.
|
|
|
|
6. **Only if a file is reported as locally changed: decide whose file it is, then reconcile it.**
|
|
The classification is against the sha256 the *installed* release recorded, so "locally
|
|
changed" means the working tree differs from what this instance was given - deliberately or
|
|
by a stray editor save.
|
|
|
|
| Whose file | What to do |
|
|
|---|---|
|
|
| The instance's own | Cannot appear here, which is worth knowing so a report that looks like it is read again rather than acted on: a file the instance owns either ships only as `<name>.template` (`kb/CONVENTIONS.md`, each `COLLECTION.md`, `USER.md`/`SOUL.md`/`ENVIRONMENT.md`) and is never classified at all, or is seeded once and then kept out of the write set (`.wikitool-kb.json`, `CHANGES.md`) |
|
|
| Machinery (a `CONTRACT.md`, anything under `tools/`, `types/`, `instructions/`, `AGENTS.md`, and every `<name>.template` beside an owned file) | It should not have local changes at all. Take the release's version: `--take-release <path>`, one per file |
|
|
| Machinery this instance changed **on purpose** | `--keep-local` keeps every listed file untouched - but the new stamp records the release digest anyway, so the same file is reported again at every future upgrade. That is the right answer only for a difference the instance intends to carry indefinitely |
|
|
|
|
The decision is per path, and the two flags compose - which is what a mixed report needs, one
|
|
file reset and another kept. Preview it before it writes:
|
|
|
|
```bash
|
|
tools/wikitool dist upgrade <tarball> --dry-run --take-release <path> [--take-release <path>]
|
|
```
|
|
|
|
The preview marks every named path as one it would overwrite from the release, and a path that
|
|
is not actually in the locally-changed list is refused *here* rather than in the writing run.
|
|
Nothing else is needed: no copy out of the unpacked tarball by hand, and no commit made only
|
|
to satisfy the next command's clean-tree precondition. Carry the flags you settled on into
|
|
step 7.
|
|
|
|
**Where `--keep-local` answers for some paths and `--take-release` for others, both go on the
|
|
same call.** Without `--keep-local`, a locally changed path that no `--take-release` names
|
|
still aborts the run: every one of them has to be answered for, and the abort's own text
|
|
names the three answers with the command line already filled in.
|
|
|
|
7. **Swap the machinery**, with whatever step 6 settled on. Note the commit the instance is on
|
|
first - step 13 compares against it:
|
|
|
|
```bash
|
|
git rev-parse --short HEAD # the pre-swap commit; keep it
|
|
tools/wikitool dist upgrade <tarball> [--take-release <path>] [--keep-local]
|
|
```
|
|
|
|
It writes, and commits nothing.
|
|
|
|
8. **Republish the skills.** `tools/wikitool instructions sync` - the published skill directories
|
|
are copies, so until this runs the harness is still offering the previous release's skills.
|
|
|
|
9. **Verify the machinery, and fix what the release said would need fixing:**
|
|
|
|
```bash
|
|
tools/wikitool doctor
|
|
tools/wikitool docs verify
|
|
tools/wikitool instructions verify
|
|
tools/wikitool lint
|
|
```
|
|
|
|
A `docs verify` failure naming a missing or stale table of contents is repaired with
|
|
`tools/wikitool docs toc --apply`, never by hand - a release that widened the set of files
|
|
carrying a region will produce exactly that on files this instance adopted before the
|
|
widening. Any other failure is read against step 2's **Breaking Change:** line: if the release
|
|
predicted it, the notes also say what fixes it; if it did not, stop and report it rather than
|
|
improvising.
|
|
|
|
10. **Publish the machinery swap.** A release swap is far above the Mass-Update Gate's threshold,
|
|
so expect exit 42. That is not an error and not yours to clear: reproduce the file breakdown
|
|
it prints for the operator, stop, and publish with the token it named once they have
|
|
approved it. See [gates.md](gates.md).
|
|
|
|
Publishing here, before the content migrations, is deliberate. The intermediate state -
|
|
new machinery, content still at the old shape - is a state the stack names rather than
|
|
avoids (`.wikitool-kb.json` records it), and it keeps a 200-file swap out of the same commit
|
|
as a content rewrite.
|
|
|
|
11. **Restart the agent session.** Everything the previous steps replaced - `AGENTS.md`, the
|
|
contracts, the type-specs, the skills - is still in the running session's context in its
|
|
*old* form. A migration document written against a rule that arrived in this release will
|
|
otherwise be carried out against the rule it replaced, and nothing checks that.
|
|
|
|
The new session resumes at step 12. `tools/wikitool migrate status` is the resume point:
|
|
it is stateful, so it says what is left without being told what already happened.
|
|
|
|
12. **Work the migration chain.** `tools/wikitool migrate status` lists what is outstanding, in
|
|
the order it has to run - a jump across several releases lists several. For each one, run
|
|
the named document under `instructions/migrations/` following
|
|
[migrate-corpus.md](migrate-corpus.md), then record it:
|
|
|
|
```bash
|
|
tools/wikitool migrate done <version>
|
|
```
|
|
|
|
An `offered` migration is a separate decision, not part of the chain: it changes a file this
|
|
instance owns, blocks nothing, and recording it does not move `kb_version`. Take it or
|
|
decline it deliberately; both are correct answers.
|
|
|
|
**Whatever the migration changes, capture the before.** Where a document asks that some
|
|
command's output "read the same as before", that is only checkable if the before was written
|
|
down - redirect it to a file first and `diff` afterwards, rather than reading two long
|
|
outputs from memory. Reading either one through `head` or `tail` is how a difference in the
|
|
middle survives the check.
|
|
|
|
13. **Verify the content, then publish.** Only after the chain has run, and against the commit
|
|
noted in step 7:
|
|
|
|
```bash
|
|
tools/wikitool migrate verify --from <pre-swap commit>
|
|
tools/wikitool lint
|
|
```
|
|
|
|
`migrate verify` is the only check that sees a page which lost a citation, a wikilink or a
|
|
generated-region marker in the rewrite - `lint` reports a corpus that is internally
|
|
consistent, which a corpus that quietly lost something still is. Then publish, the same way
|
|
as in step 10.
|
|
|
|
## Decision points
|
|
|
|
- **`version check` reports `state: migration` (a compatibility boundary)?** That is a statement
|
|
about the machinery being a drop-in replacement, not about the corpus. A boundary crossing with
|
|
an empty migration chain is normal and means the hand-work is elsewhere - which is precisely
|
|
what step 2's **Breaking Change:** line names.
|
|
- **`dist upgrade` refuses because the tree is not clean?** Commit or stash what is there first,
|
|
and look at what it is: work in progress is committed through `publish`, an editor's stray
|
|
reformatting of machinery is step 6's case.
|
|
- **A required migration cannot be completed now?** Stop after step 10 and leave it. The
|
|
intermediate state is legitimate and `migrate status` resumes it; what is not legitimate is
|
|
recording a migration with `migrate done` that was not carried out - the version then describes
|
|
a shape the corpus is not in.
|
|
- **`doctor` reports `kb-version` behind `VERSION` after everything is done?** Correct when the
|
|
release's chain was empty or carried only `offered` entries: an offer changes a file the
|
|
instance owns, not the shape of its content, so the content version stays where it was.
|
|
|
|
## Scope
|
|
|
|
For an instance that receives releases as tarballs. Not the origin repo, which has no upgrade
|
|
path of its own, and not a clone with shared history - see the second paragraph. Anything about
|
|
*writing* a migration document rather than running one is
|
|
[migrate-corpus.md](migrate-corpus.md) § "Writing the migration document".
|
|
|
|
What a human decides before any of this starts - which release, whether to take it at all, where
|
|
the tarball comes from - is [INSTALL.md](../INSTALL.md) § "Version und Updates".
|