@indigoai-us/hq-cloud 6.15.87 → 6.15.89

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.
Files changed (40) hide show
  1. package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
  2. package/dist/bin/sync-runner-watch-loop.js +58 -28
  3. package/dist/bin/sync-runner-watch-loop.js.map +1 -1
  4. package/dist/bin/sync-runner.test.js +309 -0
  5. package/dist/bin/sync-runner.test.js.map +1 -1
  6. package/dist/cli/reindex.d.ts.map +1 -1
  7. package/dist/cli/reindex.js +34 -9
  8. package/dist/cli/reindex.js.map +1 -1
  9. package/dist/cli/reindex.test.js +39 -7
  10. package/dist/cli/reindex.test.js.map +1 -1
  11. package/dist/cognito-auth.test.js +16 -0
  12. package/dist/cognito-auth.test.js.map +1 -1
  13. package/dist/hermetic-test-env.test.d.ts +2 -0
  14. package/dist/hermetic-test-env.test.d.ts.map +1 -0
  15. package/dist/hermetic-test-env.test.js +61 -0
  16. package/dist/hermetic-test-env.test.js.map +1 -0
  17. package/dist/journal-store.test.js +66 -2
  18. package/dist/journal-store.test.js.map +1 -1
  19. package/dist/journal.d.ts +5 -0
  20. package/dist/journal.d.ts.map +1 -1
  21. package/dist/journal.js +53 -6
  22. package/dist/journal.js.map +1 -1
  23. package/dist/machine-auth.test.js +3 -0
  24. package/dist/machine-auth.test.js.map +1 -1
  25. package/dist/sync/area-ledger-migration.d.ts +4 -0
  26. package/dist/sync/area-ledger-migration.d.ts.map +1 -1
  27. package/dist/sync/area-ledger-migration.js +5 -0
  28. package/dist/sync/area-ledger-migration.js.map +1 -1
  29. package/dist/sync/parallel-sync-coordinator.d.ts +2 -1
  30. package/dist/sync/parallel-sync-coordinator.d.ts.map +1 -1
  31. package/dist/sync/parallel-sync-coordinator.js +29 -11
  32. package/dist/sync/parallel-sync-coordinator.js.map +1 -1
  33. package/dist/sync/parallel-sync-coordinator.test.js +76 -1
  34. package/dist/sync/parallel-sync-coordinator.test.js.map +1 -1
  35. package/dist/sync/push-receiver.test.js +12 -2
  36. package/dist/sync/push-receiver.test.js.map +1 -1
  37. package/dist/sync/sync-work.d.ts +2 -0
  38. package/dist/sync/sync-work.d.ts.map +1 -1
  39. package/dist/sync/sync-work.js.map +1 -1
  40. package/package.json +3 -3
@@ -17,6 +17,7 @@ import { FakeClock, TreeWatcher, } from "../watcher.js";
17
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, resolveWatchPollMs, normalizeCoordinatorPaths, shouldQuarantineWatcherDeleteIntents, shouldUseAreaStorage, WATCHER_REDISCOVERY_RETRY_MS, WATCHER_REDISCOVERY_RETRY_MAX_MS, } from "./sync-runner-watch-loop.js";
18
18
  import { AreaLedgerMigration, openJournalStateStoreForMigration, PERSONAL_VAULT_JOURNAL_SLUG, readJournal, writeJournal, } from "../journal.js";
19
19
  import { AreaResolver } from "../sync/area-resolver.js";
20
+ import { AreaMaintenanceCursorStore } from "../sync/per-area-maintenance.js";
20
21
  import { HQ_CLOUD_VERSION } from "../version.js";
21
22
  import { lockPathFor, OPERATION_LOCKED_EXIT } from "../operation-lock.js";
22
23
  import { TRANSIENT_NETWORK_EXIT } from "../lib/net-errors.js";
@@ -4349,6 +4350,73 @@ describe("runRunnerWithLoop — event-push wiring", () => {
4349
4350
  await loop;
4350
4351
  expect(disposeCalls).toBe(1);
4351
4352
  });
