Skip to content

M6: Workspace isolation — per-project KAS_WORK_DIR and shared repo-ref #80

Description

@koenkooi

Part of #72.

KAS_WORK_DIR=work/<name>/ plus KAS_REPO_REF_DIR=work/.repo-ref, _mackas_derive_project()'s third cwd case, and a confirm()-offered move for checkouts converted by --from before this landed.

Gated on virtiofs verification — verified 2026-08-24: proceed

The gate is cleared. Verdict: works, with two caveats to build in. High confidence. Ship the shared ref
dir; do not fall back to full per-project clones on filesystem grounds.

Method: 47 assertions run twice from inside the container via mackas exec — once with the object store on
virtiofs (the work/ bind mount) and once on ext4 (a volume) as a control. Every assertion matched
line-for-line; only loose-object rounding differed. Coverage included what virtiofs classically breaks —
hardlinks (st_nlink and inode identity), rename() over an existing file, flock, fcntl record locks,
mmap, fsync — plus the whole alternates path: file created and resolved, objects genuinely not duplicated
(4 KiB borrower against a 20 MB reference), fsck clean, all reachable objects readable, an object only the
reference holds readable from the borrower, gc in the borrower neither absorbing borrowed objects nor
dropping the alternates file, --dissociate, and git's hardlinking local-clone path.

The assertions were themselves mutation-controlled: with --reference omitted the borrower duplicated all
10 MB, and with the reference moved aside cat-file and fsck both failed, then recovered when it returned.
So they can fail.

Caveat 1 — alternates must be rewritten to a RELATIVE path

kas writes the absolute, container-namespaced path into .git/objects/info/alternates, which makes the
checkout unreadable from macOS: host-side git log / status / fsck fail with unable to normalize alternate object path (rc 128/26/128). That is not academic — skills/mackas/SKILL.md tells users to run
host-side git -C work/<layer> to confirm their commit stack survived a --skip build, and #72 calls
hand-typed work the primary workflow.

A path relative to .git/objects resolves correctly from both namespaces (verified). That imposes a
structural requirement: the reference store must sit at a fixed relative offset from the clones, i.e.
inside the work tree at work/.repo-ref — not at a separate /repo-ref mount. The layout this issue
already specifies is therefore correct, and now has a reason attached; treat it as load-bearing rather than
incidental, and do not let a later cleanup relocate it.

Caveat 2 — never gc/repack --prune the reference while a build may read it

Pruned objects vanish from under a borrower. The concurrency case passed on both filesystems, so this is a
git-level hazard rather than a virtiofs one — which means it will not announce itself.

What this did NOT establish

  • kas's own plumbing is untested. The experiment tested git's semantics deliberately, not
    KAS_REPO_REF_DIR through kas or kas-container's /repo-ref forwarding — exercising kas's repo handling
    against real checkouts is what the safety rules forbid. A kas-level smoke test in a throwaway workspace
    still has to happen before this milestone closes.
  • Scale. Synthetic repos: 10-12 commits, 20 MB of incompressible blobs, one branch, no submodules. poky is
    ~500k commits with very different pack characteristics. No size-dependent behaviour was observed, but
    clone/fetch wall-clock at poky scale is unmeasured.
  • Cross-namespace concurrency. Four parallel clones inside one container VM passed. A host-side macOS git
    process and a container-side git process writing the same reference simultaneously was not tested — the
    one-VM rule does not cover it, and virtiofs cache coherency between namespaces is where a surprise is most
    likely.
  • The saving is real but partial: a borrower still fetches whatever the reference lacks, so the ref dir needs
    its own refresh step to stay useful. Worth a line in the docs.

Highest risk in the epic; do not bundle it with anything.

Note the ordering wart: M3-M5 give pinned projects distinct volumes and configs while work/ is still flat, which is precisely the configuration where the layer-reset hazard bites hardest (separate TMPDIRs mean nothing forces the rebuild that would surface the mismatch). M6 should not lag far behind M3.

Size: L. Risk: highest in the epic.

Activity

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

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions