Skip to content

Connected authority mutations and Web application authority

This page is the normative PETRA 1.0 contract for connected channel and ORBAT authority changes, the narrow Directory-owned relationship that lets the Web core application distribute approved state, and the relationship-bound issuance of snapshot authority. It extends the Zenoh and DDIL data-plane contract and the authoritative snapshot contract. It does not make Web a universal authority bypass.

Coordinated release boundary

The actor-signed wire, automatic Web relationship, all-cell profile, and manual recorder facets form one hard-cut candidate. They are not live production until the component PRs merge at one Common revision and the integrated rack runout passes. Existing Web SQL configuration is not a Directory relationship and grants no data-plane read authority.

Permanent boundary

Directory is the only authority issuer. A human or machine actor requests one closed semantic mutation and signs it with the key bound to its exact IdentityToken. Web may forward those bytes unchanged, but it cannot create, replace, or translate the actor signature. Directory re-evaluates the actor against current Directory state and derives the complete committed result.

There are three distinct identities:

Identity May do Must not do
Actor Sign a connected authority request for an action and scope it currently controls Supply storage keys, sealed values, ledger versions, commitments, or capabilities
Web core machine Forward an actor request; distribute/query exact state and publish Web-authored records or snapshots within its current relationship Act as the actor, delegate its machine authority, or expose its key/capabilities to a browser
FIDO-bound browser endpoint Sign its own short-lived subject-bound data-plane traffic where Directory has issued an exact human grant Use Web-machine authority, persist the set, publish position, or claim a Web-machine signature as its own
Bearer-only browser session Use authenticated HTTPS application surfaces Refresh capabilities, publish/query PETRA data-plane traffic, or use unsigned liveliness

An ordinary authenticated connected edge actor can call the mutation API directly. The contract is not Web-only, and Web forwarding adds no authority. Directory records the verified actor and, when different, the authenticated forwarding Web machine as separate audit principals.

Common wire

Common owns the protobuf, deterministic encoding, Rust and TypeScript signing helpers, verifiers, generated bindings, and shared hostile vectors. Version 1 admits only these mutation kinds:

enum AuthorityMutationKindV1 {
  AUTHORITY_MUTATION_KIND_V1_UNSPECIFIED = 0;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_CREATE = 1;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_UPDATE = 2;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_INVITE_ISSUE = 3;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_INVITE_REVOKE = 4;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_MEMBER_UPSERT = 5;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_MEMBER_REMOVE = 6;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_OWNERSHIP_TRANSFER = 7;
  AUTHORITY_MUTATION_KIND_V1_CHANNEL_RETIRE = 8;
  AUTHORITY_MUTATION_KIND_V1_ORBAT_BATCH = 9;
}

enum AuthorityChannelKindV1 {
  AUTHORITY_CHANNEL_KIND_V1_UNSPECIFIED = 0;
  AUTHORITY_CHANNEL_KIND_V1_CHAT = 1;
  AUTHORITY_CHANNEL_KIND_V1_VOICE = 2;
}

message ChannelCreateMutationV1 {
  AuthorityChannelKindV1 channel_kind = 1;
  string name = 2;
  string color = 3;
  waypoint.ConfidentialityLabel classification = 4;
  string operation_id = 5;
}

message ChannelUpdateMutationV1 {
  string name = 1;
  string color = 2;
}

message ChannelInviteIssueMutationV1 {
  string invitee_principal_id = 1;
  bool is_admin = 2;
}

message ChannelInviteRevokeMutationV1 {
  string invitee_principal_id = 1;
}

message ChannelMemberUpsertMutationV1 {
  string member_principal_id = 1;
  bool is_admin = 2;
}

message ChannelMemberRemoveMutationV1 {
  string member_principal_id = 1;
}

message ChannelOwnershipTransferMutationV1 {
  string new_owner_principal_id = 1;
}

message ChannelRetireMutationV1 {}

