@izagood/avcs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +221 -0
- package/dist/api/repo.d.ts +616 -0
- package/dist/api/repo.d.ts.map +1 -0
- package/dist/api/repo.js +1772 -0
- package/dist/api/repo.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +660 -0
- package/dist/cli.js.map +1 -0
- package/dist/concurrency/lease.d.ts +27 -0
- package/dist/concurrency/lease.d.ts.map +1 -0
- package/dist/concurrency/lease.js +63 -0
- package/dist/concurrency/lease.js.map +1 -0
- package/dist/core/canonical.d.ts +16 -0
- package/dist/core/canonical.d.ts.map +1 -0
- package/dist/core/canonical.js +66 -0
- package/dist/core/canonical.js.map +1 -0
- package/dist/core/cbor.d.ts +9 -0
- package/dist/core/cbor.d.ts.map +1 -0
- package/dist/core/cbor.js +213 -0
- package/dist/core/cbor.js.map +1 -0
- package/dist/core/clock.d.ts +18 -0
- package/dist/core/clock.d.ts.map +1 -0
- package/dist/core/clock.js +32 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/identity.d.ts +34 -0
- package/dist/core/identity.d.ts.map +1 -0
- package/dist/core/identity.js +62 -0
- package/dist/core/identity.js.map +1 -0
- package/dist/hub/hubClient.d.ts +38 -0
- package/dist/hub/hubClient.d.ts.map +1 -0
- package/dist/hub/hubClient.js +157 -0
- package/dist/hub/hubClient.js.map +1 -0
- package/dist/hub/hubServer.d.ts +28 -0
- package/dist/hub/hubServer.d.ts.map +1 -0
- package/dist/hub/hubServer.js +365 -0
- package/dist/hub/hubServer.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/objects/types.d.ts +352 -0
- package/dist/objects/types.d.ts.map +1 -0
- package/dist/objects/types.js +17 -0
- package/dist/objects/types.js.map +1 -0
- package/dist/observe/logger.d.ts +27 -0
- package/dist/observe/logger.d.ts.map +1 -0
- package/dist/observe/logger.js +37 -0
- package/dist/observe/logger.js.map +1 -0
- package/dist/observe/metrics.d.ts +20 -0
- package/dist/observe/metrics.d.ts.map +1 -0
- package/dist/observe/metrics.js +42 -0
- package/dist/observe/metrics.js.map +1 -0
- package/dist/policy/owners.d.ts +5 -0
- package/dist/policy/owners.d.ts.map +1 -0
- package/dist/policy/owners.js +38 -0
- package/dist/policy/owners.js.map +1 -0
- package/dist/policy/reliability.d.ts +7 -0
- package/dist/policy/reliability.d.ts.map +1 -0
- package/dist/policy/reliability.js +41 -0
- package/dist/policy/reliability.js.map +1 -0
- package/dist/query/diff.d.ts +16 -0
- package/dist/query/diff.d.ts.map +1 -0
- package/dist/query/diff.js +32 -0
- package/dist/query/diff.js.map +1 -0
- package/dist/reducer/incremental.d.ts +2 -0
- package/dist/reducer/incremental.d.ts.map +1 -0
- package/dist/reducer/incremental.js +14 -0
- package/dist/reducer/incremental.js.map +1 -0
- package/dist/reducer/policy.d.ts +17 -0
- package/dist/reducer/policy.d.ts.map +1 -0
- package/dist/reducer/policy.js +143 -0
- package/dist/reducer/policy.js.map +1 -0
- package/dist/reducer/reducer.d.ts +155 -0
- package/dist/reducer/reducer.d.ts.map +1 -0
- package/dist/reducer/reducer.js +849 -0
- package/dist/reducer/reducer.js.map +1 -0
- package/dist/release/sbom.d.ts +7 -0
- package/dist/release/sbom.d.ts.map +1 -0
- package/dist/release/sbom.js +26 -0
- package/dist/release/sbom.js.map +1 -0
- package/dist/semantic/contract.d.ts +32 -0
- package/dist/semantic/contract.d.ts.map +1 -0
- package/dist/semantic/contract.js +150 -0
- package/dist/semantic/contract.js.map +1 -0
- package/dist/semantic/symbols.d.ts +45 -0
- package/dist/semantic/symbols.d.ts.map +1 -0
- package/dist/semantic/symbols.js +323 -0
- package/dist/semantic/symbols.js.map +1 -0
- package/dist/store/applyRedactions.d.ts +16 -0
- package/dist/store/applyRedactions.d.ts.map +1 -0
- package/dist/store/applyRedactions.js +60 -0
- package/dist/store/applyRedactions.js.map +1 -0
- package/dist/store/lock.d.ts +12 -0
- package/dist/store/lock.d.ts.map +1 -0
- package/dist/store/lock.js +63 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/objectStore.d.ts +127 -0
- package/dist/store/objectStore.d.ts.map +1 -0
- package/dist/store/objectStore.js +549 -0
- package/dist/store/objectStore.js.map +1 -0
- package/dist/validation/repair.d.ts +31 -0
- package/dist/validation/repair.d.ts.map +1 -0
- package/dist/validation/repair.js +37 -0
- package/dist/validation/repair.js.map +1 -0
- package/dist/validation/runner.d.ts +20 -0
- package/dist/validation/runner.d.ts.map +1 -0
- package/dist/validation/runner.js +90 -0
- package/dist/validation/runner.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
// Append-only, content-addressed object store.
|
|
2
|
+
//
|
|
3
|
+
// Physical layout (under <repo>/.avcs):
|
|
4
|
+
// objects/<aa>/<oid>.json immutable objects, sharded by oid prefix
|
|
5
|
+
// refs/<name> named pointers (e.g. the default view), mutable
|
|
6
|
+
// HEAD the active view name
|
|
7
|
+
//
|
|
8
|
+
// Objects are never modified or deleted. "Changing" the world means appending a new
|
|
9
|
+
// object (a new operation, a decision, a superseding op). This is what makes AVCS
|
|
10
|
+
// fully auditable: the entire causal history of how code reached its current state
|
|
11
|
+
// is replayable.
|
|
12
|
+
import { mkdir, readFile, readdir, stat, open, rename, appendFile, rm } from "node:fs/promises";
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { join, dirname } from "node:path";
|
|
15
|
+
import { Buffer } from "node:buffer";
|
|
16
|
+
import { computeOid, sha256hex } from "../core/canonical.js";
|
|
17
|
+
import { encodeCbor, decodeCbor, looksLikeCbor } from "../core/cbor.js";
|
|
18
|
+
import { withLock } from "./lock.js";
|
|
19
|
+
/**
|
|
20
|
+
* A stored object's bytes could not be decoded — bit-rot, truncation, or a torn write
|
|
21
|
+
* that slipped past the atomic-write guarantee (D1). Typed (not an opaque `SyntaxError`)
|
|
22
|
+
* and carries the offending `oid` so a decode failure deep in `materialize`/`pull` is
|
|
23
|
+
* actionable: the caller knows exactly which object to `fsck`/repair. F1 (docs/13).
|
|
24
|
+
*/
|
|
25
|
+
export class CorruptObjectError extends Error {
|
|
26
|
+
oid;
|
|
27
|
+
constructor(message, opts) {
|
|
28
|
+
super(message, opts?.cause !== undefined ? { cause: opts.cause } : undefined);
|
|
29
|
+
this.name = "CorruptObjectError";
|
|
30
|
+
this.oid = opts?.oid;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Deserialize a stored object: CBOR (new format) or legacy canonical-JSON, sniffed by
|
|
34
|
+
* the first byte. oids are JSON-derived so both formats address identically (B1). Any
|
|
35
|
+
* malformed input (truncated CBOR, broken JSON, empty file) is normalized to a typed
|
|
36
|
+
* {@link CorruptObjectError} carrying `oid` — never an opaque parser throw (F1). */
|
|
37
|
+
function decodeObject(raw, oid) {
|
|
38
|
+
try {
|
|
39
|
+
return (looksLikeCbor(raw) ? decodeCbor(raw) : JSON.parse(raw.toString("utf8")));
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
const where = oid ? ` ${oid}` : "";
|
|
43
|
+
throw new CorruptObjectError(`undecodable object${where}: ${e.message}`, { oid, cause: e });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Opt-out of fsync for throughput-bound bulk loads (D1). Durability traded for speed. */
|
|
47
|
+
const NO_FSYNC = process.env.AVCS_NO_FSYNC === "1";
|
|
48
|
+
export class ObjectStore {
|
|
49
|
+
root; // the .avcs directory
|
|
50
|
+
#wc = 0; // temp-file counter for atomic writes
|
|
51
|
+
#packLoc = null; // lazy oid → pack location index (B2)
|
|
52
|
+
constructor(repoDir) {
|
|
53
|
+
this.root = join(repoDir, ".avcs");
|
|
54
|
+
}
|
|
55
|
+
async init() {
|
|
56
|
+
await mkdir(join(this.root, "objects"), { recursive: true });
|
|
57
|
+
await mkdir(join(this.root, "refs"), { recursive: true });
|
|
58
|
+
await mkdir(join(this.root, "locks"), { recursive: true });
|
|
59
|
+
await mkdir(join(this.root, "indexes", "entity"), { recursive: true });
|
|
60
|
+
if (!existsSync(join(this.root, "HEAD"))) {
|
|
61
|
+
await this.#writeAtomic(join(this.root, "HEAD"), "main");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Crash- and concurrency-safe write: write a unique temp file in the same dir,
|
|
66
|
+
* fsync it, then atomically rename over the target. A reader therefore sees either
|
|
67
|
+
* the old file or the complete new one — never a torn/partial read. (H-5)
|
|
68
|
+
*
|
|
69
|
+
* After the rename we fsync the *containing directory* (D1): a fsync of the file
|
|
70
|
+
* persists its bytes but not necessarily the directory entry created by the rename,
|
|
71
|
+
* so a power loss could otherwise lose a just-written object/ref/HEAD even after
|
|
72
|
+
* this call returned. Set AVCS_NO_FSYNC=1 to skip all fsyncs for throughput-bound
|
|
73
|
+
* bulk loads (durability traded for speed).
|
|
74
|
+
*/
|
|
75
|
+
async #writeAtomic(path, data) {
|
|
76
|
+
const tmp = `${path}.tmp-${process.pid}-${++this.#wc}`;
|
|
77
|
+
const fh = await open(tmp, "w");
|
|
78
|
+
try {
|
|
79
|
+
await fh.writeFile(data);
|
|
80
|
+
if (!NO_FSYNC)
|
|
81
|
+
await fh.sync();
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await fh.close();
|
|
85
|
+
}
|
|
86
|
+
await rename(tmp, path); // atomic on the same filesystem
|
|
87
|
+
await this.#fsyncDir(dirname(path)); // persist the new directory entry
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* fsync a directory so a just-created/renamed/appended entry survives power loss.
|
|
91
|
+
* Best-effort: some platforms reject opening a directory for fsync (EISDIR/EPERM/
|
|
92
|
+
* EINVAL) — there the rename's own ordering is the durability guarantee, so we
|
|
93
|
+
* swallow those rather than fail the write. No-op under AVCS_NO_FSYNC.
|
|
94
|
+
*/
|
|
95
|
+
async #fsyncDir(dir) {
|
|
96
|
+
if (NO_FSYNC)
|
|
97
|
+
return;
|
|
98
|
+
let dh;
|
|
99
|
+
try {
|
|
100
|
+
dh = await open(dir, "r");
|
|
101
|
+
await dh.sync();
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
const code = e.code;
|
|
105
|
+
if (code && !["EISDIR", "EPERM", "EINVAL", "ENOENT", "EACCES"].includes(code))
|
|
106
|
+
throw e;
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
await dh?.close();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Durable append: append `line` to a file, fsync the file's data, and fsync its
|
|
114
|
+
* directory (the first append also creates the directory entry). This is what keeps
|
|
115
|
+
* the op-log and entity index from losing their last record(s) on a hard crash. (D1)
|
|
116
|
+
*/
|
|
117
|
+
async #appendDurable(path, line) {
|
|
118
|
+
await appendFile(path, line, "utf8");
|
|
119
|
+
if (NO_FSYNC)
|
|
120
|
+
return;
|
|
121
|
+
let fh;
|
|
122
|
+
try {
|
|
123
|
+
fh = await open(path, "r+");
|
|
124
|
+
await fh.sync();
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await fh?.close();
|
|
128
|
+
}
|
|
129
|
+
await this.#fsyncDir(dirname(path));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Atomically write a derived auxiliary file under the repo's `.avcs` root, reusing the
|
|
133
|
+
* crash-safe temp→fsync→rename→fsync-dir path (D1/D2). For repo-managed caches the
|
|
134
|
+
* store doesn't model as objects — e.g. the compaction snapshot. `relPath` is resolved
|
|
135
|
+
* under root; parent dirs are created. Crash-safe: a reader sees old-or-complete, and
|
|
136
|
+
* the file survives a hard crash once this returns.
|
|
137
|
+
*/
|
|
138
|
+
async writeAux(relPath, data) {
|
|
139
|
+
const p = join(this.root, relPath);
|
|
140
|
+
await mkdir(dirname(p), { recursive: true });
|
|
141
|
+
await this.#writeAtomic(p, data);
|
|
142
|
+
}
|
|
143
|
+
/** Durably append a line to an auxiliary log under the repo's `.avcs` root (e.g. the
|
|
144
|
+
* hub audit log, E7). Reuses the fsync-file + fsync-dir append path. */
|
|
145
|
+
async appendAux(relPath, line) {
|
|
146
|
+
const p = join(this.root, relPath);
|
|
147
|
+
await mkdir(dirname(p), { recursive: true });
|
|
148
|
+
await this.#appendDurable(p, line);
|
|
149
|
+
}
|
|
150
|
+
/** Run a critical section under a named cross-process lock (see lock.ts). */
|
|
151
|
+
async withLock(name, fn, opts) {
|
|
152
|
+
return withLock(join(this.root, "locks"), name, fn, opts);
|
|
153
|
+
}
|
|
154
|
+
// ── entity index (Phase 9) ──────────────────────────────────────────────
|
|
155
|
+
// An append-only secondary index: entity key → op oids, sharded by key hash, so
|
|
156
|
+
// "history of this symbol" is O(ops-on-that-entity) instead of a full-store scan.
|
|
157
|
+
// It is a rebuildable cache (O_APPEND keeps small records atomic across processes).
|
|
158
|
+
#indexPathFor(key) {
|
|
159
|
+
const h = sha256hex(key);
|
|
160
|
+
return join(this.root, "indexes", "entity", h.slice(0, 2), `${h.slice(0, 32)}.idx`);
|
|
161
|
+
}
|
|
162
|
+
async appendEntityIndex(key, oid) {
|
|
163
|
+
const p = this.#indexPathFor(key);
|
|
164
|
+
await mkdir(dirname(p), { recursive: true });
|
|
165
|
+
await this.#appendDurable(p, `${oid}\n`);
|
|
166
|
+
}
|
|
167
|
+
async readEntityIndex(key) {
|
|
168
|
+
const p = this.#indexPathFor(key);
|
|
169
|
+
if (!existsSync(p))
|
|
170
|
+
return [];
|
|
171
|
+
const seen = new Set();
|
|
172
|
+
for (const line of (await readFile(p, "utf8")).split("\n"))
|
|
173
|
+
if (line)
|
|
174
|
+
seen.add(line);
|
|
175
|
+
return [...seen];
|
|
176
|
+
}
|
|
177
|
+
static isRepo(repoDir) {
|
|
178
|
+
return existsSync(join(repoDir, ".avcs", "objects"));
|
|
179
|
+
}
|
|
180
|
+
#pathFor(oid) {
|
|
181
|
+
// shard by the first 2 hex chars after the type prefix
|
|
182
|
+
const hexStart = oid.indexOf("_") + 1;
|
|
183
|
+
const shard = oid.slice(hexStart, hexStart + 2) || "00";
|
|
184
|
+
return join(this.root, "objects", shard, `${oid}.json`);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Write an object. Returns its oid. Idempotent: writing identical content yields
|
|
188
|
+
* the same oid and is a no-op if already present (append-only honored).
|
|
189
|
+
*/
|
|
190
|
+
async put(obj) {
|
|
191
|
+
const { oid: _ignore, ...payload } = obj;
|
|
192
|
+
void _ignore;
|
|
193
|
+
const oid = computeOid(obj.type, payload);
|
|
194
|
+
const p = this.#pathFor(oid);
|
|
195
|
+
if (!existsSync(p)) {
|
|
196
|
+
await mkdir(dirname(p), { recursive: true });
|
|
197
|
+
// Atomic: concurrent writers of the same oid write distinct temp files and the
|
|
198
|
+
// rename is a no-op overwrite with identical content; never a torn object.
|
|
199
|
+
// Stored as canonical CBOR (B1) — oid stays JSON-derived, so this is oid-neutral.
|
|
200
|
+
await this.#writeAtomic(p, encodeCbor({ ...payload, oid }));
|
|
201
|
+
// Op-log (docs/11 A5): append the oid of every NEWLY-written operation to a single
|
|
202
|
+
// append-only log, AFTER the object is durable. This is the choke point through
|
|
203
|
+
// which every op enters the store — authoring, pull, importBundle, hub push — so
|
|
204
|
+
// the log is automatically consistent with the op set regardless of ingress path.
|
|
205
|
+
// It lets a reader tail only the ops added since its last read (incremental reduce)
|
|
206
|
+
// instead of scanning every shard. O_APPEND keeps small records atomic across
|
|
207
|
+
// processes (same pattern as the entity index).
|
|
208
|
+
if (obj.type === "operation")
|
|
209
|
+
await this.#appendDurable(join(this.root, "oplog"), `${oid}\n`);
|
|
210
|
+
// Object-log (E5 / docs/13): append EVERY newly-written object's oid (all types)
|
|
211
|
+
// to a single append-only log in arrival order. A hub serves `GET /sync?since=N`
|
|
212
|
+
// from it so a client fetches only objects added since its last sync, instead of
|
|
213
|
+
// diffing the whole oid set each time. Append-only (never reordered in normal
|
|
214
|
+
// operation), so a numeric cursor is stable. Rebuildable cache; backfilled lazily.
|
|
215
|
+
await this.#appendDurable(join(this.root, "objlog"), `${oid}\n`);
|
|
216
|
+
}
|
|
217
|
+
return oid;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Op-log in authoring/arrival order (docs/11 A5). Returns oids of every operation ever
|
|
221
|
+
* written, deduped, FIRST-WRITE order preserved. May include oids of operations later
|
|
222
|
+
* removed by GC (the store is the source of truth — callers tolerate a missing object).
|
|
223
|
+
* Empty for a store created before the op-log existed; `rebuildOpLog` backfills it.
|
|
224
|
+
*/
|
|
225
|
+
async readOpLog() {
|
|
226
|
+
const p = join(this.root, "oplog");
|
|
227
|
+
if (!existsSync(p))
|
|
228
|
+
return [];
|
|
229
|
+
const seen = new Set();
|
|
230
|
+
const out = [];
|
|
231
|
+
for (const line of (await readFile(p, "utf8")).split("\n"))
|
|
232
|
+
if (line && !seen.has(line)) {
|
|
233
|
+
seen.add(line);
|
|
234
|
+
out.push(line);
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Object-log in arrival order (E5): oids of EVERY object ever written, deduped,
|
|
240
|
+
* first-write order preserved. A store predating the log (or one that just upgraded)
|
|
241
|
+
* is backfilled once from a full scan — that scan order becomes this hub's stable
|
|
242
|
+
* append base. Append-only afterward, so an index into it is a valid sync cursor.
|
|
243
|
+
*/
|
|
244
|
+
async readObjLog() {
|
|
245
|
+
const p = join(this.root, "objlog");
|
|
246
|
+
if (!existsSync(p))
|
|
247
|
+
await this.#backfillObjLog();
|
|
248
|
+
if (!existsSync(p))
|
|
249
|
+
return [];
|
|
250
|
+
const seen = new Set();
|
|
251
|
+
const out = [];
|
|
252
|
+
for (const line of (await readFile(p, "utf8")).split("\n"))
|
|
253
|
+
if (line && !seen.has(line)) {
|
|
254
|
+
seen.add(line);
|
|
255
|
+
out.push(line);
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
/** One-time backfill of the object-log for a store that predates it. */
|
|
260
|
+
async #backfillObjLog() {
|
|
261
|
+
const oids = [];
|
|
262
|
+
for await (const o of this.list())
|
|
263
|
+
oids.push(o.oid);
|
|
264
|
+
if (oids.length)
|
|
265
|
+
await this.#writeAtomic(join(this.root, "objlog"), oids.map((o) => `${o}\n`).join(""));
|
|
266
|
+
}
|
|
267
|
+
/** Backfill the op-log from a full scan (for stores predating it, or after corruption).
|
|
268
|
+
* Rewrites it atomically to the current operation set in canonical oid order. */
|
|
269
|
+
async rebuildOpLog() {
|
|
270
|
+
const oids = [];
|
|
271
|
+
for await (const o of this.list("operation"))
|
|
272
|
+
oids.push(o.oid);
|
|
273
|
+
oids.sort();
|
|
274
|
+
await this.#writeAtomic(join(this.root, "oplog"), oids.map((o) => `${o}\n`).join(""));
|
|
275
|
+
return oids.length;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Redaction exception (Phase 12): overwrite the object stored AT `oid` with new
|
|
279
|
+
* content that no longer hashes to it. This is the ONE place append-only/content-
|
|
280
|
+
* addressing yields — used only by an admin-signed Redaction to evict leaked bytes
|
|
281
|
+
* while keeping the oid (and every reference to it) valid.
|
|
282
|
+
*/
|
|
283
|
+
async overwriteAt(oid, obj) {
|
|
284
|
+
const { oid: _drop, ...payload } = obj;
|
|
285
|
+
void _drop;
|
|
286
|
+
const p = this.#pathFor(oid);
|
|
287
|
+
await mkdir(dirname(p), { recursive: true }); // shard dir may not exist yet on a fresh clone
|
|
288
|
+
await this.#writeAtomic(p, encodeCbor({ ...payload, oid }));
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* GC exception: delete an object file. Used only by `repo.gc` to reclaim objects
|
|
292
|
+
* that are unreachable from the authoritative graph (orphan blobs, expired
|
|
293
|
+
* quarantined ops). The append-only audit history of accepted ops is never removed.
|
|
294
|
+
*/
|
|
295
|
+
async deleteObject(oid) {
|
|
296
|
+
const p = this.#pathFor(oid);
|
|
297
|
+
if (existsSync(p))
|
|
298
|
+
await rm(p, { force: true });
|
|
299
|
+
}
|
|
300
|
+
async get(oid) {
|
|
301
|
+
const p = this.#pathFor(oid);
|
|
302
|
+
if (existsSync(p))
|
|
303
|
+
return decodeObject(await readFile(p), oid); // loose shadows packs
|
|
304
|
+
const loc = (await this.#packLocations()).get(oid);
|
|
305
|
+
if (loc)
|
|
306
|
+
return decodeObject(await this.#readPackSlice(loc), oid);
|
|
307
|
+
return decodeObject(await readFile(p), oid); // absent → throws ENOENT (prior behavior)
|
|
308
|
+
}
|
|
309
|
+
async has(oid) {
|
|
310
|
+
return existsSync(this.#pathFor(oid)) || (await this.#packLocations()).has(oid);
|
|
311
|
+
}
|
|
312
|
+
/** Stream every object of a given type — loose objects first, then packed ones (B2). */
|
|
313
|
+
async *list(type) {
|
|
314
|
+
const seen = new Set();
|
|
315
|
+
const objectsDir = join(this.root, "objects");
|
|
316
|
+
if (existsSync(objectsDir)) {
|
|
317
|
+
for (const shard of await readdir(objectsDir)) {
|
|
318
|
+
const shardDir = join(objectsDir, shard);
|
|
319
|
+
if (!(await stat(shardDir)).isDirectory())
|
|
320
|
+
continue;
|
|
321
|
+
for (const file of await readdir(shardDir)) {
|
|
322
|
+
if (!file.endsWith(".json"))
|
|
323
|
+
continue;
|
|
324
|
+
if (type && !file.startsWith(`${type}_`))
|
|
325
|
+
continue;
|
|
326
|
+
seen.add(file.slice(0, -".json".length));
|
|
327
|
+
yield decodeObject(await readFile(join(shardDir, file)), file.slice(0, -".json".length));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
for (const [oid, loc] of await this.#packLocations()) {
|
|
332
|
+
if (seen.has(oid))
|
|
333
|
+
continue; // a re-added loose copy already yielded
|
|
334
|
+
if (type && !oid.startsWith(`${type}_`))
|
|
335
|
+
continue;
|
|
336
|
+
yield decodeObject(await this.#readPackSlice(loc), oid);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// ── packing (docs/11 B2) ──────────────────────────────────────────────────
|
|
340
|
+
// Many tiny loose object files are inode-heavy and slow to scan. `pack` folds them
|
|
341
|
+
// into a single append-only packfile + index (oid → offset,length). Reads check loose
|
|
342
|
+
// first, then packs, so packing is a transparent read optimization. BLOBS are never
|
|
343
|
+
// packed: redaction overwrites a blob's bytes in place (overwriteAt), and rewriting a
|
|
344
|
+
// packfile to evict bytes is costly — keeping blobs loose makes redaction always able
|
|
345
|
+
// to scrub plaintext. (Operations/evidence/decisions/etc. are append-only & immutable.)
|
|
346
|
+
async #packLocations() {
|
|
347
|
+
if (this.#packLoc)
|
|
348
|
+
return this.#packLoc;
|
|
349
|
+
const m = new Map();
|
|
350
|
+
const dir = join(this.root, "packs");
|
|
351
|
+
if (existsSync(dir)) {
|
|
352
|
+
for (const f of await readdir(dir)) {
|
|
353
|
+
if (!f.endsWith(".idx"))
|
|
354
|
+
continue;
|
|
355
|
+
const packFile = join(dir, `${f.slice(0, -".idx".length)}.pack`);
|
|
356
|
+
for (const line of (await readFile(join(dir, f), "utf8")).split("\n")) {
|
|
357
|
+
if (!line)
|
|
358
|
+
continue;
|
|
359
|
+
const [oid, off, len] = line.split(" "); // oids contain no spaces
|
|
360
|
+
if (oid)
|
|
361
|
+
m.set(oid, { file: packFile, offset: Number(off), length: Number(len) });
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
this.#packLoc = m;
|
|
366
|
+
return m;
|
|
367
|
+
}
|
|
368
|
+
async #readPackSlice(loc) {
|
|
369
|
+
const fh = await open(loc.file, "r");
|
|
370
|
+
try {
|
|
371
|
+
const buf = Buffer.alloc(loc.length);
|
|
372
|
+
await fh.read(buf, 0, loc.length, loc.offset);
|
|
373
|
+
return buf;
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
await fh.close();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Fold all loose NON-blob objects into a new packfile (+ index), then delete the loose
|
|
381
|
+
* copies. Idempotent in effect (already-packed objects have no loose file). Reads stay
|
|
382
|
+
* correct throughout (loose-first, then packs). Returns how many objects were packed.
|
|
383
|
+
*/
|
|
384
|
+
async pack() {
|
|
385
|
+
return this.withLock("pack", async () => {
|
|
386
|
+
const objectsDir = join(this.root, "objects");
|
|
387
|
+
if (!existsSync(objectsDir))
|
|
388
|
+
return { packed: 0 };
|
|
389
|
+
const entries = [];
|
|
390
|
+
for (const shard of await readdir(objectsDir)) {
|
|
391
|
+
const shardDir = join(objectsDir, shard);
|
|
392
|
+
if (!(await stat(shardDir)).isDirectory())
|
|
393
|
+
continue;
|
|
394
|
+
for (const file of await readdir(shardDir)) {
|
|
395
|
+
if (!file.endsWith(".json") || file.startsWith("blob_"))
|
|
396
|
+
continue; // blobs stay loose
|
|
397
|
+
entries.push({ oid: file.slice(0, -".json".length), bytes: await readFile(join(shardDir, file)) });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (entries.length === 0)
|
|
401
|
+
return { packed: 0 };
|
|
402
|
+
entries.sort((a, b) => (a.oid < b.oid ? -1 : a.oid > b.oid ? 1 : 0)); // deterministic layout
|
|
403
|
+
const packDir = join(this.root, "packs");
|
|
404
|
+
await mkdir(packDir, { recursive: true });
|
|
405
|
+
const n = (await readdir(packDir)).filter((f) => f.endsWith(".pack")).length;
|
|
406
|
+
const base = `pack-${n}`;
|
|
407
|
+
const idxLines = [];
|
|
408
|
+
let offset = 0;
|
|
409
|
+
for (const e of entries) {
|
|
410
|
+
idxLines.push(`${e.oid} ${offset} ${e.bytes.length}`);
|
|
411
|
+
offset += e.bytes.length;
|
|
412
|
+
}
|
|
413
|
+
// Write the packfile + index BEFORE removing loose copies (crash-safe: a crash
|
|
414
|
+
// leaves both, and reads prefer loose — never a lost object).
|
|
415
|
+
await this.#writeAtomic(join(packDir, `${base}.pack`), Buffer.concat(entries.map((e) => e.bytes)));
|
|
416
|
+
await this.#writeAtomic(join(packDir, `${base}.idx`), `${idxLines.join("\n")}\n`);
|
|
417
|
+
for (const e of entries)
|
|
418
|
+
await rm(this.#pathFor(e.oid), { force: true });
|
|
419
|
+
this.#packLoc = null; // invalidate the index cache
|
|
420
|
+
return { packed: entries.length };
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
async collect(type) {
|
|
424
|
+
const out = [];
|
|
425
|
+
for await (const o of this.list(type))
|
|
426
|
+
out.push(o);
|
|
427
|
+
return out;
|
|
428
|
+
}
|
|
429
|
+
// ── refs ────────────────────────────────────────────────────────────────
|
|
430
|
+
async setRef(name, oid) {
|
|
431
|
+
await this.#writeAtomic(join(this.root, "refs", name), oid);
|
|
432
|
+
}
|
|
433
|
+
async getRef(name) {
|
|
434
|
+
const p = join(this.root, "refs", name);
|
|
435
|
+
if (!existsSync(p))
|
|
436
|
+
return null;
|
|
437
|
+
return (await readFile(p, "utf8")).trim();
|
|
438
|
+
}
|
|
439
|
+
/** All named refs as name → oid (for hub governance distribution). */
|
|
440
|
+
async listRefs() {
|
|
441
|
+
const dir = join(this.root, "refs");
|
|
442
|
+
if (!existsSync(dir))
|
|
443
|
+
return new Map();
|
|
444
|
+
const out = new Map();
|
|
445
|
+
for (const name of await readdir(dir)) {
|
|
446
|
+
out.set(name, (await readFile(join(dir, name), "utf8")).trim());
|
|
447
|
+
}
|
|
448
|
+
return out;
|
|
449
|
+
}
|
|
450
|
+
async setHead(viewName) {
|
|
451
|
+
await this.#writeAtomic(join(this.root, "HEAD"), viewName);
|
|
452
|
+
}
|
|
453
|
+
async getHead() {
|
|
454
|
+
return (await readFile(join(this.root, "HEAD"), "utf8")).trim();
|
|
455
|
+
}
|
|
456
|
+
// ── integrity check (D3 / docs/12) ────────────────────────────────────────
|
|
457
|
+
/**
|
|
458
|
+
* Re-derive every stored object's content address and compare it to the address it
|
|
459
|
+
* lives at — catching bit-rot, truncation, and a torn write that slipped past the
|
|
460
|
+
* atomic-write guarantee. A redacted blob is exempt: its bytes were deliberately
|
|
461
|
+
* overwritten by an admin Redaction and no longer hash to their oid (that's the one
|
|
462
|
+
* sanctioned exception to content-addressing). Also reconciles the op-log against the
|
|
463
|
+
* actual operation set: operation objects missing from the log are real drift (the
|
|
464
|
+
* fast-path could skip them); log entries with no object are GC'd/lost (informational).
|
|
465
|
+
* Read-only unless `rebuild` is set, which rewrites the op-log to match the object set.
|
|
466
|
+
*/
|
|
467
|
+
async fsck(opts = {}) {
|
|
468
|
+
const corrupt = [];
|
|
469
|
+
let objectsChecked = 0;
|
|
470
|
+
const verify = (oid, raw) => {
|
|
471
|
+
objectsChecked++;
|
|
472
|
+
let obj;
|
|
473
|
+
try {
|
|
474
|
+
obj = decodeObject(raw, oid);
|
|
475
|
+
}
|
|
476
|
+
catch (e) {
|
|
477
|
+
corrupt.push({ oid, reason: `undecodable: ${e.message}` });
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (obj.type === "blob" && obj.redacted === true)
|
|
481
|
+
return; // sanctioned overwrite
|
|
482
|
+
const { oid: _drop, ...payload } = obj;
|
|
483
|
+
void _drop;
|
|
484
|
+
let recomputed;
|
|
485
|
+
try {
|
|
486
|
+
recomputed = computeOid(obj.type, payload);
|
|
487
|
+
}
|
|
488
|
+
catch (e) {
|
|
489
|
+
corrupt.push({ oid, reason: `unhashable content: ${e.message}` });
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (recomputed !== oid)
|
|
493
|
+
corrupt.push({ oid, reason: `content hashes to ${recomputed}` });
|
|
494
|
+
};
|
|
495
|
+
// loose objects
|
|
496
|
+
const objectsDir = join(this.root, "objects");
|
|
497
|
+
if (existsSync(objectsDir)) {
|
|
498
|
+
for (const shard of await readdir(objectsDir)) {
|
|
499
|
+
const shardDir = join(objectsDir, shard);
|
|
500
|
+
if (!(await stat(shardDir)).isDirectory())
|
|
501
|
+
continue;
|
|
502
|
+
for (const file of await readdir(shardDir)) {
|
|
503
|
+
if (!file.endsWith(".json"))
|
|
504
|
+
continue;
|
|
505
|
+
verify(file.slice(0, -".json".length), await readFile(join(shardDir, file)));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// packed objects (loose copies, if any, already covered above and shadow these)
|
|
510
|
+
const looseChecked = new Set(); // avoid double-count of a re-added loose copy
|
|
511
|
+
for (const [oid, loc] of await this.#packLocations()) {
|
|
512
|
+
if (looseChecked.has(oid) || existsSync(this.#pathFor(oid)))
|
|
513
|
+
continue;
|
|
514
|
+
verify(oid, await this.#readPackSlice(loc));
|
|
515
|
+
}
|
|
516
|
+
// op-log reconciliation — collect operation oids by ADDRESS (filename / pack index),
|
|
517
|
+
// never by decoding, so a corrupt object (caught above) doesn't crash the log check.
|
|
518
|
+
const logged = new Set(await this.readOpLog());
|
|
519
|
+
const actualOps = new Set();
|
|
520
|
+
if (existsSync(objectsDir)) {
|
|
521
|
+
for (const shard of await readdir(objectsDir)) {
|
|
522
|
+
const shardDir = join(objectsDir, shard);
|
|
523
|
+
if (!(await stat(shardDir)).isDirectory())
|
|
524
|
+
continue;
|
|
525
|
+
for (const file of await readdir(shardDir))
|
|
526
|
+
if (file.startsWith("operation_") && file.endsWith(".json"))
|
|
527
|
+
actualOps.add(file.slice(0, -".json".length));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
for (const oid of (await this.#packLocations()).keys())
|
|
531
|
+
if (oid.startsWith("operation_"))
|
|
532
|
+
actualOps.add(oid);
|
|
533
|
+
const opsMissingFromLog = [...actualOps].filter((o) => !logged.has(o)).sort();
|
|
534
|
+
const logEntriesMissingObject = [...logged].filter((o) => !actualOps.has(o)).sort();
|
|
535
|
+
let repaired;
|
|
536
|
+
if (opts.rebuild && opsMissingFromLog.length) {
|
|
537
|
+
const n = await this.rebuildOpLog();
|
|
538
|
+
repaired = { oplogRebuilt: true, oplogEntries: n };
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
objectsChecked,
|
|
542
|
+
ok: corrupt.length === 0 && opsMissingFromLog.length === 0,
|
|
543
|
+
corrupt,
|
|
544
|
+
oplogDrift: { opsMissingFromLog, logEntriesMissingObject },
|
|
545
|
+
repaired,
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
//# sourceMappingURL=objectStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"objectStore.js","sourceRoot":"","sources":["../../src/store/objectStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Decision, Evidence, Operation } from "../objects/types.ts";
|
|
2
|
+
export interface RepairContext {
|
|
3
|
+
/** The operations that failed and must be repaired. */
|
|
4
|
+
failedOps: {
|
|
5
|
+
oid: string;
|
|
6
|
+
purpose: string;
|
|
7
|
+
target: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
}[];
|
|
10
|
+
/** The failing evidence, with its (truncated) output. */
|
|
11
|
+
failures: {
|
|
12
|
+
kind: string;
|
|
13
|
+
result: string;
|
|
14
|
+
command?: string;
|
|
15
|
+
detail?: string;
|
|
16
|
+
}[];
|
|
17
|
+
/** Decisions that touch these ops — prior rulings the repair must respect. */
|
|
18
|
+
relatedDecisions: {
|
|
19
|
+
oid: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
futurePolicy?: string;
|
|
22
|
+
}[];
|
|
23
|
+
/** A short, imperative instruction for the agent. */
|
|
24
|
+
suggestion: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a repair packet from a set of ops and the evidence/decisions about them.
|
|
28
|
+
* Pure; the caller supplies the already-loaded objects.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildRepairContext(ops: Operation[], evidence: Evidence[], decisions: Decision[]): RepairContext;
|
|
31
|
+
//# sourceMappingURL=repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../../src/validation/repair.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7E,yDAAyD;IACzD,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChF,8EAA8E;IAC9E,gBAAgB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3E,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,SAAS,EAAE,EAChB,QAAQ,EAAE,QAAQ,EAAE,EACpB,SAAS,EAAE,QAAQ,EAAE,GACpB,aAAa,CA2Bf"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Phase 3: RepairContext — when validation fails, hand the agent the *minimum* it
|
|
2
|
+
// needs to fix the problem, not the whole repo. Re-reading everything is how agents
|
|
3
|
+
// burn context and lose the plot; a focused repair packet keeps the loop tight.
|
|
4
|
+
/**
|
|
5
|
+
* Build a repair packet from a set of ops and the evidence/decisions about them.
|
|
6
|
+
* Pure; the caller supplies the already-loaded objects.
|
|
7
|
+
*/
|
|
8
|
+
export function buildRepairContext(ops, evidence, decisions) {
|
|
9
|
+
const opIds = new Set(ops.map((o) => o.oid));
|
|
10
|
+
const failures = evidence
|
|
11
|
+
.filter((e) => e.result === "fail" && e.forOps.some((o) => opIds.has(o)))
|
|
12
|
+
.map((e) => ({ kind: e.kind, result: e.result, command: e.command, detail: truncate(e.detail, 1500) }));
|
|
13
|
+
const relatedDecisions = decisions
|
|
14
|
+
.filter((d) => [...d.chosenOps, ...d.rejectedOps].some((o) => opIds.has(o)))
|
|
15
|
+
.map((d) => ({ oid: d.oid, reason: d.reason, futurePolicy: d.futurePolicy }));
|
|
16
|
+
const kinds = [...new Set(failures.map((f) => f.kind))];
|
|
17
|
+
const suggestion = failures.length
|
|
18
|
+
? `Fix the ${kinds.join(", ")} failure(s) by appending a new operation; do not hide or rewrite the failing op. Re-run the same checks. ${relatedDecisions.length ? "Respect the related prior decision(s)." : ""}`.trim()
|
|
19
|
+
: "No failing evidence found for these ops.";
|
|
20
|
+
return {
|
|
21
|
+
failedOps: ops.map((o) => ({
|
|
22
|
+
oid: o.oid,
|
|
23
|
+
purpose: o.declaredPurpose,
|
|
24
|
+
target: `${o.target.entityKind}:${o.target.entityId}`,
|
|
25
|
+
path: o.body.path,
|
|
26
|
+
})),
|
|
27
|
+
failures,
|
|
28
|
+
relatedDecisions,
|
|
29
|
+
suggestion,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function truncate(s, n) {
|
|
33
|
+
if (s === undefined)
|
|
34
|
+
return undefined;
|
|
35
|
+
return s.length > n ? s.slice(0, n) + `… (+${s.length - n} chars)` : s;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=repair.js.map
|