Add phase-aware pidfs process ownership records

This commit is contained in:
ms2k 2026-07-14 01:46:58 +09:00
commit de57e77dc8

View file

@ -98,7 +98,7 @@ classDiagram
Domain "1" --> "0..*" Generation
Generation "1" --> "0..*" Participant
Participant --> ParticipantState
Participant --> ParticipantOwnership
Participant --> "0..1" ParticipantOwnership
Generation "1" --> "0..*" Session
Session "1" --> "0..1" SessionTerminal
SessionTerminal --> SessionTerminalState
@ -108,7 +108,121 @@ classDiagram
`durable_decision` and `session_phase` contain values defined by the application
protocol model. This schema records them without redefining either state machine.
Each store carries its own schema identity and version.
Each store carries its own schema identity and version. The current Domain Store
identity is `lazaret-domain-store-v2` with version `2`. Domain Store v1 metadata
dispatches only to legacy migration handling; it is never decoded as v2. The
Storage Catalog remains `lazaret-storage-catalog-v1` with version `1`.
### Host process identity and staged ownership
```mermaid
classDiagram
class PidfsProcessAuthorityV1 {
boot_id
pidfs_st_dev
pidfs_st_ino
}
class PidfsProcessIdentityV1 {
host_pid
start_time_ticks
}
class LegacyUnverifiedProcessIdentityV1 {
host_pid
start_time_ticks
}
class HostProcessIdentity {
<<union>>
PidfsV1
LegacyUnverifiedV1
}
class PersistedHostProcessOwnership {
<<union>>
Unassigned
Staged
Committed
}
class HostProcessOwnershipSlot {
<<enumeration>>
SandboxHostCoordinator
SandboxRuntimeSupervisor
SandboxAttachedRunsc
StateAnchorDaemon
GitRoutingDaemon
NetworkRuntimeSupervisor
HelperConnectivityHelper
HelperRuntimeSupervisor
SessionTerminalHostCoordinator
SessionTerminalExecClient
EscalationHostProcess
}
class ProcessOwnershipMessageVersion {
<<enumeration>>
V1
}
class StagedProcessOwnership {
version
domain_id
generation_id
coordinator_id
slot
identity
}
class ProcessOwnershipCommitAck {
version
committed
}
PidfsProcessIdentityV1 --> PidfsProcessAuthorityV1 : authority
HostProcessIdentity --> PidfsProcessIdentityV1 : PidfsV1
HostProcessIdentity --> LegacyUnverifiedProcessIdentityV1 : LegacyUnverifiedV1
PersistedHostProcessOwnership --> PidfsProcessIdentityV1 : Staged
PersistedHostProcessOwnership --> HostProcessIdentity : Committed
StagedProcessOwnership --> ProcessOwnershipMessageVersion
StagedProcessOwnership --> HostProcessOwnershipSlot
StagedProcessOwnership --> PidfsProcessIdentityV1
ProcessOwnershipCommitAck --> ProcessOwnershipMessageVersion
ProcessOwnershipCommitAck --> StagedProcessOwnership : committed
```
`boot_id` is the canonical 16-byte UUID value from the current Linux boot ID;
`pidfs_st_dev` and `pidfs_st_ino` are distinct unsigned 64-bit pidfs types. Only
their typed `PidfsProcessAuthorityV1` tuple is positive durable authority.
`host_pid` is an unsigned 32-bit host-PID-namespace locator and
`start_time_ticks` is unsigned 64-bit negative evidence. Equality of the latter
two fields cannot produce or upgrade authority.
Every persisted host-process edge uses `PersistedHostProcessOwnership`.
`Unassigned` records that no process ownership has been acquired. `Staged`
contains only a current pidfs identity. It is positive authority for exact
same-handle cleanup and `PidfsRecoveryMatch`, including bootstrap recovery, but
cannot satisfy readiness, publication, dependent-resource creation, or
adoption. `Committed` may contain a current pidfs identity or a
legacy-unverified v1 PID/start-only value. Only committed current pidfs
ownership is serviceable; the legacy variant always refuses positive process
action. There is no observation-based conversion from legacy data to
`PidfsProcessIdentityV1`.
Participant `Intent` and `ReleaseIntent` may retain any process-slot phase.
Every active participant state and Session Terminal `Running` requires current
committed ownership in every role-required process slot. `Clean` requires every
process slot to be `Unassigned`.
`StagedProcessOwnership` binds one acquisition to its Domain, generation,
generation-scoped Session Coordinator ID, exact ownership slot, and complete
pidfs identity. `ProcessOwnershipCommitAck.committed` echoes that exact staged
value. The receiver accepts one matching v1 acknowledgment only while that
exact launch barrier is pending on the authenticated generation channel. A
mismatched, duplicated after release, unknown-version, lost, or unauthenticated
acknowledgment cannot release a barrier. These shapes define correlation and
the durable boundary; they do not select the authentication or transport codec.
### Session terminal ownership
@ -127,31 +241,35 @@ classDiagram
inode
}
class ProcessIdentity {
pid
start_time
}
class GuestProcessIdentity {
leader_pid
leader_start_time
process_group_id
}
SessionTerminal --> ProcessIdentity : host_coordinator
SessionTerminal --> PersistedHostProcessOwnership : host_coordinator
SessionTerminal --> PtyIdentity : pty_master
SessionTerminal --> ProcessIdentity : exec_client
SessionTerminal --> PersistedHostProcessOwnership : exec_client
SessionTerminal --> GuestProcessIdentity : guest_process
```
Host process identities use host pid and start time. Guest process identity uses
the leader PID and start time observed inside the exact generation-bound runsc
container; its process-group ID is relative to that container's root PID
namespace.
Host process ownership uses the phase-aware pidfs dispatch above. Guest
process identity uses the leader PID and start time observed inside the exact
generation-bound runsc container; its process-group ID is relative to that
container's root PID namespace and never converts to host process authority.
The PTY identity is exact only in combination with its Host Coordinator process
identity. `SessionTerminalState` is a physical recovery state below the
application protocol model; it does not redefine `session_phase`.
`SessionTerminal=Intent` permits partial acquisition: `container_id`,
`pty_master`, and `guest_process` are optional, while both process slots use the
three-phase ownership union. `Running` requires all three non-process identities
and current committed HC and exec-client ownership. `ReleaseIntent` retains all
recorded evidence, including staged current pidfs authority. `Clean` requires
all three optional identities absent and both process slots unassigned. A bare
Intent may become this explicit cleared snapshot only after runtime absence is
proven.
## Session terminal protocol
```mermaid
@ -452,11 +570,6 @@ classDiagram
<<union>>
}
class ProcessIdentity {
pid
start_time
}
class NamespaceIdentity {
device
inode
@ -469,57 +582,57 @@ classDiagram
}
class PreparedLowerOwnership {
prepared_artifact_id
source_identity
lease_state
path
device
inode
optional prepared_artifact_id
optional source_identity
optional lease_state
optional path
optional device
optional inode
}
class StateAnchorOwnership {
lower_artifact_id
upper_path
work_path
merged_path
optional lower_artifact_id
optional upper_path
optional work_path
optional merged_path
daemon
mount
optional mount
}
class GitRoutingOwnership {
mountpoint
host_root
isolated_root
optional mountpoint
optional host_root
optional isolated_root
daemon
mount
optional mount
}
class NetworkOwnership {
derived_policy_digest
readiness_fingerprint
readiness_evidence
namespace
optional derived_policy_digest
optional readiness_fingerprint
optional readiness_evidence
optional namespace
runtime_supervisor
}
class HelperOwnership {
network_sidecar_id
optional network_sidecar_id
connectivity_helper
runtime_supervisor
}
class SandboxOwnership {
container_id
runtime_root
bundle_digest
optional container_id
optional runtime_root
optional bundle_digest
host_coordinator
runtime_supervisor
attached_runsc
}
class PublicationOwnership {
socket_path
identity_path
optional socket_path
optional identity_path
}
ParticipantOwnership --> PreparedLowerOwnership
@ -529,20 +642,62 @@ classDiagram
ParticipantOwnership --> HelperOwnership
ParticipantOwnership --> SandboxOwnership
ParticipantOwnership --> PublicationOwnership
StateAnchorOwnership --> ProcessIdentity : daemon
StateAnchorOwnership --> PersistedHostProcessOwnership : daemon
StateAnchorOwnership --> MountIdentity : mount
GitRoutingOwnership --> ProcessIdentity : daemon
GitRoutingOwnership --> PersistedHostProcessOwnership : daemon
GitRoutingOwnership --> MountIdentity : mount
NetworkOwnership --> NamespaceIdentity : namespace
NetworkOwnership --> ProcessIdentity : runtime_supervisor
NetworkOwnership --> PersistedHostProcessOwnership : runtime_supervisor
NetworkOwnership --> NetworkReadinessEvidence : readiness_evidence
HelperOwnership --> ProcessIdentity : connectivity_helper
HelperOwnership --> ProcessIdentity : runtime_supervisor
SandboxOwnership --> ProcessIdentity : host_coordinator
SandboxOwnership --> ProcessIdentity : runtime_supervisor
SandboxOwnership --> ProcessIdentity : attached_runsc
HelperOwnership --> PersistedHostProcessOwnership : connectivity_helper
HelperOwnership --> PersistedHostProcessOwnership : runtime_supervisor
SandboxOwnership --> PersistedHostProcessOwnership : host_coordinator
SandboxOwnership --> PersistedHostProcessOwnership : runtime_supervisor
SandboxOwnership --> PersistedHostProcessOwnership : attached_runsc
```
`Participant.ownership=None` is the single encoding of a bare role-bound
Intent. Once a role snapshot exists it never returns to `None`. `Intent` admits
a non-empty partial matching snapshot. `ReleaseIntent` admits a non-empty
partial or complete matching snapshot and retains every exact acquired value.
`Clean` requires a matching explicit empty snapshot: all optional physical
fields are absent and all process slots are unassigned. This distinguishes
"nothing acquired yet" from "absence was proved and cleanup committed."
The only serviceable role/state pairs are:
| Role | Active state | Required physical evidence |
|---|---|---|
| `PreparedLower` | `LeaseHeld` | artifact ID, source, `lease_state=LeaseHeld`, path, device, inode |
| `StateAnchor` | `Prepared` | lower artifact, three paths, mount, current committed daemon |
| `GitRouting` | `Prepared` | three paths, mount, current committed daemon |
| `Network` | `Committed` | policy digest, fingerprint, readiness evidence, namespace, current committed RS |
| `Helper` | `Committed` | sidecar ID, current committed helper and RS |
| `Sandbox` | `Committed` | container, runtime root, bundle digest, current committed HC, RS, and runsc |
| `Publication` | `Committed` | socket and identity paths |
Network readiness evidence must name the enclosing Participant generation and
match its policy digest, fingerprint, namespace, and committed RS identity.
Intent acquisition is monotonic: optional fields move only absent-to-present,
and newly acquired child slots move only `Unassigned` to `Staged` to exact
matching current `Committed`. A current committed owner or supervisor may
enter a newly created dependent-role snapshot directly and is then immutable;
legacy ownership cannot use this rule. Recorded evidence cannot be replaced or
cleared. A transition to ReleaseIntent preserves all evidence; PreparedLower
changes only its lease phase to `ReleaseIntent`. ReleaseIntent becomes Clean
only after independent absence proof and atomically clears every physical
field. A bare Intent may become Clean only after the same sealed runtime-absence
check.
The direct existing-process edges are Network RS, Helper RS, Sandbox HC, and
Session Terminal HC. State Anchor daemon, Git-routing daemon, Helper process,
Sandbox RS, attached runsc, and Session Terminal exec client are acquired child
edges and require staging.
No bare Intent moves directly to an active state. PreparedLower must also move
from recorded `lease_state=Intent` to `LeaseHeld`; it cannot acquire the catalog
lease from an absent lease phase.
## Storage Catalog
```mermaid
@ -720,11 +875,6 @@ classDiagram
inode
}
class ProcessIdentity {
pid
start_time
}
class NetworkReachabilityProbe {
domain_id
generation_id
@ -751,8 +901,8 @@ classDiagram
NetworkReadinessEvidence --> NetworkReadinessIdentity : fingerprints
NetworkReadinessEvidence --> NetworkReachabilityProbe : includes
NetworkReadinessAttestation --> NamespaceIdentity : enforcement_namespace
NetworkReadinessAttestation --> ProcessIdentity : runtime_supervisor
NetworkReadinessAttestation --> ProcessIdentity : connectivity_helper
NetworkReadinessAttestation --> PidfsProcessIdentityV1 : runtime_supervisor
NetworkReadinessAttestation --> PidfsProcessIdentityV1 : connectivity_helper
NetworkReadinessAttestation --> NetworkObservation
NetworkObservation --> PolicyDelivery
NetworkReadinessIdentity --> NamespaceIdentity : enforcement_namespace