# Internal: Workspace ## Purpose Explain the helpers that construct local session and run paths, coordinate single-writer access, and confine cleanup. The authoritative physical layout and retention workflow belong in [Operations](../operations.md#local-state-layout). ## Path Ownership `internal/artifacts` owns canonical session, run, spool, cache, and previous-cache path construction. `SessionPathsFor` provides the session-scoped path model, and layout creation goes through `EnsureLayoutFor`. Callers should consume those helpers instead of rebuilding relative paths. `internal/pathsafe` validates relative destinations. `internal/fileops` opens cleanup roots and their descendants through no-follow directory handles before removing them. `internal/fileops` owns the ordinary workspace mode contract. On POSIX, `WorkspaceDirectoryMode` is setgid `02775` and `WorkspaceFileMode` is `0664`. `EnsureWorkspaceDirectory` reapplies the directory mode after creation so a restrictive umask cannot remove group access, while retaining existing ownership and group. Credential paths are outside this contract; the platform-specific operational requirements are in [Operations](../operations.md#workspace-permissions). ## Run-Local Stage Layout `internal/stage/run_local.go` maps stage outputs and diagnostics into an invocation-scoped layout. Successful outputs are validated and atomically materialized into canonical session paths before stage success. Managed previous-session cache paths remain session-durable and are never redirected into run-local output space. Extraction uses run-local receipt, stderr, and output-root helpers, then promotes the validated external bundle to the unique immutable Notarius bundle path supplied by `internal/artifacts`. `internal/fileops.PromoteDirectory` copies only regular files and directories to a same-filesystem temporary sibling. Source traversal uses confined directory handles and identity checks so replacing an inspected root, directory, or file is rejected rather than followed. The completed tree is atomically renamed without replacing an existing destination. Exact physical paths belong in [Operations](../operations.md#extraction-workflow). ## Locking `artifacts.LocalStore` enforces the single-writer session lock via an operating-system lock held on `.lock` (`ErrLockConflict` on contention). The file retains owner metadata after release or process death; its existence is not evidence that a lock is active. Command and restore flows wait for this lock only while their context remains active, and report a release failure. ## Cleanup Semantics Automatic post-publish cleanup: - is created only after a successful publish commit with complete publish metadata, then is persisted before any deletion; - requires `uploaded=true`, a remote commit key, and a current commit-pointer key in publish metadata; - consumes the resolved cleanup policy described in [Configuration](../config.md); - refuses unsafe deletes (root delete, out-of-root delete, and symlinked ancestors or entries); - retries any recorded incomplete target on later invocations even when no publish work is selected. Missing targets are a successful, idempotent cleanup result only after the completion evidence is saved. Manual cleanup uses the same root-confined deletion mechanism. Invocation syntax and exact deletion scope belong in [CLI](../cli.md#clean) and [Operations](../operations.md#cleanup). ## Invariants - campaign-aware session root is mandatory. - manifest-driven stage state is durable across runs. - cleanup guardrails prevent destructive root/out-of-scope deletion. - ordinary workspace paths retain group-writable directory and file modes across nested creation, replacement, and Notarius promotion. ## Implementation And Tests - Path model and local store: `internal/artifacts/paths.go`, `internal/artifacts/local.go` - Run-local materialization: `internal/stage/run_local.go` - Immutable bundle promotion: `internal/fileops/directory.go` - Workspace modes: `internal/fileops/modes.go` - Cleanup confinement: `internal/fileops/cleanup.go`, `internal/app/cleanup_targets.go`, `internal/app/post_publish_cleanup.go` - Tests: `internal/artifacts/paths_model_test.go`, `internal/artifacts/local_test.go`, `internal/stage/run_local_test.go`, `internal/fileops/directory_test.go`, `internal/fileops/modes_posix_test.go`, `internal/fileops/cleanup_test.go`, `internal/app/cleanup_targets_test.go`, `internal/app/post_publish_cleanup_test.go`