Contracts
startup-asset-escalation.md
Contract: startup asset torn-read escalation
build_serialized(build: Callable[[], T], *, logger: logging.Logger | None = None) -> T
Preconditions
buildconstructs a freshAssetPreparationon every call. It does everything up to and includingfinish()and performs no shared, non-retriable side effect (no_GlobalAssetPreparation.include()).
Postconditions
- P1. If the first
build()succeeds, it is returned. No lock is acquired, andbuildis called exactly once. - P2. If the first
build()raisesTornReadErrorwith a destination role while_HELD_LOCKSis empty (no serialization point held by this process; see P4), the following happens: - Exactly one INFO record is logged; it does not contain "Error".
_serialize_owner(exc.lock_paths, exc.anchor)is entered exactly once, andbuild()is called exactly once more inside it.- That result is returned, or its exception propagates.
- P3. If the first
build()raisesTornReadErrorwith a source role, it propagates immediately. No lock is taken andbuildis not re-called. - P4. If the first
build()raisesTornReadErrorwhile_HELD_LOCKSis non-empty (this process is already inside any serialization point), it propagates immediately. No lock is taken. This rules out nesting. Owners that share an anchor share one non-reentrant cold-install sentinel, so a nested escalation could self-deadlock on it. Nesting across differently-keyed locks would risk lock-order inversion. Owner anchors coincide in the default layout, but not when e.g.XDG_CONFIG_HOMElives outsideHOME. - P5. Any other exception from
build()propagates immediately and unchanged. - P6. After return or raise,
_HELD_LOCKSequals its value on entry.
_serialize_owner(lock_paths: tuple[Path, ...], anchor: Path) (context manager)
- It acquires exactly the lock set that
recheck_assetsacquires for aPreparedAssetswith the samelock_pathsandanchor. - Lock files are never read (
read_content=Falsediscipline, #4703).
Startup entry points (ensure_runtime, ensure_global_agent_commands via _apply_command_assessment, ensure_global_agent_skills)
- An incomplete assessment, or an apply outcome other than
applied/skipped, raisesStartupAssetError. StartupAssetErroris a subclass of bothkernel.errors.GuardedReadErrorandRuntimeError.- Through the CLI,
_run_app_with_error_hookrenders it: exit code 1; without--json, exactly oneError: …line on stderr and no traceback; with--json, one JSON object on stdout.