Sprint 0-9 Closeout Checklist
Concrete closeout checklist based on the current codebase audit.
Current conclusion: we are not ready to honestly declare Sprint 10 complete-in-practice yet. The main blockers are:
- Sprint 0's tolerated-diff categories are still deferred until afs-ld can emit real linked output for Mach-O-to-Mach-O differential checks.
Sprint 10 Gate
Do not declare "we are on Sprint 10" until all of these are true:
- Sprint 9 reloc referents are remapped to atom-aware forms.
- Sprint 8 resolution orchestration exists as a real callable stage, not just loose helper APIs.
-
cargo test -p afs-ldis green after the closeout work. -
cargo clippy -p afs-ld --all-targets -- -D warningsis green after the closeout work. -
README.mdand sprint docs no longer materially misstate the current state of the crate.
Recommended Order
- Close Sprint 9 reloc-to-atom remap first.
- Close Sprint 8 resolution orchestration and option coverage second.
- Close Sprint 6 TBD/SDK search gaps third.
- Close Sprint 4 nested archive support fourth.
- Finish the deferred Sprint 0 differential-harness tolerance work once afs-ld can emit real output.
Cross-Sprint Exit Criteria
- Every closeout chunk lands with tests.
- Every bug fix or behavioral gap gets a regression test.
- No newly-discovered roadmap/code mismatch is left undocumented.
- Any user-facing diagnostic we touch stays deterministic and testable.
Sprint 0
Status: closed
Validated:
-
afs-ldexists as its own git submodule in the parent workspace. - Parent
Cargo.tomlincludesafs-ldas a workspace member. -
CLAUDE.md,README.md, crate wiring, and test harness scaffolding exist. - Reference repos are present under parent
.refs/(ld64,mold,lld). -
tests/reader_empty.rsenforces the empty-invocation CLI contract. -
tests/diff_harness_sanity.rsandtests/diff_harness_finds_critical.rsexist and pass. -
cargo clippy -p afs-ld --all-targets -- -D warningsis currently clean.
Remaining closeout work:
- Explicitly downscope Sprint 0 docs so the current diff harness is described as synthetic until end-to-end linking exists.
- Add tolerated-diff categories once real Mach-O-to-Mach-O comparisons exist.
Sprint 1
Status: closed
Validated:
- Mach-O constants are duplicated locally in
src/macho/constants.rs. -
MachHeader64parsing exists and rejects malformed headers. - Load-command dispatch exists and preserves unknown commands as raw bytes.
- Segment and section-header metadata parsing exists.
-
LC_BUILD_VERSIONandLC_LINKER_OPTIMIZATION_HINTdecoding exists. -
--dumpexists throughsrc/dump.rsandsrc/main.rs. - Corpus round-trip tests pass in
tests/reader_corpus_round_trip.rs.
Remaining closeout work:
- Add an
otool -lVparity test for dumper output shape across the corpus. - Add a panic-focused malformed-input stress pass beyond the current unit tests so the "no panics on malformed input" claim is defensible.
Sprint 2
Status: closed
Validated:
- Section classification exists in
src/section.rs. -
InputSectioncarries section data and raw relocation bytes. -
RawNlist/InputSymbolparsing and classification exist insrc/symbol.rs. - Common symbols, weak flags, private externs, and indirect aliases are surfaced.
-
StringTableexists and handles suffix-dedup overlaps. -
DysymtabCmdis parsed and exposed throughObjectFile. -
ObjectFileintegrates header, commands, sections, symbols, strings, and dysymtab.
Remaining closeout work:
- Add
nm -aparity tests for symbol view and classification. - Add
otool -rparity checks for relocation-offset surfaces promised by Sprint 2, with section/load-command parity covered by the Sprint 1otool -lVgate. - Add stronger malformed-symbol / malformed-string-table stress coverage if we want the "never panics" bar to be explicit.
Sprint 3
Status: closed enough for current closeout
Validated:
- ARM64 relocation constants exist.
- Raw relocation parsing and writing exist.
- Fused
Relocform exists. -
ADDENDandSUBTRACTOR + UNSIGNEDpairing is fused inparse_relocs. - Validation logic exists in
validate_relocs. - Write-side round-trip support exists.
- Unit coverage is broad and current corpus relocation round-trips pass.
Remaining closeout work:
- No audit-blocking work found for Sprint 3.
Sprint 4
Status: closed
Validated:
- BSD, SysV, and GNU-thin archive flavors are recognized.
- Archive headers and name decoding are implemented.
- Symbol-index parsing exists for BSD and SysV archives.
- Lazy member fetch exists via
fetch_object_defining. -
libarmfortas_rt.ais exercised bytests/archive_runtime.rs. - Archive dump mode exists via
--dump-archive.
Remaining closeout work:
- Implement one-level nested archive support (
.amember inside.a) and preserve provenance for diagnostics. - Formally treat
resolve::force_load_archive/force_load_allas the Sprint 4 completion surface and document that surface instead of adding a parallel archive-only helper. - Add
ar -tshape/parity coverage for--dump-archive.
Sprint 5
Status: partially closed
Validated:
-
DylibFileexists and parses binaryMH_DYLIB. -
LC_ID_DYLIB, dependency dylib commands, ordinals, and rpaths are decoded. - Export trie decoding exists with cycle/depth protection.
- Real clang-built dylib coverage exists in
tests/dylib_integration.rs. - Dylib dump mode exists via
--dump-dylib.
Remaining closeout work:
- Prove recursive re-export / umbrella lookup behavior with a focused test, not just dependency collection.
- Confirm the public dylib surface matches what Sprint 5 intended for re-exported symbols, not only direct exports.
Sprint 6
Status: closed
Validated:
- The custom YAML subset parser exists in
src/macho/tbd_yaml.rs. - TBD schema decoding exists in
src/macho/tbd.rs. -
DylibFile::from_tbdexists and materializes TBDs into the same linker-facing surface. - Real
libSystem.tbdsmoke/integration coverage exists intests/tbd_smoke.rsandtests/tbd_integration.rs. - TBD dump mode exists via
--dump-tbd.
Remaining closeout work:
- Implement SDK
-syslibrootlibrary search helpers for.tbd/.dylib. - Implement framework search helpers promised by Sprint 6.
- Make target filtering fail loudly when the requested target is not exported, instead of only materializing matching targets when the caller already knows one exists.
- No further audit-blocking work found for Sprint 6 in the current helper/test surface.
Sprint 7
Status: closed
Validated:
-
Symbolsum type exists with the planned major variants. -
StringInterner, opaque ids, andSymbolTableexist. - The insertion matrix is heavily unit-tested.
- Weak/strong/common coalescing behavior is covered in unit tests.
- Alias-cycle detection and chain resolution exist.
- Transition logging exists.
Remaining closeout work:
- Add the differential weak-coalescing / duplicate-behavior coverage against system
ldthat Sprint 7 originally called for.
Sprint 8
Status: closed
Validated:
- Archive seeding, object seeding, and dylib seeding exist.
- Fixed-point archive fetch draining exists.
-
force_load_archiveandforce_load_allhelpers exist insrc/resolve.rs. - Undefined classification exists for
Error,Warning,Suppress, andDynamicLookup. - Did-you-mean support exists.
- Duplicate-symbol and undefined-symbol formatting helpers exist.
- Real integration coverage exists for archive pull plus unresolved-symbol reporting.
Remaining closeout work:
- Add a real orchestration entrypoint for resolution (
seed -> optional force load -> drain -> classify) that can be called as a coherent stage. - Add option/state plumbing for
all_load,force_load, and undefined treatment so resolution is not just a bag of helper APIs. - Add an archive order-sensitivity test.
- Add dedicated tests for
force_load_archiveandforce_load_all. - Add dedicated tests for
UndefinedTreatment::Warning,Suppress, andDynamicLookup. - Add a dedicated test that unresolved weak refs stay accepted regardless of treatment.
- Tighten diagnostics toward the Sprint 8 format by carrying section/offset provenance and aggregate repeated relocation sites when available.
Sprint 9
Status: closed
Validated:
- Atom model and atom table exist.
- Section splitting at symbol boundaries exists.
-
.alt_entryfolding exists. - CString atom splitting exists and is integration-tested.
- Compact-unwind atom splitting and
parent_ofwiring exist. - Backpatching of
Symbol::Defined { atom }exists. -
N_NO_DEAD_STRIPand weak-def flags are propagated into atom flags. - Embedded payload addends on symbol-based data relocs are folded into local atom offsets or preserved on external refs.
Remaining closeout work:
- Remap relocations from raw section/symbol referents into atom-aware referents.
- Add atom-local relocation storage or an equivalent per-atom relocation view.
- Ensure same-object references point at target atoms, not raw section offsets.
- Add a focused integration test proving a local branch or data reference resolves to the callee/target atom.
- Add a boundary-crossing reloc diagnostic test.
- Confirm no raw section-relative relocation state leaks into Sprint 10 inputs.
- No further audit-blocking work found for Sprint 9 in the current corpus and targeted local-addend probes.
Documentation Closeout
- Update
README.mdso it no longer says the crate is only Sprint 0 scaffolding. - Refresh sprint docs whose deliverables have been implemented under a different surface than originally planned.
- Keep
CLAUDE.mdas the authority for discipline, but make user-facing docs match the actual code.
Verification Commands
-
cargo test -p afs-ld -
cargo clippy -p afs-ld --all-targets -- -D warnings - Focused xcrun-backed checks when touching reader/resolve/atom/TBD/dylib paths:
-
cargo test -p afs-ld --test reader_corpus_round_trip -- --nocapture -
cargo test -p afs-ld --test resolve_integration -- --nocapture -
cargo test -p afs-ld --test atom_integration -- --nocapture -
cargo test -p afs-ld --test dylib_integration -- --nocapture -
cargo test -p afs-ld --test tbd_integration -- --nocapture
-
View source
| 1 | # Sprint 0-9 Closeout Checklist |
| 2 | |
| 3 | Concrete closeout checklist based on the current codebase audit. |
| 4 | |
| 5 | Current conclusion: we are not ready to honestly declare Sprint 10 complete-in-practice yet. |
| 6 | The main blockers are: |
| 7 | |
| 8 | - Sprint 0's tolerated-diff categories are still deferred until afs-ld can emit real linked output for Mach-O-to-Mach-O differential checks. |
| 9 | |
| 10 | ## Sprint 10 Gate |
| 11 | |
| 12 | Do not declare "we are on Sprint 10" until all of these are true: |
| 13 | |
| 14 | - [x] Sprint 9 reloc referents are remapped to atom-aware forms. |
| 15 | - [x] Sprint 8 resolution orchestration exists as a real callable stage, not just loose helper APIs. |
| 16 | - [x] `cargo test -p afs-ld` is green after the closeout work. |
| 17 | - [x] `cargo clippy -p afs-ld --all-targets -- -D warnings` is green after the closeout work. |
| 18 | - [x] `README.md` and sprint docs no longer materially misstate the current state of the crate. |
| 19 | |
| 20 | ## Recommended Order |
| 21 | |
| 22 | - [x] Close Sprint 9 reloc-to-atom remap first. |
| 23 | - [x] Close Sprint 8 resolution orchestration and option coverage second. |
| 24 | - [x] Close Sprint 6 TBD/SDK search gaps third. |
| 25 | - [x] Close Sprint 4 nested archive support fourth. |
| 26 | - [ ] Finish the deferred Sprint 0 differential-harness tolerance work once afs-ld can emit real output. |
| 27 | |
| 28 | ## Cross-Sprint Exit Criteria |
| 29 | |
| 30 | - [ ] Every closeout chunk lands with tests. |
| 31 | - [ ] Every bug fix or behavioral gap gets a regression test. |
| 32 | - [ ] No newly-discovered roadmap/code mismatch is left undocumented. |
| 33 | - [ ] Any user-facing diagnostic we touch stays deterministic and testable. |
| 34 | |
| 35 | ## Sprint 0 |
| 36 | |
| 37 | Status: closed |
| 38 | |
| 39 | Validated: |
| 40 | |
| 41 | - [x] `afs-ld` exists as its own git submodule in the parent workspace. |
| 42 | - [x] Parent `Cargo.toml` includes `afs-ld` as a workspace member. |
| 43 | - [x] `CLAUDE.md`, `README.md`, crate wiring, and test harness scaffolding exist. |
| 44 | - [x] Reference repos are present under parent `.refs/` (`ld64`, `mold`, `lld`). |
| 45 | - [x] `tests/reader_empty.rs` enforces the empty-invocation CLI contract. |
| 46 | - [x] `tests/diff_harness_sanity.rs` and `tests/diff_harness_finds_critical.rs` exist and pass. |
| 47 | - [x] `cargo clippy -p afs-ld --all-targets -- -D warnings` is currently clean. |
| 48 | |
| 49 | Remaining closeout work: |
| 50 | |
| 51 | - [x] Explicitly downscope Sprint 0 docs so the current diff harness is described as synthetic until end-to-end linking exists. |
| 52 | - [ ] Add tolerated-diff categories once real Mach-O-to-Mach-O comparisons exist. |
| 53 | |
| 54 | ## Sprint 1 |
| 55 | |
| 56 | Status: closed |
| 57 | |
| 58 | Validated: |
| 59 | |
| 60 | - [x] Mach-O constants are duplicated locally in `src/macho/constants.rs`. |
| 61 | - [x] `MachHeader64` parsing exists and rejects malformed headers. |
| 62 | - [x] Load-command dispatch exists and preserves unknown commands as raw bytes. |
| 63 | - [x] Segment and section-header metadata parsing exists. |
| 64 | - [x] `LC_BUILD_VERSION` and `LC_LINKER_OPTIMIZATION_HINT` decoding exists. |
| 65 | - [x] `--dump` exists through `src/dump.rs` and `src/main.rs`. |
| 66 | - [x] Corpus round-trip tests pass in `tests/reader_corpus_round_trip.rs`. |
| 67 | |
| 68 | Remaining closeout work: |
| 69 | |
| 70 | - [x] Add an `otool -lV` parity test for dumper output shape across the corpus. |
| 71 | - [x] Add a panic-focused malformed-input stress pass beyond the current unit tests so the "no panics on malformed input" claim is defensible. |
| 72 | |
| 73 | ## Sprint 2 |
| 74 | |
| 75 | Status: closed |
| 76 | |
| 77 | Validated: |
| 78 | |
| 79 | - [x] Section classification exists in `src/section.rs`. |
| 80 | - [x] `InputSection` carries section data and raw relocation bytes. |
| 81 | - [x] `RawNlist` / `InputSymbol` parsing and classification exist in `src/symbol.rs`. |
| 82 | - [x] Common symbols, weak flags, private externs, and indirect aliases are surfaced. |
| 83 | - [x] `StringTable` exists and handles suffix-dedup overlaps. |
| 84 | - [x] `DysymtabCmd` is parsed and exposed through `ObjectFile`. |
| 85 | - [x] `ObjectFile` integrates header, commands, sections, symbols, strings, and dysymtab. |
| 86 | |
| 87 | Remaining closeout work: |
| 88 | |
| 89 | - [x] Add `nm -a` parity tests for symbol view and classification. |
| 90 | - [x] Add `otool -r` parity checks for relocation-offset surfaces promised by Sprint 2, with section/load-command parity covered by the Sprint 1 `otool -lV` gate. |
| 91 | - [x] Add stronger malformed-symbol / malformed-string-table stress coverage if we want the "never panics" bar to be explicit. |
| 92 | |
| 93 | ## Sprint 3 |
| 94 | |
| 95 | Status: closed enough for current closeout |
| 96 | |
| 97 | Validated: |
| 98 | |
| 99 | - [x] ARM64 relocation constants exist. |
| 100 | - [x] Raw relocation parsing and writing exist. |
| 101 | - [x] Fused `Reloc` form exists. |
| 102 | - [x] `ADDEND` and `SUBTRACTOR + UNSIGNED` pairing is fused in `parse_relocs`. |
| 103 | - [x] Validation logic exists in `validate_relocs`. |
| 104 | - [x] Write-side round-trip support exists. |
| 105 | - [x] Unit coverage is broad and current corpus relocation round-trips pass. |
| 106 | |
| 107 | Remaining closeout work: |
| 108 | |
| 109 | - [x] No audit-blocking work found for Sprint 3. |
| 110 | |
| 111 | ## Sprint 4 |
| 112 | |
| 113 | Status: closed |
| 114 | |
| 115 | Validated: |
| 116 | |
| 117 | - [x] BSD, SysV, and GNU-thin archive flavors are recognized. |
| 118 | - [x] Archive headers and name decoding are implemented. |
| 119 | - [x] Symbol-index parsing exists for BSD and SysV archives. |
| 120 | - [x] Lazy member fetch exists via `fetch_object_defining`. |
| 121 | - [x] `libarmfortas_rt.a` is exercised by `tests/archive_runtime.rs`. |
| 122 | - [x] Archive dump mode exists via `--dump-archive`. |
| 123 | |
| 124 | Remaining closeout work: |
| 125 | |
| 126 | - [x] Implement one-level nested archive support (`.a` member inside `.a`) and preserve provenance for diagnostics. |
| 127 | - [x] Formally treat `resolve::force_load_archive` / `force_load_all` as the Sprint 4 completion surface and document that surface instead of adding a parallel archive-only helper. |
| 128 | - [x] Add `ar -t` shape/parity coverage for `--dump-archive`. |
| 129 | |
| 130 | ## Sprint 5 |
| 131 | |
| 132 | Status: partially closed |
| 133 | |
| 134 | Validated: |
| 135 | |
| 136 | - [x] `DylibFile` exists and parses binary `MH_DYLIB`. |
| 137 | - [x] `LC_ID_DYLIB`, dependency dylib commands, ordinals, and rpaths are decoded. |
| 138 | - [x] Export trie decoding exists with cycle/depth protection. |
| 139 | - [x] Real clang-built dylib coverage exists in `tests/dylib_integration.rs`. |
| 140 | - [x] Dylib dump mode exists via `--dump-dylib`. |
| 141 | |
| 142 | Remaining closeout work: |
| 143 | |
| 144 | - [ ] Prove recursive re-export / umbrella lookup behavior with a focused test, not just dependency collection. |
| 145 | - [ ] Confirm the public dylib surface matches what Sprint 5 intended for re-exported symbols, not only direct exports. |
| 146 | |
| 147 | ## Sprint 6 |
| 148 | |
| 149 | Status: closed |
| 150 | |
| 151 | Validated: |
| 152 | |
| 153 | - [x] The custom YAML subset parser exists in `src/macho/tbd_yaml.rs`. |
| 154 | - [x] TBD schema decoding exists in `src/macho/tbd.rs`. |
| 155 | - [x] `DylibFile::from_tbd` exists and materializes TBDs into the same linker-facing surface. |
| 156 | - [x] Real `libSystem.tbd` smoke/integration coverage exists in `tests/tbd_smoke.rs` and `tests/tbd_integration.rs`. |
| 157 | - [x] TBD dump mode exists via `--dump-tbd`. |
| 158 | |
| 159 | Remaining closeout work: |
| 160 | |
| 161 | - [x] Implement SDK `-syslibroot` library search helpers for `.tbd` / `.dylib`. |
| 162 | - [x] Implement framework search helpers promised by Sprint 6. |
| 163 | - [x] Make target filtering fail loudly when the requested target is not exported, instead of only materializing matching targets when the caller already knows one exists. |
| 164 | - [x] No further audit-blocking work found for Sprint 6 in the current helper/test surface. |
| 165 | |
| 166 | ## Sprint 7 |
| 167 | |
| 168 | Status: closed |
| 169 | |
| 170 | Validated: |
| 171 | |
| 172 | - [x] `Symbol` sum type exists with the planned major variants. |
| 173 | - [x] `StringInterner`, opaque ids, and `SymbolTable` exist. |
| 174 | - [x] The insertion matrix is heavily unit-tested. |
| 175 | - [x] Weak/strong/common coalescing behavior is covered in unit tests. |
| 176 | - [x] Alias-cycle detection and chain resolution exist. |
| 177 | - [x] Transition logging exists. |
| 178 | |
| 179 | Remaining closeout work: |
| 180 | |
| 181 | - [ ] Add the differential weak-coalescing / duplicate-behavior coverage against system `ld` that Sprint 7 originally called for. |
| 182 | |
| 183 | ## Sprint 8 |
| 184 | |
| 185 | Status: closed |
| 186 | |
| 187 | Validated: |
| 188 | |
| 189 | - [x] Archive seeding, object seeding, and dylib seeding exist. |
| 190 | - [x] Fixed-point archive fetch draining exists. |
| 191 | - [x] `force_load_archive` and `force_load_all` helpers exist in `src/resolve.rs`. |
| 192 | - [x] Undefined classification exists for `Error`, `Warning`, `Suppress`, and `DynamicLookup`. |
| 193 | - [x] Did-you-mean support exists. |
| 194 | - [x] Duplicate-symbol and undefined-symbol formatting helpers exist. |
| 195 | - [x] Real integration coverage exists for archive pull plus unresolved-symbol reporting. |
| 196 | |
| 197 | Remaining closeout work: |
| 198 | |
| 199 | - [x] Add a real orchestration entrypoint for resolution (`seed -> optional force load -> drain -> classify`) that can be called as a coherent stage. |
| 200 | - [x] Add option/state plumbing for `all_load`, `force_load`, and undefined treatment so resolution is not just a bag of helper APIs. |
| 201 | - [x] Add an archive order-sensitivity test. |
| 202 | - [x] Add dedicated tests for `force_load_archive` and `force_load_all`. |
| 203 | - [x] Add dedicated tests for `UndefinedTreatment::Warning`, `Suppress`, and `DynamicLookup`. |
| 204 | - [x] Add a dedicated test that unresolved weak refs stay accepted regardless of treatment. |
| 205 | - [x] Tighten diagnostics toward the Sprint 8 format by carrying section/offset provenance and aggregate repeated relocation sites when available. |
| 206 | |
| 207 | ## Sprint 9 |
| 208 | |
| 209 | Status: closed |
| 210 | |
| 211 | Validated: |
| 212 | |
| 213 | - [x] Atom model and atom table exist. |
| 214 | - [x] Section splitting at symbol boundaries exists. |
| 215 | - [x] `.alt_entry` folding exists. |
| 216 | - [x] CString atom splitting exists and is integration-tested. |
| 217 | - [x] Compact-unwind atom splitting and `parent_of` wiring exist. |
| 218 | - [x] Backpatching of `Symbol::Defined { atom }` exists. |
| 219 | - [x] `N_NO_DEAD_STRIP` and weak-def flags are propagated into atom flags. |
| 220 | - [x] Embedded payload addends on symbol-based data relocs are folded into local atom offsets or preserved on external refs. |
| 221 | |
| 222 | Remaining closeout work: |
| 223 | |
| 224 | - [x] Remap relocations from raw section/symbol referents into atom-aware referents. |
| 225 | - [x] Add atom-local relocation storage or an equivalent per-atom relocation view. |
| 226 | - [x] Ensure same-object references point at target atoms, not raw section offsets. |
| 227 | - [x] Add a focused integration test proving a local branch or data reference resolves to the callee/target atom. |
| 228 | - [x] Add a boundary-crossing reloc diagnostic test. |
| 229 | - [x] Confirm no raw section-relative relocation state leaks into Sprint 10 inputs. |
| 230 | - [x] No further audit-blocking work found for Sprint 9 in the current corpus and targeted local-addend probes. |
| 231 | |
| 232 | ## Documentation Closeout |
| 233 | |
| 234 | - [x] Update `README.md` so it no longer says the crate is only Sprint 0 scaffolding. |
| 235 | - [x] Refresh sprint docs whose deliverables have been implemented under a different surface than originally planned. |
| 236 | - [x] Keep `CLAUDE.md` as the authority for discipline, but make user-facing docs match the actual code. |
| 237 | |
| 238 | ## Verification Commands |
| 239 | |
| 240 | - [x] `cargo test -p afs-ld` |
| 241 | - [x] `cargo clippy -p afs-ld --all-targets -- -D warnings` |
| 242 | - [ ] Focused xcrun-backed checks when touching reader/resolve/atom/TBD/dylib paths: |
| 243 | - [x] `cargo test -p afs-ld --test reader_corpus_round_trip -- --nocapture` |
| 244 | - [x] `cargo test -p afs-ld --test resolve_integration -- --nocapture` |
| 245 | - [x] `cargo test -p afs-ld --test atom_integration -- --nocapture` |
| 246 | - [x] `cargo test -p afs-ld --test dylib_integration -- --nocapture` |
| 247 | - [x] `cargo test -p afs-ld --test tbd_integration -- --nocapture` |