message OrbatDefinitionPatchV1 {
  string parent_unit_id = 1;
  string name = 2;
  waypoint.records.RecordOrigin origin = 3;
  bool provisional = 4;
}

message OrbatMembershipPatchV1 {
  repeated string member_principal_ids = 1;
  repeated string member_callsigns = 2;
}

message OrbatAppointmentPatchV1 {
  string commander_principal_id = 1; // empty means remove the appointment
}

message OrbatUnitUpdateMutationV1 {
  OrbatDefinitionPatchV1 definition = 1;   // presence means replace this field set
  OrbatMembershipPatchV1 membership = 2;   // presence means replace the complete set
  OrbatAppointmentPatchV1 appointment = 3; // presence means replace the appointment
  string new_owner_principal_id = 4;        // empty means preserve the current owner
  waypoint.ConfidentialityLabel classification = 5;
}

message OrbatUnitRetireMutationV1 {
  waypoint.ConfidentialityLabel classification = 1;
}

message OrbatUnitMutationV1 {
  string unit_id = 1;
  oneof mutation {
    OrbatUnitUpdateMutationV1 update = 2;
    OrbatUnitRetireMutationV1 retire = 3;
  }
}

message OrbatBatchMutationV1 {
  repeated OrbatUnitMutationV1 units = 1; // 1..256, unit-id UTF-8 order, unique
}

message ConnectedAuthorityMutationRequestV1 {
  uint32 version = 1;                  // exactly 1
  bytes actor_identity_token = 2;      // exact canonical IdentityToken bytes
  bytes directory_challenge_nonce = 3; // exactly 32 bytes
  uint64 issued_at_ms = 4;
  string request_id = 5;               // canonical lowercase RFC 4122 UUID
  AuthorityMutationKindV1 mutation_kind = 6;
  string aggregate_scope_id = 7;       // channel id or operation id
  oneof mutation {
    ChannelCreateMutationV1 channel_create = 8;
    ChannelUpdateMutationV1 channel_update = 9;
    ChannelInviteIssueMutationV1 channel_invite_issue = 10;
    ChannelInviteRevokeMutationV1 channel_invite_revoke = 11;
    ChannelMemberUpsertMutationV1 channel_member_upsert = 12;
    ChannelMemberRemoveMutationV1 channel_member_remove = 13;
    ChannelOwnershipTransferMutationV1 channel_ownership_transfer = 14;
    ChannelRetireMutationV1 channel_retire = 15;
    OrbatBatchMutationV1 orbat_batch = 16;
  }
  bytes actor_signature = 17;          // Ed25519, exactly 64 bytes
}

The oneof member must exactly match mutation_kind. Empty or unknown kinds, absent or multiple bodies, unknown protobuf fields, duplicate scalar fields, non-minimal varints, invalid UTF-8, a non-canonical UUID, and non-deterministic set ordering fail closed. Identifiers are non-blank, case-sensitive UTF-8 of at most 256 bytes. A shared chat id is exactly CHAT- followed by a canonical lowercase RFC 4122 UUID; a shared voice id is exactly VOICE- followed by one, and aggregate_scope_id must match the selected kind. The local-only ids CHAT-local and VOICE-local never enter Directory authority. A channel name is its own trimmed value, contains no Unicode control character, and is 1–128 UTF-8 bytes. color is exactly lowercase #[0-9a-f]{6}. Create requires a canonical classification label. Update preserves the id, kind, creator, creation time, owner, and classification and may change only name and color. Target principal ids are canonical lowercase RFC 4122 UUIDs and Directory additionally requires their current active, unrevoked row. ORBAT member ids are unique and in ascending UTF-8 byte order; callsigns are canonical and index-aligned; an ORBAT batch contains 1–256 unique units in ascending unit-id byte order. An update changes at least one present patch or owner, and Directory turns it into one complete Directory #145 OrbatRecord without losing an omitted definition, membership, or appointment. A retire turns the current complete record into its higher-sequence tombstone. The existing 65,536-member and 1 MiB committed-value bounds remain.

