diff --git a/canon/architecture/adr-002-custodian-agent-runtime-design.md b/canon/architecture/adr-002-custodian-agent-runtime-design.md index b95e2bdb..c67a2d0e 100644 --- a/canon/architecture/adr-002-custodian-agent-runtime-design.md +++ b/canon/architecture/adr-002-custodian-agent-runtime-design.md @@ -4,9 +4,11 @@ type: architecture-decision-record title: "Custodian Agent Runtime — v0.1 Bootstrap Design" status: accepted owner: the-custodian -revision: "accepted-1" -last_reviewed: "2026-03-12" +revision: "accepted-2" +last_reviewed: "2026-10-11" review_interval: 6m +reviewed_by: "codex — technical source/currency review" +review_scope: "Historical decision retained; current factual and authority scope clarified, no new grant" decided_by: Bernd Worsch date: "2026-03-12" tags: ["architecture", "agent-runtime", "llm", "ooda", "bounded-agency"] @@ -18,7 +20,44 @@ tags: ["architecture", "agent-runtime", "llm", "ooda", "bounded-agency"] Accepted. -## Context +## Technical currency review — 2026-10-11 + +The accepted decision remains the **v0.1 bootstrap architecture for the +standalone package under `runtime/`**, not a grant to every coding agent or +an assertion that a privileged autonomous runtime is deployed. Current source +still implements D1–D5: this package location, a single synchronous CLI cycle, +configurable `llm-connect` with `claude-code` default, three explicit HTTP write +classes, and a fenced JSON action plan plus a session note. All 32 existing +offline runtime tests pass with HTTP calls mocked. That verifies the described +prototype behavior; it proves no live authorization, runtime isolation, +credential boundary, semantic correctness of task updates, or rollout state. + +D4's original permission is limited to that bootstrap's named low-impact +coordination operations. It is neither an approval token nor a Codex autopilot +grant, and it does not override owner-source work records, API authorization, +work-record lanes or agent-specific supervision. Current governance is +`docs/agent-autonomy-decision.md` (founder, 2026-09-28): new scopes start +supervised and autopilot requires a separate explicit scoped grant and verified +runtime enforcement. The inspected `custodian-codex` supervision record remains +supervised, with no autopilot grant and interactive isolation not yet migrated. +This review changes no such authority or record. + +The March dependency/deployment statements below are historical context. +The review does not reaffirm that every deployment has Claude Code, that the +bootstrap is scheduled or deployed, or that its narrow operation list provides +credential isolation. API addresses and live change procedures belong to +`docs/agent-environment-orientation.md`; task/workplan sources follow ADR-001 +and the later accepted ADR-012. The code's direct task-status HTTP branch is +prototype implementation evidence, not permission to override file-backed +owner records. Any widening of D4 or promotion remains a separate decision. + +The original 2026-03-12 decision and accepted-1 bytes are retained in +`docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.md`. +`accepted-2` is this dated factual/scope annotation, not a new human adoption +of an expanded action surface. The detailed source hashes and test receipt +are in `docs/evidence/2026-10-11-adr-currency-review/review.json`. + +## Context (historical decision basis) CUST-WP-0001 requires a first working skeleton of the Custodian as an acting agent: a loop that observes project state, reasons about it, and executes diff --git a/canon/architecture/adr-004-connectivity-first-network-posture.md b/canon/architecture/adr-004-connectivity-first-network-posture.md index 5299dc1e..b596bacf 100644 --- a/canon/architecture/adr-004-connectivity-first-network-posture.md +++ b/canon/architecture/adr-004-connectivity-first-network-posture.md @@ -4,9 +4,11 @@ type: architecture-decision-record title: "Connectivity-First Network Posture for Custodian Infrastructure" status: accepted owner: the-custodian -revision: "accepted-1" -last_reviewed: "2026-03-26" +revision: "accepted-2" +last_reviewed: "2026-10-11" review_interval: 6m +reviewed_by: "codex — technical source/currency review" +review_scope: "Historical decision retained; current factual and authority scope clarified, no new grant" decided_by: Bernd Worsch date: "2026-03-26" tags: ["architecture", "network", "ops-bridge", "connectivity", "isolation", "security-posture"] @@ -18,7 +20,60 @@ tags: ["architecture", "network", "ops-bridge", "connectivity", "isolation", "se Accepted. -## Context +## Technical currency review — 2026-10-11 + +The accepted decision remains a **transport-connectivity posture**: needed +connections use named, observable, managed paths with deliberate lifecycle +continuity. Persistent transport is compatible with independently limited +credentials, authenticated callers and resource-side authorization. It grants +neither access to every connected component nor authority to bypass isolation +required by the current security model. No blanket trust, permanent credential +permission or autonomous privileged execution is adopted by this review. + +The March Context, Rationale and deployment consequences below are retained +as the original decision's historical basis, not current environment facts or +a present security assurance. Specifically: + +- The central State Hub is on railiance01. The workstation address + `http://127.0.0.1:8000` is a managed local forward; remote in-cluster callers + use `http://10.43.68.154:8000`. The old remote-to-workstation reverse tunnel + `http://127.0.0.1:18000` is retired. An optional local relay at :18080 is a + separate explicitly enabled route, not the primary hub. +- OpsBridge owns observable connectivity, not credentials or authorization. + Its INTENT explicitly disclaims credential-authority and security-policy + ownership. Its older SCOPE still describes a workstation-local Hub and must + not be used as current topology proof. Use the Custodian environment + orientation and current owner records before selecting a route. +- Observability and a read-model design are **not proof that unauthorized + writes, lateral movement or credential exposure are prevented**. The old + narrow-write rationale is not a current control assurance. Source authority + is governed by accepted ADR-001/ADR-012, and concrete service security is + governed by its owners and accepted NetKingdom security-layer v0.8. +- SSH encryption protects its transport; it does not guarantee that a + forwarded application is authenticated, that listener binding exposes no + service, or that credentials cannot reach a process or log. The original + “no inbound ports exposed” and age/SOPS phrases are not estate-wide proof. + Current custody routing and secret-output rules remain mandatory. +- Build mode and absence of customers do not waive tenant boundaries, service + admission, credential isolation or exact live-change approval. The + agent-specific supervision decision of 2026-09-28 governs privileged + execution; the Kubernetes change gate of 2026-09-21 governs its change path. + Those existing decisions, not this transport ADR, supply authority. + +These clarifications apply existing accepted governance rather than replacing +the connectivity-first decision with a new isolation-first mandate. Changing +the transport posture or granting new authority would require a separate +proposal and human disposition. No fresh live topology or isolation audit was +performed by this source review; environment facts above retain the evidence +dates and ownership in `docs/agent-environment-orientation.md`. + +The original 2026-03-26 decision and accepted-1 bytes are retained in +`docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.md`. +`accepted-2` is this dated factual/scope annotation; the original decision +author and date remain history. Detailed source hashes and review findings +are in `docs/evidence/2026-10-11-adr-currency-review/review.json`. + +## Context (historical decision basis) The Custodian infrastructure spans multiple machines: a primary workstation, a shared compute node (COULOMBCORE), and Railiance cluster nodes. Agents running diff --git a/docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.html b/docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.html new file mode 100644 index 00000000..029635b2 --- /dev/null +++ b/docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.html @@ -0,0 +1,242 @@ + + + + +Custodian Agent Runtime — v0.1 Bootstrap Design + +
CUST-ADR-002 accepted · accepted-1 the-custodian reviewed 2026-03-12generated from canonical source — do not edit

Custodian Agent Runtime — v0.1 Bootstrap Design

Source: the-custodian · canon/architecture/adr-002-custodian-agent-runtime-design.md · 4039c9d1c08c92014ecc0a65dda63cc73ba187bb

Review due: 2026-09-12

Status

+

Accepted.

+
+

Context

+

CUST-WP-0001 requires a first working skeleton of the Custodian as an acting agent: a loop that observes project state, reasons about it, and executes bounded write operations — without human interaction for each step.

+

The dependencies (llm-connect, operational Railiance infra) are now resolved. This ADR captures the five key architectural decisions for the v0.1 bootstrap.

+
+

Decisions

+

D1 — Location: runtime/ inside the-custodian (not a new repo)

+

Decision: The runtime lives under the-custodian/runtime/ as a standalone Python package (pyproject.toml, own venv) rather than a new repository.

+

Rationale: The runtime is tightly coupled to canon (reads constitution, memory) and the state-hub (its primary coordination layer). A separate repo adds friction with no v0.1 benefit. The existing runtime/ scaffold confirms the original intent. Extraction to its own repo is deferred to when the runtime has stable boundaries and multiple consumers.

+

D2 — OODA loop: single-pass synchronous CLI

+

Decision: One run() call = one complete Observe → Orient → Decide → Act cycle. Entry point is a CLI (agent.py) invoked manually or by a cron job.

+
Observe  — HTTP GET to state-hub: state summary or domain summary
+Orient   — Load constitution + build structured LLM context prompt
+Decide   — Single LLM call (via llm-connect) returns a JSON action plan
+Act      — Execute only sanctioned write operations from the plan
+

Rationale: Async event loops and daemons add operational complexity that v0.1 doesn't need. A single-pass CLI is testable, debuggable, and can be scheduled externally. The transition to an event-driven loop is Phase 2.

+

D3 — LLM backend: ClaudeCodeAdapter by default

+

Decision: The runtime uses llm_connect.ClaudeCodeAdapter as its default LLM backend (shells out to claude --print). Provider is configurable via --llm flag to support gemini, openrouter, or openai.

+

Rationale: ClaudeCodeAdapter requires no API key and honours the Local-First value (V2). All current deployments have Claude Code available. The llm-connect abstraction means switching providers is a one-line change.

+

D4 — Action constraint: three sanctioned write operations only

+

Decision: The agent may execute exactly three state-hub write operations without human approval:

+
  1. add_progress_event — append an observation to the event log
  2. update_task_status — mark a task done/in_progress (reversible)
  3. flag_for_human — raise an intervention flag (escalation, not action)
+

All other operations (create workstream, record decision, resolve decision, write to canon) require human approval before execution.

+

Rationale: Constitution §3/§4 require bounded agency. The three operations are either append-only (progress events), reversible (task status), or explicitly escalating (flag). They cannot produce irreversible harm.

+

D5 — LLM response format: JSON block in markdown

+

Decision: The LLM is prompted to return a Markdown response with a fenced ```json block containing the structured action plan:

+
{
+  "observations": ["..."],
+  "progress_events": [
+    {"summary": "...", "workstream_id": "...", "event_type": "note"}
+  ],
+  "tasks_to_update": [
+    {"task_id": "...", "status": "done"}
+  ],
+  "tasks_to_flag": [
+    {"task_id": "...", "note": "..."}
+  ]
+}
+

The surrounding Markdown is preserved as a human-readable reasoning trace and written to memory/working/ as a session note.

+

Rationale: JSON blocks are robust to extraction (delimited), LLMs produce them reliably with clear instructions, and the surrounding prose gives Bernd an auditable reasoning trace without requiring a separate reasoning step.

+
+

Consequences

+
  • runtime/ becomes a standalone Python package; make agent-run DOMAIN=x invokes it.
  • The runtime has no DB schema changes and no new API endpoints — it is a pure client of the existing state-hub HTTP API.
  • Autonomous actions are limited to append-only writes and escalations. Any expansion of the action surface requires a new ADR and human approval.
  • The v0.1 loop is single-user (Bernd). Multi-agent expansion is Phase 2+.
+
+

Deferred

+
  • Async event loop / daemon mode (Phase 2)
  • RAG over canon (Phase 1 roadmap item)
  • Tool adapters beyond state-hub HTTP (planned in runtime/tool_adapters/)
  • Deployment on Railiance k3s as a scheduled CronJob
+
diff --git a/docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.md b/docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.md new file mode 100644 index 00000000..b95e2bdb --- /dev/null +++ b/docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.md @@ -0,0 +1,126 @@ +--- +id: CUST-ADR-002 +type: architecture-decision-record +title: "Custodian Agent Runtime — v0.1 Bootstrap Design" +status: accepted +owner: the-custodian +revision: "accepted-1" +last_reviewed: "2026-03-12" +review_interval: 6m +decided_by: Bernd Worsch +date: "2026-03-12" +tags: ["architecture", "agent-runtime", "llm", "ooda", "bounded-agency"] +--- + +# ADR-002: Custodian Agent Runtime — v0.1 Bootstrap Design + +## Status + +Accepted. + +## Context + +CUST-WP-0001 requires a first working skeleton of the Custodian as an acting +agent: a loop that observes project state, reasons about it, and executes +bounded write operations — without human interaction for each step. + +The dependencies (llm-connect, operational Railiance infra) are now resolved. +This ADR captures the five key architectural decisions for the v0.1 bootstrap. + +## Decisions + +### D1 — Location: `runtime/` inside the-custodian (not a new repo) + +**Decision:** The runtime lives under `the-custodian/runtime/` as a standalone +Python package (`pyproject.toml`, own venv) rather than a new repository. + +**Rationale:** The runtime is tightly coupled to canon (reads constitution, +memory) and the state-hub (its primary coordination layer). A separate repo +adds friction with no v0.1 benefit. The existing `runtime/` scaffold confirms +the original intent. Extraction to its own repo is deferred to when the +runtime has stable boundaries and multiple consumers. + +### D2 — OODA loop: single-pass synchronous CLI + +**Decision:** One `run()` call = one complete Observe → Orient → Decide → Act +cycle. Entry point is a CLI (`agent.py`) invoked manually or by a cron job. + +``` +Observe — HTTP GET to state-hub: state summary or domain summary +Orient — Load constitution + build structured LLM context prompt +Decide — Single LLM call (via llm-connect) returns a JSON action plan +Act — Execute only sanctioned write operations from the plan +``` + +**Rationale:** Async event loops and daemons add operational complexity that +v0.1 doesn't need. A single-pass CLI is testable, debuggable, and can be +scheduled externally. The transition to an event-driven loop is Phase 2. + +### D3 — LLM backend: ClaudeCodeAdapter by default + +**Decision:** The runtime uses `llm_connect.ClaudeCodeAdapter` as its default +LLM backend (shells out to `claude --print`). Provider is configurable via +`--llm` flag to support `gemini`, `openrouter`, or `openai`. + +**Rationale:** `ClaudeCodeAdapter` requires no API key and honours the +Local-First value (V2). All current deployments have Claude Code available. +The llm-connect abstraction means switching providers is a one-line change. + +### D4 — Action constraint: three sanctioned write operations only + +**Decision:** The agent may execute exactly three state-hub write operations +without human approval: +1. `add_progress_event` — append an observation to the event log +2. `update_task_status` — mark a task done/in_progress (reversible) +3. `flag_for_human` — raise an intervention flag (escalation, not action) + +All other operations (create workstream, record decision, resolve decision, +write to canon) require human approval before execution. + +**Rationale:** Constitution §3/§4 require bounded agency. The three operations +are either append-only (progress events), reversible (task status), or +explicitly escalating (flag). They cannot produce irreversible harm. + +### D5 — LLM response format: JSON block in markdown + +**Decision:** The LLM is prompted to return a Markdown response with a +fenced ```json block containing the structured action plan: + +```json +{ + "observations": ["..."], + "progress_events": [ + {"summary": "...", "workstream_id": "...", "event_type": "note"} + ], + "tasks_to_update": [ + {"task_id": "...", "status": "done"} + ], + "tasks_to_flag": [ + {"task_id": "...", "note": "..."} + ] +} +``` + +The surrounding Markdown is preserved as a human-readable reasoning trace +and written to `memory/working/` as a session note. + +**Rationale:** JSON blocks are robust to extraction (delimited), LLMs produce +them reliably with clear instructions, and the surrounding prose gives Bernd +an auditable reasoning trace without requiring a separate reasoning step. + +## Consequences + +- `runtime/` becomes a standalone Python package; `make agent-run DOMAIN=x` + invokes it. +- The runtime has no DB schema changes and no new API endpoints — it is a + pure client of the existing state-hub HTTP API. +- Autonomous actions are limited to append-only writes and escalations. Any + expansion of the action surface requires a new ADR and human approval. +- The v0.1 loop is single-user (Bernd). Multi-agent expansion is Phase 2+. + +## Deferred + +- Async event loop / daemon mode (Phase 2) +- RAG over canon (Phase 1 roadmap item) +- Tool adapters beyond state-hub HTTP (planned in `runtime/tool_adapters/`) +- Deployment on Railiance k3s as a scheduled CronJob diff --git a/docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.html b/docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.html new file mode 100644 index 00000000..753df7ad --- /dev/null +++ b/docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.html @@ -0,0 +1,236 @@ + + + + +Connectivity-First Network Posture for Custodian Infrastructure + +
CUST-ADR-004 accepted · accepted-1 the-custodian reviewed 2026-03-26generated from canonical source — do not edit

