docs: correct the version-bump gate and branch-refresh documentation

ADR-0022 and gates.md now state the merge-base baseline, the fail-closed
cases, the PyYAML requirement and the multi-ref push gap (shared with
check-release-needed); the new hook gets its own gates.md group. Both
ADR additions follow each file's amendment format. README and AGENTS.md
now say to discard a refreshed apm.lock.yaml on a feature branch, and
that an .apm/ edit is live only once it is on the remote's main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-16 10:33:34 +00:00
parent 1ce596cdbe
commit dd0b9233e6
5 changed files with 110 additions and 62 deletions

View File

@@ -115,9 +115,8 @@ A test pins the reference.
> emptied it. `tests/test-apm-current-hook.sh` still pins the literal string.
**Session startup gets slower when the install is stale.** Measured: ~0.7 s for the `apm outdated`
check when everything is current, ~10.4 s when six packages are behind and the refresh runs
(re-measured 2026-09-16: ~24–26 s for the same six-behind refresh, warm, on a LAN remote — still
well inside the budget below). The hook declares `timeout: 380` to cover a cold multi-package fetch. That number is not free-standing:
check when everything is current, ~10.4 s when six packages are behind and the refresh runs. The
hook declares `timeout: 380` to cover a cold multi-package fetch. That number is not free-standing:
the script imposes its own `timeout 60` on `apm outdated` and `timeout 300` on `apm update`, so the
host-side timeout has to exceed their sum or the host kills the hook mid-update and leaves
`.claude/skills/` half-deployed with no notice emitted. An earlier revision declared `320`, which
@@ -125,6 +124,10 @@ was below the 360 s the script can legitimately take. A test asserts the invaria
literal — it parses every `timeout N` out of the script, sums them, and requires the `hooks.json`
value to be larger — so changing either side without the other fails the suite.
> **Amendment (2026-09-16) — the refresh is slower than first measured, still inside the budget.**
> Re-measured: ~24–26 s for the same six-behind refresh, warm, on a LAN remote — well inside the
> 380 s above.
**Reading a human-readable CLI for a control decision cost a silent failure, again.** `apm outdated`
has no `--json` or other machine-readable flag (confirmed against 0.28.0), so the hook must match
its prose. The first attempt matched `outdated dependencies found` — plural only. apm emits
@@ -146,20 +149,21 @@ to plural-only fails it.
deploy until this change is merged and `apm update` has run once against the new default branch.
Until then the repo has the mechanism in source and not in effect.
**On a feature branch, the refresh installs `main`, not the branch.** Added 2026-09-16, after it
happened. The dependencies resolve against the remote default branch, so a session opened on a
branch that changes `plugins/` loads `main`'s content, refreshed or not — the branch's own edits
are never live until merged. Two visible effects follow. Content the branch *removes* comes back in
the deployed install: on `docs/simplification-audit` a refresh redeployed `main`'s `skill-audit`
and `agent-audit` over the branch's merged `factory-audit`, and re-materialised `main`'s
`plugins/bin/.mcp.json` into `apm_modules/`, so the gitignored root `.mcp.json` regained the
`obsidian` server the branch deleted — invisible to `git status`. And the rewritten
`apm.lock.yaml` records `main`'s commit, so on a branch it should be discarded
(`git checkout -- apm.lock.yaml`, then `apm install` to bring the deployed tree back in line with
the lock, or `apm pack --check-clean` refuses to run), not committed. Skipping the refresh off the
default branch was considered and rejected: it would not make the branch live, only freeze the
session on an older `main` — the silent staleness this ADR exists to prevent. Both effects end when
the branch merges; apm removes a server that is no longer declared on its next update.
> **Amendment (2026-09-16) — on a feature branch, the refresh installs `main`, not the branch.**
> Recorded after it happened. The dependencies resolve against the remote default branch, so a
> session opened on a branch that changes `plugins/` loads `main`'s content, refreshed or not — a
> branch's own `.apm/` edits are live only once they are on the remote's `main`. Two visible
> effects follow. Content the branch *removes* comes back in the deployed install: on
> `docs/simplification-audit` a refresh redeployed `main`'s `skill-audit` and `agent-audit` over
> the branch's merged `factory-audit`, and re-materialised `main`'s `plugins/bin/.mcp.json` into
> `apm_modules/`, so the gitignored root `.mcp.json` regained the `obsidian` server the branch
> deleted — invisible to `git status`. And the rewritten `apm.lock.yaml` records `main`'s commit,
> so on a branch it should be discarded (`git checkout -- apm.lock.yaml`, then `apm install` to
> bring the deployed tree back in line with the lock, or `apm pack --check-clean` refuses to run),
> not committed. Skipping the refresh off the default branch was considered and rejected: it would
> not make the branch live, only freeze the session on an older `main` — the silent staleness this
> ADR exists to prevent. Both effects end when the branch merges; apm removes a server that is no
> longer declared on its next update.
**`.claude/settings.json` stops being `{"hooks": {}}`.** apm merges the hook into it and tracks
ownership in a `.claude/apm-hooks.json` sidecar, with the script copied to