The channel id or ORBAT operation id appears exactly once as aggregate_scope_id. Channel creation additionally carries its canonical operation_id; Directory persists that immutable binding on the channel aggregate, and every later channel mutation loads it rather than accepting it again from the caller. Directory derives every stream id from the selected typed body. Channel creation derives its owner from the actor and its creation time from the commit. Invitation, membership, transfer, and retirement bodies carry only the semantic target. Directory constructs the complete definition, invite, membership, ownership, lifecycle, or ORBAT value. Definitions use the existing deterministic Chat or Voice wire, membership uses ChannelMembershipSetV1, and Common defines closed version-1 channel invite, ownership, and lifecycle projection messages; ORBAT uses the complete OrbatRecord. Invite issue sets the exact invitee pending and records its proposed admin bit; revoke removes that pending relationship. A successful member upsert consumes any pending invite for that principal in the same transaction, while member removal never recreates it. Channel retirement removes every pending invite. No request field can carry an opaque key expression, ciphertext, sequence or ledger version, mutation commitment, storage-use proof, or authority capability.

Channel-create operation context

For an endpoint, ChannelCreateMutationV1.operation_id comes only from the exact current verified OperationContextV1 member of the signed complete capability refresh described in the data-plane contract. The member is a bounded, bytewise ordered Directory projection of each operation in which the bound subject can currently create the named channel kind. It is a UI selection aid, not delegated authority: Directory reloads and revalidates the operation relationship, effective action, classification, identity/key/revocation state, and kind at the commit.

No token, ProfileBundle, ORBAT/content projection, local profile, display label, user input, stale context, or prior receipt can supply or repair this field. An offline, expired, omitted, or no-longer-kind-eligible context leaves only an unactivated local draft. It cannot create a channel definition, publish shared state, alter membership, or enter an authority outbox. A receipt is followed by a higher-generation complete refresh before the client represents the new channel as active.

Actor signing input

Let canonical_mutation_body be the deterministic protobuf encoding of the selected typed body, excluding its enclosing field tag. All strings are UTF-8; str32(s) = u32be(len(utf8(s))) || utf8(s) and bytes32(b) = u32be(len(b)) || b. The actor signs:

ascii("petra-connected-authority-mutation-request-v1\0")
|| u32be(version)
|| bytes32(actor_identity_token)
|| directory_challenge_nonce[32]
|| u64be(issued_at_ms)
|| str32(request_id)
|| u32be(mutation_kind)
|| str32(aggregate_scope_id)
|| bytes32(canonical_mutation_body)

The challenge is Directory's 32-byte, single-use, 120-second challenge. The request time uses Common's 60-second clock-skew window. The token must be canonical, Directory-signed, unexpired, and bound to the exact Ed25519 key that verifies actor_signature. Login, capability-refresh, snapshot, envelope, and other challenge signatures are in different domains and cannot be substituted.

request_sha256 is SHA-256 of the canonical deterministic complete request including the 64-byte actor signature. An exact committed retry is identified by (actor principal, request_id) and that digest. Directory may return the stored receipt for those byte-identical request bytes even though the original challenge is already consumed; this bypasses only the consumed-nonce check and second commit. Directory still reloads and rechecks the actor's current token/key, revocation, action, relationship, appointment, and clearance before returning the stored receipt. Reusing the id with any different token, nonce, timestamp, kind, scope, body, or signature returns AUTHORITY_IDEMPOTENCY_CONFLICT. A challenge replay that is not this exact committed retry fails.

Directory verification and commit

