A record from the Factory repository, docs/repository-nlink-receipt.json, shown as committed except that its local paths appear as placeholders in angle brackets, such as <local evidence archive>, standing for files that are not published; a placeholder that stands in for a key keeps the file's name, as in <local evidence file: report.md>. Every hash, date and count is as recorded. The build review says what the Factory's receipts support.
{
"recordedAt": "2026-09-28T22:31:32+00:00",
"base": "2e2ed37",
"disposition": "accepted-local",
"scope": "Native loose-object finalisation concurrency repair and the ownership checks it relies on; no identity, protocol, authority or invoke-once policy change",
"describes": "src/repository.ts from this commit on; repository-lock-receipt.json keeps its own hashes, which are now of superseded versions of src/repository.ts and the repository tests",
"defect": "Every invokeOnce writes the shared empty tree 4b825dc6. Apple Git 2.50.1 finalises a loose object by linking tmp_obj_XXXXXX to its name, then unlinking the temporary name, so a concurrent first write briefly leaves nlink 2. The unpack guard required nlink 1, so a racing sibling refused its own repository as unavailable before any claim: a false refusal, failing closed.",
"reproduction": {
"nativeGitHeldShape": "test/helpers/repository.ts holdGitFinalisation: the pinned Git writes an object with its fan-out directory append-only (uappnd), so its own unlink is refused and the two-link shape is held",
"finalTestsOnMain": "50 repository tests against main's src/repository.ts ce04aaa3: 40 pass, 10 fail (every new tolerance, race, owner, bound and limit test), including 'an object a sibling's Git is still finalising' refused as unavailable",
"guardRaceProbe": "real guard against 4 native Git writers of the same 300 fresh objects: main 353 false refusals in each of two runs; repaired 0",
"endToEnd": "concurrent first integrations in fresh stores: main 1 spurious unavailable in 200 (20 rounds x 10) and 2 in 90 in an earlier run; repaired 0 in 200"
},
"repair": "A loose object about to be written may be absent or singly linked as before, or in Git's own finalisation: two links, the other a tmp_obj_XXXXXX name beside it in the same fan-out directory (found by a search of at most 65,536 entries), or settled to one link. It must inflate to exactly the object's bytes with nothing after them, and only after that read are its links accounted; every observation must be the same inode and this user's. Nothing is waited for, deleted or taken. objects, refs, objects/info and objects/pack must be of this user. A path the guard cannot examine refuses as unavailable, never with a raw file-system error. Claim, target update, receipt and unknown-effect semantics are unchanged.",
"review": {
"model": "gpt-6-astra",
"effort": "high",
"sandbox": "read-only; runtime tests blocked there by EPERM, so archived runs were checked against file hashes",
"rounds": [
{
"report": "<local evidence archive>",
"verdict": "FAIL",
"findings": "link accounting before the content read; objects/ replacement; unbounded directory scan"
},
{
"report": "<local evidence archive>",
"verdict": "FAIL",
"findings": "settlement without an owner check; objects/ replacement; objects directory owners unchecked"
},
{
"report": "<local evidence archive>",
"verdict": "PASS",
"findings": "none; keep the stated exclusions in acceptance claims"
}
],
"narrowed": "objects/ replaced by another real directory of this user is not detected (the identity pins only the root; pinning it needs a new identity and protocol version). Stated in docs/agents/repository.md and tested: an incomplete one fails closed, a complete singly linked copy serves as the same store."
},
"beforeAfter": {
"before": {
"src/repository.ts": "ce04aaa3e7ea4848fa177c6147e77718cd9b6f5bcfb5997ef6549bb34eacfd0d",
"guardRaceProbeRefusals": 353,
"heldShape": "refused unavailable"
},
"after": {
"src/repository.ts": "e5fdfb433cde85e7c1924744c056d95bbf0468641f830ff12b8a9fb7965d27c8",
"guardRaceProbeRefusals": 0,
"heldShape": "confirmed, dispatched once, temporary name untouched"
}
},
"raceTestPreWrite": "The empty-tree pre-write in the race tests (factory/producers 3b71cd1) is not on this branch; the race tests here race the first empty-tree write natively and pass. Keep it absent when integrating.",
"verification": {
"strictTypecheck": "passed",
"focusedRepositoryTests": 50,
"fullTests": 379,
"failures": 0,
"skipped": 0,
"checkExit": 0,
"checkLog": "<local evidence archive>"
},
"limits": [
"Trusted local repository storage only; no hostile concurrent writer guarantee: a same-user writer acting between the guard's calls is not excluded, though the guard repeats after Git ends",
"objects/ replaced by another real directory of this user is not detected; its objects are still verified on read and each written object's links accounted inside the root",
"Git's finalisation link in a fan-out directory of more than 65,536 entries refuses unless its temporary name is among those examined",
"Foreign owners are exercised with reported stat results, not with another account; Git is not authenticated as the link's creator",
"Apple Git 2.50.1 link-then-unlink finalisation with core.fsyncMethod=fsync only"
],
"evidenceSha256": {
"src/repository.ts": "e5fdfb433cde85e7c1924744c056d95bbf0468641f830ff12b8a9fb7965d27c8",
"test/helpers/repository.ts": "af0bf928459fc7e0b1a79449752e21656ee84f93e713fa2cc253ba1eb1f7881a",
"test/repository-boundaries.test.ts": "3311e771703b99ca55dda62797f595aee384062e4867cf4ed2747139e8d59bed",
"test/repository-integration.test.ts": "6b7ed08b80d784dd2259b6a9f768e8c150f0b414d8751d7e7cd191e904847bf0",
"test/repository-nlink-adversarial.test.ts": "4b2c016072bde64d439fef18332750dd1111a6e960089fe4ab674d84e36d8075",
"docs/agents/repository.md": "1b378acad07cfb921aecb40dc9d54a6c84bda26cc0d1d10a002cbcf9aba5b1f2",
"docs/build-review.md": "c921ba37a826f79865c2da44764c93480ec41c4c2c4b75bb62cf10980dd5e4ec",
"<local evidence archive: astra-r1.md>": "e84fde054562e09fda192fc3da7b72ed9a9af87be156bd0b36ce8e9168b03980",
"<local evidence archive: astra-r2.md>": "7c55823c46e1669511dce0d7e84fe7c9cbba6a6e9738e89e7a3efb408b64e002",
"<local evidence archive: astra-r3.md>": "9135a4f9179d74106d45b17cd2d9c79c4079eb8b0c8676ee3dc6376ecaea19b8",
"<local evidence archive: astra-r2-context.txt>": "865ff18bdcb62a604a1b3e60a75aa3cbd87cb146cf9b65e891b983c327dfc77b",
"<local evidence archive: astra-r3-context.txt>": "a131c2aeb04e3ede63f15c58c2d0af2e8c66dfc829a0bc7c909c4e10a9e4e148",
"<local evidence archive: race-probe.ts>": "49cc33d55670cd49830e9e6ad5ba61061bb73058cef9a0a2edabafd9975a189c",
"<local evidence archive: expose.mjs>": "39ac9155ea6461ed3ded179e74fd636c69e25d3ff48ca3ef8403c04ca713d554",
"<local evidence archive: race-probe-before-after.log>": "3c66266e3df201499473f723823cc132ef91bfad9cb16cefe7a04dde967d7383",
"<local evidence archive: race-probe-after.log>": "272a1eb4bfb772eb36e1ce1af1ceb6bf1936e78c869053fb6eef88937cbb5591",
"<local evidence archive: final-tests-on-main.log>": "13995b1d38a04a35cb224e7e90a367a38b193ca77edea802a825ad28b73c1c0e",
"<local evidence archive: e2e-stress-after.test.ts>": "97a6a252d160bc0c834d47333d79fbe14164de017b0797b485ad9cfff53146f5",
"<local evidence archive: e2e-stress-before-10.log>": "9b5c58b7fe97a7ca3f30026b22b192c3f23b7b3a3005a135cb4e08beb555f42a",
"<local evidence archive: e2e-stress-old.log>": "68acb4c247cd19cf0ef8ac914384f0fcc4b49ba5b3de86c6ce3db686eb8fbd05",
"<local evidence archive: e2e-stress-after-10.log>": "c9b7e8dd9e0422c4ea075640585db7320d00fde8b02ef500cd14984200a457d4",
"<local evidence archive: repository-focused.log>": "a42ad648d4aa8505d811e1348036d264d82aa740f2396b222d145d549c29cfce",
"<local evidence archive: check.log>": "3c5e3df726c8013b452341cde4a0884eeed9b59fa12fc3d9a8700b40535817be"
}
}
