Add the browser edge (contract rev 8.2/9): a Preact/Vite SPA under web/,
an embedded placeholder bundle, the /web/* auth and action handlers, and
the explicit browser-action allowlist. The SPA and the API share the one
plaintext :8080 listener; there is no second port and no peer edge, so
main.go also drops the mTLS listener and the identity mounts in the debug
compose fall away. /_manifest announces the web block only while the SPA is
mounted (honesty rule), always with the single service port.
The DSNs move to the shared database's scram-sha-256 credentials, matching
rev 9's removal of the PKI layer.
Committed web/bun.lock because web/package.json and vite.config.ts are new
in this commit. src/web/dist/index.html is a hand-written placeholder, not
a generated bundle: it keeps bare `go build`/`go vet` working from a clean
checkout, while /web/dist (the real build output) stays gitignored.
Replace Air's kill-and-rerun loop in the debug image with the pilot
persistent-delve supervisor: src/dev/dlv-watch.sh owns one headless
`dlv exec --multiclient --continue` server, rebuilds ./tmp/main on save and
restarts only the debug target through the tiny rpc2 client in
src/dev/dlv-restart. An attached VS Code session (and its breakpoints) now
survives saves instead of reconnecting after every reload.
The debug compose builds locally with `pull_policy: build` and without
`build.network: host`: compose cannot grant the network.host entitlement, so
a cold `up` previously failed with "additional privileges requested"; the
default bridge reaches the dev Gitea for module resolution.
Renames the server-side plaintext escape hatch from INSECURE_INTERNAL to
DCNTRLIZED_DEBUG in the debug compose and the listener log line; bumps the
shared auth module.
- go.mod: dcntrlized-auth v0.1.1 -> v0.1.2 (tlsutil.IsDev/AuthBaseURL and the
identity-mount client fallback).
- docker-compose.debug.yaml: DEV_MODE replaced by DCNTRLIZED_DEV=true (the
single dev selector); mount the devboot-issued identity at the shared-module
default /dcntrlized/pki so the authproxy edge is mTLS. INSECURE_INTERNAL=1
stays: the RN-facing listener must stay plaintext.
Serve the listener over TLS with ClientAuth=RequireAndVerifyClientCert
trusting the instance CA (shared tlsutil.ServerConfig): only Maestro can
drive actions (T4), and the peer edge is encrypted. INSECURE_INTERNAL=1
(dev debug compose) keeps the listener plaintext for the RN client's
direct mode and hot reload.