Skip to content

Add standalone delivery-suspension CLI commands #1378

Description

@dahlia

Motivation

An operator may need to prepare a maintenance notice before shutting down an application, publish its static representation, and cancel it while the application DB is unavailable. Requiring a custom TypeScript program or importing application configuration makes that workflow harder to review and can start unrelated application services.

Expose the standalone static tools through fedify delivery-suspension. The CLI manages a local fetched-only notice and public export; it does not discover an application DB, import the application, push activities or deploy files.

Proposed command surface

fedify delivery-suspension create --workspace WS --evidence EV --key-file JWK \
  [--operation-id ID] \
  (--spec FILE | --id URL --controller URL --verification-method URL \
   (--target-inbox URL | --target-origin ORIGIN) --end-time T \
   [--published T] [--start-time T] [--summary S] [--url URL])
fedify delivery-suspension update --workspace WS \
  [--start-time T | --no-start-time] [--end-time T] \
  [--summary S | --no-summary] [--url URL | --no-url] \
  [--expect-revision N] [--operation-id ID] [--evidence EV] [--key-file JWK]
fedify delivery-suspension cancel --workspace WS \
  [--expect-revision N] [--operation-id ID] [--summary S] \
  [--key-file JWK] [--evidence EV]
fedify delivery-suspension export --workspace WS [-o FILE [--overwrite]]
fedify delivery-suspension check \
  (--workspace WS | --artifact FILE | --spec FILE | --url URL) \
  (--snapshot --evidence EV | --live [--save-evidence FILE [--overwrite]] \
   [--allow-private-address] [--timeout MS] [--max-redirection N]) \
  [--format text|json]

This is proposed grammar, with report formatting available where applicable. Evidence and keys are read only for changed transitions that need them; no-op/replayed commands can be keyless. Spec and creation flags are exclusive, announcement fields are rejected for fetched-only mode, and origin input uses canonical ASCII with suggested corrections rather than implicit Unicode conversion.

An operator workflow is:

fedify delivery-suspension check --spec maintenance.json --live --save-evidence evidence.json
fedify delivery-suspension create --spec maintenance.json --workspace maintenance --evidence evidence.json --key-file controller.jwk --operation-id maintenance-create
fedify delivery-suspension export --workspace maintenance -o public/maintenance.json
# After maintenance actually finishes:
fedify delivery-suspension cancel --workspace maintenance --key-file controller.jwk --operation-id maintenance-cancel
fedify delivery-suspension export --workspace maintenance -o public/maintenance.json --overwrite

The operator publishes the exported file and required public control/key resources separately. Export success is local file completion, not remote deployment or peer acceptance.

Local state and recovery

Use a versioned private workspace, with a write-once identity manifest and recorded public key binding, immutable revision artifacts, authoritative head, full resolved pre-sign intents and operation receipts. Never persist the private JWK in workspace/evidence/output/logs. verificationMethod is the Multikey ID, not the HTTP-signature key ID.

Before signing, lock the local workspace and persist/fsync the complete normalized request, first-resolved published/proof-created times, operation ID and base/target revisions. Write the captured artifact once, atomically advance the head with supported durability steps, record the receipt, then remove the intent. Receipt filenames are the lowercase hex SHA-256 of the operation ID. The receipt body stores the exact operation ID and request, which are compared on replay. Lowercasing base64url hashes was rejected because it loses information.

A matching complete artifact can roll forward using the recorded public key without a private key. An incomplete same operation resumes with pinned inputs. Pending or ambiguous signed cancellation blocks later active mutations. Explicit cancellation may supersede an incomplete non-cancel intent only by burning its target revision and recording the new cancellation intent. Do not silently discard a pending cancellation or recycle revisions.

Export uses the static tool's head snapshot/atomic recorder contract and returns current committed bytes without re-signing or selecting an old active revision. Local locks do not prevent forks between copied workspaces on other hosts; stale PID alone does not justify automatic lock breaking. Generic repair/recover/show verbs and update-supersede flags were left out of this first complete workflow.

Checks and output

create, update, and cancel perform offline mutations using supplied evidence and the shared tools. create and update run control consistency and transition gates before signing, then self-verify the result; they do not require an as-yet nonexistent artifact to pass authenticity first. Cancellation can end state using its recorded create-time key binding during control-plane outage, without claiming that binding proves current public authority.

Spec live check is control-only preflight before a notice exists. Save the exact evidence captured by the shared library; do not implement a second CLI fetcher. Snapshot checks are zero-network, including contexts; live checks bypass the existing persistent CLI cache. Report shape, authenticity, evidence consistency, head-relative currentness and served representation separately. A forged higher revision is not an authoritative fork, and same-revision unproven equality is incomplete rather than a false conflict.

Use exit 0 for local success/check pass, 1 for decisive invalidity, 2 for input/I/O or actual corruption, 3 for incomplete evidence, and 4 for a local conflict. Preserve the existing global behavior of the CLI's argument parser. Decisive check failure takes precedence over conflict/incomplete findings. Stdout is artifact bytes or one report; diagnostics go to stderr. Do not make private-network access or key sources ambient global-config behavior.

Shipping criteria and docs

Test the five-verb parser, output/exit precedence, no-network mutation, cache bypass, intent/head/receipt crash points, terminal cancellation, keyless replay, filesystem-case behavior and secret boundaries. Verify supported Node/Deno/Bun and OS/filesystem combinations before advertising them. No app import or online publisher is needed.

Add docs/cli/delivery-suspension.md or a complete section in docs/cli.md, cross-link the static workflow in docs/manual/delivery-suspension.md, update packages/cli/README.md, actual CLI help/completion/config documentation, fedify-cli skill and CLI changelog. Keep filesystem recovery limits and the distinction between public export and private workspace explicit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions