Files
PaperClipAI/maps/agent-access-map/instance-operations.md
T
DottaandPaperclip 567c043b17 feat(server): expose bounded hot-upgrade readiness (#18037)
## Thinking Path

> - Paperclip coordinates agent work and keeps its authority in the
server.
> - Remote native runners can preserve execution through a server
replacement.
> - Deployment operators need evidence that current runs support that
recovery.
> - Process-local drain counters do not establish this fact.
> - This PR adds an optional, operator-only readiness observation from
existing records.
> - A deployment consumer can use that report while the existing runtime
retains recovery authority.

## Linked Issues or Issue Description

Refs #17439.

**What happened?**

A deployment cannot distinguish recoverable remote native executions
from runs that require a task drain. The existing status endpoint
reports only process-local counts.

**Expected behavior**

An instance operator can request a bounded readiness report without
stopping admission or exposing checkpoint material. Missing ownership or
persistence evidence must prevent readiness. Ordinary status reads must
keep their current cost.

**Steps to reproduce**

Run a remote native task. Read the task-drain status. It reports active
work but supplies no recovery eligibility. Deployment code therefore has
no affirmative signal to select an active-run handover.

## What Changed

- Add `GET /api/instance/task-drain?upgradeReadiness=1` for instance
administrators and existing Cloud control callers.
- Return aggregate eligibility from current run identities, controller
leases and bound opaque checkpoint headers. Unknown work, pending
admission and incomplete reads prevent a positive report.
- Bound the explicit read to 1,001 rows, encrypted headers of at most
256 KiB each and 8 MiB total, and a two-second SQL statement timeout in
a read-only transaction. Keep ordinary status reads in memory.
- Add PostgreSQL, count-transition and route authorization tests. Update
the API contract, operator docs and access maps.

## Verification

- All seven readiness cases pass against an isolated PostgreSQL 18
fixture. They cover missing checkpoints, legacy adapters, missing
process/session identities, foreign owners, expired leases, missing
lease tokens, failure state and in-flight work. The positive SQL fixture
uses the real Runner checkpoint writer and encryption. Regular sandbox
workspace identity and plugin environment-lease identity are tested with
independent IDs. Stopped/released/undispatched plugin tasks and every
mismatched identity field are rejected. Local/legacy/malformed/oversized
or mismatched headers are rejected. A held PostgreSQL table lock proves
the two-second cancellation budget, rollback/connection release and
unrelated query responsiveness.
- All 123 focused readiness, instance-settings and Cloud control
assertion tests pass, including operator-only access and no readiness
read on ordinary status requests. Runner’s 168 checkpoint tests pass.
Runner and server typechecks pass after review fixes.
- Workspace typecheck, full build, module-boundary and map checks passed
locally before the master rebase. Current-head GitHub CI is now green,
including typecheck, build, all grouped/serialized server and Runner
tests, browser shards, policy and review-dispatch checks. Greptile
completed cleanly at 5/5 for `f15fb0c7e9dfb975090cd5d791a1c8e6701275f8`;
all actionable threads are resolved.
- The broad local test run was stopped after the macOS embedded
PostgreSQL fixture failed to bootstrap. The SQL test was then run on the
isolated PostgreSQL fixture. No assertion or timeout was weakened. One
unrelated existing route test exceeded its 15-second limit under
concurrent local builds; it passed on one isolated retry and the
subsequent whole route suite passed.
- Hosted active-run upgrade acceptance has not run. This PR supplies an
observation; it does not change rollout policy or establish live
continuity by itself.

## Risks

This is an instance-wide observation, so company members and agent keys
must not receive it. A readiness snapshot can age as work changes;
shutdown and startup retain their existing execution authority and
fencing. The report does not validate a replacement artifact or
authorize a schema migration. It decrypts only bounded headers through
the checkpoint owner and delegates format/identity inspection to Runner;
full journal restoration and physical sandbox authentication remain with
recovery. No migration, recurring query, new checkpoint write or wire
protocol change is included. The additive Runner header inspection
contract reuses its existing parser.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, source inspection, tool
use and code execution. The host does not expose the exact serving model
ID or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass for the affected contracts;
the broad-run limitation is recorded above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 11:28:15 -05:00

199 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Installation, configuration, updates, and backups — agent access
Product map: [Installation, configuration, updates, and
backups](../feature-map/instance-operations.md).
Feature ID: `instance-operations`.
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
qualified. No live agent execution is claimed. Follow the [map contract](../README.md)
for format, permission checks, evidence and maintenance.
## `install-update`
Capability ID: `instance-operations/install-update`.
Review: `baseline`.
API: `not-applicable` — No uniform company REST updater API. Treat pre-start
installation as an operator exception or design an explicit delegated operator API.
Agent access: `operator-only` — Existing CLI install/update/rollback commands.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: No uniform company REST updater API. Treat pre-start installation as an operator
exception or design an explicit delegated operator API.
## `server-service`
Capability ID: `instance-operations/server-service`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/health`.
Agent access: `operator-only` — Existing CLI service/dev controls; health REST; owned
workspace services have separate agent APIs.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: Instance start/stop and task workspace start/stop are different capabilities.
Local service control is not agent company authority.
## `configuration`
Capability ID: `instance-operations/configuration`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/instance/settings`.
- `PATCH /api/instance/settings`.
- `GET /api/instance/settings/experimental`.
- `PATCH /api/instance/settings/experimental`.
Agent access: `restricted` — Board/admin instance settings; CLI configure/env; local
configuration files.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Settings APIs cover parts of configuration; pre-start database/binding/storage
configuration is local operator tooling.
Cloud stack Admins may update experimental settings through the trusted Cloud
actor without receiving other instance-admin powers. This uses the current
stack role on each request; company membership alone does not grant it.
Members, Support users, agents, and ordinary self-hosted sessions remain denied.
Cloud staging exposes experimental controls to instance admins and stack Admins.
It permits saved overrides of Cloud-disabled experimental defaults. Cloud-enabled
features remain true on every managed stack, including staging, and the settings
service rejects attempts to disable them with 403 before saving.
This exception requires a managed instance
and a provisioner-supplied `*.staging.paperclip.app` primary hostname; request
headers do not establish staging. Ordinary board members and agents still cannot
mutate instance settings. Only an explicit feature allowlist is editable on staging. Cloud
owner-admin elevation and managed-sandbox execution policy remain managed, and
production policy and other Cloud floors remain.
Local [route tests](../../server/src/__tests__/instance-settings-routes.test.ts)
cover stack Admin experiment access and auditing, denial for other instance
controls and actor sources, hidden-setting restrictions, and a spoofed request hostname;
the [Cloud actor tests](../../server/src/middleware/cloud-tenant-actor.test.ts)
cover role changes and preserved instance-admin isolation;
no live Cloud or agent-credential verification is claimed.
## `diagnostics`
Capability ID: `instance-operations/diagnostics`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/health`.
- `GET /api/instance/task-drain?upgradeReadiness=1` — instance-admin or signed
Cloud control only. Returns aggregate restart eligibility, never checkpoint
contents, task identities or credentials. Company members and agent keys are
denied. The explicit request performs bounded read-only SQL; ordinary drain
status remains an in-memory read. [Route coverage](../../server/src/__tests__/instance-settings-routes.test.ts)
and [PostgreSQL coverage](../../server/src/services/heartbeat/upgrade-readiness.test.ts)
establish this local boundary; hosted active-run continuity requires separate proof.
- `GET /api/liveness` and `HEAD /api/liveness` — public process startup status
and build commit only; no database readiness or workspace identity.
Liveness is anonymous and runs before actor/session resolution. Hostname and
signed-bootstrap endpoint validation still apply. It grants no instance control
authority. [Liveness tests](../../server/src/__tests__/liveness.test.ts) cover idle
drain, invalid ambient credentials, unavailable SQL, and startup recovery with
local Express fixtures; no live provider or agent access is claimed.
Agent access: `partial` — REST health plus local CLI doctor.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Health is an API; full local doctor/repair inspects host configuration and is not
equivalent to that response.
## `backup`
Capability ID: `instance-operations/backup`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/instance/database-backups`.
Agent access: `restricted` — Board/admin backup API; local CLI db:backup; restore into
an authorized separate target.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: API creation exists. Restore/lifecycle are operator workflows rather than ordinary
company agent capabilities.
## `runtime-setup`
Capability ID: `instance-operations/runtime-setup`.
Review: `baseline`.
API: `not-applicable` — these commands provision an operator-owned published package and local filesystem cache. They have no company-domain REST equivalent and deliberately bypass instance config, environment, and credential initialization.
Agent access: `operator-only` — explicit host/package provisioning through the runtime CLI, with the installed release’s verified assets. A company agent grant does not authorize another host’s installation or private operator cache.
Policy: Host setup verifies public pinned assets without model calls and requires the published server package layout/identity. Import requires a trusted manifest digest, exact installed source/profile identity, Linux x64 companion inventory/pack/ELF integrity, and a private operator-owned cache. Import performs no downloads or executable probes. A Pi companion does not enable remote Cursor or qualify credentials.
Evidence: `source-only` — reviewed at `9ef434fe79c57d976b8b03b14c5242db270b8320`. [Runtime CLI](../../cli/src/commands/runtime.ts), [instance-config bypass](../../cli/src/index.ts), [Pi provisioning](../../packages/paperclip-runner/scripts/provision-pi.mjs), [Cursor provisioning](../../packages/paperclip-runner/scripts/provision-cursor.mjs), and [companion importer](../../server/src/services/native-runtime/remote-pi-companion.ts).
Verification: `not-run` — Inspect setup identity/path and repeat reuse on an owned disposable published installation. Verify a matching trusted companion import and reject altered/cross-release/linked inventory while preserving unrelated files. Check no instance credentials are loaded and no model is called. Qualify actual adapter/account task execution separately.
Gaps: Source-checkout setup, different platforms, remote Cursor, provider execution, and published-package acceptance remain separate scopes. Local fixture materialization does not establish remote model readiness.