mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-31 22:24:16 +01:00
135 lines
7.6 KiB
Markdown
135 lines
7.6 KiB
Markdown
# Cloud configuration migration and package qualification
|
|
|
|
This procedure covers saved adapter preferences, the allowlisted nonsecret
|
|
startup configuration, and selected bundled plugin packages. The result is a
|
|
point-in-time report. It does not authorize a deployment, guarantee zero
|
|
downtime, establish general Railway admission, or prove that a volume can be
|
|
removed. Secret and key bytes, database credentials, artifacts, logs, local
|
|
storage, workspaces, and plugin state outside PostgreSQL need their own storage
|
|
and replacement checks. This includes the decision signing key and local
|
|
encryption keys. Their byte authority is unchanged by this procedure.
|
|
Runtime environment and secret equality, plus an actual HTTP handoff between
|
|
application processes, remain separate rollout prerequisites. The package digest
|
|
does not establish those conditions.
|
|
|
|
## Migration prerequisite
|
|
|
|
Stop every legacy file writer before the first import. This includes old
|
|
application replicas and operator commands that can write configuration or
|
|
adapter settings. One maintenance window is sufficient. The importer cannot
|
|
make an old file writer participate in its database transaction. Keep those
|
|
writers stopped after import; later file edits do not update database authority.
|
|
|
|
Keep the normal database backup and recovery procedure for the instance. Use the
|
|
new release with the same managed environment and database connection. The
|
|
server runs migration before constructing configuration-dependent services.
|
|
For an explicit source-checkout invocation, use:
|
|
|
|
```sh
|
|
pnpm exec tsx server/src/qualify-cloud-configuration.ts --migrate
|
|
```
|
|
|
|
The command uses `DATABASE_URL` and the normal Cloud environment. It does not
|
|
accept credentials as arguments. It writes the receipt to PostgreSQL and prints
|
|
a JSON report; no report file or local completion marker is required. Exit code
|
|
0 means the requested configuration/package check passed, 2 means the report has
|
|
blockers, and 1 means the operation failed. A fresh installation can report a
|
|
missing plugin registration before normal boot installation completes. Run the
|
|
check again after that installation settles.
|
|
|
|
## Database authority and retry behavior
|
|
|
|
The private `instance_settings` singleton `cloud-configuration-migration:v1`
|
|
contains the versioned receipt. The transaction locks that row and composes the
|
|
adapter and startup-config owners' atomic seed methods. Completion and both
|
|
seeds commit together. A failed write or crash before commit leaves no completed
|
|
receipt. A retry uses committed database state and never replaces a later
|
|
settings revision. Earlier independently seeded owner records remain authoritative.
|
|
|
|
The receipt records source kind, a digest of the nonsecret semantic candidate,
|
|
the imported revision, and bounded legacy external-registration evidence.
|
|
An absent startup configuration remains an authoritative `config: null`; it is
|
|
distinct from an uninitialized database record. No raw secret values are copied.
|
|
Once the receipt exists, ordinary boots do not reread legacy source files.
|
|
A replacement home can be empty or absent without changing saved authority.
|
|
|
|
All legacy readers have a 64 KiB limit. They require regular files, reject
|
|
symlinks and FIFOs, and use bounded reads. External registration inspection reads
|
|
metadata only. It never loads a registered module or follows a registered package
|
|
path. A nonempty, invalid, or unreadable registration file creates a durable
|
|
blocker. Removing the old home does not clear that blocker.
|
|
|
|
To resolve an external-registration blocker, stop its writer, deliberately
|
|
remove the unsupported registration metadata at the original source location,
|
|
and leave a present valid empty JSON array file. Read the current receipt revision
|
|
from the report, then run:
|
|
|
|
```sh
|
|
pnpm exec tsx server/src/qualify-cloud-configuration.ts --recheck-external-revision 3
|
|
```
|
|
|
|
Use the actual current revision in place of `3`. A changed revision, a different
|
|
source location, or a missing/invalid source file rejects the recheck. Reusing
|
|
the same container path with an empty home is insufficient. This is an explicit
|
|
operator resolution; qualification never clears the blocker automatically.
|
|
|
|
## Current packages and overlap comparison
|
|
|
|
Every qualification reads current settings revisions and plugin registrations.
|
|
It resolves selected packages from this image with the same bundled package
|
|
identity rules as normal loading. It verifies package bytes before importing a
|
|
trusted image manifest, then compares that manifest with the approved database
|
|
registration. Missing packages, missing evidence, incompatible versions,
|
|
unselected registrations, and integrity failures prevent qualification. Legacy
|
|
package paths and npm discovery cannot supply missing image bytes.
|
|
|
|
Image inspection happens outside database write locks. A short transaction then
|
|
locks and rereads the current configuration and registration records. A change
|
|
during inspection produces a blocker and requires a new check. The report gives
|
|
`adapterRevision`, `configRevision`, `configurationDigest`, and
|
|
`packageEvidenceDigest`. A historical completed receipt is evidence, not current
|
|
authorization. Call qualification again for a current result.
|
|
|
|
The server records this report before ordinary bundled-plugin reconciliation.
|
|
It retains `lastPackageMismatch` after later successful checks, so reconciliation
|
|
cannot erase the evidence seen before an upgrade. The report does not block
|
|
normal maintenance upgrades or replace capability approval. After an upgrade
|
|
settles, its current packages can qualify normally.
|
|
|
|
For a same-package comparison, capture the current release's
|
|
`packageEvidenceDigest` and pass it explicitly on the replacement:
|
|
|
|
```sh
|
|
pnpm exec tsx server/src/qualify-cloud-configuration.ts --expected-package-evidence sha256:REPLACE_WITH_THE_64_HEX_DIGEST
|
|
```
|
|
|
|
`configurationPackagesEligible` describes current database/configuration/package
|
|
compatibility. `samePackageOverlapEligible` is true only when an explicit expected
|
|
digest also matches. There is no permanent first-release baseline that would
|
|
prevent future maintenance releases from establishing their own evidence.
|
|
|
|
The package evidence digest covers selected packages, not container image bytes.
|
|
Distribution packages reuse and reverify their catalog digest. Builtin packages
|
|
have a bounded inventory of physical file bytes, modes, and contained symlink
|
|
text, including standalone pnpm dependency trees. Dangling or escaping links,
|
|
special files, more than 10,000 entries, depth above 32, or more than 256 MiB per
|
|
package fail verification. Inventory work is synchronous and linear in selected
|
|
package bytes. It runs only during startup before the application is constructed
|
|
or in the explicit operator process, with no idle polling. The report includes
|
|
`packageInspectionDurationMs`. Packages must remain immutable throughout a check.
|
|
|
|
## Verification scope
|
|
|
|
The focused PostgreSQL tests use two independent clients and separate home/image
|
|
roots. They import legacy settings, change saved revisions, remove the old roots,
|
|
reconstruct from the database, and start a real plugin worker from the replacement
|
|
image fixture. They also cover concurrent migration, commit failure and retry,
|
|
database failure, stale sources, durable external blockers, package mismatch,
|
|
maintenance reconciliation, and changes during manifest inspection.
|
|
|
|
Set `PAPERCLIP_CLOUD_CONFIGURATION_TEST_DATABASE_URL` only to an owned disposable
|
|
PostgreSQL database when embedded PostgreSQL is unavailable. The suite applies
|
|
migrations and writes/deletes test records. A complete release image, hosted
|
|
replacement, overlapping production processes, secret-byte migration, and volume
|
|
removal are not established by these local fixtures.
|