docs(adr): record the feature-branch refresh hazard in ADR-0019

The session-start refresh resolves against main, so on a branch it
redeploys content the branch removed and rewrites the lock to main's
commit. Documented as a consequence rather than skipped in code, since
a skip would only freeze the session on an older main. Also records the
re-measured refresh time (~24-26 s). Simplification audit finding 34.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-16 10:09:59 +00:00
parent 2def06054a
commit afcf477ede

View File

@@ -115,8 +115,9 @@ A test pins the reference.
> emptied it. `tests/test-apm-current-hook.sh` still pins the literal string. > 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` **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. The check when everything is current, ~10.4 s when six packages are behind and the refresh runs
hook declares `timeout: 380` to cover a cold multi-package fetch. That number is not free-standing: (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:
the script imposes its own `timeout 60` on `apm outdated` and `timeout 300` on `apm update`, so the 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 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 `.claude/skills/` half-deployed with no notice emitted. An earlier revision declared `320`, which
@@ -145,6 +146,21 @@ to plural-only fails it.
deploy until this change is merged and `apm update` has run once against the new default branch. 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. 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.
**`.claude/settings.json` stops being `{"hooks": {}}`.** apm merges the hook into it and tracks **`.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 ownership in a `.claude/apm-hooks.json` sidecar, with the script copied to
`.claude/hooks/<pkg>/`. The sidecar and the script directory are gitignored install output; the `.claude/hooks/<pkg>/`. The sidecar and the script directory are gitignored install output; the