Directory verifies the complete actor proof before mutation and then, inside the same serializable authority transaction:

  1. Loads the current active actor principal and exact signing key, current subject/key revocation, current clearance, and current roles from Directory storage. It resolves role actions only through Common's effectiveCapabilities; signed but stale token role claims never grant an action.
  2. Re-evaluates the relationship required by the selected mutation: current channel owner/membership and target-principal state, or current ORBAT ownership, membership, command appointment, unit graph, and operation scope. Action and relationship must both pass. A machine receives no implicit mutation right from being a core service.
  3. Validates origination and classification against the current actor clearance. A missing relationship, removed role or appointment, unknown role, revoked target, retired aggregate, graph cycle, or cross-operation unit fails closed.
  4. Locks the aggregate, derives its canonical opaque key, next version, exact complete semantic value, immutable metadata, and commitment. It seals the complete value once, persists those same bytes once, advances the projection and entitlement index, checks that every affected complete capability set remains within 4,096 entries and 16 MiB, and commits all affected ORBAT units atomically.
  5. Audits the actor proof and committed result. If an authenticated Web machine forwarded the request, Directory writes a separate forwarder audit link; it does not rewrite actor provenance.

The version-1 action/relationship matrix is closed. Every action cell is resolved through Common effectiveCapabilities; Directory never checks a raw role name. Both columns must pass, and an unknown action or missing relationship grants nothing.

Mutation Required current action Required Directory relationship
Create chat create_chat Exact accessible operation scope, or Directory-owned deployment administrator oversight
Create voice create_voice Exact accessible operation scope, or Directory-owned deployment administrator oversight
Update definition, issue/revoke invite, upsert/remove member, transfer, or retire Current owner authority or manage_channels The exact active channel and its persisted operation scope must be accessible to the actor; administrator override additionally requires manage_members and Directory-owned deployment oversight
Apply an ORBAT batch manage_members Current command/ownership appointment covering every affected unit in the exact operation; administrator override requires Directory-owned deployment oversight

Channel membership alone never authorizes a control mutation. Ownership supplies the documented Directory-owned action authority; the alternative manager path is resolved only through Common effectiveCapabilities. Either path still requires the exact active channel and its persisted operation relationship. manage_members without the exact appointment/oversight relationship grants nothing. Creation never infers operation scope from the new channel id. Transfer requires the new owner to be an active, unrevoked subject in the same operation scope. A mixed ORBAT batch fails in full if authority is missing for any one unit.

Directory returns DIRECTORY_CONNECTIVITY_REQUIRED when the authority service cannot be reached. That outcome changes no effective Web or endpoint state, emits no Zenoh authority sample, and creates no authority outbox. Web must commit Directory first and only then project the returned result locally; there is no SQL-first-then-toast path.

Exact committed receipt

Common also owns the receipt schema:

message CommittedAuthorityResultV1 {
  string canonical_publication_key = 1;
  bytes committed_canonical_value = 2; // exact once-sealed persisted bytes
  waypoint.ConfidentialityLabel committed_classification = 3;
  string committed_owner_principal_id = 4;
  waypoint.EnvelopePurpose purpose = 5; // exactly DURABLE_GRANT
  uint64 authority_ledger_version = 6;
  bytes committed_mutation_sha256 = 7; // exactly 32 bytes
}

message ConnectedAuthorityMutationResponseV1 {
  uint32 version = 1;                  // exactly 1
  string actor_principal_id = 2;
  bytes actor_signing_key = 3;         // exactly 32 bytes
  string request_id = 4;
  bytes request_sha256 = 5;            // exactly 32 bytes
  uint64 committed_at_ms = 6;
  repeated CommittedAuthorityResultV1 results = 7;
  bytes results_sha256 = 8;             // exactly 32 bytes
  bytes directory_key_id = 9;           // SHA-256(Directory public key), 32 bytes
  bytes directory_signature = 10;       // Ed25519, exactly 64 bytes
}

Results are non-empty, sorted by ascending bytewise canonical_publication_key, and have no duplicate key. Every channel mutation returns exactly one committed projection; invite consumption/removal also updates Directory's pending relationship state transactionally but never adds an unrequested receipt result. An ORBAT batch returns exactly one result per requested unit, in particular never more than 256. Each value is at most 1 MiB, and the canonical encoded response is at most 16,777,216 bytes. Common and Directory enforce the response bound before decode, allocation, commit, and return; if the exact receipt would not fit, the whole transaction rolls back. canonical_result is the deterministic protobuf encoding of one result:

