Add handoff notes: state, deploy blockers, next steps

Work stops here — the deploy is blocked on Maven, which is under construction.
Records what shipped, the five behavioural changes to read before deploying
(notably that hexisd now refuses to start without a token and that execute
requires Nexus liveness), what is blocked versus doable now, and the
limitations accepted along the way.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uea55zaiWuEByEDC4UBSdd
This commit is contained in:
kami
2026-07-31 00:46:43 +04:00
parent ae6bd08ad8
commit 66f5c397f7
+132
View File
@@ -0,0 +1,132 @@
# Hexis — handoff
Date: 2026-07-31
State: all code work from `REVIEW-2026-07-30.md` is **committed and pushed**; **nothing is deployed**.
Branch `master`, remote `origin` = `ssh://git@192.168.1.104:2222/kami/hexis`.
Stopped here deliberately: the deploy is blocked on Maven, which is under
construction.
---
## What shipped
Eight commits, `945e4ba..ae6bd08`. All eight review findings are closed.
| commit | what | findings |
|---|---|---|
| `c7325a2` | Auth on `/api/v1/` + server-derived capability guards | 1, 2 |
| `d428560` | Execution audit fields + in-flight guard as a SQL constraint | 4, 7 |
| `47be24c` | Target validation against Nexus | 3 |
| `be08938` | `context` through `Provider.Execute`; read-only timeouts | 6 |
| `9e6b995` | Dead code + three tests that assert nothing | 5 |
| `dda4acf` | One capability serializer + `GET /api/v1/executions` | §4.5, wire shapes |
| `3ac0fbb` | gofmt realignment | — |
| `ae6bd08` | Makefile, README, the review itself | — |
Verified at HEAD: `go build`, `go vet`, `go test ./...`, `go test -race ./...`
all pass; `gofmt -l` clean; a fresh database migrates to the final
`user_version` and reopening is a no-op.
**Intermediate commits are not individually compile-verified — only HEAD is.**
Several hunks span findings (one 124-line `engine.go` hunk covers both target
validation and a dead-code import removal), so whole hunks were assigned to
their dominant commit rather than hand-split. Concretely, `c7325a2` also
carries the `listCapabilities` serializer change and registers the
`/executions` route whose handler does not arrive until `dda4acf`. `git bisect`
across the middle of this range may not build.
## What changed behaviourally (read before deploying)
1. **`hexisd` refuses to start without `HEXIS_API_TOKEN`.** Fails closed twice:
`log.Fatalf` before listening, and the middleware returns 503 rather than
ever serving unauthenticated. `/health` and `/ready` stay open.
2. **Execute now requires Nexus liveness.** An unreachable Nexus means 503
`ErrTargetUnverifiable`, not a permitted execution. This dependency did not
exist before.
3. **`enabled` and `requires_confirmation` are no longer accepted from the
request body at all** — both derived from the risk tier server-side.
4. **The 11 → 12 migration writes to existing rows.** Duplicate in-flight rows
are rewritten to `status='unknown'` (lowest `id` per pair kept), because the
new partial UNIQUE index cannot be created otherwise. Check first:
```sql
SELECT capability_id, target_entity_id, COUNT(*) FROM executions
WHERE status='started' GROUP BY 1,2 HAVING COUNT(*)>1;
```
5. Capabilities now execute at all — 14 `read` + 1 `low` enabled without
confirmation, 3 `medium` docker mutations enabled *with* confirmation.
`ssh.exec` remains allowlist-skipped.
## Next steps, in order
### 1. Blocked on Maven — the deploy (Vikunja 355)
Cannot proceed while Maven is under construction. When it resumes, these ship
**together** or voice execution breaks:
- Maven: `go mod vendor` (the vendored client at
`Maven/vendor/github.com/kami/hexis/pkg/client/client.go` predates even
`WithToken`).
- Maven: `cmd/mavend/ecosystem.go:322` →
`hexisclient.New(cfg.Hexis.URL).WithToken(cfg.Hexis.Token)`, plus a `Token`
field on the Hexis config block and the token in deploy config.
- Hexis: `HEXIS_API_TOKEN` in `Maven/deploy/ecosystem/docker-compose.yml`.
- Bring up workspace-mcp (container is `Exited (0)`, nothing on `:9930`) and
confirm Nexus is up on `:9740`.
- Rebuild **from a commit**. The running image was built 2026-07-19 21:14,
~3.5h before the first commit existed — it has never corresponded to any
revision. `docker-compose` uses `build: ../../../hexis` with no tag or
digest, so `make compose-up` ships whatever is in the working tree.
- Then verify live: a read capability returns `succeeded` with non-empty
`changes`.
Task 343's serializer change does **not** break Maven — it reads only `.ID`,
`.Name`, `.Description`, `.ReadOnly`, all unchanged, and `id` is still on the
wire. The only break is auth.
### 2. Not blocked — can be done any time
- **Vikunja 354** — `Maven/deploy/ecosystem/nginx.conf:32-42` is a template
with a wildcard `listen 80;` and no ACL. The *live* config is correctly
locked to WireGuard + LAN with `deny all`, but anyone following the repo's
own instructions would produce the internet-exposed config the review
described. Also: public DNS for `hexis./maven./nexus./vikunja..kvmx.ru`
resolves to `109.229.102.117`, which is not this host and is unreachable —
stale records, worth cleaning up.
- **Vikunja 357 — a decision, not code.** Blessing is specified in
`ECOSYSTEM-SPEC.md` (§1.2, §4.3, §7.1, §8 Phase 5, §10 invariant 7) and
implemented nowhere in Nexus: no column, no migration, no TODO, no tracker
item. What shipped in `47be24c` stops free-text targets but does **not**
stop mutation of an auto-discovered entity, which is what blessing exists to
prevent. Either blessing lands in Nexus, or the spec gets amended to describe
the guard that actually exists. Right now the spec documents a protection
that is absent everywhere.
### 3. Latent — a tripwire, not a bug (Vikunja 358)
`GET /api/v1/executions?since=` pages on the executions row's implicit SQLite
`rowid`. Safe **only** while nothing deletes execution rows and nothing runs
`VACUUM`; either renumbers and silently invalidates outstanding cursors, so a
polling client would skip or repeat rows with no error. The table grows
unboundedly, so retention will eventually be wanted — add an explicit monotonic
`seq` column **first**. Documented at the `executionColumns` declaration in
`internal/storage/sqlite.go`.
## Known limitations accepted
- Rows predating the 11 → 12 migration get `capability_version = 0`,
indistinguishable from a genuine 0. Backfill is impossible — the capabilities
have since mutated and the executions never recorded what they ran against.
- Both `id` and `capability_id` are emitted, carrying the same value. Kept
deliberately so Maven does not take a second breaking change alongside auth.
Retiring `id` is an announced removal, not a tidy-up; a test says so.
- `schema_migrations` was **not** dropped despite the review's remove list.
`migrate()` applies migrations by slice index and writes
`user_version = index + 1`, so removing an element renumbers every later
migration and any database past that point would permanently skip one. The
`CREATE TABLE` is now a no-op holding its slot.
## One thing to reconsider
`REVIEW-2026-07-30.md` is committed in-tree. It documents the unauthenticated
execute attack path and names `hexis.kvmx.ru`. Fine on a LAN Gitea; reconsider
before this repo is mirrored anywhere wider.