Connectivity-First Network Posture for Custodian Infrastructure

Source: the-custodian · canon/architecture/adr-004-connectivity-first-network-posture.md · 4039c9d1c08c92014ecc0a65dda63cc73ba187bb

Review due: 2026-09-26

Status

+

Accepted.

+
+

Context

+

The Custodian infrastructure spans multiple machines: a primary workstation, a shared compute node (COULOMBCORE), and Railiance cluster nodes. Agents running on remote machines need to reach the state-hub API and MCP server, which live on the workstation. Human operators and agents also need to reach remote services (k3s API, Gitea, Temporal) from the workstation.

+

Two network postures were considered for how these components communicate:

+

Option A — Connectivity-first: Components are connected by default via controlled, observable access paths (reverse SSH tunnels managed by ops-bridge). Isolation is added selectively where there is a specific threat model or compliance reason to do so.

+

Option B — Isolation-first (zero-trust): No component trusts any other by default. Every connection requires mutual authentication, short-lived credentials, and explicit authorisation at the point of use. Connectivity is earned, not assumed.

+

This decision is architectural policy — it governs how ops-bridge tunnels are designed, how agent-to-hub communication works, and how new infrastructure components are onboarded.

+
+

Decision

+

Connectivity-first, with isolation as a deliberate option.

+

The default posture for Custodian infrastructure is: components that need to work together are connected. Access paths are explicit, observable, and managed (via ops-bridge), but they are persistent by default rather than ephemeral. Isolation is introduced where there is a specific, articulated reason — not as a blanket policy applied uniformly.

+
+

Rationale

+

1. Scale and team size

+

The infrastructure is operated by a single human and a bounded set of automation agents. The overhead of zero-trust (credential rotation, SPIFFE/SPIRE identity, mTLS everywhere, short-lived tokens per request) is disproportionate for this scale. It would consume significant operational complexity without a commensurate security return.

+

2. Observability over perimeter hardening

+