results_sha256 = SHA-256(
  ascii("petra-connected-authority-mutation-results-v1\0")
  || u32be(result_count)
  || concat(bytes32(canonical_result))
)

Directory signs:

ascii("petra-connected-authority-mutation-response-v1\0")
|| u32be(version)
|| str32(actor_principal_id) || actor_signing_key[32]
|| str32(request_id) || request_sha256[32]
|| u64be(committed_at_ms) || results_sha256[32] || directory_key_id[32]

The response is a signed commit receipt, not a reusable publication grant. Distribution uses the exact COMMITTED_AUTHORITY_MUTATION capability/value entry subsequently issued to an entitled subject. That entry's key, once-sealed value, metadata, ledger version, and commitment must equal the stored result byte for byte; Directory, Web, and an exact retry never decrypt, reconstruct, re-encode, or reseal it.

Web core-application relationship

Directory stores an explicit current relationship for an active machine device whose Directory-side platform_type is exactly web. platform_type is not added to IdentityToken. The relationship binds:

  • the Web principal and its current 32-byte signing key;
  • exact deployment and operation scopes;
  • exact canonical geohash-5 cells, with the existing maximum of 256;
  • exact channel recorder entries, each pairing one channel with only its configured chat and/or voice recorder family;
  • exact position-recorder geohash-5 cells, distinct from any caller-declared map AOI;
  • a closed allowlist of retained/query/publication families;
  • exact snapshot family/scope plus canonical semantic audience descriptors; and
  • one classification ceiling that cannot exceed the machine's current clearance.

The first authorized operation setup automatically creates the non-expiring automatic_orbat relationship for the current Web machine and each subsequent authorized operation setup adds its exact operation scope. Directory derives the profile from current operation, ORBAT, channel, and device ledgers on each complete-set refresh; it does not copy an ever-growing list of units, channels, invites, or cells into a second authority store. Retiring or deleting an operation removes that scope, and retiring the final current operation removes the automatic profile through complete-set replacement.

This setup behavior is part of the operation transaction. An administrator does not configure a distribution audience or cell list afterwards, and Web does not repair missing authority locally. The authenticated setup actor must still have deployment oversight, manage_members, and view_operation; a manual, expired, removed, revoked, or wrong-signing-key relationship is a permanent deny marker and is never widened or revived automatically. Web cannot self-declare a platform type, signing key, scope, family, audience, or ceiling.

The deployment group key follows the machine credential lifecycle, not an operation audience form. Web fetches it automatically from Directory's authenticated /api/group-key endpoint as part of login/refresh; Directory denies that endpoint to Relay + Storage principals. Operation setup supplies the automatic capability relationship; it neither creates a separate group key nor sends key material through Server.

Each audience is persisted as a canonical SnapshotAudienceDescriptorV1: one exact deployment segment and an ascending unique set of typed principal, unit, or channel members. Neither the administrator nor Web supplies an audience digest or opaque audience segment. Directory validates every member against the relationship's operation scope, deterministically encodes the descriptor, computes its SHA-256 digest, and derives the segment under snapshot-audience. A relationship has an absolute expires_at_ms; it is never rebased from a cache or retry. Directory groups snapshot grant scopes only when principal, signing key, audience descriptor, classification ceiling, and relationship deadline are all identical. Any difference produces a separate grant and selector pair.

Directory intersects the relationship with current Directory state on every atomic full-set refresh. It issues only the following allowlisted grants:

Current relationship facet Exact grant
Approved channel/ORBAT scope The current exact Directory #145 committed heads needed for distribution, preserving their once-sealed bytes and immutable metadata
Approved operation, channel, unit, cell, or snapshot scope Exact QUERY expressions for the configured families in that scope
Assigned exact geohash-5 cell plus drawing family Exact-cell drawing publication/tombstone grant subject to the ordinary ownership/moderation checks
Assigned exact geohash-5 cell plus target family Exact-cell target publication/tombstone grant; nominate_target still grants no COP publication
Approved Web-authored plan or report-requirement family and exact operation/unit scope Exact record publication grant; no report or ORBAT mutation grant follows
Approved snapshot family/scope/audience SnapshotAuthorityGrantV1 and its matching bounded snapshot manifest/chunk publication selectors

There is no unrestricted deployment-wide family, cross-operation, or cross-audience wildcard. The automatic profile uses only Common's registered all-cell drawing, target, and position selectors and five closed aggregate retained-query selectors; manual relationships remain exact. Existing 4,096-entry, 16 MiB refresh-response, 1 MiB committed value, clearance, identity, and offline-horizon bounds all apply. Revocation, machine-key rotation, relationship removal, and every removed scope, cell, family, or audience remove their grants by omission from the next verified atomic complete set.

Web never decrypts or reseals a committed Directory #145 authority head. It publishes the exact key, once-sealed value, metadata, ledger version, and commitment returned by Directory, using the capability issued for that exact committed result. A mismatch is Directory/Web equivocation and fails closed.

Web recorder read authority

Web's server-side archive is a trusted application consumer with a closed capability profile. An automatic Web relationship receives the registered all-cell position selector and the five aggregate retained-query selectors in the data-plane contract. A manual relationship receives QUERY capabilities only when both the active Web machine relationship and the exact recorder entry are present:

