chore(brain): deprecate + remove brain_write legacy params (domain/type/knowledge-path) (ADR-0012) #79

Closed
opened 2026-07-07 07:45:36 +00:00 by mathias · 2 comments
Owner

Charter: ADR-0012 ("legacy-param debt is real and in scope") · needs versioned-deprecation discipline

Problem

brain_write's schema carries legacy params from before the wing/hall model: domain, type, and the knowledge/ landing path (the description literally says "(legacy)" several times). They're live API surface, so every caller has to read past them, and the two code paths (legacy knowledge/ write with old frontmatter vs. wing+hall wiki/ write) mean brain_write has two behaviours depending on which optional fields are set. That's exactly the mechanism-leak + surface-rot ADR-0012 warns about.

What to do (versioned deprecation, NOT a hard break)

Per ADR-0012's migration discipline — add-new / deprecate-old / migrate-callers / then-remove:

  1. Audit callers — grep SKILLs, agents, agentsquad, harvest paths, capture's BrainStore for any use of domain/type/the knowledge/ path. Capture the real usage before changing anything.
  2. Mark deprecated — annotate the legacy params in the schema/description as deprecated with the wing/hall replacement, so no new caller adopts them.
  3. Migrate live callers to wing/hall.
  4. Collapse the code path — once no caller uses the legacy fields, remove them and the knowledge/-landing branch so brain_write has one behaviour.

