Operation
This section is for operators running Synchronic Web infrastructure in real environments.
It covers deployment, service roles, network API behavior, routine operations, and protocol specifications.
Unless otherwise noted, examples target the deploy/compose/general stack.
Deployment
Section titled “Deployment”This section describes how to bring up and manage the reference runtime stack used throughout the rest of this guide.
Compose deployment
Section titled “Compose deployment”The Compose deployment is the baseline operating mode for local, staging, and many production-like environments.
It works with Compose-compatible runtimes such as Docker Compose, Podman Compose, and podman-compose.
It provides a predictable process model so operators can troubleshoot behavior without guessing which component wiring changed.
Required/important environment variables:
COMPOSE_PROJECT_NAME(recommended): stack identity; isolates generated volumes and prefixes container/network namesSECRET(required): Root secret supplied only to JournalINTERFACE_SECRET(required): independently rotatable Interface bearer supplied to Journal and Gateway and persisted in private Root state; it must differ fromSECRETthroughout installation and rotationINTERFACE_ADMINS(defaultadmin): comma-separated local usernames installed as(*state* <name>)administrators on a fresh databaseADMIN_USERNAME/ADMIN_PASSWORD: independent identity-provider bootstrap accountHTTP_PORT(default8192): published HTTP portHTTPS_PORT(default8193): published HTTPS portPERIOD(default2): stepping cadence parameter passed to journalWINDOW(default1024): retention window for unpinned historyTLS_CERT_HOST_PATH(optional): host certificate file mounted into routerTLS_KEY_HOST_PATH(optional): host key file mounted into router
Start:
COMPOSE_PROJECT_NAME=sync-local SECRET=root-password \INTERFACE_SECRET=interface-password ADMIN_PASSWORD=admin-pass \tests/api/local-compose.sh upSmoke validation:
COMPOSE_PROJECT_NAME=sync-local tests/api/local-compose.sh smokeDirect local HTTP deployment (no TLS):
COMPOSE_PROJECT_NAME=sync-dev SECRET=root-password \INTERFACE_SECRET=interface-password ADMIN_PASSWORD=admin-pass \HTTP_PORT=8192 HTTPS_PORT=8193 \docker compose -f deploy/compose/general/compose.yaml up -dOptional public TLS deployment with the same compose file:
COMPOSE_PROJECT_NAME=sync-prod \TLS_CERT_HOST_PATH=/absolute/path/to/fullchain.pem \TLS_KEY_HOST_PATH=/absolute/path/to/privkey.pem \SECRET=root-password INTERFACE_SECRET=interface-password \ADMIN_PASSWORD='<independent-password>' ORIGIN=https://example.com HTTP_PORT=80 HTTPS_PORT=443 \docker compose -f deploy/compose/general/compose.yaml up -dStop without deleting data:
COMPOSE_PROJECT_NAME=sync-dev docker compose -f deploy/compose/general/compose.yaml downOnly add -v when you intentionally want to delete that stack’s database and identity-provider volumes.
The default stack includes:
- journal runtime (
journal-sdkplus mounted general Lisp deployment inputs) - router/nginx entrypoint
- gateway API service
- explorer UI
- workbench UI
- file-system WebDAV service
The compose stack does not use a separate immutable general image. Instead,
journal-sdk starts through deploy/compose/general/run.sh, which reads mounted
records/lisp/*.scm files. Sync Web 1.5 supports fresh database installation
only. Its installer rejects every nonfresh root atomically, so
JOURNAL_UPDATE=1 cannot update an existing database with this release line.
Compose startup accepts only the exact successful installer result. A process
failure, Scheme error value, or malformed result exits nonzero before writing the
fresh version marker or launching the server, and result/credential content is
omitted from diagnostics. With JOURNAL_UPDATE=0, a correctly version-marked
database reopens normally without reinstalling or interpreting mounted record
source during startup.
The 1.5 Tree-native value layout removes the released Document wrapper and all record-code migration machinery. Do not apply 1.5 in place to a supported 1.4.x database or an earlier 1.5 development database.
Root remains host-only and is never supplied to Gateway or persisted. The independently rotatable Interface bearer is private Root state so trusted periodic orchestration can reenter the ordinary Interface. It never enters Ledger/Federation objects, user state, proofs, traces, or public configuration. Treat Journal backups as live Interface credentials and rotate after disclosure or untrusted restoration.
Transitioning from 1.4.x
Section titled “Transitioning from 1.4.x”Before starting 1.5, stop the old journal cleanly and preserve:
- a consistent copy of the RocksDB database volume;
- the exact 1.4.x journal image or binary;
- deployment configuration and the secrets needed to authenticate historical reads; and
- a manifest recording the image digest, platform version, chain size, and backup checksum.
Restore that archive in isolation and verify representative historical reads,
including index 0 and (*state* *time*), before changing the production
service. Keep the archive read-only: do not run periodic steps, writes, or bridge
synchronization against it. Start 1.5 with a new database volume, recreate local
policy and reciprocal bridges, and import only application values selected for
the new history. A logical import does not preserve old Merkle roots, signatures,
pins, or journal identity.
Routing
Section titled “Routing”The service split allows teams to scale or replace one layer at a time. For example, router behavior can be adjusted independently from journal runtime updates. The router service is the public nginx entry point for the deployment. It serves runtime query routes and UI routes:
| Route | Purpose |
|---|---|
/interface | Scheme or JSON request endpoint selected by request Content-Type. |
/docs | Gateway Swagger/OpenAPI documentation and route orientation. |
/api/v1/... | Versioned gateway API endpoints proxied to gateway service. |
/explorer/ | Browser UI with Ledger, Stage, Self-local Access, and admin-only Self-local Admin modes. |
/workbench/ | Developer-oriented query workspace with API aids. |
/webdav/ | WebDAV file-system projection: /stage (mutable), /ledger/state (current committed, index optional), /control/pin (pin directives). |
Router mode is selected at startup:
- HTTP mode when TLS cert/key files are not found.
- TLS mode when both cert/key files are present.
Network API
Section titled “Network API”Implemented by records/lisp/interface.scm on top of root.scm, standard.scm, and ledger.scm.
Permission boundaries are central to safe operation, so operators should treat function families as security domains.
Function Families
Section titled “Function Families”| Family | Description | Functions |
|---|---|---|
| Public bridge/control/proof | Direct protocol operations with no signed application invocation. Outward Gateway $federation context is rejected. | size, info, route, synchronize!, constrained trace, trace-batch |
| Authenticated application | Local calls use session/API-token authentication; signed federation is limited to scalar staged access, dedicated staged batch access, and committed scalar resolution. | get, set!, get-batch, set-batch!, resolve |
| Authenticated committed batch | Gateway outward federation context is rejected; Interface groups canonical committed paths and routes compatible remote groups internally. | resolve-batch |
| Local retention/policy/admin | Authenticated and always mutated at Self; outward federation context is rejected. | pin!, unpin!, pin-batch!, unpin-batch!, authorization, config, bridge, admin, window, and secret operations |
| Root/Admin | Root commands for runtime mutation and administrative lifecycle management. | *eval*, *call*, *step*, *set-secret*, *set-step*, *set-query* |
Function Reference
Section titled “Function Reference”Use this reference when building runbooks or on-call procedures. The same function names appear in Explorer/Workbench, automated scripts, and incident diagnostics.
Public Functions
Section titled “Public Functions”| Function | Purpose |
|---|---|
size | Current permanent-chain size |
synchronize! | Accept a reciprocal signed-head exchange and return the receiver’s signed head |
info | Return the public root-signed journal descriptor |
route | Follow committed bridge control state and return terminal routing/authentication material |
trace | Return only authorized public crypto/bridge proof structure rooted at an index |
trace-batch | Return one compact authorized union proof for paths sharing one history anchor |
Restricted Functions
Section titled “Restricted Functions”| Function | Purpose |
|---|---|
get | Read current Stage, locally or through a signed working route |
set! | Stage a write locally or through a signed working route |
resolve | Resolve exact committed content locally or through a signed route/history cursor |
call! | Execute a staged Scheme program locally as the root caller or a configured Interface administrator; rules and ownership cannot grant it |
pin! / unpin! | Mutate only Self’s retained permanent proof state |
authorize! / deauthorize! / authorizations | Manage Self-local path-scoped get/set!/resolve grants |
bridge! / delete-bridge! | Manage reciprocal bridges locally |
config / update-config! | Read or update local ledger configuration under local policy |
get-batch / set-batch! | Perform ordered snapshot reads or atomic prewrite-snapshot mutations locally or over one signed working route; conditional writes require both read and write authority for every member |
resolve-batch / pin-batch! / unpin-batch! | Perform grouped committed resolution and atomic origin-local retention changes without outward Gateway federation context |
*secret* | Rotate the local interface secret/key material |
*admins-get* / *admins-set* | Read/replace local administrator principals |
*window-set* | Update the local public retention window |
Deleting a bridge removes its active route/configuration and associated grants but retains the alias↔journal-root identity binding. Re-establishing the same alias/root is valid and idempotent; substituting another root or moving the root to another alias is rejected as an identity conflict.
Root/Admin Functions
Section titled “Root/Admin Functions”| Function | Purpose |
|---|---|
*eval* | Evaluate arbitrary Scheme in admin context |
*call* | Invoke function with root object |
*step* | Execute full step cycle |
*set-secret* | Rotate root/admin secret |
*set-step* | Replace step handler |
*set-query* | Replace query handler |
Root Plane API
Section titled “Root Plane API”root.scm provides authentication of privileged operations, enforces root mutation/update discipline, and defines hook points for query and step behavior.
Root Object Methods
Section titled “Root Object Methods”These are the public root methods exposed by the root module’s base record object.
| Method | Signature | Description |
|---|---|---|
get | ((root 'get) path) | Read value at path; returns value, (nothing), or a directory listing. |
set! | ((root 'set!) path value) | Write value at path; supports structured node/object values and deletion via (nothing). |
copy! | ((root 'copy!) source target) | Copy source to target; a missing source deletes the target. |
equal? | ((root 'equal?) source target) | Exact structural equality check between two paths. |
equivalent? | ((root 'equivalent?) source target) | Digest-equivalence check between two paths. |
Root Commands
Section titled “Root Commands”These are public root commands handled by the transition function in root.scm.
| Command | Signature | Description |
|---|---|---|
*eval* | (*eval* <admin-secret> <expression>) | Evaluate expression in admin context. |
*call* | (*call* <admin-secret> <function>) | Invoke function with root object and persist resulting state. |
*step* | (*step* <admin-secret>) | Execute configured step handler pipeline. |
*set-secret* | (*set-secret* <old> <new>) | Rotate admin secret used by root plane. |
*set-step* | (*set-step* <admin-secret> <step-function>) | Replace step handler logic. |
*set-query* | (*set-query* <admin-secret> <query-function>) | Replace query handler logic. |
This API is intentionally powerful and low-level, so access should be tightly controlled and audited.
General API Bootstrap
Section titled “General API Bootstrap”interface.scm overlays the instantiated ledger object and dispatches ((function ...)) requests to ledger and bridge-helper methods, with permission checks on each call.
It also handles remote bridge fetch/merge flows before handing the final operation to ledger. A grant remains a normal recursive prefix grant. When a caller requests an ancestor directory of an applicable grant, the interface returns that directory’s ordinary immediate listing. This makes folder names traversable without synthetic parent grants, but reading or mutating any listed child still requires authorization for that child. Proof responses preserve the committed directory listing without granting access to child content.
General API Methods
Section titled “General API Methods”| Method | Permission | Description |
|---|---|---|
size, info | Public control | Return local public metadata. |
route, synchronize!, constrained trace | Public control | Operate on bridge/proof control structure, never as signed application calls. |
get | Authenticated/federatable | Read current staged content under terminal-local policy. |
set! | Authenticated/federatable | Stage a write under terminal-local policy; optional expected content makes it conditional and requires read authority. |
call! | Local admin | Interface loads the current staged procedure once, evaluates it outside sync-let in a masked environment, and runs it non-atomically as root or a configured local Interface administrator. Namespace owners, policy grantees, and remote principals are denied before program loading. |
resolve | Authenticated/federatable | Resolve exact committed content and verify optional returned proof. |
pin!, unpin! | Local authenticated | Retain/remove proof only in Self’s permanent chain. |
get-batch, set-batch! | Local authenticated | Read one staged snapshot or atomically write staged paths; optional expected values make every write conditional. |
resolve-batch, pin-batch!, unpin-batch! | Authenticated paths; local mutation | Resolve ordered committed paths or atomically mutate Self’s retained proof state. |
authorizations, authorize!, deauthorize! | Local authenticated | Inspect or mutate Self-local grants. |
bridge!, delete-bridge! | Local admin | Manage reciprocal bridges. |
config, update-config! | Local admin | Inspect or mutate local ledger configuration. |
*secret*, *admins-get*, *admins-set*, *window-set* | Local admin | Manage local interface identity and policy. |
Root commands (*eval*, *call*, *step*, *set-secret*, *set-step*, *set-query*) remain Journal-local in the standard deployment. Gateway receives only INTERFACE_SECRET and does not expose the Root plane.
This keeps externally visible behavior stable while allowing implementation details inside ledger classes to evolve.
Public ledger/interface paths use flat Scheme lists or JSON arrays, for example (*state* alice notes) and ["*state*", "alice", "notes"]. Nested path lists remain an internal ledger storage detail and should not be used in API requests.
Dedicated batch and conditional-write contract
Section titled “Dedicated batch and conditional-write contract”Every dedicated batch accepts at most 1,024 paths. Malformed, over-limit, and mismatched-cardinality requests fail before mutation. Empty read/write/retention batches are identity operations; trace-batch alone requires at least one path because it must select a history anchor. Results preserve request order and duplicates; a missing value is (nothing), not #f or (unknown). There is deliberately no arbitrary mixed batch! endpoint and no general copy endpoint. Application-specific orchestration belongs in administrator-only staged call! programs.
get-batch reads every staged path from one snapshot. resolve-batch groups complete origin-relative paths by exact route and history anchor, verifies one compact proof per compatible remote group, and returns only ordered content plus optional origin-local pinned? status. trace-batch requires one history anchor and returns the compact serialized union proof itself. pin-batch! resolves and verifies all required remote proof groups before one atomic Self-local retention mutation; unpin-batch! atomically applies digest-preserving local cuts. Any malformed or failed member rolls back the entire retention change.
Conditional set! distinguishes an omitted expected field from every explicit value, including #f and (nothing). Conditional set-batch! requires one expected value per path. All expectations compare against the same pre-write Stage snapshot before any replacement is applied; duplicate paths therefore compare with the same old value, while successful replacements retain input order and the last duplicate wins. A mismatch returns #f without changing Stage or its transition history. Conditional writes require both exact get and set! authorization because equality is observable. Concurrent writers using the same expected value have one winner; colliding Journal evaluations retry against the new root and return #f after the winner commits.
Scheme examples:
((function get-batch) (arguments ((paths ((*state* alice one) (*state* alice missing))) (expression? #t))) (authentication ((identity (*state* alice)) (credentials "secret"))))
((function set-batch!) (arguments ((paths ((*state* alice one) (*state* alice two))) (values (new-one new-two)) (expected (old-one old-two)) (expression? #t))) (authentication ((identity (*state* alice)) (credentials "secret"))))
((function resolve-batch) (arguments ((paths ((-1 *state* alice one) (-1 peer-a -1 *state* bob shared))) (pinned? #t) (expression? #t))) (authentication ((identity (*state* alice)) (credentials "secret"))))Equivalent Gateway JSON:
{ "paths": [["*state*", "alice", "one"], ["*state*", "alice", "two"]], "values": ["new-one", "new-two"], "expected": ["old-one", "old-two"], "expression?": true}The Gateway exposes dedicated /api/v1/general/{get-batch,set-batch,resolve-batch,trace-batch,pin-batch,unpin-batch} routes. JSON and Scheme requests use the same argument shapes and receive the same Journal semantic errors. HTTP body, response, and timeout limits still apply independently of the 1,024-path cap.
Monitoring
Section titled “Monitoring”Gateway Prometheus metrics are internal deployment telemetry. In the Compose stack, scrape http://gateway/metrics from a collector attached to the private sync-net network. Gateway has no host-published port, and the public router returns 404 for exact /metrics requests in both HTTP and TLS modes. Migrate monitors that previously scraped router /metrics to the internal service endpoint or another explicitly private collector.
Operations
Section titled “Operations”This section provides common operational procedures. Each example includes both Lisp and JSON forms. These are direct calls that can be run manually, but they also serve as templates for operational automation.
Secret Rotation
Section titled “Secret Rotation”Secret rotation is the minimum operational hygiene task for any deployed environment and should be part of regular runbooks.
Rotate interface secret
Section titled “Rotate interface secret”((function *secret*) (arguments ((secret "new-password"))) (authentication ((credentials "old-password")))){ "function": "*secret*", "arguments": { "secret": {"*type/string*": "new-password"} }, "authentication": { "credentials": {"*type/string*": "old-password"} }}Rotate root/admin secret
Section titled “Rotate root/admin secret”(*set-secret* "old-admin" "new-admin")[ "*set-secret*", {"*type/string*": "old-admin"}, {"*type/string*": "new-admin"}]Runtime lifecycle and configuration
Section titled “Runtime lifecycle and configuration”A configured local Interface administrator may stage one procedure at
(*state* *periodic*). When an outer periodic step creates a new Ledger index,
Interface launches that program exactly once through nonblocking call! and
passes the committed zero-based index as its sole argument. Unchanged steps and
internal step continuations never launch it. Different indexes may
run concurrently and finish out of order; program effects retain ordinary
non-atomic call! semantics. Deleting the path disables later launches. This is
not a durable scheduler/outbox: process failure after commit but before detached
dispatch can lose that launch.
The bundled 1.5 record composition is not an in-place record-code migration
surface. Do not replace Standard, Tree, Chain, Ledger, Federation,
Authorization, Interface, or Root code in a persistent deployment through
*eval*, *call*, or direct root-layout mutation. Those root-plane operations
remain privileged implementation mechanisms, not a supported upgrade procedure.
Supported runtime administration uses the query-interface operations documented
above: secret and administrator changes, config/update-config!, retention
window changes, authorization rules, and reciprocal bridge management. Apply
record-code changes by creating a fresh database with the new release, then
validate service behavior before switching traffic.
Inspect current public configuration through the authenticated config call:
((function config) (authentication ((credentials "password")))){ "function": "config", "authentication": { "credentials": {"*type/string*": "password"} }}For a release transition, preserve the old database/runtime pair first, deploy a
fresh candidate under a separate Compose project and ports, run health and
semantic probes, and switch only after the fresh stack passes. Never use
JOURNAL_UPDATE=1 as a 1.4.x-to-1.5 conversion mechanism.