docs/runtime-semantics-and-recovery.md
Rama main · réplica de lectura del repositorio original.
# Runtime semantics and recovery
This document defines operational behavior that must be explicit before production.
## 1. Grant expiry during long-running jobs
An elevated job derives an immutable job grant at start.
Default:
~~~text
job_deadline <= grant_expiry
~~~
When the grant expires:
1. stop accepting new privileged mutations from that job
2. send graceful termination to the managed process/cgroup
3. after a bounded grace period, force termination
4. persist the final state
5. emit audit
Routine Scoped jobs do not need an elevated grant.
If a specific administrative job must outlive the interactive grant, require a separate action-specific completion grant with its own bounded deadline.
## 2. SQLite concurrency
SQLite is intentionally single-writer and acceptable initially.
Rules:
- only Broker opens the DB
- transactions are short
- never keep a transaction open while shell/deploy/migration/Docker work runs
- persist transition, commit, perform external work, persist next transition
- long-lived exclusion uses logical resource locks with deadlines, not long DB transactions
- enable WAL
- use busy timeout/backoff for short contention
Migrate only if measured contention becomes material.
### Resource-lock fencing
Locks with TTL/deadline must include a monotonically increasing fencing token.
A stale job can never release a resource or commit a protected step using an older token. Release is compare-and-delete on resource + owner/action_id + fencing token.
This closes the classic ABA race:
```text
A acquires token 1
A stalls and expires
B acquires token 2
A wakes up late
A must NOT release/overwrite B
```
### Idempotency crash window
For replay-protected effects, create an operation journal row before the external side effect:
```text
PENDING -> effect -> DONE
```
If the Broker crashes after the effect but before DONE, the next attempt does not re-execute automatically. It enters action-specific reconciliation or returns an indeterminate/reconcile-required result.
## 3. Idempotency is infrastructure metadata
Do not depend on the LLM to invent a stable idempotency key.
Preferred behavior:
- Gateway/integration layer generates or derives retry identity
- bind it to subject + canonical tool + normalized request hash + invocation identity
- use a client/transport invocation identity when available
- if no stable retry identity exists, do not auto-retry state-changing operations
Identical arguments do not prove a retry; the user may legitimately request the same action twice.
## 4. Secret management
The MVP has no secret-reading tools.
Default VPS mechanisms:
- root-owned files outside the repository
- systemd credentials
Broker resolves secret_ref internally and injects the value only into the target process.
Rules:
- Gateway cannot read plaintext secret storage
- model-facing tools cannot enumerate secret values
- secrets never enter audit payloads
- redact known secrets from stdout/stderr/logs where practical
External secret managers are optional adapters when a real need appears.
## 5. Approval friction
Routine unattended work uses pre-authorized Scoped policy.
Out-of-band approval is reserved for exceptional elevation.
This avoids approval fatigue while keeping administrative access deliberate.
## 6. Recovery
### Broker restarts during a job
- jobs run in managed systemd units/cgroups where appropriate
- every job has a deadline
- Broker restart reconciles persisted state with live units/processes
- orphan jobs are adopted for monitoring or terminated by policy
### SQLite corruption
Fail closed:
1. stop new Gateway/Broker writes
2. invalidate pending approvals
3. treat elevated grants as revoked
4. preserve damaged DB
5. restore latest verified backup
6. reconcile active job units
7. re-enable only after integrity checks
### Broker audit write failure (AUD-03)
Privileged or potentially state-changing requests follow a fail-closed audit
protocol. The Broker commits an append-only hash-chain `intent` event (bound to
the request invocation ID when present) **before** invoking an external effect;
it records a separate `allow` or `deny` outcome afterward. New or unknown
tool names are **mutating by default** unless explicitly reviewed as read-only.
Potentially mutating requests are serialized through this boundary.
- If durable intent cannot be written, the Broker rejects the operation
**before** any external mutation.
- If the effect happened but the outcome cannot be written, the response is
`reconcile_required`, **not** a success or a claim that the effect was
rolled back. The intent remains in the audit chain.
- On any audit append failure, the Broker latches a degraded state and refuses
subsequent state-changing requests, even if SQLite immediately recovers.
A new Broker process is required **after deliberate operator reconciliation**.
An operator must not retry unsafe actions automatically or clear the database
to bypass the fence.
- The operator should independently check the affected resource's actual
state, match audit `intent` to its invocation ID and operation journal,
inspect hash-chain integrity, repair storage safely, and decide whether a
restart is warranted. For operations with idempotency keys, replays use the
stored operation status; without stable keys, do not assume retry safety.
- Hash-chained intent and result are distinct database commits; they do not
make an external shell command, Docker call or filesystem write an atomic
transaction. A crash may leave a valid unmatched `intent` that requires
explicit inspection.
Audit events contain metadata, never request-body secrets. This gate does not
replace transactional approval/grant resolution, OAuth checks or revocation.
### Erroneously issued grant
Provide an operator command outside the AI surface:
~~~text
vps-agent revoke-all
~~~
It must:
- revoke all elevated grants
- block new elevated starts
- terminate or quarantine affected active jobs according to emergency policy
- emit an audit record/checkpoint appropriate to the maturity stage
Rotate credentials separately if credential compromise is suspected.
### Gateway route compromise
Stopping/removing the MCP route must not stop application workloads.
## 7. Backups
At the stage where these assets exist, back up:
- policy configuration
- SQLite state
- audit checkpoints
- deployment unit files
Do not include plaintext secrets unless intentionally encrypted.
## 8. Readiness
### Scoped production
Require:
- Gate 0A/0B and the typed privileged path passed;
- Scoped real-stack behavior proven for the documented use case;
- recovery tested for enabled state/jobs;
- secret path tested if secrets are used;
- Gateway/Broker removal leaves workloads running;
- release compatibility/support boundaries documented;
- long-running reliability evidence appropriate to the production claim.
The release candidate satisfies the implementation/E2E gates but does not yet claim the long-running R4 reliability history.
### Full production
Additionally require:
- grant/job expiry semantics tested
- revoke-all tested
- approval flow tested
- remote audit checkpointing tested
- network elevation separation tested