Skip to main content
Version: 0.1.0-alpha.4 (alpha)

Durable administrative audit

Capability audit and inspection extends this same owner with typed capability grant/call/provider evidence and optional policy-required admission. It preserves the query and resource contracts below.

latent-audit provides a bounded durable journal for security and administrative history. An optional node configuration opens one filesystem owner and one worker, shared by management, admission verification and native-cache producers. It creates no worker per tenant, release or service. See standalone node configuration and the closed configuration schema.

The standalone node stores the journal at dataDirectory/audit. Omission permits unaudited operation only while that reserved path is absent; existing history, partial initialization or a symlink prevents silent downgrade. Linux is the supported standalone configuration. The native journal requires Unix filesystem semantics and explicitly rejects unsupported platforms before mutation.

The earlier BoundedPhase2AuditJournal remains an explicit volatile embedding API. It starts no worker and loses its records on restart. Its bounded metadata maps and secret-bearing-key checks do not provide the durable guarantees below. The durable journal below has a separate ownership and recovery contract.

Typed records and identity​

Each AuditStoredRecord has a version, journal epoch, monotonically increasing sequence, previous-record digest, durable acceptance timestamp, scope and actor. Its closed payload is one of three forms:

PayloadMeaning
AuditObservationA diagnostic result with a fixed event kind, outcome, reason and optional cache kind. Acceptance queues it; it does not acknowledge durability.
AuditOperationAttemptAn attributed control operation with operation ID, exact request digest, action, expected generations and explicit replay flag.
AuditOperationConclusionA terminal result linked to its attempt sequence: Committed, Rejected, NotStarted or Unknown, with a receipt digest only where established and an optional typed canary decision summary.

Tenant and node scope are distinct. Management actors come from the authenticated principal; internal producers use fixed host actors. Identifiers remain separate: validated package manifest, component release, digest of received manifest bytes, selected evidence revision, policy role/scope/generation/digest, deployment and deployment generation, rollout, revision, route generation and lifecycle generation. Absent identities stay absent. A digest of rejected manifest bytes does not assert a valid package, and trusted-local content has no invented package identity.

Release attempts also require the digest of the entire validated canonical prospective lifecycle receipt. This binds the exact preview while preserving its status as a preview. Expected lifecycle and deployment generations use separate fields. These records, copied receipts and diagnostic successes grant no admission, execution or promotion authority.

The durable model has no arbitrary attribute map or free-form reason text. Strings, policy rows, digests and complete encoded record envelopes are checked before queue admission; unknown fields, duplicate fields and explicit null options are rejected. Raw envelopes, credentials, private paths, signing keys, payloads and external error bodies are not audit fields. Event kinds and reasons are suitable fixed metric dimensions; identities and digests are not.

Mutation durability and ambiguous outcomes​

The release adapter validates the complete prospective success or rejection response before beginning the critical audit protocol. ReleaseAuditGuard reserves both an attempt record and its terminal record, then waits for the attempt to become durable on the existing bounded control worker. Only afterward does it mark the mutation started and enter the catalog operation. Audit waits occur outside lifecycle, signing-authority and catalog commit fences; the audit worker never calls back into those owners.

Control adapters use reserve_control_critical to synchronize with the audit worker's short memory-state fence before checking the unchanged finite journal and queue limits. Recovery snapshots and reconciliation use the same fence. Journal I/O stays outside it. Capability dispatch and diagnostic capture retain their nonblocking reservation APIs; a pending critical operation or exhausted capacity still rejects a new control reservation before mutation.

The guard accepts a known conclusion only from the actual matching lifecycle receipt, or an exact scoped retained operation lookup after an error. The request identity and full preview receipt digest must match. Exact retries record the original receipt and replay flag; they do not claim a second state transition or fresh eligibility. A prospective receipt alone cannot prove a commit.

With audit configured, publication, retirement, evidence renewal and deployment apply/delete fail before mutation when their required audit begin cannot be accepted. Revoke alone may continue on audit capacity or availability failure: its ordinary durable lifecycle transaction is still mandatory, and the response reports AuditUnavailable while a fixed counter records the gap. This exception does not bypass authentication, validation or the lifecycle ledger.

Mutation disposition and audit acknowledgement are independent. A committed catalog operation stays committed if terminal audit storage fails. Its acknowledgement is OutcomeUnknown, not a fabricated rejection or rollback. Likewise, a durably recorded Unknown conclusion does not become a known outcome merely because its record was written successfully. Responses expose Durable, OutcomeUnknown, AuditUnavailable or Disabled, with the attempt sequence when one exists. Direct host embeddings must explicitly compose the same adapters; the directory catalog is also usable without them.

Dropping an accepted attempt before mutation_started produces NotStarted; dropping it afterward produces Unknown. Its prepaid terminal capacity remains owned by the worker. Deployment adapters bind the normalized request and actual returned deployment/catalog generation. Managed deployment operations retain exact receipts for startup reconciliation. A matching retained receipt can establish the committed result; an absent receipt or an unmanaged deployment attempt leaves the outcome unknown. Recovery never repeats the mutation.

Storage, recovery and retention​

The journal uses private current-UID directories (0700) and ordinary files (0600), one root lock, an immutable record file per sequence, a durable head and one bounded intent. Ancestor inspection rejects symlinks, foreign ownership and unsafe writable parents, except root-owned sticky system temporary directories. Missing ancestors are created privately and synced after bounded lexical path validation. Unknown files, links and malformed retained history are preserved and cause failure rather than being silently removed or adopted.

