| … | … | @@ -110,6 +110,24 @@ export class OverlayRepoStore { |
| 110 | 110 | return join(this._recordsDir, collection, rkey + EXT) |
| 111 | 111 | } |
| 112 | 112 | |
| 113 | // READ-ONLY: the overlay oid the record file CURRENTLY on disk hashes to, or null when absent. |
| 114 | // Writes nothing (no registration, no index entry) — safe against a live store. |
| 115 | // |
| 116 | // This is the missing half of the pointer design's integrity story. PointerSubstrate stores |
| 117 | // { $oid, size } in the shared autobase and resolves it through ensureLocal, which returns a local |
| 118 | // file hit WITHOUT comparing it to $oid — so a node holding a superseded copy of a record serves it |
| 119 | // forever and never re-fetches, while its pointer set looks perfectly converged. Nothing in the |
| 120 | // stack could even ask "does my file match the pointer?", which is why the wj62 profile divergence |
| 121 | // (two co-owners, identical 139 pointers, different avatar blob refs) was only visible by diffing |
| 122 | // two signed CARs against each other. Compare this against the pointer's $oid to answer it directly. |
| 123 | async localOid (collection, rkey) { |
| 124 | if (!this._overlay || typeof this._overlay.hashFile !== 'function') return null |
| 125 | let p |
| 126 | try { p = this._pathFor(collection, rkey) } catch { return null } |
| 127 | const r = await this._overlay.hashFile(p) |
| 128 | return r ? { oid: r.contentHash, size: r.size } : null |
| 129 | } |
| 130 | |
| 113 | 131 | // Returns { oid, size }: oid = the overlay content hash (blake2b) that a PEER fetches the bytes by |
| 114 | 132 | // (PointerSubstrate stores {oid,size} as the symmetric autobase pointer). null oid when no overlay. |
| 115 | 133 | async put (collection, rkey, record) { |