Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/system-record-managed-ownership.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ name: System-record managed ownership evidence
#
# What it does NOT prove: predecessor entries run against the CURRENT binary,
# not against each pinned commit — no predecessor is checked out or built. The
# full-state CAS has not landed, so no verified apply is dispatched here.
# B3 active-replacement CAS exists, but this ownership artifact still does
# not dispatch a verified apply. Atomic apply, lost-response recovery, and
# maximum-size p99/RSS remain separate activation gates; this workflow must not
# be cited as evidence for them.

on:
push:
Expand Down Expand Up @@ -119,9 +122,20 @@ jobs:
test/internal-graph-policy.test.ts \
test/managed-oxigraph-ownership-v1.test.ts \
test/reserved-internal-graph-mutation-guard.test.ts \
test/system-record-apply-command-v1.test.ts \
test/system-record-atomic-apply-executor-v1.test.ts \
test/system-record-materializer-lifecycle-v1.test.ts \
test/system-record-control-barrier-integration-v1.test.ts \
test/system-record-capability-discovery-v1.test.ts \
test/system-record-inspection-v1.test.ts \
test/system-record-managed-mutation-admission-v1.test.ts \
test/system-record-materialization-epoch-adapter-v1.test.ts \
test/system-record-materialization-epoch-v1.test.ts \
test/system-record-next-state-v1.test.ts \
test/system-record-rdf-schema-v1.test.ts \
test/system-record-state-snapshot-v1.test.ts \
test/system-record-utf8-order-v1.test.ts \
test/system-record-verified-replacement-v1.test.ts \
test/store-scheduler-system-record-admission.test.ts