4353
+ it("continues scheduling coordinator passes after retention and authoritative area maintenance", async () => {
4354
+ const previousCoordinator = process.env.HQ_SYNC_PARALLEL_COORDINATOR;
4355
+ const previousAreaStorage = process.env.HQ_SYNC_AREA_STORAGE;
4356
+ const previousNow = Date.now;
4357
+ const sleep = makeSteppableSleep();
4358
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-area-watch-"));
4359
+ const slug = PERSONAL_VAULT_JOURNAL_SLUG;
4360
+ let now = 0;
4361
+ Date.now = () => now;
4362
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = "1";
4363
+ process.env.HQ_SYNC_AREA_STORAGE = "1";
4364
+ writeJournal(slug, { version: "2", lastSync: "", pulls: [], files: {} });
4365
+ const migration = new AreaLedgerMigration({
4366
+ rootDir: __runnerTestStateDir,
4367
+ journalSlug: slug,
4368
+ resolver: new AreaResolver({
4369
+ format: 1,
4370
+ routerVersion: 1,
4371
+ areas: [{ id: "root:@files", prefixes: [], paths: [], rootFiles: true }],
4372
+ }),
4373
+ legacyStore: openJournalStateStoreForMigration(slug),
4374
+ });
4375
+ expect(migration.cutOver().phase).toBe("area-authoritative");
4376
+ const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
4377
+ const runBackupPrune = vi.fn().mockResolvedValue(undefined);
4378
+ let shutdown = () => { };
4379
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--poll-remote-ms", "1000", "--hq-root", hqRoot], {
4380
+ runPass,
4381
+ runBackupPrune,
4382
+ sleep: sleep.sleep,
4383
+ onShutdownSignal: (handler) => {
4384
+ shutdown = handler;
4385
+ return () => { };
4386
+ },
4387
+ });
4388
+ try {
4389
+ await flushLoopMicrotasks(30);
4390
+ now = 60_000;
4391
+ sleep.tick();
4392
+ await flushLoopMicrotasks(60);
4393
+ expect(runBackupPrune).toHaveBeenCalledOnce();
4394
+ expect(AreaMaintenanceCursorStore.open({
4395
+ rootDir: __runnerTestStateDir,
4396
+ journalSlug: slug,
4397
+ layoutEpoch: 1,
4398
+ }).read()).toMatchObject({ nextIndex: 1 });
4399
+ for (let i = 0; i < 8; i++) {
4400
+ sleep.tick();
4401
+ await flushLoopMicrotasks(30);
4402
+ }
4403
+ expect(runPass).toHaveBeenCalledTimes(2);
4404
+ }
4405
+ finally {
4406
+ shutdown();
4407
+ await loop;
4408
+ Date.now = previousNow;
4409
+ if (previousCoordinator === undefined)
4410
+ delete process.env.HQ_SYNC_PARALLEL_COORDINATOR;
4411
+ else
4412
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = previousCoordinator;
4413
+ if (previousAreaStorage === undefined)
4414
+ delete process.env.HQ_SYNC_AREA_STORAGE;
4415
+ else
4416
+ process.env.HQ_SYNC_AREA_STORAGE = previousAreaStorage;
4417
+ fs.rmSync(hqRoot, { recursive: true, force: true });
4418
+ }
4419
+ });
4352
4420
  it("activates the watcher after a successful numeric --companies pass", async () => {
4353
4421
  const watcher = makeWatcherStub();
4354
4422
  let triggerShutdown = () => { };
@@ -4859,6 +4927,10 @@ describe("runRunnerWithLoop — event-push wiring", () => {
4859
4927
  "/tmp/hq/companies/indigo/warmup-superseded.md",
4860
4928
  "companies/indigo/warmup-superseded.md",
4861
4929
  ]]),
4930
+ changes: new Map([[
4931
+ "/tmp/hq/companies/indigo/warmup-superseded.md",
4932
+ { kind: "unlinkDir" },
4933
+ ]]),
4862
4934
  },
4863
4935
  scannedPaths: 1,
4864
4936
  }));
@@ -5503,6 +5575,243 @@ describe("runRunnerWithLoop — event-push wiring", () => {
5503
5575
  fs.rmSync(hqRoot, { recursive: true, force: true });
5504
5576
  }
5505
5577
  });
