@indigoai-us/hq-cloud 6.18.18 → 6.18.19

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.
@@ -174,7 +174,7 @@ vi.mock("../sync/mass-delete-guards.js", async (importOriginal) => {
174
174
  return { ...actual, resolveMassDeleteGuards: vi.fn().mockResolvedValue(false) };
175
175
  });
176
176
  import { resolveMassDeleteGuards } from "../sync/mass-delete-guards.js";
177
- import { sync, reportNewFilesToNotify, applyRealtimeDeltaPage, isSyncMutationStdinCommand, runSyncMutationStdinJson, SYNC_MUTATION_STDIN_COMMAND, FULL_PULL_COOPERATIVE_CHECKPOINT_BATCH_SIZE, FULL_PULL_LIST_PAGE_CHECKPOINT_SIZE, setListCooperativeYieldMsForTesting, targetedJournalSessionCensusSizes, win32SymlinkFlavorBroken, _testing as syncTesting, } from "./sync.js";
177
+ import { sync, reportNewFilesToNotify, applyRealtimeDeltaPage, isSyncMutationStdinCommand, runSyncMutationStdinJson, SYNC_MUTATION_STDIN_COMMAND, FULL_PULL_COOPERATIVE_CHECKPOINT_BATCH_SIZE, FULL_PULL_LIST_PAGE_CHECKPOINT_SIZE, setListCooperativeYieldMsForTesting, setNewFilesEnrichmentBulkCapForTesting, targetedJournalSessionCensusSizes, win32SymlinkFlavorBroken, _testing as syncTesting, } from "./sync.js";
178
178
  import { share } from "./share.js";
179
179
  import * as s3Module from "../s3.js";
180
180
  import { resolvePersonalConnectorSettingsSync } from "../lib/personal-connector-settings-sync.js";
@@ -7145,6 +7145,94 @@ describe("sync", () => {
7145
7145
  const newFilesIdx = eventTypes.indexOf("new-files");
7146
7146
  expect(newFilesIdx).toBeGreaterThan(lastProgressIdx);
7147
7147
  });
7148
+ // ── Bulk-sync post-pull tail bypass ─────────────────────────────────
7149
+ // Regression for the 2026-09-30 first-sync case
7150
+ // (i-0b8c4677512e81136 · agt_3FZG3TC9GEEMRVWSRF9NJ7Q98C, hq-cloud
7151
+ // 6.18.18): 63,836 new files kept the runner ~20 minutes past
7152
+ // filesDone == filesTotal doing per-file HEAD enrichment
7153
+ // + /v1/notify/file-added POST, while the wizard already showed
7154
+ // "Sync did not finish". Above the bulk cap, the enrichment and the
7155
+ // notify POST are skipped so the pull tail after the last download is
7156
+ // O(1); new-files still emits (with addedBy: null) so downstream
7157
+ // consumers see the full list.
7158
+ describe("bulk-sync post-pull tail bypass (new-files > cap)", () => {
7159
+ const bulkFiles = Array.from({ length: 3 }, (_, i) => ({
7160
+ key: `bulk/file-${i}.md`,
7161
+ size: 10,
7162
+ lastModified: new Date(),
7163
+ etag: `"bulk-${i}"`,
7164
+ }));
7165
+ beforeEach(() => {
7166
+ // Cap at 2 so a 3-file remote trips the bypass in this test suite.
7167
+ setNewFilesEnrichmentBulkCapForTesting(2);
7168
+ });
7169
+ afterEach(() => {
7170
+ setNewFilesEnrichmentBulkCapForTesting(undefined);
7171
+ });
7172
+ it("skips per-file HeadObject enrichment when new files exceed the cap", async () => {
7173
+ vi.mocked(s3Module.listRemoteFiles).mockResolvedValueOnce(bulkFiles);
7174
+ vi.mocked(s3Module.headRemoteFile).mockResolvedValue({
7175
+ lastModified: new Date(),
7176
+ etag: '"any"',
7177
+ size: 10,
7178
+ metadata: { "created-by": "should-not-be-read@example.com" },
7179
+ });
7180
+ const newFilesEvents = [];
7181
+ await sync({
7182
+ company: "acme",
7183
+ vaultConfig: mockConfig,
7184
+ hqRoot: tmpDir,
7185
+ onEvent: (e) => {
7186
+ if (e.type === "new-files")
7187
+ newFilesEvents.push(e);
7188
+ },
7189
+ });
7190
+ // Bypass path: enrichment loop does not run for any of the 3 new
7191
+ // files, and the entire pull tail (HEAD + notify POST) is O(1).
7192
+ expect(vi.mocked(s3Module.headRemoteFile)).not.toHaveBeenCalled();
7193
+ expect(newFilesEvents).toHaveLength(1);
7194
+ expect(newFilesEvents[0].files).toHaveLength(3);
7195
+ for (const f of newFilesEvents[0].files) {
7196
+ expect(f.addedBy).toBeNull();
7197
+ }
7198
+ });
7199
+ it("skips the /v1/notify/file-added POST when new files exceed the cap", async () => {
7200
+ vi.mocked(s3Module.listRemoteFiles).mockResolvedValueOnce(bulkFiles);
7201
+ await sync({
7202
+ company: "acme",
7203
+ vaultConfig: mockConfig,
7204
+ hqRoot: tmpDir,
7205
+ onEvent: () => { },
7206
+ });
7207
+ const calls = vi.mocked(globalThis.fetch).mock.calls;
7208
+ const notifyCalls = calls.filter(([u]) => String(u).includes("/v1/notify/file-added"));
7209
+ expect(notifyCalls).toHaveLength(0);
7210
+ });
7211
+ it("still enriches when new files fit under the cap", async () => {
7212
+ // Two default remote files, cap 2 → NOT over cap → enrichment runs.
7213
+ vi.mocked(s3Module.headRemoteFile).mockResolvedValue({
7214
+ lastModified: new Date(),
7215
+ etag: '"any"',
7216
+ size: 10,
7217
+ metadata: { "created-by": "author@example.com" },
7218
+ });
7219
+ const newFilesEvents = [];
7220
+ await sync({
7221
+ company: "acme",
7222
+ vaultConfig: mockConfig,
7223
+ hqRoot: tmpDir,
7224
+ onEvent: (e) => {
7225
+ if (e.type === "new-files")
7226
+ newFilesEvents.push(e);
7227
+ },
7228
+ });
7229
+ expect(vi.mocked(s3Module.headRemoteFile)).toHaveBeenCalled();
7230
+ expect(newFilesEvents).toHaveLength(1);
7231
+ for (const f of newFilesEvents[0].files) {
7232
+ expect(f.addedBy).toBe("author@example.com");
7233
+ }
7234
+ });
7235
+ });
7148
7236
  it("stamps progress.author from the downloaded object's created-by metadata", async () => {
7149
7237
  vi.mocked(s3Module.listRemoteFiles).mockResolvedValueOnce([
7150
7238
  { key: "docs/authored.md", size: 10, lastModified: new Date(), etag: '"e1"' },