Directory-owned relationship entry Exact QUERY selector Permitted recorder use
Exact channel + chat recorder waypoint/global/chat/<opaque-chat-channel>/** Retained chat catch-up and exact-channel live ingestion
Exact channel + voice recorder waypoint/global/voice/<opaque-voice-channel>/** Exact-channel live voice ingestion only
Exact assigned recorder cell + position recorder waypoint/<geohash5>/pos/** Live position ingestion inside that one canonical cell only
Exact published plan version + plan-ack recorder waypoint/global/record/plan-ack/<opaque-plan-version>/* Retained catch-up and live ingestion for acknowledgements of that exact version only

The opaque channel is Directory-derived from the related semantic channel. The position selector contains exactly one canonical geohash-5 cell; its trailing recursive selector may match opaque position sources only within that cell. A sibling channel, adjacent cell, caller-supplied AOI, operation-wide scope, deployment-wide family, or selector that crosses an audience boundary is not contained.

QUERY means read authority and may drive either a bounded retained query or a first-party live subscription. Chat is the only recorder family above retained by Relay + Storage. Voice and position remain non-retained LIVE families: their QUERY entries let Common classify the exact first-party selector but do not authorize Storage persistence, catch-up, restart replay, or a durable query response. Stock Zenoh cannot enforce the live subscriber declaration, so Web must still verify every original publication and apply the capability's classification ceiling before opening or archiving it. The accepted live-subscription residual is unchanged.

Directory intersects each recorder grant with the Web machine's current clearance, the relationship ceiling, the channel or exact plan-version classification, and the applicable operation scope. The automatic aggregate selectors are derived only from current Directory ledgers; manual recorder visibility never expands from a caller-supplied AOI, fleet membership, or another Web table. Configuring Web recording during connected channel activation transactionally adds that exact channel/family entry to the Directory relationship in the same commit. A partial channel activation without its configured recorder relationship, or the inverse, fails closed. Web and a browser may request or forward that authenticated administrative operation but cannot self-declare, expand, or repair the relationship locally.

These recorder facets add no heartbeat, sensor, command, live command acknowledgement, snapshot, invite, membership, committed-state publication, or other authority. In particular, Directory issues no invite or membership read grant merely to support recording. Any separate management or exact committed-distribution facet remains independently authorized and does not permit the recorder to subscribe to those streams.

Adding an entry appears only through a newer verified complete set. Removing a recorder entry, removing its channel/cell/family/plan-version scope, tombstoning the channel, or removing plan-version readership omits the corresponding read grant from the next complete set. Web atomically rebuilds its exact subscriptions before ingest resumes: additions open only their new exact selectors and omissions close the removed selectors. Absolute capability, identity, relationship, and horizon deadlines stop ingestion even if refresh is unavailable. A failed refresh may preserve the previous set only while that set remains unexpired; it never rebases a deadline. Removing live authority does not delete already verified Web archive rows, which remain available under application audit/replay policy and can never be republished as original endpoint traffic.

The legacy invite/membership Zenoh recorder is retired. It has no startup subscription, catch-up query, compatibility selector, or recorder-specific grant. Connected Directory mutation receipts and Directory's authoritative audit ledger are the sole source of membership history. Web ingests those verified receipts/audit events into its activity timeline so channel invitations, joins, removals, role changes, transfers, and retirement remain present in the AAR/replay view with actor and forwarding-machine attribution. This application history is not an authority projection and cannot recreate a removed grant.

Snapshot authority consequence

Directory issues SnapshotAuthorityGrantV1 only while the exact Web relationship is current. The grant binds the current Web principal/key, an approved family/scope pair, the Directory-derived audience segment and digest, the relationship's classification ceiling, and a validity interval no longer than the earliest identity, relationship, or offline-horizon deadline. Directory places the canonical grant bytes in field 5 of every matching purpose-3 CapabilitySetEntryV1; there is no separate snapshot-authority endpoint or independently refreshed cache. A purpose-3 publication capability and its grant install or disappear as the same atomic complete-set entry. Directory repeats one grant byte-identically on exactly these two scoped publication selectors for each signed family/scope pair and audience:

waypoint/global/snapshot/<family>/<scope>/<audience>/*/manifest
waypoint/global/snapshot/<family>/<scope>/<audience>/*/chunk/*

The Directory-managed automatic_orbat relationship has one narrow aggregate exception: while at least one operation is current, its empty-audience grant may contain exactly DRAWING/*, CHANNEL/*, and INVITE/*. The matching capability selectors also carry that literal scope. Each aggregate contains only concrete opaque scopes in its own family and its one signed audience; it cannot contain TARGET, PLAN, REPORT_REQUIREMENT, SITREP_CURRENT, or ORBAT, cross an audience, change manifest/chunk kind, or authorize another purpose or action. Directory does not accept this literal from manual relationship input. Retirement of the final current operation removes the aggregate grant through complete-set replacement.

One grant containing N signed scopes therefore appears byte-identically in exactly 2 × N PUBLISH entries, two for every contained (family, scope) tuple. The wildcard is registered in the positive-decimal sequence slot and, for chunks, the canonical unsigned-32-bit index slot; only the automatic aggregate exception above may also use it as the scope. Family and audience remain exact. **, wildcard family/audience, unregistered wildcard scope, manifest-to-chunk crossing, zero or noncanonical/overflowing sequence, and noncanonical/overflowing chunk index fail closed. This is closed family authority, not a deployment or cross-family wildcard. The 4,096-entry and 16 MiB response limits count every complete entry. Web cannot mint either object.

The outer snapshot publisher is explicitly Web and signs with the Web machine key. Snapshot provenance may cite verified actor-request, endpoint-envelope, Directory-commit, and Web-ingest audit digests, but it never claims that a referenced human or endpoint signed the snapshot. Relationship or scope removal makes subsequent snapshot production unusable after complete-set refresh; cached authority never renews itself.

No delegation or impersonation

  • The Web machine private key, capability entries, use proofs, and snapshot grants never enter Inertia props, browser storage, browser workers, browser Zenoh attachments, logs, or downloadable diagnostics.
  • A Web-machine capability is never attached to a human-signed envelope.
  • Web never creates an envelope naming a human principal while signing with the Web key.
  • After a human action, Web's outer publication names Web; the verified actor request and separate Directory/Web audits preserve human attribution.
  • Machine-only actions are limited to already-authorized distribution, exact querying, approved Web-authored records, and snapshot production. Every authority mutation still requires a current actor proof.

This relationship does not authorize direct browser publishers. The FIDO-bound browser endpoint contract defines that boundary: chat, voice, drawings, commands, and exact subject queries retain the human signer under short-lived Directory issuance; channel/ORBAT changes remain actor-signed connected mutations; approved plan/requirement publication remains explicitly Web-machine authored; ordinary browser position and unsigned member liveliness are retired. A bearer-only browser never falls back to a Web-machine capability.

Required hostile and runout tests

Common, Directory, Web, and affected consumers share fixtures and integration coverage that prove:

  • replacing the actor token, key, signature, challenge, kind, scope, or body fails; login/capability/snapshot signatures cannot cross into the mutation domain;
  • an exact committed retry returns the same receipt and bytes without a second version or seal, while the same request id with any different bytes fails closed;
  • stale token roles, a removed current role, membership, ownership, ORBAT appointment, or clearance fail even when the signed token still contains the old claim;
  • a Web machine without an actor proof cannot create, invite, join, remove, transfer, retire, delete, or mutate ORBAT authority;
  • caller-supplied opaque expressions, ciphertext, ledger versions, commitments, capabilities, unknown protobuf fields, unordered sets, duplicate units, and partial ORBAT batch failure are rejected before commit;
  • the wrong Web platform, principal, signing key, operation, family, cell, audience, or classification scope receives no grant; the 256-cell and complete-set bounds reject limit-plus-one transactionally;
  • automatic recorder projection includes only the registered all-cell position and closed aggregate retained-query forms; manual projection includes only explicitly related chat/voice channels, assigned position cells, and exact plan versions. An unregistered family, cross-operation scope, caller-declared AOI, invite selector, membership selector, or action outside that profile receives no grant;
  • connected channel activation configured for recording commits the exact channel and recorder relationship together or neither, while channel tombstoning omits its chat and voice recorder grants in the next complete set without deleting archived rows;
  • Web atomically rebuilds chat/voice/position/plan-ack recorder subscriptions on complete-set addition and omission, stops them at the earliest absolute deadline, and preserves a previous set after refresh failure only while its unchanged signed deadlines remain valid;
  • verified chat, voice, position, and exact-version plan-ack samples continue to populate their replay/archive rows under exact selectors and classification ceilings, while invite/membership Zenoh recorder startup, subscriptions, code paths, and compatibility fallbacks are absent;
  • every connected membership mutation receipt and Directory audit event remains visible in Web activity/AAR replay with actor and forwarding-machine attribution after the legacy membership recorder is removed;
  • relationship, key, family, cell, operation, or audience removal disappears through the next complete set and blocks shared traffic/outbox drainage before it resumes;
  • a committed value is byte-identical across receipt, persistence, capability refresh, Web distribution, and exact retry; any decrypt/re-encode/reseal attempt changes the commitment and fails;
  • snapshot family/scope/audience confusion, an audience segment not derived by Directory, a grant without the matching publication capability, and post-removal snapshot use fail;
  • actor provenance in a snapshot remains an audit reference and never verifies as actor snapshot authorship;
  • browser exposure of a Web key/capability, a Web capability on a human envelope, a human principal signed with the Web key, or a browser attempt to act as the Web machine fails; and
  • Directory loss returns DIRECTORY_CONNECTIVITY_REQUIRED, changes no Web projection, emits no authority publication, and creates no authority outbox; a successful reconnect refresh precedes mutation retry, distribution, snapshot work, or outbox drainage.

Non-goals

  • A universal Web publication bypass or deployment-wide machine wildcard.
  • Browser delegation, actor impersonation, or machine-signed human envelopes.
  • Caller-defined opaque addressing, sealed values, versions, commitments, or authority.
  • Offline authority creation, an authority outbox, or TTL renewal from cached state.
  • A persistent browser capability cache, Web-machine delegation, ordinary browser position, or unsigned member-liveliness compatibility path.