Plan #3 at 100%. Last three items resolved: 1. Transition precondition enforcement (Phase 5): - no-inbound-edges: blocks destroy when relationships exist - backups-verified, secrets-revoked, ingress-dns-removed: checks attrs - age-key-enrolled-if-needed, mesh-joined-if-needed: workstation checks - health-check-answering: verifies entity_status health - doc-page-complete: requires at least one linked document - Soft preconditions (inventory-entry, cancelled-note, etc.): operator confirmed via transition request itself - Parses {requires: [check-name]} from lifecycle_defs.transitions JSONB 2. bootstrap.sh: already thin-client (fetches only agent files, no git clone, calls POST /clients/enroll, embeds context poller) 3. tools/context-poller.sh: standalone version — polls GET /clients/{slug}/context, applies file/tool/sops deltas, re-runs changed setup scripts
246 lines
13 KiB
Markdown
246 lines
13 KiB
Markdown
# 2026-07-08 — Plan vs implementation cross-reference
|
|
|
|
**Status:** Planned
|
|
|
|
## Goal
|
|
|
|
Snapshot each active plan against the actual codebase on disk. No action taken
|
|
— this is the map from which the next round of work is drawn.
|
|
|
|
---
|
|
|
|
## 1. Consolidate Oikos on mac-mini (2026-07-06)
|
|
|
|
**Plan status:** In Progress (Phases 1-6 implemented, pending cutover)
|
|
|
|
**Reality check:**
|
|
|
|
| Claim | Reality |
|
|
|-------|---------|
|
|
| Single binary, role subcommands | True — `cmd/oikos/main.go` handles `api\|scheduler\|notifier\|all\|migrate\|seed\|export\|secret\|version` |
|
|
| OpenAPI-first | True — 1,884-line `api/openapi.yaml`, oapi-codegen + chi, generated server stubs |
|
|
| DB as source of truth | True — seeds → DB → API round-trip works, 13 forward-only migrations |
|
|
| MCP server (official SDK) | True — `modelcontextprotocol/go-sdk`, Streamable HTTP, 21 tools registered |
|
|
| Docker stack on mac-mini | True — `docker-compose.yml` with 9 services across 3 profiles, distroless images |
|
|
| Go domain layer + sentinel errors | True — `internal/domain/` with entity/signal/execution/pattern/skill/approval/check types |
|
|
| SQLC + repositories | True — 4 query files in `internal/db/queries/`, generated into `sqlcgen/` |
|
|
| SSE event stream | True — `internal/httpapi/sse.go` |
|
|
| Matrix approval webhook loop | **DONE.** Migration 013 added `matrix_event_id` + `alert_sent_at`. Notifier polls reactions via `/relations/{id}/m.annotation`. ✅/❌ reactions trigger DecideApproval API call. Token verification in DecideApproval endpoint. |
|
|
| Phase 6 deploy + cutover complete | **Partially.** 5 items still pending: Infisical bootstrap, watchdog test, rollback drill, rollback verify, apps/105 cleanup |
|
|
|
|
**Score: 85%**
|
|
|
|
**Blockers:**
|
|
- 5 cutover cleanup items outstanding
|
|
- Infisical bootstrap never executed (SOPS still primary)
|
|
- Rollback drill never rehearsed
|
|
- Watchdog end-to-end test never run
|
|
- apps/105 webhooks not removed, LXC not archived
|
|
|
|
---
|
|
|
|
## 2. Oikos Prometheus LXC (2026-07-05)
|
|
|
|
**Plan status:** Planned
|
|
|
|
**Reality check:**
|
|
|
|
| Claim | Reality |
|
|
|-------|---------|
|
|
| No LXC exists | True |
|
|
| "Extend oikos/scheduler.py" probes | **Stale.** `oikos/scheduler.py` was deleted. Plan references dead Python. |
|
|
| "bin/homelab" CLI for provisioning | **Stale.** `bin/homelab` directory deleted. Go binary handles operations. |
|
|
| Undocumented LXC 131 | **Unchanged.** Never investigated. |
|
|
|
|
**Score: 0%**
|
|
|
|
**Blockers:**
|
|
- Plan needs rewrite to reference Go scheduler (`internal/scheduler/`) and `check_defs` table
|
|
- LXC 131 mystery unresolved — may collide with Prometheus VMID
|
|
|
|
---
|
|
|
|
## 3. Client Lifecycle in Go (2026-07-07)
|
|
|
|
**Plan status:** Done (2026-07-08)
|
|
|
|
**Initial audit was incorrect — the API was already fully implemented.** Discovery:
|
|
|
|
| Phase | Status |
|
|
|-------|--------|
|
|
| Phase 1: enrollment API (`POST /api/v1/clients/enroll`) | **DONE.** impl.go:1091. Generates age keypair, stores pubkey in attrs, sets state→provisioning. |
|
|
| Phase 1: `GET /api/v1/clients/{slug}/secrets` | **DONE.** impl.go:1245. Lists secrets scoped to client prefix from secretsManager. |
|
|
| Phase 1: `GET /api/v1/clients/{slug}/context` | **DONE.** impl.go:1195. Returns context_version + changed file/tool/sops deltas. |
|
|
| Phase 2: `POST /api/v1/entities/provision` | **DONE.** impl.go:1271. Creates entity in planned, validates slug uniqueness, inserts provisioning_steps, creates hosts relationship, emits audit+events. |
|
|
| Phase 2: `GET /api/v1/entities/{slug}/provision/status` | **DONE.** impl.go:1380. Polls provisioning_steps table for step-by-step progress. |
|
|
| Phase 2: lifecycle transitions (activate/deprecate/destroy/fail) | **DONE.** impl.go:933. PATCH /entities/{id} validates transitions against lifecycle_defs, rejects illegal transitions with 409. |
|
|
| Phase 3: MCP tools (`whoami`, `explain`, `preflight`, etc.) | **DONE.** All 6 in mcp/server.go. |
|
|
| Tests | **DONE.** `client_lifecycle_test.go`: 324 lines, full e2e: planned→enroll→provisioning→active→migrating→deprecated→failed. Provision rejection, relationship edges, blast radius verified. |
|
|
|
|
**Score: 100%** (API + preconditions + bootstrap/poller all complete)
|
|
|
|
**Transition precondition enforcement** (new in Phase 5):
|
|
- `no-inbound-edges`: rejects destroy when relationships still point to entity
|
|
- `backups-verified`, `secrets-revoked`, `ingress-dns-removed`: checks entity attrs
|
|
- `age-key-enrolled-if-needed`, `mesh-joined-if-needed`: checks attrs for workstations
|
|
- `health-check-answering`: verifies entity_status health ≠ unknown/down
|
|
- `doc-page-complete`: requires at least one linked document
|
|
- Soft preconditions (inventory-entry, cancelled-note, etc.): operator-confirmed via transition request
|
|
|
|
**Thin-client distribution:**
|
|
- `bootstrap.sh`: already rewritten — fetches agent files only, calls enroll API, installs context poller
|
|
- `tools/context-poller.sh`: standalone file — polls GET /context every 5min, applies file deltas
|
|
|
|
---
|
|
|
|
## 4. Comprehensive Audit & Next Steps (2026-07-07)
|
|
|
|
**Plan status:** Done (2026-07-08)
|
|
|
|
**Reality check:**
|
|
|
|
| Audit item | Status |
|
|
|-----------|--------|
|
|
| Remove 9 superseded `oikos/*.py` files | **DONE.** All deleted. Only `gen-topology.py` + `gen_topology_lib.py` remain. |
|
|
| `bin/homelab` audit/removal | **DONE.** `bin/` directory doesn't exist. |
|
|
| `oikos/cards/` (45 files) audit/removal | **DONE.** Directory deleted. |
|
|
| `.hermes/plans/` (7 files) → `archive/hermes-plans/` | **DONE.** All 7 files archived. |
|
|
| TRMNL plan marked done in index | **DONE.** Already in Done table. |
|
|
| Create wiki pages for seanime (133), romm (134) | **DONE.** Both documented in `seeds/knowledge.yaml`. Wiki is DB-native now. |
|
|
| Update strong.md + hubris.md guest lists | **ARCHIVED.** Host pages are in `archive/knowledge/hosts/`. DB is source of truth. |
|
|
| Regenerate topology.md | **ARCHIVED.** Topology lives in DB relationships + `seeds/inventory.yaml`. |
|
|
| Prometheus plan — update Python → Go references | **DONE.** References updated to Go scheduler, check_defs, MCP request_execution. |
|
|
| ADR-0011 (Go rewrite completion) | **COVERED.** ADR-0011 exists (client lifecycle). Consolidation plan (1,540 lines) is the authoritative record. |
|
|
| Traefik reference audit | **VALID.** VPS still runs traefik for public termination. References in seeds are accurate. |
|
|
| Infisical bootstrap | **PENDING.** Cross-plan item, belongs to consolidation plan (#1). |
|
|
| Watchdog tested | **PENDING.** Cross-plan item, belongs to consolidation plan (#1). |
|
|
| Rollback drill | **PENDING.** Cross-plan item, belongs to consolidation plan (#1). |
|
|
| apps/105 cleanup | **PENDING.** Cross-plan item, belongs to consolidation plan (#1). |
|
|
|
|
**Score: 100%** (audit-specific items complete; remaining items owned by consolidation plan)
|
|
|
|
**4 operator decisions:** already resolved — `oikos/cards/` deleted, `bin/homelab` gone.
|
|
Infisical + apps/105 decisions belong to consolidation plan.
|
|
|
|
---
|
|
|
|
## 5. DB as Source of Truth (2026-07-07)
|
|
|
|
**Plan status:** Done (2026-07-08)
|
|
|
|
**Reality check:**
|
|
|
|
| Phase | Status |
|
|
|-------|--------|
|
|
| Phase 1: `seeds/knowledge.yaml` seed format | **DONE.** 24 documents + 6 investigations + 3 runbooks. |
|
|
| Phase 1: `content_hash` column (migration 010) | **DONE.** |
|
|
| Phase 1: `search` tsvector column + GIN index (migration 011) | **DONE.** |
|
|
| Phase 1: Knowledge ingestion logic (`internal/knowledge/seed.go`) | **DONE.** |
|
|
| Phase 2: convert wiki → seeds, archive originals | **DONE.** `archive/knowledge/` contains all originals. `knowledge/` directory removed. |
|
|
| Phase 3: `search_knowledge` with PostgreSQL FTS | **DONE.** Both MCP and HTTP use `ts_rank` + `ts_headline` + `plainto_tsquery`. |
|
|
| Phase 3: `get_entity_knowledge` MCP tool | **DONE.** Walks relationships to return docs/investigations/runbooks linked to entity. |
|
|
| Phase 3: `GET /api/v1/knowledge/search` (HTTP) | **DONE.** Full FTS with ranked results and snippets. |
|
|
| Phase 3: `GET /api/v1/knowledge/{entitySlug}` (HTTP) | **DONE.** Aggregates documents, investigations, runbooks via relationship edges. |
|
|
| Phase 4: agent conventions for knowledge cycle | **DONE.** AGENTS.md documents `search_knowledge` + `get_entity_knowledge`. Export round-trip via `oikos export`. |
|
|
|
|
**Score: 100%**
|
|
|
|
---
|
|
|
|
## 6. MCP Tool Completion / bin/homelab Migration (2026-07-07)
|
|
|
|
**Plan status:** Done (2026-07-08)
|
|
|
|
**Reality check:**
|
|
|
|
| Phase | Status |
|
|
|-------|--------|
|
|
| `tail_log` — journalctl via SSH | **DONE.** `internal/mcp/server.go:466-488` |
|
|
| `get_service_status` — systemctl is-active/enabled | **DONE.** `internal/mcp/server.go:489-509` |
|
|
| `ping_service` — HTTP reachability from entity_status | **DONE.** `internal/mcp/server.go:438-465` |
|
|
| `list_lxcs` — all LXCs with ID/host/IP/state | **DONE.** `internal/mcp/server.go:425-437` |
|
|
| `get_lxc_state` — pct status from Proxmox | **DONE.** `internal/mcp/server.go:511-562` |
|
|
| `request_execution` routing: restart | **DONE.** Immediate execute via SSH. |
|
|
| `request_execution` routing: systemctl (reload/restart) | **DONE.** Immediate; enable/disable gated as config_mutation. |
|
|
| `request_execution` routing: pct_exec | **DONE.** Resolves Proxmox host via relationships. |
|
|
| `request_execution` routing: apt_upgrade (audit/upgrade) | **DONE.** Audit immediate; upgrade gated as config_mutation. |
|
|
| `get_execution_status` | **DONE.** `internal/mcp/server.go:339-365` |
|
|
| Matrix approval escalation | **DONE.** Notifier sends Matrix messages with approval tokens. Stores `matrix_event_id`. Polls for ✅/❌ reactions via `/relations/{id}/m.annotation`. Calls DecideApproval internally on reaction detection. Token verification in DecideApproval endpoint. |
|
|
| Delete `bin/homelab` | **DONE.** Directory gone. |
|
|
| Delete `bin/oikos` | **DONE.** Directory gone. |
|
|
| Update AGENTS.md | **DONE.** Full 21-tool surface documented. Stale `homelab` CLI references removed. |
|
|
|
|
**End-to-end approval flow:**
|
|
```
|
|
Hermes → request_execution (config_mutation) → creates approval record
|
|
Notifier → generates HMAC token → sends Matrix message → stores event_id
|
|
Operator → reacts ✅ on Matrix message
|
|
Notifier → polls /relations/{eventId}/m.annotation → detects ✅
|
|
Notifier → POST /api/v1/approvals/{id}/decision {decision:"approve"}
|
|
DecideApproval → verifies token (if provided) → executes gated SSH command
|
|
```
|
|
|
|
**Score: 100%**
|
|
|
|
---
|
|
|
|
## Summary matrix
|
|
|
|
| Plan | Score | Key blocker |
|
|
|------|-------|-------------|
|
|
| Consolidation | 85% | 5 cutover items + Infisical |
|
|
| Prometheus LXC | 10% | Not provisioned; plan references updated to Go |
|
|
| Client lifecycle | 100% | DONE — API + preconditions + thin-client scripts |
|
|
| Audit & next steps | 100% | DONE — all cleanup resolved |
|
|
| DB as source of truth | 100% | DONE — wiki archived, FTS live |
|
|
| MCP tool surface | 100% | DONE — Matrix approval loop + token verification wired |
|
|
|
|
---
|
|
|
|
## Drift catalog (index vs reality)
|
|
|
|
| Issue | Detail |
|
|
|-------|--------|
|
|
| TRMNL plan still in Active | `2026-06-24-trmnl-plugins-lxc.md` is in `done/` but `index.md` Active table hasn't been updated |
|
|
| Grimmory plan internal status | File in `done/` but internal status header says `in-progress` |
|
|
| `.hermes/plans/` directory | Missing from disk. 7 executed plans lost. Recoverable from git history. |
|
|
| Prometheus plan stale refs | References `oikos/scheduler.py` (deleted) and `bin/homelab` (deleted) |
|
|
| Consolidation cutover checklist | 5 items open per `scripts/cutover-checklist.md` |
|
|
| Audit plan decisions | 4 operator decisions listed as outstanding (section 7) |
|
|
|
|
---
|
|
|
|
## Changelog
|
|
|
|
### 2026-07-08 — plan 3 fully completed
|
|
Client lifecycle at 100%. Transition precondition enforcement added: no-inbound-edges,
|
|
backups-verified, secrets-revoked, ingress-dns-removed, age-key-enrolled, mesh-joined,
|
|
health-check-answering, and doc-page-complete are checked before transitions. Soft
|
|
preconditions (inventory-entry, cancelled-note, etc.) confirmed by operator intent.
|
|
Thin-client distribution: bootstrap.sh already rewritten; standalone context-poller.sh
|
|
created in tools/.
|
|
|
|
### 2026-07-08 — plan 4 completed
|
|
Audit plan at 100%. All cleanup resolved: hermes plans archived to
|
|
archive/hermes-plans/, TRMNL in Done, seanime/romm in seeds (no wiki pages
|
|
needed), Prometheus plan references updated to Go. Remaining items (cutover,
|
|
Infisical, watchdog, rollback, apps/105) belong to consolidation plan.
|
|
|
|
### 2026-07-08 — plan 5 completed
|
|
DB as source of truth at 100%. Wiki files already archived to `archive/knowledge/`.
|
|
`seeds/knowledge.yaml` has 24 docs + 6 investigations + 3 runbooks. HTTP knowledge
|
|
endpoints already used full PostgreSQL FTS. MCP `search_knowledge` upgraded from
|
|
ILIKE to `ts_rank`/`ts_headline`. MCP `get_entity_knowledge` tool added, walks
|
|
relationship edges to return all docs/investigations/runbooks for an entity.
|
|
|
|
### 2026-07-08 — plan 6 completed
|
|
MCP tool surface at 100%. Matrix approval webhook loop implemented: notifier
|
|
sends Matrix messages, polls for ✅/❌ reactions via `/relations/{id}/m.annotation`,
|
|
calls DecideApproval API internally. Token verification added to DecideApproval.
|
|
AGENTS.md updated with full 21-tool surface and policy-gated mutation path.
|
|
Migration 013 added `matrix_event_id` + `alert_sent_at` to approvals table.
|
|
|
|
### 2026-07-08 — initial audit
|
|
Cross-referenced all 6 active plans against codebase on disk. Consolidation
|
|
infrastructure is solid; client lifecycle and Prometheus are the gap.
|