@indigoai-us/hq-cloud 6.16.65 → 6.16.67
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/dist/bin/sync-runner-company.d.ts +14 -0
- package/dist/bin/sync-runner-company.d.ts.map +1 -1
- package/dist/bin/sync-runner-company.js +42 -8
- package/dist/bin/sync-runner-company.js.map +1 -1
- package/dist/bin/sync-runner-company.test.js +62 -7
- package/dist/bin/sync-runner-company.test.js.map +1 -1
- package/dist/bin/sync-runner-planning.d.ts +12 -3
- package/dist/bin/sync-runner-planning.d.ts.map +1 -1
- package/dist/bin/sync-runner-planning.js +65 -3
- package/dist/bin/sync-runner-planning.js.map +1 -1
- package/dist/bin/sync-runner-planning.test.js +172 -1
- package/dist/bin/sync-runner-planning.test.js.map +1 -1
- package/dist/bin/sync-runner-watch-loop.d.ts +51 -2
- package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
- package/dist/bin/sync-runner-watch-loop.js +409 -165
- package/dist/bin/sync-runner-watch-loop.js.map +1 -1
- package/dist/bin/sync-runner-watch-routes.d.ts +19 -2
- package/dist/bin/sync-runner-watch-routes.d.ts.map +1 -1
- package/dist/bin/sync-runner-watch-routes.js +40 -5
- package/dist/bin/sync-runner-watch-routes.js.map +1 -1
- package/dist/bin/sync-runner-watch-routes.test.js +47 -0
- package/dist/bin/sync-runner-watch-routes.test.js.map +1 -1
- package/dist/bin/sync-runner.d.ts +59 -5
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js +48 -4
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +1553 -192
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/onepass-pull-planner-regressions.test.d.ts +2 -0
- package/dist/cli/onepass-pull-planner-regressions.test.d.ts.map +1 -0
- package/dist/cli/onepass-pull-planner-regressions.test.js +300 -0
- package/dist/cli/onepass-pull-planner-regressions.test.js.map +1 -0
- package/dist/cli/onepass-pull-planner.test.d.ts +2 -0
- package/dist/cli/onepass-pull-planner.test.d.ts.map +1 -0
- package/dist/cli/onepass-pull-planner.test.js +266 -0
- package/dist/cli/onepass-pull-planner.test.js.map +1 -0
- package/dist/cli/push-scan-exclusions.test.js +4 -4
- package/dist/cli/push-scan-exclusions.test.js.map +1 -1
- package/dist/cli/share.d.ts +31 -1
- package/dist/cli/share.d.ts.map +1 -1
- package/dist/cli/share.js +143 -8
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +350 -5
- package/dist/cli/share.test.js.map +1 -1
- package/dist/cli/streaming-pull-planner.bench.test.d.ts +15 -0
- package/dist/cli/streaming-pull-planner.bench.test.d.ts.map +1 -0
- package/dist/cli/streaming-pull-planner.bench.test.js +273 -0
- package/dist/cli/streaming-pull-planner.bench.test.js.map +1 -0
- package/dist/cli/sync-scope.test.js +8 -0
- package/dist/cli/sync-scope.test.js.map +1 -1
- package/dist/cli/sync.d.ts +12 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +297 -125
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +255 -2
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/journal-row-store.d.ts +40 -5
- package/dist/journal-row-store.d.ts.map +1 -1
- package/dist/journal-row-store.js +240 -21
- package/dist/journal-row-store.js.map +1 -1
- package/dist/journal-row-store.test.js +54 -0
- package/dist/journal-row-store.test.js.map +1 -1
- package/dist/journal-snapshot-v4.d.ts.map +1 -1
- package/dist/journal-snapshot-v4.js +11 -6
- package/dist/journal-snapshot-v4.js.map +1 -1
- package/dist/journal-store.test.js +324 -7
- package/dist/journal-store.test.js.map +1 -1
- package/dist/journal.d.ts +51 -16
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +303 -79
- package/dist/journal.js.map +1 -1
- package/dist/lib/exit-codes.d.ts +15 -0
- package/dist/lib/exit-codes.d.ts.map +1 -1
- package/dist/lib/exit-codes.js +15 -0
- package/dist/lib/exit-codes.js.map +1 -1
- package/dist/personal-vault.d.ts.map +1 -1
- package/dist/personal-vault.js +10 -3
- package/dist/personal-vault.js.map +1 -1
- package/dist/personal-vault.test.js +35 -0
- package/dist/personal-vault.test.js.map +1 -1
- package/dist/remote-pull.d.ts.map +1 -1
- package/dist/remote-pull.js +9 -2
- package/dist/remote-pull.js.map +1 -1
- package/dist/remote-pull.test.js +59 -2
- package/dist/remote-pull.test.js.map +1 -1
- package/dist/s3.d.ts +1 -0
- package/dist/s3.d.ts.map +1 -1
- package/dist/s3.js +20 -2
- package/dist/s3.js.map +1 -1
- package/dist/s3.list-cost.test.d.ts +2 -0
- package/dist/s3.list-cost.test.d.ts.map +1 -0
- package/dist/s3.list-cost.test.js +51 -0
- package/dist/s3.list-cost.test.js.map +1 -0
- package/dist/sync/area-ledger.d.ts +27 -3
- package/dist/sync/area-ledger.d.ts.map +1 -1
- package/dist/sync/area-ledger.js +149 -39
- package/dist/sync/area-ledger.js.map +1 -1
- package/dist/sync/area-ledger.test.js +192 -5
- package/dist/sync/area-ledger.test.js.map +1 -1
- package/dist/sync/parallel-sync-coordinator.test.js +29 -0
- package/dist/sync/parallel-sync-coordinator.test.js.map +1 -1
- package/dist/sync/realtime-telemetry.d.ts +1 -1
- package/dist/sync/realtime-telemetry.d.ts.map +1 -1
- package/dist/sync/realtime-telemetry.js +14 -6
- package/dist/sync/realtime-telemetry.js.map +1 -1
- package/dist/sync/realtime-telemetry.test.js +136 -16
- package/dist/sync/realtime-telemetry.test.js.map +1 -1
- package/dist/sync/remote-file-spool.d.ts +16 -0
- package/dist/sync/remote-file-spool.d.ts.map +1 -0
- package/dist/sync/remote-file-spool.js +91 -0
- package/dist/sync/remote-file-spool.js.map +1 -0
- package/dist/sync/remote-file-spool.test.d.ts +2 -0
- package/dist/sync/remote-file-spool.test.d.ts.map +1 -0
- package/dist/sync/remote-file-spool.test.js +77 -0
- package/dist/sync/remote-file-spool.test.js.map +1 -0
- package/dist/sync/state-store.d.ts +6 -0
- package/dist/sync/state-store.d.ts.map +1 -1
- package/dist/sync/state-store.js +14 -2
- package/dist/sync/state-store.js.map +1 -1
- package/dist/watcher.d.ts +12 -0
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +131 -0
- package/dist/watcher.js.map +1 -1
- package/dist/watcher.test.js +63 -0
- package/dist/watcher.test.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onepass-pull-planner-regressions.test.d.ts","sourceRoot":"","sources":["../../src/cli/onepass-pull-planner-regressions.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Additional freshness and scoped-cost regression coverage.
|
|
3
|
+
* Exercise sync -> streamRemoteFiles -> ObjectIO, with fresh pages on EVERY
|
|
4
|
+
* pass. Do not import sync.test.ts's firstPassFilesByContext caching double.
|
|
5
|
+
* Stop at the public plan event so no transfer or cloud mutation can run.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { clearContextCache } from "../context.js";
|
|
12
|
+
import * as journalModule from "../journal.js";
|
|
13
|
+
import * as spoolModule from "../sync/remote-file-spool.js";
|
|
14
|
+
import { readJournal, releaseCachedAreaJournalMigrations, writeJournal } from "../journal.js";
|
|
15
|
+
import { setObjectIOFactory, } from "../object-io.js";
|
|
16
|
+
import { sync } from "./sync.js";
|
|
17
|
+
const SLUG = "onepass-gates";
|
|
18
|
+
const STOP_AFTER_PLAN = Symbol("onepass-gates-plan-observed");
|
|
19
|
+
const ORIGINAL_STATE_DIR = process.env.HQ_STATE_DIR;
|
|
20
|
+
const vaultConfig = {
|
|
21
|
+
apiUrl: "https://vault-api.test",
|
|
22
|
+
authToken: "onepass-test-token",
|
|
23
|
+
region: "us-east-1",
|
|
24
|
+
companyVaultUsesPresign: true,
|
|
25
|
+
};
|
|
26
|
+
let baseDir;
|
|
27
|
+
let hqRoot;
|
|
28
|
+
let companyRoot;
|
|
29
|
+
function row(key, size = 1) {
|
|
30
|
+
return { key, size, lastModified: new Date("2026-09-14T00:00:00Z"), etag: `"etag-${key}"` };
|
|
31
|
+
}
|
|
32
|
+
function pagedListing(rows, pageSize, beforePage) {
|
|
33
|
+
let pass = 0;
|
|
34
|
+
const pages = [];
|
|
35
|
+
const forbidden = async () => {
|
|
36
|
+
throw new Error("planner gate reached a transfer instead of stopping at plan");
|
|
37
|
+
};
|
|
38
|
+
const listObjects = vi.fn(async (input) => {
|
|
39
|
+
if (input.continuationToken === undefined)
|
|
40
|
+
pass += 1;
|
|
41
|
+
const start = input.continuationToken === undefined ? 0 : Number(input.continuationToken);
|
|
42
|
+
const end = Math.min(start + pageSize, rows.length);
|
|
43
|
+
const page = { pass, start, keys: rows.slice(start, end).map(({ key }) => key) };
|
|
44
|
+
beforePage?.(page);
|
|
45
|
+
pages.push(page);
|
|
46
|
+
return {
|
|
47
|
+
// Each transport call owns fresh objects; no pass is cached or coalesced.
|
|
48
|
+
objects: rows.slice(start, end).map((object) => ({ ...object })),
|
|
49
|
+
nextContinuationToken: end < rows.length ? String(end) : undefined,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
const io = {
|
|
53
|
+
listObjects,
|
|
54
|
+
putObject: forbidden,
|
|
55
|
+
getObject: forbidden,
|
|
56
|
+
deleteObject: forbidden,
|
|
57
|
+
headObject: forbidden,
|
|
58
|
+
};
|
|
59
|
+
return { io, listObjects, pages, passCount: () => pass };
|
|
60
|
+
}
|
|
61
|
+
async function planWith(listing, options = {}) {
|
|
62
|
+
setObjectIOFactory(() => listing.io);
|
|
63
|
+
let plan;
|
|
64
|
+
try {
|
|
65
|
+
await sync({
|
|
66
|
+
company: SLUG,
|
|
67
|
+
vaultConfig,
|
|
68
|
+
hqRoot,
|
|
69
|
+
syncMode: "all",
|
|
70
|
+
propagateDeletePolicy: "owned-only",
|
|
71
|
+
fileTombstones: new Map(),
|
|
72
|
+
skipReindex: true,
|
|
73
|
+
operationLockAlreadyHeld: true,
|
|
74
|
+
...options,
|
|
75
|
+
onEvent: (event) => {
|
|
76
|
+
if (event.type !== "plan")
|
|
77
|
+
return;
|
|
78
|
+
plan = event;
|
|
79
|
+
throw STOP_AFTER_PLAN;
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error !== STOP_AFTER_PLAN)
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
expect(plan, "sync must reach the real, completed pull plan").toBeDefined();
|
|
88
|
+
return plan;
|
|
89
|
+
}
|
|
90
|
+
function seed(files = {}) {
|
|
91
|
+
writeJournal(SLUG, { version: "2", lastSync: "seed", pulls: [], files });
|
|
92
|
+
}
|
|
93
|
+
function knownEntry(key) {
|
|
94
|
+
return {
|
|
95
|
+
hash: "a".repeat(64),
|
|
96
|
+
size: 11,
|
|
97
|
+
syncedAt: "2026-09-14T00:00:00Z",
|
|
98
|
+
direction: "up",
|
|
99
|
+
remoteEtag: `etag-${key}`,
|
|
100
|
+
kind: "file",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function commitDeleteIntent(key) {
|
|
104
|
+
const journal = readJournal(SLUG);
|
|
105
|
+
const entry = journal.files[key];
|
|
106
|
+
journal.files[key] = {
|
|
107
|
+
...entry,
|
|
108
|
+
localDeleteIntent: {
|
|
109
|
+
version: 1,
|
|
110
|
+
remoteEtag: entry.remoteEtag,
|
|
111
|
+
localHash: entry.hash,
|
|
112
|
+
localKind: "file",
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
writeJournal(SLUG, journal);
|
|
116
|
+
}
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
baseDir = fs.mkdtempSync(path.join(os.tmpdir(), "hq-onepass-gates-"));
|
|
119
|
+
hqRoot = path.join(baseDir, "hq");
|
|
120
|
+
companyRoot = path.join(hqRoot, "companies", SLUG);
|
|
121
|
+
fs.mkdirSync(companyRoot, { recursive: true });
|
|
122
|
+
process.env.HQ_STATE_DIR = path.join(baseDir, "state");
|
|
123
|
+
fs.mkdirSync(process.env.HQ_STATE_DIR, { recursive: true });
|
|
124
|
+
clearContextCache();
|
|
125
|
+
releaseCachedAreaJournalMigrations();
|
|
126
|
+
vi.stubGlobal("fetch", async (url) => {
|
|
127
|
+
const target = String(url);
|
|
128
|
+
if (target.includes("/entity/check-slug/me")) {
|
|
129
|
+
return { ok: true, status: 200, json: async () => ({ available: false, conflictingCompanyUid: "cmp_onepass_gates" }), text: async () => "" };
|
|
130
|
+
}
|
|
131
|
+
if (target.includes("/entity/by-slug/") || target.includes("/entity/cmp_")) {
|
|
132
|
+
return {
|
|
133
|
+
ok: true, status: 200,
|
|
134
|
+
json: async () => ({ entity: { uid: "cmp_onepass_gates", slug: SLUG, bucketName: "hq-vault-onepass-gates", status: "active" } }),
|
|
135
|
+
text: async () => "",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
throw new Error(`unexpected planner fixture request: ${target}`);
|
|
139
|
+
});
|
|
140
|
+
seed();
|
|
141
|
+
});
|
|
142
|
+
afterEach(() => {
|
|
143
|
+
setObjectIOFactory(null);
|
|
144
|
+
clearContextCache();
|
|
145
|
+
releaseCachedAreaJournalMigrations();
|
|
146
|
+
vi.restoreAllMocks();
|
|
147
|
+
vi.unstubAllGlobals();
|
|
148
|
+
if (ORIGINAL_STATE_DIR === undefined)
|
|
149
|
+
delete process.env.HQ_STATE_DIR;
|
|
150
|
+
else
|
|
151
|
+
process.env.HQ_STATE_DIR = ORIGINAL_STATE_DIR;
|
|
152
|
+
fs.rmSync(baseDir, { recursive: true, force: true });
|
|
153
|
+
});
|
|
154
|
+
describe("one-pass freshness and scoped planner costs", () => {
|
|
155
|
+
it("refreshes an EARLY row when its delete commits on the final page", async () => {
|
|
156
|
+
const victim = "docs/early-victim.md";
|
|
157
|
+
const rows = [row(victim, 11), row("docs/control.md", 7)];
|
|
158
|
+
seed({ [victim]: knownEntry(victim) });
|
|
159
|
+
const baseline = await planWith(pagedListing(rows, 1));
|
|
160
|
+
expect(baseline.filesToDownload).toBe(2);
|
|
161
|
+
expect(baseline.bytesToDownload).toBe(18);
|
|
162
|
+
const reads = vi.spyOn(journalModule, "readJournalForPass");
|
|
163
|
+
const listing = pagedListing(rows, 1, (page) => {
|
|
164
|
+
if (page.start === 1)
|
|
165
|
+
commitDeleteIntent(victim);
|
|
166
|
+
});
|
|
167
|
+
const plan = await planWith(listing);
|
|
168
|
+
expect(plan.filesToDownload).toBe(1);
|
|
169
|
+
expect(plan.bytesToDownload).toBe(7);
|
|
170
|
+
expect(reads.mock.results.some((result) => result.type === "return" &&
|
|
171
|
+
result.value.files[victim]?.removedReason === "local-delete")).toBe(true);
|
|
172
|
+
console.log("early-row freshness control: no intent downloads=2 bytes=18; late intent downloads=1 bytes=7; local-delete recorded=true");
|
|
173
|
+
});
|
|
174
|
+
it("reclassifies an early unchanged file deleted during a later page", async () => {
|
|
175
|
+
const victim = "docs/early-unchanged.md";
|
|
176
|
+
const localPath = path.join(companyRoot, victim);
|
|
177
|
+
fs.mkdirSync(path.dirname(localPath), { recursive: true });
|
|
178
|
+
fs.writeFileSync(localPath, "local bytes");
|
|
179
|
+
seed({ [victim]: { ...knownEntry(victim), hash: journalModule.hashFile(localPath) } });
|
|
180
|
+
const rows = [row(victim, 11), row("docs/control.md", 7)];
|
|
181
|
+
const baseline = await planWith(pagedListing(rows, 1));
|
|
182
|
+
expect(baseline.filesToDownload).toBe(1);
|
|
183
|
+
expect(baseline.filesToSkip).toBe(1);
|
|
184
|
+
const reads = vi.spyOn(journalModule, "readJournalForPass");
|
|
185
|
+
const plan = await planWith(pagedListing(rows, 1, (page) => {
|
|
186
|
+
if (page.start !== 1)
|
|
187
|
+
return;
|
|
188
|
+
fs.unlinkSync(localPath);
|
|
189
|
+
commitDeleteIntent(victim);
|
|
190
|
+
}));
|
|
191
|
+
expect(plan.filesToDownload).toBe(1);
|
|
192
|
+
expect(plan.bytesToDownload).toBe(7);
|
|
193
|
+
expect(plan.filesToSkip).toBe(0);
|
|
194
|
+
expect(reads.mock.results.some((result) => result.type === "return" &&
|
|
195
|
+
result.value.files[victim]?.removedReason === "local-delete")).toBe(true);
|
|
196
|
+
console.log("early-skip freshness control: before delete skips=1; after late delete skips=0; downloads=1 bytes=7; local-delete recorded=true");
|
|
197
|
+
});
|
|
198
|
+
it("disposes the completed spool on journal-refresh failure and plan completion", async () => {
|
|
199
|
+
const actual = spoolModule.spoolRemoteFiles;
|
|
200
|
+
const disposals = [];
|
|
201
|
+
vi.spyOn(spoolModule, "spoolRemoteFiles").mockImplementation(async (rows) => {
|
|
202
|
+
const spool = await actual(rows);
|
|
203
|
+
const dispose = vi.fn(spool.dispose);
|
|
204
|
+
disposals.push(dispose);
|
|
205
|
+
return { ...spool, dispose };
|
|
206
|
+
});
|
|
207
|
+
await planWith(pagedListing([row("docs/control.md")], 1));
|
|
208
|
+
expect(disposals).toHaveLength(1);
|
|
209
|
+
expect(disposals[0]).toHaveBeenCalledTimes(1);
|
|
210
|
+
vi.spyOn(journalModule, "readJournalForPass").mockImplementationOnce(() => { throw new Error("refresh failure control"); });
|
|
211
|
+
await expect(planWith(pagedListing([row("docs/control.md")], 1))).rejects.toThrow("refresh failure control");
|
|
212
|
+
expect(disposals).toHaveLength(2);
|
|
213
|
+
expect(disposals[1]).toHaveBeenCalledTimes(1);
|
|
214
|
+
console.log("sync lifecycle control: completed spools=2; normal plan dispose calls=1; journal-refresh failure dispose calls=1");
|
|
215
|
+
});
|
|
216
|
+
it("does not copy out-of-scope journal keys into the scoped presence set", async () => {
|
|
217
|
+
seed(Object.fromEntries(Array.from({ length: 100 }, (_, i) => {
|
|
218
|
+
const key = `outside/presence-probe-${i}.md`;
|
|
219
|
+
return [key, knownEntry(key)];
|
|
220
|
+
})));
|
|
221
|
+
let tracing = false;
|
|
222
|
+
let additions = 0;
|
|
223
|
+
const original = Set.prototype.add;
|
|
224
|
+
const add = vi.spyOn(Set.prototype, "add").mockImplementation(function (value) {
|
|
225
|
+
if (tracing && typeof value === "string" && value.startsWith("outside/presence-probe-"))
|
|
226
|
+
additions++;
|
|
227
|
+
return original.call(this, value);
|
|
228
|
+
});
|
|
229
|
+
tracing = true;
|
|
230
|
+
const control = new Set(["outside/presence-probe-control.md"]);
|
|
231
|
+
expect(control.size).toBe(1);
|
|
232
|
+
expect(additions).toBe(1);
|
|
233
|
+
tracing = false;
|
|
234
|
+
additions = 0;
|
|
235
|
+
try {
|
|
236
|
+
const plan = await planWith(pagedListing([row("docs/control.md")], 1), {
|
|
237
|
+
syncMode: "custom", prefixSet: ["docs/"], onHeartbeat: () => { tracing = true; },
|
|
238
|
+
});
|
|
239
|
+
expect(plan.filesToDownload).toBe(1);
|
|
240
|
+
expect(additions).toBe(0);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
tracing = false;
|
|
244
|
+
add.mockRestore();
|
|
245
|
+
}
|
|
246
|
+
console.log(`scoped presence control: known out-of-scope Set.add detected=1; production additions=${additions}; out-of-scope journal rows=100`);
|
|
247
|
+
});
|
|
248
|
+
it("scoped classification has no per-row microtask interleaving or ancestor flatMap", async () => {
|
|
249
|
+
const rows = Array.from({ length: 200 }, (_, index) => row(`docs/shared/deep/row-${index}.md`));
|
|
250
|
+
// Same observation as the production heartbeat: queue a microtask on the
|
|
251
|
+
// first row and count whether it runs before all rows have been visited.
|
|
252
|
+
async function interleavingControl() {
|
|
253
|
+
let visited = 0;
|
|
254
|
+
let observed = 0;
|
|
255
|
+
for await (const _row of rows) {
|
|
256
|
+
visited++;
|
|
257
|
+
if (visited === 1)
|
|
258
|
+
Promise.resolve().then(() => { observed = visited; });
|
|
259
|
+
}
|
|
260
|
+
return observed;
|
|
261
|
+
}
|
|
262
|
+
const control = await interleavingControl();
|
|
263
|
+
expect(control).toBe(1);
|
|
264
|
+
const original = Array.prototype.flatMap;
|
|
265
|
+
let flattenedAncestors = 0;
|
|
266
|
+
const flatMap = vi.spyOn(Array.prototype, "flatMap").mockImplementation(function (...args) {
|
|
267
|
+
const result = original.apply(this, args);
|
|
268
|
+
if (this.length === rows.length && this[0]?.key === rows[0].key) {
|
|
269
|
+
flattenedAncestors += result.length;
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
});
|
|
273
|
+
// Detect the actual old allocation shape with this same probe.
|
|
274
|
+
const legacy = new Set(rows.flatMap((file) => ["docs", "docs/shared", file.key.slice(0, file.key.lastIndexOf("/"))]));
|
|
275
|
+
expect(legacy.size).toBe(3);
|
|
276
|
+
expect(flattenedAncestors).toBe(600);
|
|
277
|
+
const allocationControl = flattenedAncestors;
|
|
278
|
+
flattenedAncestors = 0;
|
|
279
|
+
let visited = 0;
|
|
280
|
+
let earlyMicrotasks = 0;
|
|
281
|
+
const plan = await planWith(pagedListing(rows, rows.length), {
|
|
282
|
+
syncMode: "custom", prefixSet: ["docs/"],
|
|
283
|
+
onHeartbeat: () => {
|
|
284
|
+
visited++;
|
|
285
|
+
if (visited === 1)
|
|
286
|
+
Promise.resolve().then(() => {
|
|
287
|
+
if (visited < rows.length)
|
|
288
|
+
earlyMicrotasks++;
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
expect(plan.filesToDownload).toBe(rows.length);
|
|
293
|
+
expect(visited).toBeGreaterThanOrEqual(rows.length);
|
|
294
|
+
expect(earlyMicrotasks).toBe(0);
|
|
295
|
+
expect(flattenedAncestors).toBe(0);
|
|
296
|
+
flatMap.mockRestore();
|
|
297
|
+
console.log(`scoped controls: for-await microtask observed after row=${control}/200; legacy flatMap retained ancestors=${allocationControl}; production early microtasks=${earlyMicrotasks}; production flattened ancestors=${flattenedAncestors}; downloads=${plan.filesToDownload}`);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
//# sourceMappingURL=onepass-pull-planner-regressions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onepass-pull-planner-regressions.test.js","sourceRoot":"","sources":["../../src/cli/onepass-pull-planner-regressions.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onepass-pull-planner.test.d.ts","sourceRoot":"","sources":["../../src/cli/onepass-pull-planner.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fails-first gates for the one-pass all-mode planner, based on 481138a.
|
|
3
|
+
* Exercise sync -> streamRemoteFiles -> ObjectIO, with fresh pages on EVERY
|
|
4
|
+
* pass. Do not import sync.test.ts's firstPassFilesByContext caching double.
|
|
5
|
+
* Stop at the public plan event so no transfer or cloud mutation can run.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { clearContextCache } from "../context.js";
|
|
12
|
+
import * as journalModule from "../journal.js";
|
|
13
|
+
import { readJournal, releaseCachedAreaJournalMigrations, writeJournal } from "../journal.js";
|
|
14
|
+
import { setObjectIOFactory, } from "../object-io.js";
|
|
15
|
+
import { sync } from "./sync.js";
|
|
16
|
+
const SLUG = "onepass-gates";
|
|
17
|
+
const STOP_AFTER_PLAN = Symbol("onepass-gates-plan-observed");
|
|
18
|
+
const ORIGINAL_STATE_DIR = process.env.HQ_STATE_DIR;
|
|
19
|
+
const vaultConfig = {
|
|
20
|
+
apiUrl: "https://vault-api.test",
|
|
21
|
+
authToken: "onepass-test-token",
|
|
22
|
+
region: "us-east-1",
|
|
23
|
+
companyVaultUsesPresign: true,
|
|
24
|
+
};
|
|
25
|
+
let baseDir;
|
|
26
|
+
let hqRoot;
|
|
27
|
+
let companyRoot;
|
|
28
|
+
function row(key, size = 1) {
|
|
29
|
+
return { key, size, lastModified: new Date("2026-09-14T00:00:00Z"), etag: `"etag-${key}"` };
|
|
30
|
+
}
|
|
31
|
+
function pagedListing(rows, pageSize, beforePage) {
|
|
32
|
+
let pass = 0;
|
|
33
|
+
const pages = [];
|
|
34
|
+
const forbidden = async () => {
|
|
35
|
+
throw new Error("planner gate reached a transfer instead of stopping at plan");
|
|
36
|
+
};
|
|
37
|
+
const listObjects = vi.fn(async (input) => {
|
|
38
|
+
expect(input.prefix).toBeUndefined();
|
|
39
|
+
if (input.continuationToken === undefined)
|
|
40
|
+
pass += 1;
|
|
41
|
+
const start = input.continuationToken === undefined ? 0 : Number(input.continuationToken);
|
|
42
|
+
const end = Math.min(start + pageSize, rows.length);
|
|
43
|
+
const page = { pass, start, keys: rows.slice(start, end).map(({ key }) => key) };
|
|
44
|
+
beforePage?.(page);
|
|
45
|
+
pages.push(page);
|
|
46
|
+
return {
|
|
47
|
+
// Each transport call owns fresh objects; no pass is cached or coalesced.
|
|
48
|
+
objects: rows.slice(start, end).map((object) => ({ ...object })),
|
|
49
|
+
nextContinuationToken: end < rows.length ? String(end) : undefined,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
const io = {
|
|
53
|
+
listObjects,
|
|
54
|
+
putObject: forbidden,
|
|
55
|
+
getObject: forbidden,
|
|
56
|
+
deleteObject: forbidden,
|
|
57
|
+
headObject: forbidden,
|
|
58
|
+
};
|
|
59
|
+
return { io, listObjects, pages, passCount: () => pass };
|
|
60
|
+
}
|
|
61
|
+
async function planWith(listing) {
|
|
62
|
+
setObjectIOFactory(() => listing.io);
|
|
63
|
+
let plan;
|
|
64
|
+
try {
|
|
65
|
+
await sync({
|
|
66
|
+
company: SLUG,
|
|
67
|
+
vaultConfig,
|
|
68
|
+
hqRoot,
|
|
69
|
+
syncMode: "all",
|
|
70
|
+
propagateDeletePolicy: "owned-only",
|
|
71
|
+
fileTombstones: new Map(),
|
|
72
|
+
skipReindex: true,
|
|
73
|
+
operationLockAlreadyHeld: true,
|
|
74
|
+
onEvent: (event) => {
|
|
75
|
+
if (event.type !== "plan")
|
|
76
|
+
return;
|
|
77
|
+
plan = event;
|
|
78
|
+
throw STOP_AFTER_PLAN;
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error !== STOP_AFTER_PLAN)
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
expect(plan, "sync must reach the real, completed pull plan").toBeDefined();
|
|
87
|
+
return plan;
|
|
88
|
+
}
|
|
89
|
+
function seed(files = {}) {
|
|
90
|
+
writeJournal(SLUG, { version: "2", lastSync: "seed", pulls: [], files });
|
|
91
|
+
}
|
|
92
|
+
function knownEntry(key) {
|
|
93
|
+
return {
|
|
94
|
+
hash: "a".repeat(64),
|
|
95
|
+
size: 11,
|
|
96
|
+
syncedAt: "2026-09-14T00:00:00Z",
|
|
97
|
+
direction: "up",
|
|
98
|
+
remoteEtag: `etag-${key}`,
|
|
99
|
+
kind: "file",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function commitDeleteIntent(key) {
|
|
103
|
+
const journal = readJournal(SLUG);
|
|
104
|
+
const entry = journal.files[key];
|
|
105
|
+
journal.files[key] = {
|
|
106
|
+
...entry,
|
|
107
|
+
localDeleteIntent: {
|
|
108
|
+
version: 1,
|
|
109
|
+
remoteEtag: entry.remoteEtag,
|
|
110
|
+
localHash: entry.hash,
|
|
111
|
+
localKind: "file",
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
writeJournal(SLUG, journal);
|
|
115
|
+
}
|
|
116
|
+
beforeEach(() => {
|
|
117
|
+
baseDir = fs.mkdtempSync(path.join(os.tmpdir(), "hq-onepass-gates-"));
|
|
118
|
+
hqRoot = path.join(baseDir, "hq");
|
|
119
|
+
companyRoot = path.join(hqRoot, "companies", SLUG);
|
|
120
|
+
fs.mkdirSync(companyRoot, { recursive: true });
|
|
121
|
+
process.env.HQ_STATE_DIR = path.join(baseDir, "state");
|
|
122
|
+
fs.mkdirSync(process.env.HQ_STATE_DIR, { recursive: true });
|
|
123
|
+
clearContextCache();
|
|
124
|
+
releaseCachedAreaJournalMigrations();
|
|
125
|
+
vi.stubGlobal("fetch", async (url) => {
|
|
126
|
+
const target = String(url);
|
|
127
|
+
if (target.includes("/entity/check-slug/me")) {
|
|
128
|
+
return { ok: true, status: 200, json: async () => ({ available: false, conflictingCompanyUid: "cmp_onepass_gates" }), text: async () => "" };
|
|
129
|
+
}
|
|
130
|
+
if (target.includes("/entity/by-slug/") || target.includes("/entity/cmp_")) {
|
|
131
|
+
return {
|
|
132
|
+
ok: true, status: 200,
|
|
133
|
+
json: async () => ({ entity: { uid: "cmp_onepass_gates", slug: SLUG, bucketName: "hq-vault-onepass-gates", status: "active" } }),
|
|
134
|
+
text: async () => "",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
throw new Error(`unexpected planner fixture request: ${target}`);
|
|
138
|
+
});
|
|
139
|
+
seed();
|
|
140
|
+
});
|
|
141
|
+
afterEach(() => {
|
|
142
|
+
setObjectIOFactory(null);
|
|
143
|
+
clearContextCache();
|
|
144
|
+
releaseCachedAreaJournalMigrations();
|
|
145
|
+
vi.restoreAllMocks();
|
|
146
|
+
vi.unstubAllGlobals();
|
|
147
|
+
if (ORIGINAL_STATE_DIR === undefined)
|
|
148
|
+
delete process.env.HQ_STATE_DIR;
|
|
149
|
+
else
|
|
150
|
+
process.env.HQ_STATE_DIR = ORIGINAL_STATE_DIR;
|
|
151
|
+
fs.rmSync(baseDir, { recursive: true, force: true });
|
|
152
|
+
});
|
|
153
|
+
describe("one-pass all-mode pull planner gates", () => {
|
|
154
|
+
it("fetches exactly one paged LIST for a complete all-mode plan", async () => {
|
|
155
|
+
const rowCount = 5;
|
|
156
|
+
const pageSize = 2;
|
|
157
|
+
const singlePassPages = Math.ceil(rowCount / pageSize);
|
|
158
|
+
const listing = pagedListing(Array.from({ length: rowCount }, (_, i) => row(`docs/row-${i}.md`)), pageSize);
|
|
159
|
+
// Positive control: use the SAME transport and counters on a known page.
|
|
160
|
+
const control = await listing.io.listObjects({});
|
|
161
|
+
expect(control.objects.map(({ key }) => key)).toEqual(["docs/row-0.md", "docs/row-1.md"]);
|
|
162
|
+
expect(listing.listObjects).toHaveBeenCalledTimes(1);
|
|
163
|
+
expect(listing.pages).toHaveLength(1);
|
|
164
|
+
listing.listObjects.mockClear();
|
|
165
|
+
listing.pages.length = 0;
|
|
166
|
+
const plan = await planWith(listing);
|
|
167
|
+
expect(plan.filesToDownload).toBe(rowCount);
|
|
168
|
+
// Check every page and the partial tail, not only the counter's wiring.
|
|
169
|
+
expect(listing.pages.slice(0, singlePassPages).map(({ start, keys }) => ({ start, keys }))).toEqual([
|
|
170
|
+
{ start: 0, keys: ["docs/row-0.md", "docs/row-1.md"] },
|
|
171
|
+
{ start: 2, keys: ["docs/row-2.md", "docs/row-3.md"] },
|
|
172
|
+
{ start: 4, keys: ["docs/row-4.md"] },
|
|
173
|
+
]);
|
|
174
|
+
expect.soft(listing.listObjects.mock.calls.length, "listObjects invocations must equal one complete paged pass").toBe(singlePassPages);
|
|
175
|
+
expect.soft(listing.pages.length, "pages fetched must equal one complete paged pass").toBe(singlePassPages);
|
|
176
|
+
});
|
|
177
|
+
it("honors a watcher delete committed during the LAST LIST feeding classification", async () => {
|
|
178
|
+
const victim = "docs/deleted-during-list.md";
|
|
179
|
+
const control = "docs/download-control.md";
|
|
180
|
+
const rows = [row(control, 7), row(victim, 11)];
|
|
181
|
+
const journalReads = vi.spyOn(journalModule, "readJournalForPass");
|
|
182
|
+
seed({ [victim]: knownEntry(victim) });
|
|
183
|
+
// Calibrate against a real plan, not an assumed implementation pass count.
|
|
184
|
+
// This also keeps the regression meaningful once production uses one pass.
|
|
185
|
+
// Positive control: absent WITHOUT intent, the very same victim downloads.
|
|
186
|
+
const baselineListing = pagedListing(rows, 1);
|
|
187
|
+
const baseline = await planWith(baselineListing);
|
|
188
|
+
expect(baseline.filesToDownload).toBe(2);
|
|
189
|
+
expect(baseline.bytesToDownload).toBe(18);
|
|
190
|
+
const lastPass = baselineListing.passCount();
|
|
191
|
+
expect(lastPass).toBeGreaterThan(0);
|
|
192
|
+
// A precommitted intent is a fixture/control check for the strict policy:
|
|
193
|
+
// the victim becomes a local-delete tombstone and only the 7-byte control
|
|
194
|
+
// downloads. Observe the real journal projection without replacing it.
|
|
195
|
+
commitDeleteIntent(victim);
|
|
196
|
+
const controlPlan = await planWith(pagedListing(rows, 1));
|
|
197
|
+
expect(controlPlan.filesToDownload).toBe(1);
|
|
198
|
+
expect(controlPlan.bytesToDownload).toBe(7);
|
|
199
|
+
const intentionalKeys = () => journalReads.mock.results.flatMap((result) => result.type === "return"
|
|
200
|
+
? Object.entries(result.value.files)
|
|
201
|
+
.filter(([, entry]) => entry.removedReason === "local-delete").map(([key]) => key)
|
|
202
|
+
: []);
|
|
203
|
+
expect(intentionalKeys()).toContain(victim);
|
|
204
|
+
seed({ [victim]: knownEntry(victim) });
|
|
205
|
+
journalReads.mockClear();
|
|
206
|
+
fs.mkdirSync(path.dirname(path.join(companyRoot, victim)), { recursive: true });
|
|
207
|
+
fs.writeFileSync(path.join(companyRoot, victim), "local bytes");
|
|
208
|
+
const commits = [];
|
|
209
|
+
const listing = pagedListing(rows, 1, (page) => {
|
|
210
|
+
if (page.pass !== lastPass || !page.keys.includes(victim))
|
|
211
|
+
return;
|
|
212
|
+
// On 481138a this lands in PASS TWO, after the freshness reload, just
|
|
213
|
+
// before its victim page returns to classification: the dangerous LIST.
|
|
214
|
+
// Pass one is independently served and never commits this intent.
|
|
215
|
+
// A one-pass rewrite instead injects on its sole (last) pass.
|
|
216
|
+
fs.unlinkSync(path.join(companyRoot, victim));
|
|
217
|
+
commitDeleteIntent(victim);
|
|
218
|
+
commits.push(page);
|
|
219
|
+
});
|
|
220
|
+
const plan = await planWith(listing);
|
|
221
|
+
expect(commits).toEqual([{ pass: lastPass, start: 1, keys: [victim] }]);
|
|
222
|
+
expect(listing.passCount()).toBe(lastPass);
|
|
223
|
+
expect(readJournal(SLUG).files[victim]?.localDeleteIntent).toEqual({
|
|
224
|
+
version: 1, remoteEtag: `etag-${victim}`, localHash: "a".repeat(64), localKind: "file",
|
|
225
|
+
});
|
|
226
|
+
expect(listing.pages.filter(({ pass }) => pass === lastPass).map(({ keys }) => keys)).toEqual([[control], [victim]]);
|
|
227
|
+
// Same probes as the positive controls above: suppress the victim's
|
|
228
|
+
// download, retain the known download, and classify intentional absence.
|
|
229
|
+
expect.soft(plan.filesToDownload, "only the positive-control file should download").toBe(1);
|
|
230
|
+
expect.soft(plan.bytesToDownload, "the deleted victim's 11 bytes must not be scheduled").toBe(7);
|
|
231
|
+
expect.soft(intentionalKeys(), "the plan must classify the victim as an intentional local delete").toContain(victim);
|
|
232
|
+
});
|
|
233
|
+
it("preserves skip-overlay-marker-with-children when the marker precedes its children (feedback_d2082110)", async () => {
|
|
234
|
+
const marker = "docs/overlay";
|
|
235
|
+
const child = `${marker}/child.md`;
|
|
236
|
+
const collision = "docs/genuine-collision";
|
|
237
|
+
fs.mkdirSync(path.join(companyRoot, marker), { recursive: true });
|
|
238
|
+
fs.mkdirSync(path.join(companyRoot, collision), { recursive: true });
|
|
239
|
+
const preserved = path.join(companyRoot, marker, "materialized.md");
|
|
240
|
+
fs.writeFileSync(preserved, "keep this local content");
|
|
241
|
+
const errors = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
242
|
+
// Deliberately marker FIRST, child on a LATER PAGE. Children-first would
|
|
243
|
+
// hide the exact lookahead requirement the one-pass design must preserve.
|
|
244
|
+
const listing = pagedListing([row(marker, 30), row(child, 18), row(collision, 40)], 1);
|
|
245
|
+
const plan = await planWith(listing);
|
|
246
|
+
for (let pass = 1; pass <= listing.passCount(); pass += 1) {
|
|
247
|
+
expect(listing.pages.filter((page) => page.pass === pass).map(({ keys }) => keys)).toEqual([[marker], [child], [collision]]);
|
|
248
|
+
}
|
|
249
|
+
expect(plan.filesToDownload).toBe(1);
|
|
250
|
+
expect(plan.bytesToDownload).toBe(18);
|
|
251
|
+
expect(plan.filesToSkip).toBe(2);
|
|
252
|
+
const messagesFor = (key) => errors.mock.calls.map((args) => args.join(" ")).filter((message) => message.includes(`${key} `)).join("\n");
|
|
253
|
+
// Ordinary streaming skips are compacted out of plan.items. Assert the
|
|
254
|
+
// public diagnostic unique to skip-overlay-marker-with-children plus its
|
|
255
|
+
// skip count, rather than exporting/changing the production planner.
|
|
256
|
+
expect(messagesFor(marker)).toContain("is a directory-overlay marker whose contents already exist locally as a directory; keeping the local directory and ignoring the marker (no action needed)");
|
|
257
|
+
// Positive control for BOTH absence probes: a genuine collision in this
|
|
258
|
+
// same plan must produce the exact destructive/manual advice we detect.
|
|
259
|
+
expect(messagesFor(collision)).toContain("rm -rf the local directory to pull");
|
|
260
|
+
expect(messagesFor(collision)).toContain("manual reconciliation required");
|
|
261
|
+
expect(messagesFor(marker)).not.toContain("rm -rf the local directory to pull");
|
|
262
|
+
expect(messagesFor(marker)).not.toContain("manual reconciliation required");
|
|
263
|
+
expect(fs.readFileSync(preserved, "utf8")).toBe("keep this local content");
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
//# sourceMappingURL=onepass-pull-planner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onepass-pull-planner.test.js","sourceRoot":"","sources":["../../src/cli/onepass-pull-planner.test.ts"],"names":[],"mappings":"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"}
|