docs(v1): record the settings removal as a pre-lock exception

The design removes the legacy /api/v1/settings routes and the profile DTO
preference fields, while AGENTS.md states /api/v1 is additive-only and
removals go through Deprecation/Sunset. Read together those contradict.

They do not actually conflict: v1-scope.md scopes the additive-only rule to
"when the scope locks", and the scope is still open, so a removal taken now
is in scope and there is no amendment process to invoke yet. But that
reasoning lived only in the settings design, where nobody checking the API
policy would find it.

v1-scope.md now carries a pre-lock removals table naming what goes and why
waiting is worse, and states the deadline the argument depends on: a removal
listed there must ship before lock or fall back to Deprecation/Sunset.
AGENTS.md points at the table and says to treat an unlisted removal as a
mistake.

Reported by CodeRabbit review on #479.
This commit is contained in:
Quick
2026-07-27 00:33:27 +00:00
parent 6535203791
commit 5df181f733
3 changed files with 26 additions and 0 deletions
+5
View File
@@ -118,6 +118,11 @@ Additive-only within `/api/v1`:
- New features expose capability endpoints for feature detection rather than relying on version
sniffing. Contract strategy and tooling: issue #135.
Treat this as binding. The one exception: `/api/v1` is not locked yet, so a removal taken before
lock is in scope — but only when it is recorded in the pre-lock removals table in
[docs/architecture/v1-scope.md](docs/architecture/v1-scope.md) and ships before the lock. Assume
any removal not listed there is a mistake.
## Pull requests
Conventional Commit subjects (`feat(playback): add realtime session hub`). One concern per PR.
+15
View File
@@ -18,6 +18,21 @@ When the scope locks, this file becomes the source of truth and will contain:
Until lock: treat any capability not tracked as `Proposed`/`Locked` on the project as out of scope
for feature PRs (see the scope gate in `CLAUDE.md`).
## Breaking removals taken before lock
The additive-only rule in item 2 binds at lock. Before then a removal is in scope, and there is no
amendment to write because the amendment process in item 3 does not exist yet. `CLAUDE.md` states
the rule without that qualifier, which reads as a contradiction — it is not, but a removal taken
now has to be recorded here so a reader after lock can tell a deliberate decision from a violation.
Each entry names what goes, why waiting is worse, and the design that decided it. **Every removal
listed here must have shipped before the scope locks.** One still outstanding at lock loses its
justification and falls back to the Deprecation/Sunset flow like anything else.
| Removed | Release | Rationale |
|---|---|---|
| String `GET`/`PUT`/`DELETE /api/v1/settings…`, the unknown-key extension bag, preference fields on profile/library/series DTOs | Cross-platform settings contract, [design](../superpowers/specs/2026-07-10-cross-platform-user-settings-contract-design.md) | Replaced wholesale by the typed settings contract. Deferring past lock would mean carrying the Deprecation/Sunset surface *and* the untyped key bag — which lets any client invent a production setting the server stores unvalidated — through the deprecation window, which is the exact surface the contract exists to close. |
Feature-detection precedent: clients discover which metadata providers (including the
built-in NFO provider, #216) apply to a library type via
`GET /api/v1/libraries/provider-defaults` rather than version sniffing. New capabilities
@@ -521,6 +521,12 @@ the amendment process it describes only exists *after* lock. There is therefore
write and no exception to request: before lock, removing the legacy settings surface is simply in
scope.
That argument does not live only here. Reasoning kept in a design doc is invisible to whoever reads
the policy later and sees a removal that appears to break it, so the removal is recorded in the
**pre-lock removals** table in `docs/architecture/v1-scope.md`, which is the file that governs it.
The table also carries the deadline: **this work must ship before the scope locks.** If it has not,
the justification lapses and the removal goes through Deprecation/Sunset like anything else.
**This is an argument for doing the work now rather than after lock.** After lock, the same removal
would need the Deprecation/Sunset flow the v1 policy mandates and the codebase already implements
(`internal/api/handlers/legacy_read_routes.go`), which reintroduces exactly the transitional