2026-09-14 05:44:08 +00:00
|
|
|
# Contributing to PackFS
|
|
|
|
|
|
|
|
|
|
## Before changing anything
|
|
|
|
|
|
|
|
|
|
Read [`concept.md`](concept.md) in full. It is the project's specification,
|
|
|
|
|
not background reading — every backend, lock, and on-disk field in `src/`
|
|
|
|
|
exists because a section of `concept.md` requires it, and most functions'
|
|
|
|
|
comments cite the section they implement rather than re-explaining it.
|
|
|
|
|
`concept.md` is frozen (see [`CLAUDE.md`](CLAUDE.md)): if you believe the
|
|
|
|
|
design itself needs to change, that belongs in a new document that amends
|
|
|
|
|
or supersedes it, not in an edit to `concept.md`.
|
|
|
|
|
|
|
|
|
|
Then read [`CLAUDE.md`](CLAUDE.md), which states the load-bearing constraints
|
|
|
|
|
a change must respect (static linking, the write model, the concurrency
|
|
|
|
|
model, path containment, pack integrity) and the documentation register this
|
|
|
|
|
project is written in.
|
|
|
|
|
|
|
|
|
|
## Workflow
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
make test # must pass before any PR
|
|
|
|
|
cc ... -fsanitize=address,undefined # ASan/UBSan: see .github/workflows/ci.yml for exact flags
|
|
|
|
|
cc ... -fsanitize=thread # TSan, for anything touching src/upper.c, src/overlay.c, or src/vfs.c
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Any change to the concurrency-sensitive files (`upper.c`, `overlay.c`,
|
|
|
|
|
`vfs.c`) must be run under ThreadSanitizer, not just the plain test suite —
|
|
|
|
|
a data race there is exactly the class of bug Section 5 of `concept.md`
|
|
|
|
|
exists to prevent, and the plain build will not surface it.
|
|
|
|
|
|
2026-09-14 07:40:42 +00:00
|
|
|
A change to the index structure in `upper.c` (`snapshot_upsert`,
|
|
|
|
|
`snapshot_remove`, or the `UpperSnapshot`/`UpperEntry` representation)
|
|
|
|
|
should be run through `make bench` before and after, not just `make test`:
|
|
|
|
|
`BENCH.md` records a real, measured O(n²) cost in bulk sequential
|
|
|
|
|
create/unlink that any such change is liable to affect, for better or
|
|
|
|
|
worse, in ways the correctness-only test suite cannot detect.
|
|
|
|
|
|
2026-09-14 05:44:08 +00:00
|
|
|
## Scope
|
|
|
|
|
|
|
|
|
|
Changes that add functionality `concept.md` Section 10 lists as explicitly
|
|
|
|
|
out of scope for v0 (full POSIX semantics, enforced permissions/symlinks/hard
|
|
|
|
|
links, cross-process concurrency, content-defined chunking/delta
|
|
|
|
|
compression) should discuss the tradeoff with a maintainer first — those
|
|
|
|
|
exclusions were deliberate design decisions, not gaps waiting to be filled.
|
|
|
|
|
|
|
|
|
|
**`zip` and `tar` import/export backends will not be accepted, full stop —
|
|
|
|
|
not discussed, not behind a flag.** `concept.md` Section 11 recommends them,
|
|
|
|
|
but that recommendation is permanently superseded; see `CLAUDE.md`, "Project
|
|
|
|
|
decisions that supersede concept.md." This is a harder line than the v0
|
|
|
|
|
exclusions above, which are open to future discussion — this one is not.
|
|
|
|
|
|
|
|
|
|
## Static-linking constraint
|
|
|
|
|
|
|
|
|
|
`concept.md` Section 11.1 is a hard constraint: the core must build with
|
|
|
|
|
zero required third-party libraries and zero dynamic loading. In practice
|
|
|
|
|
this project has no optional-dependency boundary at all: `concept.md`
|
|
|
|
|
described one at the `zip`/`tar` backend for `miniz`/`libarchive`, but per
|
|
|
|
|
the decision above, that backend will never exist, so there is no path by
|
|
|
|
|
which a third-party dependency enters this codebase — a change proposing
|
|
|
|
|
one, for any backend, will not be accepted.
|
|
|
|
|
|
|
|
|
|
## Style
|
|
|
|
|
|
|
|
|
|
Match the register already in the file you're editing — precise,
|
|
|
|
|
constraint-labeled comments citing the `concept.md` section they implement,
|
|
|
|
|
no filler. See the "Documentation standard" section of `CLAUDE.md` for the
|
|
|
|
|
full rule; it applies to code comments and commit messages, not only to
|
|
|
|
|
`.md` files.
|