fix: hyperguild brain write requires wing/hall, not legacy type/slug
CI / Lint / Test / Vet (pull_request) Successful in 35s
CI / Mirror to GitHub (pull_request) Skipped

PR #131 removed WriteNote's legacy brain/knowledge/ fallback branch that
activated when wing/hall were both empty, but never updated the CLI that
was the only caller relying on it. Since `hyperguild brain write` never
sent wing/hall, every invocation of the CLI's most load-bearing brain
command started hard-erroring "wing and hall are required" — a live,
README-documented command broken on every call.

Separately, writeRequest never had a `slug` field (pre-existing, unrelated
to #131): the CLI's slug value was silently dropped server-side even
before this PR, falling back to a timestamp filename.

Fix:
- `hyperguild brain write <wing> <hall> <slug>` replaces the old
  `<type> <slug>` shape. Positional args, mirroring the existing
  `brain query <topic>` pattern and matching writeHallNote's own
  wing/hall/slug parameter order server-side (handler.go's
  brain.NotePath(brainDir, wing, hall, slug)) — no new flags needed since
  wing/hall/slug are all required, not optional filters.
- brainClient.Write now sends {wing, hall, filename, content}, matching
  writeRequest exactly (writeRequest already gained a Filename field in
  #131, so no server-side change was needed — only the CLI was sending
  the wrong shape). This also fixes the dead slug bug: slug now arrives
  server-side as filename instead of being silently dropped.
- Added TestWrite_CLIPayloadRoundTrips in ingestion/internal/api, which
  POSTs the CLI's exact JSON envelope to the real Handler.Write (not a
  mock) and asserts a real file with real wing/hall frontmatter lands on
  disk. cmd/hyperguild and ingestion are separate Go modules (no
  go.work), so this can't be a single cross-module test — instead the
  wire contract is pinned from the server side, closing the gap where
  cmd/hyperguild/http_test.go's TestBrainClient_Write_Success used only a
  hand-rolled httptest mock and stayed green through the wing/hall
  regression.
- Updated cmd/hyperguild/README.md and the 2026-05-03 CLI design spec's
  stale `<type> <slug>` examples.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 07:40:16 +02:00
co-authored by Claude Sonnet 5
parent e8e233823d
commit 975b61c9d7
7 changed files with 80 additions and 29 deletions
@@ -16,7 +16,7 @@ Three needs converge on a single small Go binary:
- [ ] `hyperguild tier` returns the same `tier.Info` that `internal/tier.Detect` produces for the same probe URLs, in < 3 s under all three tier conditions, with both human-readable and `--json` output.
- [ ] `hyperguild brain query <topic>` returns BM25 results from the brain HTTP REST `/query` endpoint, exit 0 on success and non-zero on transport failure.
- [ ] `hyperguild brain write <type> <slug>` reads markdown content from stdin, posts to `/write` with the type and slug, and creates `brain/knowledge/<slug>.md`. A round-trip (`hyperguild brain query <slug>` immediately after) finds the entry.
- [ ] `hyperguild brain write <wing> <hall> <slug>` reads markdown content from stdin, posts to `/write` with wing/hall/filename, and creates `brain/wiki/<wing>/<hall>/<slug>.md`. A round-trip (`hyperguild brain query <slug>` immediately after) finds the entry. (Updated post-ADR-0012/#79: the legacy `<type> <slug>` shape and the `brain/knowledge/` fallback were removed; wing and hall are now required.)
- [ ] `hyperguild mode <cloud|client-local|sovereign>` writes a parseable JSON file at the target path with the per-mode `mcpServers` entries; `jq -e .mcpServers` succeeds on the output.
- [ ] All commands print usage on `--help`, exit 2 on unknown flags, exit non-zero on operational errors.
- [ ] `task check` passes (lint + test + vet) on each task and on the merged branch.
@@ -50,7 +50,7 @@ Three needs converge on a single small Go binary:
- **`brain` subcommand calls the HTTP REST API.** Two nested subcommands:
- `brain query <topic>` issues `POST /query` with JSON body `{query, limit}` (default `--limit 5`), prints results in human-readable form by default and with `--json` for machine consumption.
- `brain write <type> <slug>` reads stdin, posts `POST /write` with JSON body `{type, slug, content}`, prints the resulting path on success.
- `brain write <wing> <hall> <slug>` reads stdin, posts `POST /write` with JSON body `{wing, hall, filename, content}`, prints the resulting path on success. (Updated post-ADR-0012/#79: wing and hall are required, replacing the old `<type> <slug>` shape and the `brain/knowledge/` legacy fallback.)
Rationale: HTTP REST is simpler than MCP framing for a CLI. Per CLAUDE.md, the REST endpoints are documented as the official non-MCP interface.
- **`mode <name>` writes a per-mode `.mcp.json` template.** Defaults to writing `./.mcp.json` (cwd); accepts `--out <path>`. Per-mode bodies: