7.3 KiB
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:
- 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. - Schema conventions match the rest of this homelab, not just
"compiles." This project's own
memory-db(M2.x) andagent-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 scanningk8s/infra/databases/should find the same shape twice: sameCluster/DatabaseCRD structure, samestorageClass, sameenableSuperuserAccess: 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
- On the Mac, with agent-manager built from the fully-ported
add-headless-spawnbranch (M6.3 complete) and configured to use M6.4/M6.5's route and credential: run thespawnCLI subcommand to create a real session. - 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.
- 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.
- Diff
k8s/infra/databases/agent-manager-db.yamlagainstk8s/infra/databases/memory-db.yamlfield-by-field for the convention-consistency check. - Confirm both ArgoCD Applications (agent-manager's and this project's
memory-db, once it exists) are tracked from therepoURLeach 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. - 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.yamlandmemory-db.yamlmatch on every field that isn't inherently app-specific (name, storage size).- No manual
kubectl apply/psqlanywhere 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:
a1_full_roundtrip— create/update/set-review/delete via the real CLI; assert no error at any step.a2_no_orphan_review_rows— after delete, queryreview_targets/review_bases/review_scopesdirectly (from inside the cluster, as a final-state check) for the deleted session's id; assert zero rows, with no explicitDELETE FROM review_*having been issued by the CLI (proves the FK cascade did the work, not leftover manual-cleanup code nobody removed).a3_survives_restart— kill agent-manager between status-update and delete; restart; assert the status update is still visible before proceeding to delete.a4_schema_convention_match— diff the twoClustermanifests' non app-specific fields; assert empty diff.a5_repourl_confirmed— for each of the two ArgoCD Applications involved, print whichrepoURLit watches and confirm it matches which remote was actually pushed.a6_no_manual_apply_in_history— review the shell history / session log from M6.1 through M6.5 for akubectl applyorpsqlwrite 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/*.yamlfiles 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.