- name: Run live managed-ownership gate
Expand Down
10 changes: 8 additions & 2 deletions devnet/issue-2052-managed-ownership/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,10 @@ async function main(): Promise<void> {
(await countQuadsInGraph(server.queryEndpoint, SYSTEM_RECORD_V1_SHADOW_AGENTS_GRAPH));

// ---- Capability fail-closed matrix against the LIVE endpoint.
const ownership = createManagedOxigraphOwnershipControllerV1();
const ownership = createManagedOxigraphOwnershipControllerV1(
server.queryEndpoint,
server.updateEndpoint,
);
ownership.bindReadyGeneration();
const handoff: ManagedOxigraphSupervisorHandoffV1 = {
stopAndProveOwnedChildDead: async () => undefined,
Expand Down Expand Up @@ -638,7 +641,10 @@ async function main(): Promise<void> {
capability.throughEnabledChangelog =
withChangelog.getSystemRecordLaneControllerV1?.() !== undefined;

const terminalOwnership = createManagedOxigraphOwnershipControllerV1();
const terminalOwnership = createManagedOxigraphOwnershipControllerV1(
server.queryEndpoint,
server.updateEndpoint,
);
terminalOwnership.bindReadyGeneration();
terminalOwnership.invalidate('port-release-unproven');
const terminal = await build(
Expand Down
66 changes: 57 additions & 9 deletions docs/adr/0002-system-record-sync-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,10 @@ roots (15 current-plus-historical roots total), 16 fixed preallocated conflict-d
materialization epoch, and accounted bytes. Its digest domain is
`dkg-system-record-applied-state-v1\n` and excludes only the digest field. Global
capacity state has its own revision, live-record count, and accounted bytes.
The current authority sequence is derived from the retained contiguous lineage;
the current head version is stored as a separate storage-private predicate in the
same reserved RDF tuple. This keeps the frozen B1 applied-state codec and digest
stable while allowing the atomic writer to reject stale same-authority heads.
For every present record, `accountedBytes` is canonical and exact:
`64 KiB fixed state/security precharge + ownedSubjectTableBytes + projectionBytes +
pendingDeletionTableBytes`. The pending term is zero when omitted; current JSON size is
Expand All @@ -726,6 +730,11 @@ The exact canonical sorted duplicate-free prior subject list lives in a separate
indexed per-record reserved table in the same transaction boundary. Its encoded bytes
are capped at 256 KiB and committed by the state table digest/count; header and table
bytes both count toward per-record and aggregate accounting.
For every nonzero verified candidate authority sequence, the opaque authority summary also
binds the latest transition's prior-head digest. Storage consults that value only for a
local `+1` authority transition and requires it to equal the currently applied head digest;
ordinary same-sequence version advancement never derives predecessor authority from local
state or from a caller-authored field.

Stack B2 exposes a passive controller. Merely discovering it performs no work; an
explicit non-serializable activation lease opens a generation-bound session. Callers
Expand Down Expand Up @@ -847,6 +856,18 @@ callers cannot author a delete scope. Storage consumes it once and, for tombston
recomputes the table digest/count against the verified predecessor head before deriving
the exact deletion. Missing/mismatched/reused/cross-session payloads fail before dispatch.

The storage transition is guarded by both the reserved-state CAS and a
scheduler-fenced projection preflight. While holding the exclusive `agents` permit,
storage reads the exact prior/next subject union from the selected projection graph,
incrementally hashes its strict canonical graphless N-Triples lines under
`dkg-ka-projection-v1\n`, and compares digest, byte count, and quad count with the
applied snapshot. Canonical line-order failure or any present-state mismatch defers
with zero update dispatch, as does a pre-existing candidate-subject row in absent
shadow storage. For absent authoritative state, bounded rows on the exact next-subject
union are legacy content and the initial transaction replaces them. Equal-head
projection drift always defers. Inspected prior rows are never enumerated into the
SPARQL update.

The expected-state CAS covers `(stateRevision, appliedStateDigest, headDigest,
transitionLineage,
conflictEvidenceDigest?, ownedSubjectTableDigest,
Expand Down Expand Up @@ -955,15 +976,18 @@ The controller owns at most one aggregate session per store for the enabled
`disabled|enabling|enabled|reconciling|disabling|shutdown|unavailable`; transition
precedence is `shutdown > disable > recovery/revive > open`. Same-descriptor calls
coalesce/idempotently return and incompatible opens reject. `disabled -> enabling`
atomically seals admission before enqueueing its epoch transition. Every queued/running
mutation and V1 call binds activation and child-generation abort scopes at enqueue;
atomically seals admission before enqueueing its epoch transition. Every mutation
enqueued after activation intent and every V1 call binds activation and child-generation
abort scopes at enqueue. A managed mutation already queued on the default-off path is
rechecked at dispatch and rejected if activation has committed in the meantime;
transitions cancel queued retired scopes and drain or physically terminate running
ones before state changes. A different enabled-set descriptor requires disabling and
reopening this same aggregate session; `ontology` never creates a second controller,
barrier, epoch, or accountant.

The process-global scheduler accepts exactly one daemon-managed owned-store controller
registration. A second registration fails before capability exposure, open, or any
The process-global scheduler is the explicit single managed-writer activation gate:
it accepts exactly one daemon-managed owned-store controller registration. A second
registration fails before capability exposure, open, or any
mutation and can never enter recovery. Other unowned/legacy store
identities stay outside the capability and never wait on ordinary enabled-lane barriers,
although each enable handoff conservatively drains pre-existing untagged work.
Expand All @@ -981,8 +1005,9 @@ honor the bound; only ACK/health work in unrelated domains bypasses `agents`. A
generation/control transition seals every mutation for the managed store only. The default-off undefined path keeps current
O(1) head selection with no metadata allocation/evaluation. Because the scheduler is
process-global and disabled-mode work has no store identity, each enable takes one
conservative global watermark. Queued predispatch work may run or be removed/timeout
before dispatch. Active work must physically settle; a logical timeout never decrements
conservative global watermark. Queued predispatch reads may run or be removed/timeout;
managed writes queued before activation fail closed if they reach dispatch after commit.
Active work must physically settle; a logical timeout never decrements
the transition watermark. If an untagged active operation cannot be attributed and
proven settled, activation fails closed. Regardless of apparent completion, every
`disabled -> enabling` transition destroys the old managed HTTP client, stops/proves
Expand All @@ -1006,7 +1031,7 @@ SPARQL mutation consumes and reports one ordinary store slot as
`control_epoch_active_slot_ms` plus latency.

An HTTP 204 does not reveal whether a conditional update matched. The transaction
writes one bounded nonce/receipt only when full state, every root claim/reverse binding,
writes one deterministic state-bound receipt only when full state, every root claim/reverse binding,
epoch, and capacity match; a bounded post-read maps it to a typed result. Timeout,
lost/malformed response, or child-generation change in flight is indeterminate:
validated state is invalidated, wrappers dirty, and generation admission seals.
Expand Down Expand Up @@ -1164,8 +1189,11 @@ claim about serialized payload size. The object cache is disk-only.

One atomic record additionally has distinct preflight ceilings: 1 MiB encoded
bundle, 64 KiB signed head envelope, 10,000 quads/2,048 union subjects, 2 MiB
canonical decoded terms, 4 MiB encoded SPARQL request body, and 12 MiB weighted
end-to-end transient heap. Only one bundle decode/apply lease and one materializer write
canonical decoded terms, 1 MiB encoded exact-reserved inspection response, 4 MiB
encoded projection-inspection response and SPARQL request body, 8 MiB storage-local
retained preparation/inspection/receipt buffers, and 12 MiB weighted end-to-end
transient heap. The 8-MiB bound is a subset of, not an addition to, the 12-MiB
lease. Only one bundle decode/apply lease and one materializer write
may be physically in flight. Exact-object transport has two separate process-wide,
nonqueued permits: one outbound requester response stream and one inbound provider
response stream. Requester permit absence is typed slice-deferred; provider permit or
Expand Down Expand Up @@ -1455,6 +1483,26 @@ the materialization epoch, restores legacy authority for the cohort, and require
fresh complete activation gate before re-entry. Mainnet needs its own reviewed
activation release.

The B3 storage transaction may merge only as a default-unused boundary: production
composition retains the registry consumer and deliberately discards its matching issuer,
and no lifecycle path opens the lane. Before any producer or receiver receives that
issuer or opens the lane, the remaining storage activation gates are mandatory:

- verified same-version forks and root-claim collisions atomically quarantine the
incumbent with exact post-read and uncertain-write recovery;
- a tuple from a prior materialization epoch is recovered or replaced under the current
epoch instead of becoming a permanent validation mismatch;
- the 64-MiB runtime accountant is one injected process owner shared by decode, apply,
recovery, transport, control, and signature-verification reservations;
- the maximum 10,000-row/2,048-subject transaction fits the 12-MiB weighted lease and
8-MiB prepared subcap in a live test, or the frozen row/byte limits are lowered; and
- producer/receiver caller abort, lost-response recovery, and maximum-size p99/RSS
evidence pass the live activation gate.

Until those conditions are implemented and measured, the private consumer must reject
every caller-authored proof before inspection or mutation, and the ownership workflow
must continue to report only lifecycle evidence rather than atomic-apply conformance.

## Rollout and Rollback

1. Merge canonical objects, validators, and storage capability default-unused.
Expand Down
Loading
Loading