An append syncs its staged record and intent, publishes the exact record, then syncs the new head before acknowledging durability. Recovery validates hashes, lengths, canonical records and the old/new head relationship before rolling a single interrupted transaction forward. It never resets the sequence behind a missing acknowledged record. The mode marker distinguishes interrupted first initialization from disappearance of a previously initialized head. Per-append write work is bounded independently of retained history; startup scans are bounded by the configured count and byte ceilings.

The SHA-256 chain detects inconsistent or missing content within the trusted private-filesystem boundary. It is not a MAC, signature, external witness or protection against the node owner rewriting the whole journal and head.

Startup opens the journal before catalog recovery and reconciles its at most one pending critical attempt before serving management requests. A matching retained release receipt establishes the outcome. An absent or evicted lifecycle-ring receipt means Unknown; an uncertain lifecycle transaction must first recover. Recovery never reexecutes the mutation. Durable unknown outcomes remain counted after restart. Volatile loss counters cannot establish prior-session completeness, so previousSessionLossUnknown is explicitly true after reopening.

Retention rejects new records when full. There is no hidden pruning, overwrite, rotation or remote exporter. Operators must provision finite capacity; reducing limits cannot discard existing history to make it fit.

ResourceDefaultHard ceiling
Retained records4,09616,384
Encoded record16 KiB16 KiB
Retained record bytes64 MiB256 MiB
Metadata allowance8 MiB32 MiB
Queued operations / bytes64 / 256 KiB256 / 1 MiB
Records per query page128256
Encoded page allowance256 KiB1 MiB
Retained query owners416
Aggregate page allowance1 MiB4 MiB
Entries scanned per page1,0244,096

These are independent limits with validated minimums and dependent metadata bounds. A page reserves four times its requested encoded allowance for decoded and response ownership, so aggregate bytes may reject it before owner count. Critical terminal reservations cannot be consumed by diagnostic or query traffic. Snapshots expose retained and reserved records/bytes, queued work, page owners, pending attempts and fixed loss counters. stage_bytes is a conservative 68 KiB reconciliation reservation while unhealthy, not a measurement of filesystem allocation or process RSS.

Query authorization and ownership​

AuditService.QueryPhase2Audit returns typed records. Tenant queries require an administrator bound to exactly the authenticated tenant. Node queries additionally require the trusted latent.node.operator claim; it grants no cross-tenant query access. Every query supplies an explicit scope and returns coverage with its records.

Cursors bind the journal epoch, exact scope and filters, position and frozen high watermark. They grant no authorization. Later appends are excluded from the same pagination sequence. Filters select event kind, actor and an inclusive time range over durable acceptance timestamps, not caller-supplied occurrence timestamps. Scan work counts nonmatching entries too: a valid empty ScanLimit page can have a continuation. Coverage reports retained floor, high watermark, scanned count, stop reason, dropped observations, durable unknown outcomes and prior-session loss uncertainty. Reaching the end does not prove complete observation coverage.

Queries have an absolute deadline checked before work, during scanning and after the final read/decode, including empty pages. Count, byte, scan and transport limits apply independently. An AuditPage owns its decoded allowance; conversion transfers the cloneable AuditResponseLease through response-body consumption and retained transport frames. Dropping the request future cannot refund bytes still owned by a queued read or response. A page lease retains its compact budget, not the journal root lock.

Shutdown first quiesces control producers, closes new audit admission and then observes the same worker's completion within a finite deadline. Already started attempts can still deliver their prepaid conclusion after close. A live attempt keeps the worker and root owned until completion or abandonment. A timed-out join retains ownership and prevents a clean shutdown report; dropping the handle does not synchronously perform filesystem cleanup or pretend the thread stopped.

Integrated producers and verification​

AuditedAdmissionAuthority captures accepted/rejected explicit verification and recovery, including publisher, provenance and SBOM checks performed by the underlying authority. It captures only available checked identities and policy identity. These are lossy diagnostics after the authority call, not separate records for every cryptographic subcheck. Verification can finish and queue a diagnostic before publication response preflight; such a record does not claim publication began or committed.

The configured native-cache preparation path captures persistent hit, miss and corruption decisions with identities from its sealed catalog input. Capture cannot change loading or preparation success. Resident prepared hits and raw cache operations retain their aggregate counters rather than creating an audit record for every access. Managed release operations and existing deployment apply/delete use the critical protocol above. No durable audit enqueue, disk I/O or worker is added to Invoke or the final activation-start gate.

Canary outcome observation separately collects bounded, attributable activation outcomes. It does not emit one durable record per invocation. The rollout coordinator uses exact retained receipts for progression and startup reconciliation. Canary promotion records its declared thresholds, selected/admitted-terminal and success/failure/slow counts, fixed verdict and reason. Its typed identities retain the policy digest, window epoch and evidence digest where available. Healthy evaluation alone never emits a committed promotion result. Rollback records the caller's expected target generation on the attempt and the validated historical target separately from the new route generation on committed conclusions. Exact receipt reconciliation also covers rollback; known rejected preparation creates no committed catalog receipt.

Focused tests exercise transaction cutpoints, missing acknowledged history, private paths, full-record capacity, exact replay, post-commit sink failure, scope/cursor/deadline behavior, response leases and shutdown with live attempts. The tests cover journal behavior and canary integration. For a live incident, inspect both the operation owner's retained result and the audit acknowledgement; neither a missing response nor an incomplete audit history proves rollback.