The primary security control at this scale is observability: knowing what connected, when, from where, and what it did. ops-bridge provides this — every tunnel is named, actor-attributed, health-checked, and audited. A perimeter of invisible short-lived connections would actually reduce observability.

+

3. The threat model does not require zero-trust today

+

The main threats are:

+
  • A runaway agent consuming resources (mitigated by nproc/memory cgroups)
  • A compromised workload reaching state-hub and corrupting state (mitigated by the read-model design of state-hub — write surface is narrow and sanctioned)
  • An external attacker reaching internal services (mitigated by the tunnels being reverse SSH — no inbound ports exposed)
+

Zero-trust would address a different threat model: lateral movement between hostile tenants, or untrusted code running in the same environment as sensitive data. That is not the current situation.

+

4. Degrade-gracefully requires persistent connectivity

+

The Custodian's foundational value of local-first, degrade-gracefully requires that agents can orient themselves even when some connections are slow or partially degraded. Ephemeral connectivity (zero-trust tokens, service mesh sidecars) introduces additional failure modes that conflict with graceful degradation. Persistent SSH tunnels with auto-reconnect are more resilient to intermittent conditions.

+

5. Isolation remains the right choice in specific cases

+

Connectivity-first does not mean no isolation. The following cases call for explicit isolation and are handled separately:

+
  • Tenant separation (when/if multi-user or multi-org) — each tenant gets its own network segment
  • Privileged execution — CI runners and agent actions with write access to production systems run in ephemeral, isolated environments (per the Privileged Execution Control standard)
  • Secrets — credentials are never transmitted over tunnels in plaintext; age-encrypted at rest, SOPS for config
+
+

Consequences

+

Immediate

+
  • ops-bridge tunnels are persistent (max_attempts: 0, auto-reconnect) and are treated as infrastructure, not one-off connections
  • Agents on remote machines check tunnel health at session start and restore dropped tunnels before accessing state-hub (documented in global CLAUDE.md)
  • New infrastructure components are onboarded with a named tunnel entry in ~/.config/bridge/tunnels.yaml — not ad-hoc SSH commands
+

Deferred

+
  • If the infrastructure grows to multi-tenant or multi-operator, this decision should be revisited. At that point, isolation-first becomes proportionate.
  • If a security audit identifies a specific lateral movement risk, targeted isolation (network policy, mTLS for that service) is the response — not a wholesale posture change.
+
+

Alternatives Rejected

+

Zero-trust / isolation-first

+

Rejected for current scale. The operational overhead (credential lifecycle, service mesh, mutual TLS) is disproportionate, observability would decrease, and the threat model does not require it. Noted for re-evaluation at multi- tenant scale.

+

VPN (WireGuard / Tailscale)

+

Considered briefly. VPN would solve the connectivity problem but introduces a persistent network layer that all traffic traverses, reducing the explicitness of individual access paths. ops-bridge tunnels are per-service and per-actor, which gives better observability and blast-radius control. VPN is not ruled out as a future complement but is not the primary approach.

+

Ad-hoc SSH (no ops-bridge)

+

The pre-ops-bridge approach. Rejected because it has no health checks, no actor attribution, no audit log, and requires manual intervention to restore. ops-bridge formalises the same SSH tunnel pattern with operational discipline.

+
diff --git a/docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.md b/docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.md new file mode 100644 index 00000000..5299dc1e --- /dev/null +++ b/docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.md @@ -0,0 +1,147 @@ +--- +id: CUST-ADR-004 +type: architecture-decision-record +title: "Connectivity-First Network Posture for Custodian Infrastructure" +status: accepted +owner: the-custodian +revision: "accepted-1" +last_reviewed: "2026-03-26" +review_interval: 6m +decided_by: Bernd Worsch +date: "2026-03-26" +tags: ["architecture", "network", "ops-bridge", "connectivity", "isolation", "security-posture"] +--- + +# ADR-004: Connectivity-First Network Posture for Custodian Infrastructure + +## Status + +Accepted. + +## Context + +The Custodian infrastructure spans multiple machines: a primary workstation, a +shared compute node (COULOMBCORE), and Railiance cluster nodes. Agents running +on remote machines need to reach the state-hub API and MCP server, which live +on the workstation. Human operators and agents also need to reach remote +services (k3s API, Gitea, Temporal) from the workstation. + +Two network postures were considered for how these components communicate: + +**Option A — Connectivity-first:** Components are connected by default via +controlled, observable access paths (reverse SSH tunnels managed by ops-bridge). +Isolation is added selectively where there is a specific threat model or +compliance reason to do so. + +**Option B — Isolation-first (zero-trust):** No component trusts any other by +default. Every connection requires mutual authentication, short-lived +credentials, and explicit authorisation at the point of use. Connectivity is +earned, not assumed. + +This decision is architectural policy — it governs how ops-bridge tunnels are +designed, how agent-to-hub communication works, and how new infrastructure +components are onboarded. + +## Decision + +**Connectivity-first, with isolation as a deliberate option.** + +The default posture for Custodian infrastructure is: components that need to +work together are connected. Access paths are explicit, observable, and managed +(via ops-bridge), but they are persistent by default rather than ephemeral. +Isolation is introduced where there is a specific, articulated reason — not as +a blanket policy applied uniformly. + +## Rationale + +### 1. Scale and team size + +The infrastructure is operated by a single human and a bounded set of +automation agents. The overhead of zero-trust (credential rotation, SPIFFE/SPIRE +identity, mTLS everywhere, short-lived tokens per request) is disproportionate +for this scale. It would consume significant operational complexity without +a commensurate security return. + +### 2. Observability over perimeter hardening + +The primary security control at this scale is **observability**: knowing what +connected, when, from where, and what it did. ops-bridge provides this — every +tunnel is named, actor-attributed, health-checked, and audited. A perimeter of +invisible short-lived connections would actually reduce observability. + +### 3. The threat model does not require zero-trust today + +The main threats are: +- A runaway agent consuming resources (mitigated by nproc/memory cgroups) +- A compromised workload reaching state-hub and corrupting state (mitigated by + the read-model design of state-hub — write surface is narrow and sanctioned) +- An external attacker reaching internal services (mitigated by the tunnels + being reverse SSH — no inbound ports exposed) + +Zero-trust would address a different threat model: lateral movement between +hostile tenants, or untrusted code running in the same environment as sensitive +data. That is not the current situation. + +### 4. Degrade-gracefully requires persistent connectivity + +The Custodian's foundational value of **local-first, degrade-gracefully** +requires that agents can orient themselves even when some connections are slow +or partially degraded. Ephemeral connectivity (zero-trust tokens, service mesh +sidecars) introduces additional failure modes that conflict with graceful +degradation. Persistent SSH tunnels with auto-reconnect are more resilient to +intermittent conditions. + +### 5. Isolation remains the right choice in specific cases + +Connectivity-first does not mean no isolation. The following cases call for +explicit isolation and are handled separately: + +- **Tenant separation** (when/if multi-user or multi-org) — each tenant gets + its own network segment +- **Privileged execution** — CI runners and agent actions with write access to + production systems run in ephemeral, isolated environments (per the + Privileged Execution Control standard) +- **Secrets** — credentials are never transmitted over tunnels in plaintext; + age-encrypted at rest, SOPS for config + +## Consequences + +### Immediate + +- ops-bridge tunnels are **persistent** (max_attempts: 0, auto-reconnect) and + are treated as infrastructure, not one-off connections +- Agents on remote machines check tunnel health at session start and restore + dropped tunnels before accessing state-hub (documented in global CLAUDE.md) +- New infrastructure components are onboarded with a named tunnel entry in + `~/.config/bridge/tunnels.yaml` — not ad-hoc SSH commands + +### Deferred + +- If the infrastructure grows to multi-tenant or multi-operator, this decision + should be revisited. At that point, isolation-first becomes proportionate. +- If a security audit identifies a specific lateral movement risk, targeted + isolation (network policy, mTLS for that service) is the response — not a + wholesale posture change. + +## Alternatives Rejected + +### Zero-trust / isolation-first + +Rejected for current scale. The operational overhead (credential lifecycle, +service mesh, mutual TLS) is disproportionate, observability would decrease, +and the threat model does not require it. Noted for re-evaluation at multi- +tenant scale. + +### VPN (WireGuard / Tailscale) + +Considered briefly. VPN would solve the connectivity problem but introduces +a persistent network layer that all traffic traverses, reducing the +explicitness of individual access paths. ops-bridge tunnels are per-service +and per-actor, which gives better observability and blast-radius control. +VPN is not ruled out as a future complement but is not the primary approach. + +### Ad-hoc SSH (no ops-bridge) + +The pre-ops-bridge approach. Rejected because it has no health checks, no +actor attribution, no audit log, and requires manual intervention to restore. +ops-bridge formalises the same SSH tunnel pattern with operational discipline. diff --git a/docs/evidence/2026-10-11-adr-currency-review/publisher-preview-proof.json b/docs/evidence/2026-10-11-adr-currency-review/publisher-preview-proof.json new file mode 100644 index 00000000..6dadbe4c --- /dev/null +++ b/docs/evidence/2026-10-11-adr-currency-review/publisher-preview-proof.json @@ -0,0 +1,59 @@ +{ + "scope": "Fresh local preview only; no sourcecommit or live publication claimed", + "proof": [ + { + "id": "CUST-ADR-002", + "immutable_accepted1_preserved_byte_exact": true, + "served_page_sha256": "ea4eae05b62d50cd8204a47c1a4f3e3e0beda571880ed1de93ccbb17987d84aa", + "current_accepted2_has_dated_review": true, + "original_decided_by": "Bernd Worsch", + "original_decision_date": "2026-03-12", + "current_currency": "current" + }, + { + "id": "CUST-ADR-004", + "immutable_accepted1_preserved_byte_exact": true, + "served_page_sha256": "3db1b0f5c50543ff0fb022ea67f1d85b30f8ff691eaa1a2443220b7474b54de7", + "current_accepted2_has_dated_review": true, + "original_decided_by": "Bernd Worsch", + "original_decision_date": "2026-03-26", + "current_currency": "current" + } + ], + "records": [ + { + "id": "CUST-ADR-002", + "title": "Custodian Agent Runtime \u2014 v0.1 Bootstrap Design", + "status": "accepted", + "revision": "accepted-2", + "owner": "the-custodian", + "last_reviewed": "2026-10-11", + "review_due": "2027-04-11", + "currency": "current", + "lifecycle": "active", + "canonical_path": "adr/custodian-agent-runtime/v1/index.html", + "revision_path": "adr/custodian-agent-runtime/v1/revisions/accepted-2/index.html", + "source_repo": "the-custodian", + "source_path": "canon/architecture/adr-002-custodian-agent-runtime-design.md", + "source_revision": "sha256:b860b02b1e8f47b914d41c6ecf67f451e86326ed51c7c53dcc6b7870fc889e42", + "source_digest": "b860b02b1e8f47b914d41c6ecf67f451e86326ed51c7c53dcc6b7870fc889e42" + }, + { + "id": "CUST-ADR-004", + "title": "Connectivity-First Network Posture for Custodian Infrastructure", + "status": "accepted", + "revision": "accepted-2", + "owner": "the-custodian", + "last_reviewed": "2026-10-11", + "review_due": "2027-04-11", + "currency": "current", + "lifecycle": "active", + "canonical_path": "adr/custodian-connectivity-first/v1/index.html", + "revision_path": "adr/custodian-connectivity-first/v1/revisions/accepted-2/index.html", + "source_repo": "the-custodian", + "source_path": "canon/architecture/adr-004-connectivity-first-network-posture.md", + "source_revision": "sha256:4f9978b40c104600c0ccb981a8ee52376a5d3003da4786752029af524b7dede7", + "source_digest": "4f9978b40c104600c0ccb981a8ee52376a5d3003da4786752029af524b7dede7" + } + ] +} diff --git a/docs/evidence/2026-10-11-adr-currency-review/review.json b/docs/evidence/2026-10-11-adr-currency-review/review.json new file mode 100644 index 00000000..13756f0f --- /dev/null +++ b/docs/evidence/2026-10-11-adr-currency-review/review.json @@ -0,0 +1,130 @@ +{ + "review_date": "2026-10-11", + "reviewer": "Dedicated Custodian technical author review under current consolidation assignment", + "scope": "Source/currency review of two accepted historical ADRs; no live audit, ratification, promotion or privileged authorization", + "originals": [ + { + "id": "CUST-ADR-002", + "path": "canon/architecture/adr-002-custodian-agent-runtime-design.md", + "original_revision": "accepted-1", + "original_sha256": "6aef66cd5cf71a48f5b4e14401dc19a755e2b182445b272d5952df0eb0dea8ec", + "historical_snapshot": "docs/evidence/2026-10-11-adr-currency-review/adr-002-accepted-1.md", + "annotated_revision": "accepted-2", + "normative_decision_changed": false + }, + { + "id": "CUST-ADR-004", + "path": "canon/architecture/adr-004-connectivity-first-network-posture.md", + "original_revision": "accepted-1", + "original_sha256": "3b68adfa6ab329e73f857cf691dc405136d2d66a0135e2c37c236aabe4659557", + "historical_snapshot": "docs/evidence/2026-10-11-adr-currency-review/adr-004-accepted-1.md", + "annotated_revision": "accepted-2", + "normative_decision_changed": false + } + ], + "sources": [ + { + "path": "/home/worsch/the-custodian/runtime/agent.py", + "sha256": "3b1e6dfd8bfca20d91cd17b75ac03739a97e3ca2dd35719c2b14f76d5eab653e" + }, + { + "path": "/home/worsch/the-custodian/runtime/actions.py", + "sha256": "b69f6bc4e8ec463526a578ed28627884df6633bf13d56bc110fb77815d2e0f53" + }, + { + "path": "/home/worsch/the-custodian/runtime/context.py", + "sha256": "988e37757360207356b8292599c812ca56450ba53ea6c25fa8486a4b02d17f08" + }, + { + "path": "/home/worsch/the-custodian/runtime/README.md", + "sha256": "c9bcfe727705b1503447d863f6fed4a84e97eb18a84b335c9073dac6dbb756e4" + }, + { + "path": "/home/worsch/the-custodian/docs/agent-autonomy-decision.md", + "sha256": "4f65dfd2b56b67cd64eb9577644d574d2e687adcfd8b5bdb65a2e0d14f8bf1ff" + }, + { + "path": "/home/worsch/the-custodian/docs/agent-environment-orientation.md", + "sha256": "6eb712593adaeb2efd8c69edb22b02662e6c9b155f84f1559e7bdaeb76730439" + }, + { + "path": "/home/worsch/the-custodian/docs/kubernetes-change-gate-decision.md", + "sha256": "063d9625f9de2d40d1f4e95f9423a54186fa0b429d76d5f173caa646317a50ab" + }, + { + "path": "/home/worsch/the-custodian/.kaizen/agents/custodian-codex/supervision.json", + "sha256": "28b798e04a310eb0c502bb80780f6f0586f61326f1e16e1e85d13863384032b5" + }, + { + "path": "/home/worsch/the-custodian/canon/architecture/adr-001-workplans-as-repo-artefacts.md", + "sha256": "183023ee57bae9c29e726fec5ee0361633fe3a2b182436a57869ae4b2a27af24" + }, + { + "path": "/home/worsch/the-custodian/canon/architecture/adr-012-projection-source-and-preliminary-overlay.md", + "sha256": "b5e8582459f546ae789ad5fd62f458454aa19997b520e32b6b9f792d6af55987" + }, + { + "path": "/home/worsch/the-custodian/canon/standards/autonomy-lanes_v0.1.md", + "sha256": "106cb0c99f73983199c9f1d8491143aa2a2eb41ee450a02ec7968d3763f30399" + }, + { + "path": "/home/worsch/ops-bridge/INTENT.md", + "sha256": "2134f693649803414d7ab2f9839416f1fe06169aa86732e64c9dd962c35f412b" + }, + { + "path": "/home/worsch/ops-bridge/SCOPE.md", + "sha256": "63cd52d1cdf38e72af0285c25aa2292f959080c6befe565a1d2690747a813975" + }, + { + "path": "/home/worsch/net-kingdom/canon/standards/security-layer-model_v0.8.md", + "sha256": "3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b" + } + ], + "test": { + "cwd": "/home/worsch/the-custodian/runtime", + "argv": [ + "python3", + "-m", + "pytest", + "-q", + "-p", + "no:cacheprovider", + "tests" + ], + "env_overrides": { + "PYTHONPATH": ".", + "PYTHONDONTWRITEBYTECODE": "1" + }, + "exit_code": 0, + "stdout": "................................ [100%]\n32 passed in 0.15s\n", + "stderr": "" + }, + "findings": [ + "ADR002 remains accurate as bootstrap architecture; current deployment claims unverified and not reaffirmed.", + "ADR002 D4 does not supply Codex autopilot, scope authorization or file-source override.", + "ADR004 connectivity-only intent remains compatible; historical Hub topology and broad security-assurance rationale are obsolete or unproven and prominently qualified.", + "Existing September supervision/change gates and accepted NetKingdom model supply mandatory current controls; no fresh authority or posture change requested.", + "accepted-1 bytes retained exactly; publisher must retain existing immutable accepted-1 route and publish reviewed annotations as accepted-2, not overwrite history." + ], + "new_human_decision_required": false, + "reason": "No original architectural decision or current authority is expanded; annotations apply existing accepted constraints and correct historical/current scope.", + "historical_publication": { + "strategy": "Explicit per-document historical_revisions preserves hash-pinned actual served accepted-1 HTML from source-owned historical artifacts, even in a clean fresh build. Source snapshot identity/revision/digest and page provenance commit/digest are checked; conflicting immutable existing bytes fail.", + "served_original_source_commit": "4039c9d1c08c92014ecc0a65dda63cc73ba187bb", + "actual_served_pages": [ + { + "id": "CUST-ADR-002", + "url": "https://policy.coulomb.social/adr/custodian-agent-runtime/v1/revisions/accepted-1/index.html", + "sha256": "ea4eae05b62d50cd8204a47c1a4f3e3e0beda571880ed1de93ccbb17987d84aa" + }, + { + "id": "CUST-ADR-004", + "url": "https://policy.coulomb.social/adr/custodian-connectivity-first/v1/revisions/accepted-1/index.html", + "sha256": "3db1b0f5c50543ff0fb022ea67f1d85b30f8ff691eaa1a2443220b7474b54de7" + } + ], + "publisher_tests": "30 tests passed, including five new retention/corruption/escape regression tests.", + "actual_preview": "publisher-preview-proof.json proves both old immutable URLs byte-exact and current accepted-2 annotation pages in a fresh local output. No live publication claimed.", + "inventory": "Only existing two canonical corpus records remain active publications. Historical source/page artifacts live under docs/evidence outside canon/ADR selectors; they are explicit build dependencies in publication.json, not extra governing records or stale documents hidden from currency checks." + } +}