Skip to content

refactor: route config_seed and seed_manifest disk access through filesystem (sanitizing symptom 07) #3324

Closed

Description

@mblua

Situation

Sanitizing symptom 07 ("scattered disk access") is still the largest symptom. Gate 07 (npm run sanitizing:disk_access -- --base-ref origin/main, scripts/sanitizing_disk_access.mjs) measures disk_files = 151 on main 56a7d00e (after #3320).

Most remaining config/ files are reserved by other work (config.rs, archive_gate.rs, entity_creation*, replica_identity*, root_agent*, sessions_persistence*), belong to the settings-ownership epic #2992 (settings/, coding-agent catalog and profiles), or are touched by open PRs #3162/#3164 (agent_command*, agent_config*, local_config_io*, local_overlay.rs, teams*). Two related sub-trees are free: the config seed (copy of the seeded configuration into an instance) and the seed manifest (locked, handle-based manifest that records what was seeded). Their 6 counted production files still call std::fs directly (approximate list, read from the production body of each file):

  • config/config_seed/copy.rs - metadata x2, remove_dir_all x2, read_dir x3, create_dir_all, copy x2, read, write x3; DirEntry and Windows MetadataExt in is_symlink_or_reparse.
  • config/config_seed/perform.rs - rename x3, symlink_metadata x6, OpenOptions; Windows MetadataExt in metadata_is_reparse.
  • config/seed_manifest/guard.rs - File (lock file, File::unlock), canonicalize, read_dir.
  • config/seed_manifest/handles.rs - File, OpenOptions (Unix/Windows OpenOptionsExt, no-follow directory and file opens), symlink_metadata x4, Unix MetadataExt / Windows handle facts, is_windows_reparse.
  • config/seed_manifest/publish.rs - File locking (TryLockError), remove_file x2, rename.
  • config/seed_manifest/windows.rs - File, OpenOptions (Windows delete handle), File::from_raw_handle, rename.

Tree of symptom 07: these files are not container stores and are not filesystem; they read, copy, lock and atomically publish app data (seeded config, seed manifest) (R2), and several repeat link/reparse-point and no-follow checks that may already exist in filesystem (R1).

Precedents: #3259 (created src-tauri/src/filesystem.rs and its submodules), #3293, #3298, #3308 (PR #3314), #3320 (PR #3322).

Need

Rule 13 of the structure method: only container stores and the filesystem module touch the disk. These 6 files must stop calling std::fs directly; their disk work must go through filesystem as named business operations, or through the matching container store, which delegates physical operations to filesystem.

Intended change

  1. Decide, through architecture review, where each disk operation of the 6 files goes (filesystem submodule(s) and/or existing container stores), and whether local safety checks are replaced by existing filesystem primitives.
  2. Move the disk calls behind those owners; callers receive data or owned handles, not raw std::fs calls.
  3. Versioned, consensus-approved plan with exact files and no open decisions (partitioned in phases if the size requires it; one branch, one PR).

Scope

In: the 6 production files above, src-tauri/src/filesystem.rs (only its sorted mod lines; shared reservation) and the filesystem submodule(s) the approved design requires, and their tests as needed. src-tauri/tests/c4_state_key_census.rs: only the inventory count literal (assert_eq!(sources.len(), 1395, "inventory count")), set to the verified real .rs count for the new files of the approved plan (shared reservation, same rule as #3320).

Out: every other config/ file, in particular config.rs, config/archive_gate.rs, config/entity_creation*, config/replica_identity*, config/root_agent*, config/sessions_persistence* (reserved by other work), config/settings*, config/coding_agents_catalog*, config/coding_agent_profiles* (#2992), config/agent_command*, config/agent_config*, config/local_config_io*, config/local_overlay.rs, config/teams* (touched by open PRs); the other config_seed/ and seed_manifest/ files that gate 07 does not count (config_seed.rs, seed_manifest.rs, lifecycle.rs, path_identity.rs, state.rs, wire.rs, tests*) unless the approved design needs a call-site change there; the seed manifest row validation of #1622; cli.rs; commands/, cli/, pty/, phone/, api/; filesystem/projects* (reserved by other work); the rest of src-tauri/tests/c4_state_key_census.rs; gates and scripts/containers.json unless the approved design requires a registry entry; tests' own std::fs use.

Must not change

Behavior byte for byte: same seeded files, contents and placeholder expansion, file names and locations, staging/trash/rename order and rollback, manifest wire format, lock acquisition and timeouts, error variants and texts, NotFound handling, paths (no new or removed canonicalization), no-follow opens, link/reparse-point and handle-identity protections, Windows delete-handle semantics, atomic replace semantics, and cfg. No wider public API. Any of these requires a user decision first.

Acceptance criteria

  • Approved plan naming the owners and exact files.
  • Gate 07 on the PR: disk_files drops by 6 (none of the 6 files counted) and no new file is counted; gates check:cycles and check:arcs PASS.
  • cargo clippy --locked --manifest-path src-tauri/Cargo.toml --workspace --all-targets -- -D warnings clean, affected tests pass, CI (ci:full) green.
  • No behavior change.

Activity

  1. mblua commented on Oct 27, 2026

    @mblua
    OwnerAuthor

    Technical score (task-technical-scoring)

    Category Score Anchor / justification
    1. Scope footprint 9 6 production files in two sibling sub-trees of config/ plus new filesystem submodule(s) and call sites in their parents: a coherent module.
    2. Diagnosis difficulty 3 Gate 07 lists every counted file; the cause is stated.
    3. Domain knowledge 15 Handle-level I/O where naive moves are quietly wrong: no-follow opens (OpenOptionsExt), handle identity facts (Unix MetadataExt, Windows FFI), unsafe File::from_raw_handle, Windows delete handles, reparse-point checks, file locks.
    4. Solution-space ambiguity 11 Several viable owner splits (filesystem submodules vs existing primitives; whether handle types move or stay) with a defensible winner to pick.
    5. Blast radius 12 Config seeding copies, renames to trash and remove_dir_all inside instance directories; the manifest guards what was seeded; protections are involved. Normal rollback.
    6. Dependency load 6 Shared filesystem.rs (room-21) and the shared census literal; no external system.
    7. Verification difficulty 9 Existing tests in config_seed/tests* and seed_manifest/tests* plus gate counts; byte-for-byte preservation of Windows-only paths needs targeted checks and CI on the other OSes.
    8. State and compatibility 8 Persisted seed manifest and seeded files keep their wire format and atomic replace; no schema change.
    9. Concurrency and timing 10 Lock-file acquisition with timeouts (try_lock, TryLockError, File::unlock), atomic rename publication; clear ownership.
    10. Environment and tooling 8 cfg(windows)/cfg(unix) branches and FFI that one host cannot prove, shared build slots, clippy -D warnings per platform.

    Raw = 91. Final = round((91 - 10) / 190 * 99) + 1 = 43.

    Band 26-55 (Lite by score); escalated to Full like the precedent #3320: non-obvious owner split for security-relevant, handle-level I/O, so the Partition rule applies. Vetoes: Concurrency >= 10 (architect contract), Blast radius >= 12 (full file-impact tables at the human gate), Verification difficulty >= 8 (Grinch also reviews the proof), Environment >= 8 (owning dev states environment risk in writing before code). Author ac-architect-v5; reviewers ac-dev-rust-v5, ac-dev-rust-grinch-v5, ac-architect-grinch-v5; four matching Plan-SHA256 (and Phase-SHA256 per phase if partitioned).

    Excluded ceremony: issue creation, branch, PR, CI waits, review rounds, messaging, merge and cleanup.

  2. mblua commented on Oct 27, 2026

    @mblua
    OwnerAuthor

    Approved partition (consensus 4/4, plan v1)

    Plan: D:/0_repos/AgentsCommander_iac/.ac/plans/3324-seed-disk-access/epic.md — Plan-SHA256: 6BC179845BAEDD62C2BF7F55E51E2DA9508767DB96F7E81CA8F0B2FD96D6E0E8. One branch refactor/3324-seed-disk-access, one commit per phase, one PR. Design base main 56a7d00e.

    Phase Class Owner Files Depends on Census Gate 07 Phase-SHA256
    P01 P01-config-seed.md design-bearing ac-dev-rust-v5 5 — 1396 149 CCE5F591BD08D6C0D844D460612E2463D29114516AC931EF9079BB2D2D8670C1
    P02 P02-seed-manifest.md design-bearing ac-dev-rust-v5 9 P01 1397 145 130EEBAA04BE77546EFFFE88674EB1BE717E665705BC84BE6C14CAF42B1FFFCC

    New files: src-tauri/src/filesystem/config_seed.rs (P01), src-tauri/src/filesystem/seed_manifest.rs (P02). Votes: author READY; owning dev, Rust Grinch and architecture Grinch PLAN_APPROVED on the same digest set, PHASE_EXECUTABLE P01–P02. Step 7.5 approval pending.

  3. mblua commented on Oct 28, 2026

    @mblua
    OwnerAuthor

    Delivered

    PR #3328 merged (admin, merge commit) → main d10967ae11858ab6fa2e3c09ac6e445e3a68b8f2 (2026-10-28T00:23:00Z).

    Result: the 6 counted files (config/config_seed/{copy,perform}.rs, config/seed_manifest/{guard,handles,publish,windows}.rs) no longer call std::fs directly; physical disk work lives in src-tauri/src/filesystem/config_seed.rs and src-tauri/src/filesystem/seed_manifest.rs. Gate 07 on main d10967ae: disk_files = 138, none of the 6 files and neither new leaf counted.

    Phase Commit Files Gate 07 Review
    P01 config seed 2ca44ca4 5 144 → 142 Rust Grinch PASS
    merge origin/main 41762994 e2cc148f census literal only (real count 1401) — Rust Grinch PASS (focused)
    P02 seed manifest df4d1982 9 142 → 138 Rust Grinch PASS
    • Plan: Plan-SHA256 6BC17984…E0E8, P01=CCE5F591…70C1, P02=130EEBAA…FFCC; consensus 4/4; Step 7.5 approved (coordinator decision by delegation).
    • Final-head CI on df4d1982: run 40602580460 success; gh pr checks: 27 pass, 0 fail, 2 skipped (unexpanded matrix placeholder rows).
    • No build requested. Non-blocking follow-up noted by review: stale doc comment at src-tauri/src/pty/container_credentials.rs:28 (refers to the old config_seed::is_symlink_or_reparse location); no behavior impact.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions