@indigoai-us/hq-cloud 6.15.64 → 6.15.66

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.
@@ -14,7 +14,7 @@ import { runRunner, runRunnerWithLoop, resolveDeletePolicy, resolveSkipPersonal,
14
14
  import { PresignObjectIO, S3SdkObjectIO } from "../object-io.js";
15
15
  import { setBandwidthGovernorForTesting } from "../bandwidth.js";
16
16
  import { FakeClock, TreeWatcher, } from "../watcher.js";
17
- import { adaptivePollMs, advanceMonotonicDeadline, DEFAULT_EVENT_BATCH_LIMIT, DEFAULT_FULL_RECONCILE_MS, EVENT_BATCH_LIMIT_ENV, FULL_RECONCILE_MS_ENV, journalEntriesForWatcherDelete, resolveEventBatchLimit, resolveFullReconcileMs, shouldQuarantineWatcherDeleteIntents, WATCHER_REDISCOVERY_RETRY_MS, WATCHER_REDISCOVERY_RETRY_MAX_MS, } from "./sync-runner-watch-loop.js";
17
+ import { adaptivePollMs, advanceMonotonicDeadline, DEFAULT_EVENT_BATCH_LIMIT, DEFAULT_FAST_LANE_MAX_BYTES, DEFAULT_FAST_LANE_MAX_FILE_BYTES, DEFAULT_FAST_LANE_MAX_FILES, DEFAULT_FULL_RECONCILE_MS, EVENT_BATCH_LIMIT_ENV, FAST_LANE_MAX_BYTES_ENV, FAST_LANE_MAX_FILES_ENV, FULL_RECONCILE_MS_ENV, isFastLocalBatch, isFastReceiverBatch, partitionLocalBatch, journalEntriesForWatcherDelete, resolveEventBatchLimit, resolveFullReconcileMs, shouldQuarantineWatcherDeleteIntents, WATCHER_REDISCOVERY_RETRY_MS, WATCHER_REDISCOVERY_RETRY_MAX_MS, } from "./sync-runner-watch-loop.js";
18
18
  import { PERSONAL_VAULT_JOURNAL_SLUG, readJournal, writeJournal, } from "../journal.js";
19
19
  import { HQ_CLOUD_VERSION } from "../version.js";
20
20
  import { lockPathFor, OPERATION_LOCKED_EXIT } from "../operation-lock.js";
@@ -4340,6 +4340,63 @@ describe("runRunnerWithLoop — event-push wiring", () => {
4340
4340
  triggerShutdown();
4341
4341
  await loop;
4342
4342
  });
4343
+ it("pushes a file created before watcher ready through the warm-up catch-up", async () => {
4344
+ const watcher = makeBatchWatcherStub();
4345
+ let markReady = () => { };
4346
+ watcher.onReady = (listener) => {
4347
+ markReady = listener;
4348
+ return () => { };
4349
+ };
4350
+ watcher.collectWarmupCatchup = vi.fn(() => ({
4351
+ batch: {
4352
+ paths: new Map([[
4353
+ "/tmp/hq/companies/indigo/knowledge/created-during-warmup.md",
4354
+ "companies/indigo/knowledge/created-during-warmup.md",
4355
+ ]]),
4356
+ changes: new Map([[
4357
+ "/tmp/hq/companies/indigo/knowledge/created-during-warmup.md",
4358
+ { kind: "add" },
4359
+ ]]),
4360
+ },
4361
+ scannedPaths: 1,
4362
+ }));
4363
+ const sleep = makeSteppableSleep();
4364
+ const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
4365
+ let shutdown = () => { };
4366
+ const loop = runRunnerWithLoop([
4367
+ "--company", "indigo", "--watch", "--event-push", "--direction", "pull",
4368
+ "--hq-root", "/tmp/hq", "--poll-remote-ms", "60000",
4369
+ ], {
4370
+ runPass,
4371
+ createWatcher: () => watcher,
4372
+ sleep: sleep.sleep,
4373
+ onShutdownSignal: (handler) => {
4374
+ shutdown = handler;
4375
+ return () => { };
4376
+ },
4377
+ });
4378
+ try {
4379
+ await flushLoopMicrotasks();
4380
+ markReady();
4381
+ await flushLoopMicrotasks();
4382
+ expect(watcher.collectWarmupCatchup).toHaveBeenCalledOnce();
4383
+ expect(runPass.mock.calls.map(([argv]) => argv)).toEqual([
4384
+ ["--company", "indigo", "--direction", "pull", "--hq-root", "/tmp/hq"],
4385
+ [
4386
+ "--company", "indigo", "--direction", "push",
4387
+ "--scope-path", "knowledge/created-during-warmup.md", "--hq-root", "/tmp/hq",
4388
+ ],
4389
+ [
4390
+ "--company", "indigo", "--direction", "pull",
4391
+ "--scope-path", "knowledge/created-during-warmup.md", "--hq-root", "/tmp/hq",
4392
+ ],
4393
+ ]);
4394
+ }
4395
+ finally {
4396
+ shutdown();
4397
+ await loop;
4398
+ }
4399
+ });
4343
4400
  it("keeps every event surface off until a result proves maintenance completed", async () => {
4344
4401
  const watcher = makeWatcherStub();
4345
4402
  const sleep = makeSteppableSleep();
@@ -4592,6 +4649,632 @@ describe("runRunnerWithLoop — event-push wiring", () => {
4592
4649
  triggerShutdown();
4593
4650
  await loop;
4594
4651
  });
4652
+ it("fast lane: a small watcher batch dispatches during a slow bulk pass", async () => {
4653
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-watch-"));
4654
+ const relativePath = "companies/indigo/realtime.md";
4655
+ const absolutePath = path.join(hqRoot, relativePath);
4656
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
4657
+ fs.writeFileSync(absolutePath, "tiny realtime edit");
4658
+ const watcher = makeBatchWatcherStub();
4659
+ let triggerShutdown = () => { };
4660
+ let releaseBulk = () => { };
4661
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4662
+ const order = [];
4663
+ let fullPasses = 0;
4664
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4665
+ if (passArgv.includes("--scope-path")) {
4666
+ order.push("fast");
4667
+ return completedPassOutcome();
4668
+ }
4669
+ fullPasses += 1;
4670
+ if (fullPasses === 2) {
4671
+ order.push("bulk");
4672
+ await bulkGate;
4673
+ }
4674
+ return completedPassOutcome();
4675
+ });
4676
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "both", "--hq-root", hqRoot], {
4677
+ runPass,
4678
+ clock: new FakeClock(),
4679
+ createWatcher: () => watcher,
4680
+ sleep: () => new Promise(() => { }),
4681
+ onShutdownSignal: (handler) => {
4682
+ triggerShutdown = handler;
4683
+ return () => { };
4684
+ },
4685
+ });
4686
+ await flushLoopMicrotasks();
4687
+ watcher.emit(); // starts the second, deliberately blocked full pass
4688
+ await flushLoopMicrotasks();
4689
+ expect(order).toEqual(["bulk"]);
4690
+ watcher.emit(relativePath, { paths: new Map([[absolutePath, relativePath]]) });
4691
+ await flushLoopMicrotasks(30);
4692
+ // Regression: origin/main leaves this as ["bulk"] until releaseBulk().
4693
+ expect(order).toEqual(["bulk", "fast", "fast"]);
4694
+ releaseBulk();
4695
+ await flushLoopMicrotasks();
4696
+ triggerShutdown();
4697
+ await loop;
4698
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4699
+ });
4700
+ it("fast lane: peels a tiny watcher path from mixed multi-megabyte residue", async () => {
4701
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-mixed-watch-"));
4702
+ const tinyRel = "companies/indigo/realtime.md";
4703
+ const tiny = path.join(hqRoot, tinyRel);
4704
+ const bulk = [0, 1, 2].map((index) => path.join(hqRoot, `companies/indigo/session-${index}.log`));
4705
+ fs.mkdirSync(path.dirname(tiny), { recursive: true });
4706
+ fs.writeFileSync(tiny, "tiny realtime edit");
4707
+ for (const file of bulk)
4708
+ fs.writeFileSync(file, Buffer.alloc(8 * 1024 * 1024));
4709
+ const watcher = makeBatchWatcherStub();
4710
+ let triggerShutdown = () => { };
4711
+ let releaseBulk = () => { };
4712
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4713
+ const calls = [];
4714
+ let fullPasses = 0;
4715
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4716
+ calls.push(passArgv);
4717
+ if (!passArgv.includes("--scope-path")) {
4718
+ fullPasses += 1;
4719
+ if (fullPasses === 2)
4720
+ await bulkGate;
4721
+ }
4722
+ return completedPassOutcome();
4723
+ });
4724
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "push", "--hq-root", hqRoot], {
4725
+ runPass,
4726
+ clock: new FakeClock(),
4727
+ createWatcher: () => watcher,
4728
+ sleep: () => new Promise(() => { }),
4729
+ onShutdownSignal: (handler) => {
4730
+ triggerShutdown = handler;
4731
+ return () => { };
4732
+ },
4733
+ });
4734
+ await flushLoopMicrotasks();
4735
+ watcher.emit();
4736
+ await flushLoopMicrotasks();
4737
+ watcher.emit(tinyRel, {
4738
+ paths: new Map([
4739
+ [tiny, tinyRel],
4740
+ ...bulk.map((file, index) => [file, `companies/indigo/session-${index}.log`]),
4741
+ ]),
4742
+ });
4743
+ await flushLoopMicrotasks(30);
4744
+ // origin/main failure: expected a scoped tiny path while the bulk pass is
4745
+ // held, but #408 kept all four paths in the slow lane.
4746
+ expect(calls.filter((argv) => argv.includes("--scope-path"))).toHaveLength(1);
4747
+ expect(calls.flat().join(" ")).toContain("realtime.md");
4748
+ releaseBulk();
4749
+ await flushLoopMicrotasks(30);
4750
+ expect(calls.filter((argv) => argv.includes("--scope-path"))).toHaveLength(2);
4751
+ expect(calls.flat().join(" ")).toContain("session-0.log");
4752
+ triggerShutdown();
4753
+ await loop;
4754
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4755
+ });
4756
+ it("fast lane: a small receiver pull dispatches during a slow bulk pass", async () => {
4757
+ const watcher = makeWatcherStub();
4758
+ let triggerShutdown = () => { };
4759
+ let receiverSync;
4760
+ let releaseBulk = () => { };
4761
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4762
+ const order = [];
4763
+ let fullPasses = 0;
4764
+ const journal = readJournal("acme");
4765
+ journal.files["realtime.md"] = {
4766
+ hash: "sha256:x",
4767
+ size: 16,
4768
+ syncedAt: "2026-08-26T00:00:00.000Z",
4769
+ direction: "down",
4770
+ };
4771
+ writeJournal("acme", journal);
4772
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4773
+ if (passArgv.includes("--scope-path")) {
4774
+ order.push("fast-pull");
4775
+ return completedPassOutcome();
4776
+ }
4777
+ fullPasses += 1;
4778
+ if (fullPasses === 2) {
4779
+ order.push("bulk");
4780
+ await bulkGate;
4781
+ }
4782
+ return completedPassOutcome();
4783
+ });
4784
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--hq-root", "/tmp/hq-fast-lane-receiver"], {
4785
+ runPass,
4786
+ createWatcher: () => watcher,
4787
+ createReceiver: ({ syncBatchFn }) => {
4788
+ receiverSync = syncBatchFn;
4789
+ return { connected: true, start: async () => { }, dispose: async () => { } };
4790
+ },
4791
+ sleep: () => new Promise(() => { }),
4792
+ onShutdownSignal: (handler) => {
4793
+ triggerShutdown = handler;
4794
+ return () => { };
4795
+ },
4796
+ });
4797
+ await flushLoopMicrotasks();
4798
+ watcher.emit();
4799
+ await flushLoopMicrotasks();
4800
+ expect(order).toEqual(["bulk"]);
4801
+ await receiverSync({
4802
+ events: [{
4803
+ kind: "upsert", relativePath: "companies/acme/realtime.md", contentHash: "sha256:x",
4804
+ mtime: "2026-08-26T00:00:00.000Z", originDeviceId: "peer", originTenantId: "acme",
4805
+ sequenceNumber: 1, eventTimestamp: "2026-08-26T00:00:00.000Z",
4806
+ }],
4807
+ signal: new AbortController().signal,
4808
+ });
4809
+ expect(order).toEqual(["bulk", "fast-pull"]);
4810
+ releaseBulk();
4811
+ await flushLoopMicrotasks();
4812
+ triggerShutdown();
4813
+ await loop;
4814
+ });
4815
+ it("fast lane: retains the root lock until an outliving fast pass completes", async () => {
4816
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-lock-"));
4817
+ const relativePath = "companies/indigo/realtime.md";
4818
+ const absolutePath = path.join(hqRoot, relativePath);
4819
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
4820
+ fs.writeFileSync(absolutePath, "tiny realtime edit");
4821
+ const watcher = makeBatchWatcherStub();
4822
+ let triggerShutdown = () => { };
4823
+ let releaseBulk = () => { };
4824
+ let releaseFast = () => { };
4825
+ let markFastStarted = () => { };
4826
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4827
+ const fastGate = new Promise((resolve) => { releaseFast = resolve; });
4828
+ const fastStarted = new Promise((resolve) => { markFastStarted = resolve; });
4829
+ let fullPasses = 0;
4830
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4831
+ if (passArgv.includes("--scope-path")) {
4832
+ markFastStarted();
4833
+ await fastGate;
4834
+ return completedPassOutcome();
4835
+ }
4836
+ fullPasses += 1;
4837
+ if (fullPasses === 2)
4838
+ await bulkGate;
4839
+ return completedPassOutcome();
4840
+ });
4841
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "both", "--hq-root", hqRoot], {
4842
+ runPass,
4843
+ clock: new FakeClock(),
4844
+ createWatcher: () => watcher,
4845
+ sleep: () => new Promise(() => { }),
4846
+ onShutdownSignal: (handler) => {
4847
+ triggerShutdown = handler;
4848
+ return () => { };
4849
+ },
4850
+ });
4851
+ await flushLoopMicrotasks();
4852
+ watcher.emit();
4853
+ await flushLoopMicrotasks();
4854
+ watcher.emit(relativePath, { paths: new Map([[absolutePath, relativePath]]) });
4855
+ await fastStarted;
4856
+ releaseBulk();
4857
+ await flushLoopMicrotasks(20);
4858
+ // The slow pass has finished, but its fast bypass still mutates. A second
4859
+ // sync/rescue must not acquire the root operation lock in this interval.
4860
+ expect(fs.existsSync(lockPathFor(hqRoot))).toBe(true);
4861
+ releaseFast();
4862
+ await flushLoopMicrotasks(20);
4863
+ expect(fs.existsSync(lockPathFor(hqRoot))).toBe(false);
4864
+ triggerShutdown();
4865
+ await loop;
4866
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4867
+ });
4868
+ it("fast lane: an absent unlinkDir subtree is always slow-lane", () => {
4869
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-unlink-dir-"));
4870
+ const deletedDir = path.join(hqRoot, "companies/indigo/archive");
4871
+ fs.mkdirSync(deletedDir, { recursive: true });
4872
+ fs.rmSync(deletedDir, { recursive: true, force: true });
4873
+ expect(isFastLocalBatch([deletedDir], new Map([[deletedDir, { kind: "unlinkDir" }]]))).toBe(false);
4874
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4875
+ });
4876
+ it("fast lane: --skip-personal rejects a selected-out personal watcher batch", async () => {
4877
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-route-"));
4878
+ const relativePath = "knowledge/private.md";
4879
+ const absolutePath = path.join(hqRoot, relativePath);
4880
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
4881
+ fs.writeFileSync(absolutePath, "private");
4882
+ const watcher = makeBatchWatcherStub();
4883
+ let triggerShutdown = () => { };
4884
+ let releaseBulk = () => { };
4885
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4886
+ let fullPasses = 0;
4887
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4888
+ if (passArgv.includes("--scope-path"))
4889
+ return completedPassOutcome();
4890
+ fullPasses += 1;
4891
+ if (fullPasses === 2)
4892
+ await bulkGate;
4893
+ return completedPassOutcome();
4894
+ });
4895
+ const loop = runRunnerWithLoop(["--companies", "--skip-personal", "--watch", "--event-push", "--direction", "both", "--hq-root", hqRoot], {
4896
+ runPass,
4897
+ clock: new FakeClock(),
4898
+ createWatcher: () => watcher,
4899
+ sleep: () => new Promise(() => { }),
4900
+ onShutdownSignal: (handler) => {
4901
+ triggerShutdown = handler;
4902
+ return () => { };
4903
+ },
4904
+ });
4905
+ await flushLoopMicrotasks();
4906
+ watcher.emit();
4907
+ await flushLoopMicrotasks();
4908
+ runPass.mockClear();
4909
+ watcher.emit(relativePath, { paths: new Map([[absolutePath, relativePath]]) });
4910
+ await flushLoopMicrotasks(20);
4911
+ expect(runPass.mock.calls).toEqual([]);
4912
+ releaseBulk();
4913
+ await flushLoopMicrotasks();
4914
+ triggerShutdown();
4915
+ await loop;
4916
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4917
+ });
4918
+ it("fast lane: signals the V2 scheduler for an immediate watcher dispatch", async () => {
4919
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-signal-"));
4920
+ const relativePath = "companies/indigo/realtime.md";
4921
+ const absolutePath = path.join(hqRoot, relativePath);
4922
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
4923
+ fs.writeFileSync(absolutePath, "tiny realtime edit");
4924
+ const watcher = makeBatchWatcherStub();
4925
+ const scheduler = {
4926
+ signal: vi.fn(),
4927
+ checkHighWater: vi.fn().mockResolvedValue(undefined),
4928
+ dispose: vi.fn().mockResolvedValue(undefined),
4929
+ };
4930
+ let triggerShutdown = () => { };
4931
+ let releaseBulk = () => { };
4932
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4933
+ let fullPasses = 0;
4934
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4935
+ if (passArgv.includes("--scope-path"))
4936
+ return completedPassOutcome();
4937
+ fullPasses += 1;
4938
+ if (fullPasses === 2)
4939
+ await bulkGate;
4940
+ return completedPassOutcome();
4941
+ });
4942
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "both", "--hq-root", hqRoot], {
4943
+ runPass,
4944
+ clock: new FakeClock(),
4945
+ createWatcher: () => watcher,
4946
+ startRealtimeScheduler: async () => scheduler,
4947
+ sleep: () => new Promise(() => { }),
4948
+ onShutdownSignal: (handler) => {
4949
+ triggerShutdown = handler;
4950
+ return () => { };
4951
+ },
4952
+ });
4953
+ await flushLoopMicrotasks(20);
4954
+ watcher.emit();
4955
+ await flushLoopMicrotasks();
4956
+ scheduler.signal.mockClear();
4957
+ watcher.emit(relativePath, { paths: new Map([[absolutePath, relativePath]]) });
4958
+ await flushLoopMicrotasks(20);
4959
+ expect(scheduler.signal).toHaveBeenCalledWith("watcher");
4960
+ releaseBulk();
4961
+ await flushLoopMicrotasks();
4962
+ triggerShutdown();
4963
+ await loop;
4964
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4965
+ });
4966
+ it("fast lane: applies the receiver cap once across all eligible routes", async () => {
4967
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-receiver-cap-"));
4968
+ const watcher = makeWatcherStub();
4969
+ let receiverSync;
4970
+ let triggerShutdown = () => { };
4971
+ let releaseBulk = () => { };
4972
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
4973
+ let fullPasses = 0;
4974
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
4975
+ if (passArgv.includes("--scope-path"))
4976
+ return completedPassOutcome();
4977
+ fullPasses += 1;
4978
+ if (fullPasses === 2)
4979
+ await bulkGate;
4980
+ return completedPassOutcome();
4981
+ });
4982
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--hq-root", hqRoot], {
4983
+ runPass,
4984
+ createWatcher: () => watcher,
4985
+ createReceiver: ({ syncBatchFn }) => {
4986
+ receiverSync = syncBatchFn;
4987
+ return { connected: true, start: async () => { }, dispose: async () => { } };
4988
+ },
4989
+ sleep: () => new Promise(() => { }),
4990
+ onShutdownSignal: (handler) => {
4991
+ triggerShutdown = handler;
4992
+ return () => { };
4993
+ },
4994
+ });
4995
+ await flushLoopMicrotasks();
4996
+ watcher.emit();
4997
+ await flushLoopMicrotasks();
4998
+ runPass.mockClear();
4999
+ const events = [
5000
+ ...Array.from({ length: 17 }, (_, index) => ({
5001
+ kind: "upsert",
5002
+ relativePath: `companies/acme/a-${index}.md`,
5003
+ contentHash: "sha256:x",
5004
+ mtime: "2026-08-26T00:00:00.000Z",
5005
+ originDeviceId: "peer",
5006
+ originTenantId: "acme",
5007
+ sequenceNumber: index,
5008
+ eventTimestamp: "2026-08-26T00:00:00.000Z",
5009
+ })),
5010
+ ...Array.from({ length: 16 }, (_, index) => ({
5011
+ kind: "upsert",
5012
+ relativePath: `companies/beta/b-${index}.md`,
5013
+ contentHash: "sha256:x",
5014
+ mtime: "2026-08-26T00:00:00.000Z",
5015
+ originDeviceId: "peer",
5016
+ originTenantId: "beta",
5017
+ sequenceNumber: index + 17,
5018
+ eventTimestamp: "2026-08-26T00:00:00.000Z",
5019
+ })),
5020
+ ];
5021
+ for (const [slug, prefix, count] of [["acme", "a", 17], ["beta", "b", 16]]) {
5022
+ const journal = readJournal(slug);
5023
+ for (let index = 0; index < count; index++) {
5024
+ journal.files[`${prefix}-${index}.md`] = {
5025
+ hash: "sha256:x",
5026
+ size: 16,
5027
+ syncedAt: "2026-08-26T00:00:00.000Z",
5028
+ direction: "down",
5029
+ };
5030
+ }
5031
+ writeJournal(slug, journal);
5032
+ }
5033
+ const receiverDrain = receiverSync({
5034
+ events,
5035
+ signal: new AbortController().signal,
5036
+ });
5037
+ await flushLoopMicrotasks(20);
5038
+ // The 33-event mixed delivery peels its first 32 bounded paths into the
5039
+ // fast lane (17 acme + 15 beta); the final beta event remains slow.
5040
+ expect(runPass).toHaveBeenCalledTimes(2);
5041
+ expect(runPass.mock.calls.flat().join(" ")).toContain("a-16.md");
5042
+ expect(runPass.mock.calls.flat().join(" ")).toContain("b-14.md");
5043
+ releaseBulk();
5044
+ await receiverDrain;
5045
+ triggerShutdown();
5046
+ await loop;
5047
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5048
+ });
5049
+ it("fast lane: queues slow work behind a receiver pass that owns the root lock", async () => {
5050
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-slow-queue-"));
5051
+ const watcher = makeWatcherStub();
5052
+ let receiverSync;
5053
+ let triggerShutdown = () => { };
5054
+ let releaseFast = () => { };
5055
+ let markFastStarted = () => { };
5056
+ const fastGate = new Promise((resolve) => { releaseFast = resolve; });
5057
+ const fastStarted = new Promise((resolve) => { markFastStarted = resolve; });
5058
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
5059
+ if (passArgv.includes("--scope-path")) {
5060
+ markFastStarted();
5061
+ await fastGate;
5062
+ return completedPassOutcome();
5063
+ }
5064
+ return completedPassOutcome();
5065
+ });
5066
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--lock-timeout", "0", "--hq-root", hqRoot], {
5067
+ runPass,
5068
+ createWatcher: () => watcher,
5069
+ createReceiver: ({ syncBatchFn }) => {
5070
+ receiverSync = syncBatchFn;
5071
+ return { connected: true, start: async () => { }, dispose: async () => { } };
5072
+ },
5073
+ sleep: () => new Promise(() => { }),
5074
+ onShutdownSignal: (handler) => {
5075
+ triggerShutdown = handler;
5076
+ return () => { };
5077
+ },
5078
+ });
5079
+ let loopSettled = false;
5080
+ void loop.then(() => { loopSettled = true; });
5081
+ await flushLoopMicrotasks();
5082
+ const receiverDrain = receiverSync({
5083
+ events: [{
5084
+ kind: "upsert",
5085
+ relativePath: "companies/acme/remote.md",
5086
+ contentHash: "sha256:x",
5087
+ mtime: "2026-08-26T00:00:00.000Z",
5088
+ originDeviceId: "peer",
5089
+ originTenantId: "acme",
5090
+ sequenceNumber: 1,
5091
+ eventTimestamp: "2026-08-26T00:00:00.000Z",
5092
+ }],
5093
+ signal: new AbortController().signal,
5094
+ });
5095
+ await fastStarted;
5096
+ // This wake requests a slow reconcile while the receiver owns the lock.
5097
+ watcher.emit();
5098
+ await flushLoopMicrotasks(20);
5099
+ expect(loopSettled).toBe(false);
5100
+ releaseFast();
5101
+ await receiverDrain;
5102
+ triggerShutdown();
5103
+ await loop;
5104
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5105
+ });
5106
+ it("fast lane: keeps disjoint journal rows under a 16-path interleave with a bulk pass", async () => {
5107
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-journal-"));
5108
+ const paths = Array.from({ length: 16 }, (_, index) => {
5109
+ const relativePath = `companies/indigo/realtime-${index}.md`;
5110
+ const absolutePath = path.join(hqRoot, relativePath);
5111
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
5112
+ fs.writeFileSync(absolutePath, "tiny realtime edit");
5113
+ return [absolutePath, relativePath];
5114
+ });
5115
+ writeJournal("indigo", { version: "2", lastSync: "", pulls: [], files: {} });
5116
+ const watcher = makeBatchWatcherStub();
5117
+ let triggerShutdown = () => { };
5118
+ let releaseBulk = () => { };
5119
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
5120
+ let fullPasses = 0;
5121
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
5122
+ if (passArgv.includes("--scope-path")) {
5123
+ const fast = readJournal("indigo");
5124
+ for (let index = 0; index < paths.length; index++) {
5125
+ fast.files[`realtime-${index}.md`] = {
5126
+ hash: `fast-${index}`, size: 1, syncedAt: "", direction: "up",
5127
+ };
5128
+ }
5129
+ writeJournal("indigo", fast);
5130
+ return completedPassOutcome();
5131
+ }
5132
+ fullPasses += 1;
5133
+ if (fullPasses === 2) {
5134
+ const slow = readJournal("indigo");
5135
+ await bulkGate;
5136
+ for (let index = 0; index < paths.length; index++) {
5137
+ slow.files[`bulk-${index}.md`] = {
5138
+ hash: `slow-${index}`, size: 1, syncedAt: "", direction: "up",
5139
+ };
5140
+ }
5141
+ writeJournal("indigo", slow);
5142
+ }
5143
+ return completedPassOutcome();
5144
+ });
5145
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "push", "--hq-root", hqRoot], {
5146
+ runPass,
5147
+ clock: new FakeClock(),
5148
+ createWatcher: () => watcher,
5149
+ sleep: () => new Promise(() => { }),
5150
+ onShutdownSignal: (handler) => {
5151
+ triggerShutdown = handler;
5152
+ return () => { };
5153
+ },
5154
+ });
5155
+ await flushLoopMicrotasks();
5156
+ watcher.emit();
5157
+ await flushLoopMicrotasks();
5158
+ watcher.emit(paths[0][1], { paths: new Map(paths) });
5159
+ await flushLoopMicrotasks(30);
5160
+ expect(Object.keys(readJournal("indigo").files)).toHaveLength(paths.length);
5161
+ releaseBulk();
5162
+ await flushLoopMicrotasks();
5163
+ const journal = readJournal("indigo").files;
5164
+ expect(Object.keys(journal)).toHaveLength(paths.length * 2);
5165
+ for (let index = 0; index < paths.length; index++) {
5166
+ expect(journal[`bulk-${index}.md`]?.hash).toBe(`slow-${index}`);
5167
+ expect(journal[`realtime-${index}.md`]?.hash).toBe(`fast-${index}`);
5168
+ }
5169
+ triggerShutdown();
5170
+ await loop;
5171
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5172
+ });
5173
+ it("fast lane: a bulk pass still completes after repeated small watcher batches", async () => {
5174
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-fairness-"));
5175
+ const watcher = makeBatchWatcherStub();
5176
+ let triggerShutdown = () => { };
5177
+ let releaseBulk = () => { };
5178
+ const bulkGate = new Promise((resolve) => { releaseBulk = resolve; });
5179
+ const completed = [];
5180
+ let fullPasses = 0;
5181
+ const runPass = vi.fn().mockImplementation(async (passArgv) => {
5182
+ if (passArgv.includes("--scope-path")) {
5183
+ completed.push("fast");
5184
+ return completedPassOutcome();
5185
+ }
5186
+ fullPasses += 1;
5187
+ if (fullPasses === 2) {
5188
+ await bulkGate;
5189
+ completed.push("bulk");
5190
+ }
5191
+ return completedPassOutcome();
5192
+ });
5193
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "push", "--hq-root", hqRoot], {
5194
+ runPass,
5195
+ clock: new FakeClock(),
5196
+ createWatcher: () => watcher,
5197
+ sleep: () => new Promise(() => { }),
5198
+ onShutdownSignal: (handler) => {
5199
+ triggerShutdown = handler;
5200
+ return () => { };
5201
+ },
5202
+ });
5203
+ await flushLoopMicrotasks();
5204
+ watcher.emit();
5205
+ await flushLoopMicrotasks();
5206
+ for (let index = 0; index < 5; index++) {
5207
+ const relativePath = `companies/indigo/realtime-${index}.md`;
5208
+ const absolutePath = path.join(hqRoot, relativePath);
5209
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
5210
+ fs.writeFileSync(absolutePath, "tiny");
5211
+ watcher.emit(relativePath, { paths: new Map([[absolutePath, relativePath]]) });
5212
+ }
5213
+ await flushLoopMicrotasks(60);
5214
+ expect(completed).toEqual(["fast", "fast", "fast", "fast", "fast"]);
5215
+ releaseBulk();
5216
+ await flushLoopMicrotasks();
5217
+ expect(completed).toContain("bulk");
5218
+ triggerShutdown();
5219
+ await loop;
5220
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5221
+ });
5222
+ it("fast lane: sends only batches at or below the file and byte limits", () => {
5223
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-limit-"));
5224
+ const small = path.join(hqRoot, "small.md");
5225
+ const boundary = path.join(hqRoot, "boundary.bin");
5226
+ fs.writeFileSync(small, "small");
5227
+ fs.writeFileSync(boundary, Buffer.alloc(DEFAULT_FAST_LANE_MAX_BYTES));
5228
+ expect(isFastLocalBatch([small])).toBe(true);
5229
+ expect(isFastLocalBatch([boundary])).toBe(true);
5230
+ fs.appendFileSync(boundary, "x");
5231
+ expect(isFastLocalBatch([boundary])).toBe(false);
5232
+ expect(isFastReceiverBatch(DEFAULT_FAST_LANE_MAX_FILES)).toBe(true);
5233
+ expect(isFastReceiverBatch(DEFAULT_FAST_LANE_MAX_FILES + 1)).toBe(false);
5234
+ const previousFiles = process.env[FAST_LANE_MAX_FILES_ENV];
5235
+ const previousBytes = process.env[FAST_LANE_MAX_BYTES_ENV];
5236
+ process.env[FAST_LANE_MAX_FILES_ENV] = "1";
5237
+ process.env[FAST_LANE_MAX_BYTES_ENV] = "4";
5238
+ try {
5239
+ expect(isFastLocalBatch([small])).toBe(false);
5240
+ expect(isFastReceiverBatch(2)).toBe(false);
5241
+ }
5242
+ finally {
5243
+ if (previousFiles === undefined)
5244
+ delete process.env[FAST_LANE_MAX_FILES_ENV];
5245
+ else
5246
+ process.env[FAST_LANE_MAX_FILES_ENV] = previousFiles;
5247
+ if (previousBytes === undefined)
5248
+ delete process.env[FAST_LANE_MAX_BYTES_ENV];
5249
+ else
5250
+ process.env[FAST_LANE_MAX_BYTES_ENV] = previousBytes;
5251
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5252
+ }
5253
+ });
5254
+ it("fast lane: keeps a latest large revision in the slow residue and caps 33 small paths", () => {
5255
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-partition-"));
5256
+ const rel = "companies/indigo/revised.md";
5257
+ const absolute = path.join(hqRoot, rel);
5258
+ fs.mkdirSync(path.dirname(absolute), { recursive: true });
5259
+ // The map is the coalescing/affinity boundary: its one value is the latest
5260
+ // revision, so this path cannot appear in both sub-batches.
5261
+ fs.writeFileSync(absolute, Buffer.alloc(DEFAULT_FAST_LANE_MAX_FILE_BYTES + 1));
5262
+ const revised = partitionLocalBatch({ paths: new Map([[absolute, rel]]) });
5263
+ expect(revised.fast).toBeNull();
5264
+ expect(revised.slow?.paths.get(absolute)).toBe(rel);
5265
+ const entries = [];
5266
+ for (let index = 0; index < DEFAULT_FAST_LANE_MAX_FILES + 1; index++) {
5267
+ const file = path.join(hqRoot, `companies/indigo/small-${index}.md`);
5268
+ fs.writeFileSync(file, "x");
5269
+ entries.push([file, `companies/indigo/small-${index}.md`]);
5270
+ }
5271
+ const capped = partitionLocalBatch({ paths: new Map(entries) });
5272
+ expect(capped.fast?.paths.size).toBe(DEFAULT_FAST_LANE_MAX_FILES);
5273
+ // The 33rd path deliberately remains in the slow residue, rather than
5274
+ // creating a second concurrent realtime dispatch.
5275
+ expect(capped.slow?.paths.size).toBe(1);
5276
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5277
+ });
4595
5278
  it("U07: drains the first watcher event after activation without guarded overlap", async () => {
4596
5279
  const watcher = makeWatcherStub();
4597
5280
  let triggerShutdown = () => { };
@@ -5147,6 +5830,8 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
5147
5830
  "bare-wake": matched.includes("bare-wake"),
5148
5831
  "batch-over-limit": matched.includes("batch-over-limit"),
5149
5832
  "overflow-routes-unknown": matched.includes("overflow-routes-unknown"),
5833
+ "watcher-warmup-catch-up": matched.includes("watcher-warmup-catch-up"),
5834
+ "watcher-warmup-catch-up-failed": matched.includes("watcher-warmup-catch-up-failed"),
5150
5835
  "scheduled-interval": matched.includes("scheduled-interval"),
5151
5836
  });
5152
5837
  function expectFullReconcileDecision(record, mode, reasons) {