151 lines
7.3 KiB
Markdown
151 lines
7.3 KiB
Markdown
# M6.6 — M6 composition gate
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Phase | M6 — agent-manager migration |
|
||
| Size | M — 1–3 days |
|
||
| Status | ⬜ Not started |
|
||
| Flags | gate |
|
||
| Spec | inlined below |
|
||
| Blocks | all of M6 |
|
||
|
||
## Goal
|
||
|
||
Prove the schema, the query port, the network path, and the credentials
|
||
bind together into one working system — not four pieces that each passed
|
||
their own task in isolation. This is the property no single M6 task owns:
|
||
M6.1 proves the cluster is healthy, M6.2 proves the schema applies, M6.3
|
||
proves the queries work against a local test database, M6.4 proves a raw
|
||
TCP connection reaches the cluster, M6.5 proves the credential decrypts —
|
||
none of them alone proves agent-manager, running for real on the Mac,
|
||
through the real ingress route, with the real ksops credential, against
|
||
the real cluster, does its actual job: track a session end-to-end without
|
||
losing or corrupting data.
|
||
|
||
## Facts (inlined — no spec read needed)
|
||
|
||
**"Bind together smoothly" means two concrete things here, not a vibe:**
|
||
|
||
1. **The full network path is exercised, not simulated.** M6.3's tests run
|
||
against a disposable local Postgres — that validates the SQL, not the
|
||
route. This gate is the first (and only) task that runs agent-manager
|
||
unmodified, on the actual Mac, through M6.4's nginx `stream {}` route,
|
||
authenticating with M6.5's ksops-sourced credential, against M6.1's
|
||
real cluster.
|
||
2. **Schema conventions match the rest of this homelab, not just
|
||
"compiles."** This project's own `memory-db` (M2.x) and
|
||
`agent-manager-db` (M6.x) are two unrelated Postgres schemas landing in
|
||
the same cluster around the same time. They don't share data or a
|
||
cluster (M6.1 already ruled that out), but a reviewer scanning
|
||
`k8s/infra/databases/` should find the same shape twice: same
|
||
`Cluster`/`Database` CRD structure, same `storageClass`, same
|
||
`enableSuperuserAccess: false`, same GitOps-only provisioning
|
||
discipline. "Binds together smoothly" includes that consistency check,
|
||
not just agent-manager working in isolation.
|
||
|
||
**What a session round trip actually touches**, so the test isn't
|
||
shallow: `CreateSession` (writes `sessions` + touches `groups` via the
|
||
`ON CONFLICT DO NOTHING` insert) -> `UpdateStatus` -> `SetAgentSessionID`
|
||
-> `SetReviewRepo` (writes `review_targets`) -> `Delete` (must cascade
|
||
`review_targets` via the FK, per M6.2's decision, with no leftover row).
|
||
That single flow crosses all 4 non-`settings` tables and exercises both
|
||
the FK-cascade decision and the placeholder-conversion correctness from
|
||
M6.3 in one pass.
|
||
|
||
## Steps
|
||
|
||
1. On the Mac, with agent-manager built from the fully-ported
|
||
`add-headless-spawn` branch (M6.3 complete) and configured to use
|
||
M6.4/M6.5's route and credential: run the `spawn` CLI subcommand to
|
||
create a real session.
|
||
2. Drive it through the full lifecycle above (status update, agent
|
||
session id capture, review target set, delete) using agent-manager's
|
||
own CLI/TUI, not a hand-rolled SQL script — the point is proving the
|
||
actual client works, not that Postgres accepts hand-written SQL.
|
||
3. Kill and restart agent-manager mid-lifecycle (after step 2's status
|
||
update, before delete); confirm it reconnects and reads back the same
|
||
state — proves the connection isn't accidentally caching state
|
||
client-side that masks a write that never actually landed.
|
||
4. Diff `k8s/infra/databases/agent-manager-db.yaml` against
|
||
`k8s/infra/databases/memory-db.yaml` field-by-field for the
|
||
convention-consistency check.
|
||
5. Confirm both ArgoCD Applications (agent-manager's and this project's
|
||
`memory-db`, once it exists) are tracked from the `repoURL` each
|
||
actually watches — re-verify per M6.1's caveat, since this is the
|
||
final point where a "pushed but ArgoCD never saw it" mistake would
|
||
otherwise go unnoticed until much later.
|
||
6. Commit `expected/m6.6.txt`; diff.
|
||
|
||
## Acceptance
|
||
|
||
- A session created, updated, and deleted through agent-manager's real
|
||
CLI on the Mac round-trips correctly through the full network path.
|
||
- A mid-lifecycle restart does not lose or duplicate state.
|
||
- Deleting the session leaves zero orphan rows in `review_targets`/
|
||
`review_bases`/`review_scopes` (FK cascade, not app-level cleanup).
|
||
- `agent-manager-db.yaml` and `memory-db.yaml` match on every field that
|
||
isn't inherently app-specific (name, storage size).
|
||
- No manual `kubectl apply`/`psql` anywhere in the setup this gate
|
||
exercises.
|
||
|
||
## Verify
|
||
|
||
**Harness:** the real Mac client, the real cluster, agent-manager's own
|
||
CLI — this gate deliberately does not use a disposable/local database,
|
||
since proving the disposable path works is exactly what M6.1-M6.5 already
|
||
did.
|
||
|
||
**Integration test** — `verify/m6.6.sh` diffed against
|
||
`expected/m6.6.txt`:
|
||
1. `a1_full_roundtrip` — create/update/set-review/delete via the real CLI;
|
||
assert no error at any step.
|
||
2. `a2_no_orphan_review_rows` — after delete, query `review_targets`/
|
||
`review_bases`/`review_scopes` directly (from inside the cluster, as a
|
||
final-state check) for the deleted session's id; assert zero rows,
|
||
with no explicit `DELETE FROM review_*` having been issued by the CLI
|
||
(proves the FK cascade did the work, not leftover manual-cleanup code
|
||
nobody removed).
|
||
3. `a3_survives_restart` — kill agent-manager between status-update and
|
||
delete; restart; assert the status update is still visible before
|
||
proceeding to delete.
|
||
4. `a4_schema_convention_match` — diff the two `Cluster` manifests' non
|
||
app-specific fields; assert empty diff.
|
||
5. `a5_repourl_confirmed` — for each of the two ArgoCD Applications
|
||
involved, print which `repoURL` it watches and confirm it matches
|
||
which remote was actually pushed.
|
||
6. `a6_no_manual_apply_in_history` — review the shell history / session
|
||
log from M6.1 through M6.5 for a `kubectl apply` or `psql` write
|
||
command that wasn't inside an explicitly-flagged debugging exception;
|
||
assert none exist outside that exception.
|
||
|
||
**Command:** `bash verify/m6.6.sh | diff - expected/m6.6.txt`
|
||
|
||
**False pass:**
|
||
- Running assertion 1 against M6.3's disposable local Postgres instead of
|
||
the real cluster because it's faster/already running. That's exactly
|
||
the "four pieces that each passed in isolation" failure mode this gate
|
||
exists to catch — it must hit M6.1's actual cluster through M6.4's
|
||
actual route.
|
||
- Treating a schema diff (assertion 4) as advisory and skipping it when
|
||
short on time. A convention mismatch here is invisible today and
|
||
becomes the thing a future reviewer trips over when comparing the two
|
||
`k8s/infra/databases/*.yaml` files months later with no memory of why
|
||
they differ.
|
||
|
||
## Traps
|
||
|
||
- Discovering during this gate that M6.4's nginx route works from inside
|
||
the homelab LAN but not from wherever the Mac actually sits (VPN,
|
||
different subnet, etc.) — a gap none of M6.1-M6.5's narrower tests
|
||
would have caught, since this is the first task that tests from the
|
||
Mac's actual network position rather than "outside the cluster" in the
|
||
abstract.
|
||
- Fixing a gate failure by loosening the gate (e.g. deleting assertion 2
|
||
because the cascade "mostly works") instead of fixing the underlying
|
||
FK/migration issue. Same discipline this project's other gates
|
||
(M0.8, M1.8, M2.8...) already hold to.
|
||
|
||
---
|
||
|
||
Background: [M6.1](M6.1-agent-manager-db-manifest.md) · [M6.2](M6.2-schema-port.md) · [M6.3](M6.3-store-query-port.md) · [M6.4](M6.4-nginx-stream-routing.md) · [M6.5](M6.5-credentials-secret.md)
|