5578
+ it("parallel coordinator partitions receiver events into fast and slow realtime lanes", async () => {
5579
+ const previous = process.env.HQ_SYNC_PARALLEL_COORDINATOR;
5580
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = "1";
5581
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-parallel-receiver-lanes-"));
5582
+ const watcher = makeBatchWatcherStub();
5583
+ let receiverSync;
5584
+ let triggerShutdown = () => { };
5585
+ let releaseSlow = () => { };
5586
+ const slowGate = new Promise((resolve) => { releaseSlow = resolve; });
5587
+ const order = [];
5588
+ const journal = readJournal("indigo");
5589
+ journal.files["small.md"] = {
5590
+ hash: "sha256:small",
5591
+ size: 16,
5592
+ syncedAt: "2026-08-28T00:00:00.000Z",
5593
+ direction: "down",
5594
+ };
5595
+ writeJournal("indigo", journal);
5596
+ const runPass = vi.fn(async (argv) => {
5597
+ if (argv.includes("held-unknown.md")) {
5598
+ order.push("slow-held");
5599
+ await slowGate;
5600
+ }
5601
+ else if (argv.includes("small.md")) {
5602
+ order.push("fast-small");
5603
+ }
5604
+ else if (argv.includes("unknown.md")) {
5605
+ order.push("slow-unknown");
5606
+ }
5607
+ return completedPassOutcome();
5608
+ });
5609
+ const event = (relativePath) => ({
5610
+ kind: "upsert",
5611
+ relativePath,
5612
+ contentHash: "sha256:remote",
5613
+ mtime: "2026-08-28T00:00:00.000Z",
5614
+ originDeviceId: "peer-device",
5615
+ originTenantId: "tenant-indigo",
5616
+ sequenceNumber: 1,
5617
+ eventTimestamp: "2026-08-28T00:00:00.000Z",
5618
+ });
5619
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "pull", "--hq-root", hqRoot], {
5620
+ runPass,
5621
+ createWatcher: () => watcher,
5622
+ createReceiver: ({ syncBatchFn }) => {
5623
+ receiverSync = syncBatchFn;
5624
+ return { connected: true, start: async () => { }, dispose: async () => { } };
5625
+ },
5626
+ sleep: () => new Promise(() => { }),
5627
+ onShutdownSignal: (handler) => {
5628
+ triggerShutdown = handler;
5629
+ return () => { };
5630
+ },
5631
+ });
5632
+ try {
5633
+ await flushLoopMicrotasks(30);
5634
+ runPass.mockClear();
5635
+ const held = receiverSync({
5636
+ events: [event("companies/indigo/held-unknown.md")],
5637
+ signal: new AbortController().signal,
5638
+ });
5639
+ await flushLoopMicrotasks(20);
5640
+ expect(order).toEqual(["slow-held"]);
5641
+ const partitioned = receiverSync({
5642
+ events: [
5643
+ event("companies/indigo/small.md"),
5644
+ event("companies/indigo/unknown.md"),
5645
+ ],
5646
+ signal: new AbortController().signal,
5647
+ });
5648
+ await flushLoopMicrotasks(20);
5649
+ expect(order).toEqual(["slow-held", "fast-small"]);
5650
+ releaseSlow();
5651
+ await held;
5652
+ await partitioned;
5653
+ expect(order).toEqual(["slow-held", "fast-small", "slow-unknown"]);
5654
+ }
5655
+ finally {
5656
+ releaseSlow();
5657
+ triggerShutdown();
5658
+ await loop;
5659
+ if (previous === undefined)
5660
+ delete process.env.HQ_SYNC_PARALLEL_COORDINATOR;
5661
+ else
5662
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = previous;
5663
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5664
+ }
5665
+ });
5666
+ it("parallel coordinator submits a later route's fast receiver work before an earlier route's slow pull completes", async () => {
5667
+ const previous = process.env.HQ_SYNC_PARALLEL_COORDINATOR;
5668
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = "1";
5669
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-parallel-receiver-route-order-"));
5670
+ const watcher = makeBatchWatcherStub();
5671
+ let receiverSync;
5672
+ let triggerShutdown = () => { };
5673
+ let releaseSlow = () => { };
5674
+ const slowGate = new Promise((resolve) => { releaseSlow = resolve; });
5675
+ const order = [];
5676
+ const journal = readJournal("indigo");
5677
+ journal.files["fast.md"] = {
5678
+ hash: "sha256:fast",
5679
+ size: 16,
5680
+ syncedAt: "2026-08-28T00:00:00.000Z",
5681
+ direction: "down",
5682
+ };
5683
+ writeJournal("indigo", journal);
5684
+ const runPass = vi.fn(async (argv) => {
5685
+ if (argv.includes("slow.md")) {
5686
+ order.push("slow-acme");
5687
+ await slowGate;
5688
+ }
5689
+ else if (argv.includes("fast.md")) {
5690
+ order.push("fast-indigo");
5691
+ }
5692
+ return completedPassOutcome();
5693
+ });
5694
+ const event = (relativePath) => ({
5695
+ kind: "upsert",
5696
+ relativePath,
5697
+ contentHash: "sha256:remote",
5698
+ mtime: "2026-08-28T00:00:00.000Z",
5699
+ originDeviceId: "peer-device",
5700
+ originTenantId: "tenant-indigo",
5701
+ sequenceNumber: 1,
5702
+ eventTimestamp: "2026-08-28T00:00:00.000Z",
5703
+ });
5704
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "pull", "--hq-root", hqRoot], {
5705
+ runPass,
5706
+ createWatcher: () => watcher,
5707
+ createReceiver: ({ syncBatchFn }) => {
5708
+ receiverSync = syncBatchFn;
5709
+ return { connected: true, start: async () => { }, dispose: async () => { } };
5710
+ },
5711
+ sleep: () => new Promise(() => { }),
5712
+ onShutdownSignal: (handler) => {
5713
+ triggerShutdown = handler;
5714
+ return () => { };
5715
+ },
5716
+ });
5717
+ try {
5718
+ await flushLoopMicrotasks(30);
5719
+ runPass.mockClear();
5720
+ const delivery = receiverSync({
5721
+ events: [
5722
+ event("companies/acme/slow.md"),
5723
+ event("companies/indigo/fast.md"),
5724
+ ],
5725
+ signal: new AbortController().signal,
5726
+ });
5727
+ await flushLoopMicrotasks(20);
5728
+ // Regression: the old per-route loop started slow-acme and awaited it
5729
+ // before it even submitted fast-indigo.
5730
+ expect(order).toEqual(["fast-indigo", "slow-acme"]);
5731
+ releaseSlow();
5732
+ await delivery;
5733
+ }
5734
+ finally {
5735
+ releaseSlow();
5736
+ triggerShutdown();
5737
+ await loop;
5738
+ if (previous === undefined)
5739
+ delete process.env.HQ_SYNC_PARALLEL_COORDINATOR;
5740
+ else
5741
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = previous;
5742
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5743
+ }
5744
+ });
5745
+ it("parallel coordinator exposes delivery-wide fast and slow receiver batches", async () => {
5746
+ const previousCoordinator = process.env.HQ_SYNC_PARALLEL_COORDINATOR;
5747
+ const previousFastFiles = process.env[FAST_LANE_MAX_FILES_ENV];
5748
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = "1";
5749
+ process.env[FAST_LANE_MAX_FILES_ENV] = "1";
5750
+ const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-parallel-receiver-delivery-cap-"));
5751
+ const watcher = makeBatchWatcherStub();
5752
+ let receiverSync;
5753
+ let triggerShutdown = () => { };
5754
+ const event = (relativePath) => ({
5755
+ kind: "upsert",
5756
+ relativePath,
5757
+ contentHash: "sha256:remote",
5758
+ mtime: "2026-08-28T00:00:00.000Z",
5759
+ originDeviceId: "peer-device",
5760
+ originTenantId: "tenant-indigo",
5761
+ sequenceNumber: 1,
5762
+ eventTimestamp: "2026-08-28T00:00:00.000Z",
5763
+ });
5764
+ for (const [slug, key] of [["acme", "small.md"], ["indigo", "small.md"]]) {
5765
+ const journal = readJournal(slug);
5766
+ journal.files[key] = {
5767
+ hash: `sha256:${slug}`,
5768
+ size: 16,
5769
+ syncedAt: "2026-08-28T00:00:00.000Z",
5770
+ direction: "down",
5771
+ };
5772
+ writeJournal(slug, journal);
5773
+ }
5774
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--direction", "pull", "--hq-root", hqRoot], {
5775
+ runPass: vi.fn(async () => completedPassOutcome()),
5776
+ createWatcher: () => watcher,
5777
+ createReceiver: ({ syncBatchFn }) => {
5778
+ receiverSync = syncBatchFn;
5779
+ return { connected: true, start: async () => { }, dispose: async () => { } };
5780
+ },
5781
+ sleep: () => new Promise(() => { }),
5782
+ onShutdownSignal: (handler) => {
5783
+ triggerShutdown = handler;
5784
+ return () => { };
5785
+ },
5786
+ });
5787
+ try {
5788
+ await flushLoopMicrotasks(30);
5789
+ const batches = receiverSync.partition([
5790
+ event("companies/acme/small.md"),
5791
+ event("companies/indigo/small.md"),
5792
+ ]);
5793
+ // The cap applies once to the whole delivery, not once per route. The
5794
+ // returned batches are receiver-visible, so its existing per-batch
5795
+ // acknowledgement contract retains only a failed slow receipt.
5796
+ expect(batches.map((batch) => batch.map((event) => event.relativePath))).toEqual([
5797
+ ["companies/acme/small.md"],
5798
+ ["companies/indigo/small.md"],
5799
+ ]);
5800
+ }
5801
+ finally {
5802
+ triggerShutdown();
5803
+ await loop;
5804
+ if (previousCoordinator === undefined)
5805
+ delete process.env.HQ_SYNC_PARALLEL_COORDINATOR;
5806
+ else
5807
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = previousCoordinator;
5808
+ if (previousFastFiles === undefined)
5809
+ delete process.env[FAST_LANE_MAX_FILES_ENV];
5810
+ else
5811
+ process.env[FAST_LANE_MAX_FILES_ENV] = previousFastFiles;
5812
+ fs.rmSync(hqRoot, { recursive: true, force: true });
5813
+ }
5814
+ });
5506
5815
  it("fast lane: peels a tiny watcher path from mixed multi-megabyte residue", async () => {
5507
5816
  const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-fast-lane-mixed-watch-"));
5508
5817
  const tinyRel = "companies/indigo/realtime.md";