Caution: the knowledge/ vs wiki/ distinction is curation-state (per #43 — unreviewed vs promoted), not just legacy cruft. Confirm the promote/pending flow (#38) doesn't depend on the knowledge/ write path before removing it. If it does, that path's removal is gated on the promote-verb work, not free.

Acceptance

  • Caller audit complete (who, if anyone, uses domain/type/knowledge-path)
  • Legacy params marked deprecated in the schema
  • Live callers migrated to wing/hall
  • knowledge/-path dependency on the promote flow (#38) confirmed or ruled out before removal
  • Legacy params + dead code path removed; brain_write has one behaviour
  • task check green; existing brain_write/update tests still pass

Related

  • ADR-0012 (legacy-param debt) · #43 (knowledge/ vs wiki/ is curation-state, not cruft) · #38 (promote flow that may depend on knowledge/) · sibling #78 (brain_index)
**Charter:** ADR-0012 ("legacy-param debt is real and in scope") · needs versioned-deprecation discipline ## Problem `brain_write`'s schema carries legacy params from before the wing/hall model: `domain`, `type`, and the `knowledge/` landing path (the description literally says "(legacy)" several times). They're live API surface, so every caller has to read past them, and the two code paths (legacy `knowledge/` write with old frontmatter vs. wing+hall `wiki/` write) mean `brain_write` has two behaviours depending on which optional fields are set. That's exactly the mechanism-leak + surface-rot ADR-0012 warns about. ## What to do (versioned deprecation, NOT a hard break) Per ADR-0012's migration discipline — add-new / deprecate-old / migrate-callers / then-remove: 1. **Audit callers** — grep SKILLs, agents, agentsquad, harvest paths, capture's BrainStore for any use of `domain`/`type`/the knowledge/ path. Capture the real usage before changing anything. 2. **Mark deprecated** — annotate the legacy params in the schema/description as deprecated with the wing/hall replacement, so no *new* caller adopts them. 3. **Migrate live callers** to wing/hall. 4. **Collapse the code path** — once no caller uses the legacy fields, remove them and the `knowledge/`-landing branch so `brain_write` has one behaviour. **Caution:** the `knowledge/` vs `wiki/` distinction is *curation-state* (per #43 — unreviewed vs promoted), not just legacy cruft. Confirm the promote/pending flow (#38) doesn't depend on the `knowledge/` write path before removing it. If it does, that path's removal is gated on the promote-verb work, not free. ## Acceptance - [ ] Caller audit complete (who, if anyone, uses domain/type/knowledge-path) - [ ] Legacy params marked deprecated in the schema - [ ] Live callers migrated to wing/hall - [ ] `knowledge/`-path dependency on the promote flow (#38) confirmed or ruled out before removal - [ ] Legacy params + dead code path removed; `brain_write` has one behaviour - [ ] `task check` green; existing brain_write/update tests still pass ## Related - ADR-0012 (legacy-param debt) · #43 (knowledge/ vs wiki/ is curation-state, not cruft) · #38 (promote flow that may depend on knowledge/) · sibling #78 (brain_index)
mathias added the risk/mediumsize/mtype/chore labels 2026-08-27 05:25:42 +00:00
Author
Owner

Review verdict: BLOCKED (not merged). PR #131, head e8e2338.

Verified independently:

  • Re-grepped for WriteNoteOptions.Type/.Domain, writeLegacyNote, remaining knowledge/ write-path callers, and internal/skills/brain imports across both go.mod modules: none found. That part of the audit holds.
  • go build ./... && go vet ./... && go test ./... -race -count=1 green in both the root module and ingestion/.
  • Flip-tested the two new/changed tests by reverting the guard and by reintroducing type/domain passthrough end-to-end: both TestWriteNote_RequiresWingAndHall / TestBrainWriteRequiresWingAndHall and TestBrainWriteIgnoresLegacyTypeAndDomainParams correctly go red. Not decoration.

Blocking finding — the caller audit missed a live caller in this repo itself: cmd/hyperguild/brain.go (runBrainWrite) + cmd/hyperguild/http.go (brainClient.Write) implement the documented CLI command hyperguild brain write <type> <slug> (see cmd/hyperguild/README.md §"hyperguild brain write ", cmd/hyperguild/main.go usage text, docs/superpowers/specs/2026-05-03-hyperguild-cli-design.md). It POSTs {"type": kind, "slug": slug, "content": ...} to /write — no wing/hall ever sent. Before this PR that hit the neither wing nor hall set branch and succeeded via writeLegacyNote (into brain/knowledge/, filename auto-generated since slug isn't a recognized JSON field). After this PR, WriteNote hard-errors "wing and hall are required" on every single invocation of this command — a live, documented feature goes from succeeding to failing 100% of the time.

cmd/hyperguild/http_test.go's TestBrainClient_Write_Success stays green through this because it mocks the /write server with httptest.NewServer instead of exercising the real api.WriteNote handler — so CI green here proves nothing about this regression.

This directly fails issue #79's acceptance criteria: "Caller audit complete" and "Live callers migrated to wing/hall" — this caller was neither found nor migrated.

Fix needed before merge: either migrate hyperguild brain write to require/pass wing/hall (and update its docs/usage text), or deprecate/remove the CLI subcommand in the same PR, with a test against the real handler (not a mock) proving the CLI still round-trips.

CI (run 7859) was green on e8e2338, root/ingestion modules build+vet+test clean, internal/skills/brain deletion confirmed safe — those are not the problem. The problem is this one missed caller.

**Review verdict: BLOCKED (not merged).** PR #131, head `e8e2338`. Verified independently: - Re-grepped for `WriteNoteOptions.Type/.Domain`, `writeLegacyNote`, remaining `knowledge/` write-path callers, and `internal/skills/brain` imports across both go.mod modules: none found. That part of the audit holds. - `go build ./... && go vet ./... && go test ./... -race -count=1` green in both the root module and `ingestion/`. - Flip-tested the two new/changed tests by reverting the guard and by reintroducing `type`/`domain` passthrough end-to-end: both `TestWriteNote_RequiresWingAndHall` / `TestBrainWriteRequiresWingAndHall` and `TestBrainWriteIgnoresLegacyTypeAndDomainParams` correctly go red. Not decoration. **Blocking finding — the caller audit missed a live caller in this repo itself:** `cmd/hyperguild/brain.go` (`runBrainWrite`) + `cmd/hyperguild/http.go` (`brainClient.Write`) implement the documented CLI command `hyperguild brain write <type> <slug>` (see `cmd/hyperguild/README.md` §"hyperguild brain write <type> <slug>", `cmd/hyperguild/main.go` usage text, `docs/superpowers/specs/2026-05-03-hyperguild-cli-design.md`). It POSTs `{"type": kind, "slug": slug, "content": ...}` to `/write` — no `wing`/`hall` ever sent. Before this PR that hit the `neither wing nor hall set` branch and succeeded via `writeLegacyNote` (into `brain/knowledge/`, filename auto-generated since `slug` isn't a recognized JSON field). After this PR, `WriteNote` hard-errors `"wing and hall are required"` on every single invocation of this command — a live, documented feature goes from succeeding to failing 100% of the time. `cmd/hyperguild/http_test.go`'s `TestBrainClient_Write_Success` stays green through this because it mocks the `/write` server with `httptest.NewServer` instead of exercising the real `api.WriteNote` handler — so CI green here proves nothing about this regression. This directly fails issue #79's acceptance criteria: "Caller audit complete" and "Live callers migrated to wing/hall" — this caller was neither found nor migrated. **Fix needed before merge:** either migrate `hyperguild brain write` to require/pass `wing`/`hall` (and update its docs/usage text), or deprecate/remove the CLI subcommand in the same PR, with a test against the real handler (not a mock) proving the CLI still round-trips. CI (run 7859) was green on `e8e2338`, root/ingestion modules build+vet+test clean, `internal/skills/brain` deletion confirmed safe — those are not the problem. The problem is this one missed caller.
Author
Owner

Merged PR #131 (squash) at commit f324f04944, head 975b61c.

Re-review of the fix (975b61c) that addressed the earlier BLOCK:

  • cmd/hyperguild brain write is now <wing> <hall> <slug> (3 required positional args), errors "wing, hall and slug required" when fewer are given. README and docs/superpowers/specs/2026-05-03-hyperguild-cli-design.md updated to match. brainClient.Write now sends {wing, hall, filename, content} matching writeRequest exactly.
  • New TestWrite_CLIPayloadRoundTrips in ingestion/internal/api/handler_test.go genuinely exercises the real Handler.Write -> WriteNote -> writeHallNote path via httptest.NewServer(http.HandlerFunc(h.Write)) (not a mock). Flip-tested three ways on a true git worktree add <sha> --detach checkout (not an overlay diff, which silently keeps deleted files and gives false green):
    1. Renamed writeRequest.Filename's json tag -> test goes red (wrong path written, file not found).
    2. Reproduced the exact original-bug payload shape ({type, slug, content} instead of {wing, hall, filename, content}) -> test goes red with wing and hall are required, 400 instead of 200. This is precisely the regression the first review caught.
    3. Removing the wing==""||hall=="" guard in WriteNote did NOT reopen a silent-write hole -- writeHallNote's own taxonomy validation (invalid wing/invalid hall) still rejects empty values, just with a different error string.
  • Caller audit re-verified: no remaining references to WriteNoteOptions.Type/.Domain, writeLegacyNote, or internal/skills/brain anywhere in either module.
  • Full suite green on the true branch checkout, both modules: go build ./... && go vet ./... && go test ./... -race -count=1 in both ingestion/ and the repo-root module.
  • CI green on 975b61c (run 7863, "CI / Lint / Test / Vet": success).

Acceptance criteria in this issue: caller audit complete, legacy params removed, live callers (including the previously-missed CLI) migrated, task check-equivalent green -- all hold.

Known residual, not a blocker: TestWrite_CLIPayloadRoundTrips hardcodes the CLI's wire envelope locally (cmd/hyperguild and ingestion are separate Go modules, no go.work, so it can't import brainClient directly). Combined with cmd/hyperguild/http_test.go's TestBrainClient_Write_Success (which asserts the CLI's real marshal output field-by-field), both sides of the contract are pinned from real code, which is what actually would have caught the original regression. A literal built-binary integration test would close the last gap (nothing forces the two hardcoded envelopes to stay in sync if one side's JSON tags drift in a future change) but the cost didn't seem to be worth it for this fix; worth a follow-up if cmd/hyperguild's HTTP payloads change again.

Merged PR #131 (squash) at commit f324f04944ea842b09e6dd8f492aa970511b9ec3, head 975b61c. **Re-review of the fix (975b61c) that addressed the earlier BLOCK:** - `cmd/hyperguild brain write` is now `<wing> <hall> <slug>` (3 required positional args), errors `"wing, hall and slug required"` when fewer are given. README and `docs/superpowers/specs/2026-05-03-hyperguild-cli-design.md` updated to match. `brainClient.Write` now sends `{wing, hall, filename, content}` matching `writeRequest` exactly. - New `TestWrite_CLIPayloadRoundTrips` in `ingestion/internal/api/handler_test.go` genuinely exercises the real `Handler.Write` -> `WriteNote` -> `writeHallNote` path via `httptest.NewServer(http.HandlerFunc(h.Write))` (not a mock). Flip-tested three ways on a true `git worktree add <sha> --detach` checkout (not an overlay diff, which silently keeps deleted files and gives false green): 1. Renamed `writeRequest.Filename`'s json tag -> test goes red (wrong path written, file not found). 2. Reproduced the exact original-bug payload shape (`{type, slug, content}` instead of `{wing, hall, filename, content}`) -> test goes red with `wing and hall are required`, 400 instead of 200. This is precisely the regression the first review caught. 3. Removing the `wing==""||hall==""` guard in `WriteNote` did NOT reopen a silent-write hole -- `writeHallNote`'s own taxonomy validation (`invalid wing`/`invalid hall`) still rejects empty values, just with a different error string. - Caller audit re-verified: no remaining references to `WriteNoteOptions.Type/.Domain`, `writeLegacyNote`, or `internal/skills/brain` anywhere in either module. - Full suite green on the true branch checkout, both modules: `go build ./... && go vet ./... && go test ./... -race -count=1` in both `ingestion/` and the repo-root module. - CI green on 975b61c (run 7863, "CI / Lint / Test / Vet": success). Acceptance criteria in this issue: caller audit complete, legacy params removed, live callers (including the previously-missed CLI) migrated, `task check`-equivalent green -- all hold. Known residual, not a blocker: `TestWrite_CLIPayloadRoundTrips` hardcodes the CLI's wire envelope locally (cmd/hyperguild and ingestion are separate Go modules, no go.work, so it can't import `brainClient` directly). Combined with `cmd/hyperguild/http_test.go`'s `TestBrainClient_Write_Success` (which asserts the CLI's real marshal output field-by-field), both sides of the contract are pinned from real code, which is what actually would have caught the original regression. A literal built-binary integration test would close the last gap (nothing forces the two hardcoded envelopes to stay in sync if one side's JSON tags drift in a future change) but the cost didn't seem to be worth it for this fix; worth a follow-up if `cmd/hyperguild`'s HTTP payloads change again.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/hyperguild#79