@indigoai-us/hq-cloud 6.2.2 → 6.2.3

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 (44) hide show
  1. package/dist/bin/sync-runner.d.ts.map +1 -1
  2. package/dist/bin/sync-runner.js +8 -0
  3. package/dist/bin/sync-runner.js.map +1 -1
  4. package/dist/cli/rescue-core.d.ts.map +1 -1
  5. package/dist/cli/rescue-core.js +70 -54
  6. package/dist/cli/rescue-core.js.map +1 -1
  7. package/dist/cli/rescue-journal-reconcile.test.js +70 -48
  8. package/dist/cli/rescue-journal-reconcile.test.js.map +1 -1
  9. package/dist/cli/sync-scope.test.js +33 -1
  10. package/dist/cli/sync-scope.test.js.map +1 -1
  11. package/dist/cli/sync.d.ts +8 -0
  12. package/dist/cli/sync.d.ts.map +1 -1
  13. package/dist/cli/sync.js +16 -1
  14. package/dist/cli/sync.js.map +1 -1
  15. package/dist/journal.d.ts +1 -1
  16. package/dist/journal.d.ts.map +1 -1
  17. package/dist/journal.js +7 -1
  18. package/dist/journal.js.map +1 -1
  19. package/dist/remote-pull.d.ts +7 -0
  20. package/dist/remote-pull.d.ts.map +1 -1
  21. package/dist/remote-pull.js +5 -0
  22. package/dist/remote-pull.js.map +1 -1
  23. package/dist/remote-pull.test.js +110 -0
  24. package/dist/remote-pull.test.js.map +1 -1
  25. package/dist/scope-shrink.d.ts +20 -0
  26. package/dist/scope-shrink.d.ts.map +1 -1
  27. package/dist/scope-shrink.js +11 -0
  28. package/dist/scope-shrink.js.map +1 -1
  29. package/dist/scope-shrink.test.js +122 -0
  30. package/dist/scope-shrink.test.js.map +1 -1
  31. package/dist/types.d.ts +12 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/bin/sync-runner.ts +8 -0
  35. package/src/cli/rescue-core.ts +72 -63
  36. package/src/cli/rescue-journal-reconcile.test.ts +76 -53
  37. package/src/cli/sync-scope.test.ts +35 -1
  38. package/src/cli/sync.ts +24 -0
  39. package/src/journal.ts +7 -0
  40. package/src/remote-pull.test.ts +118 -0
  41. package/src/remote-pull.ts +12 -0
  42. package/src/scope-shrink.test.ts +128 -0
  43. package/src/scope-shrink.ts +29 -0
  44. package/src/types.ts +12 -0
@@ -62,6 +62,26 @@ export interface BuildScopeShrinkPlanInput {
62
62
  lastPrefixSet: string[];
63
63
  /** Coalesced prefixes the CURRENT pull will use. */
64
64
  currentPrefixSet: string[];
65
+ /**
66
+ * The caller's own Cognito `sub`. When set, a file the caller authored
67
+ * (`entry.createdBySub === callerSub`) is NEVER orphaned by a scope shrink —
68
+ * regardless of mode. This is the core of the authorship contract: sync mode
69
+ * governs whether you mirror *other people's* files; it must never disown
70
+ * your own work. Owners hold their whole vault by role-bypass, so without
71
+ * this guard a `shared`/`custom` scope would treat their own un-granted
72
+ * content as "someone else's file I happen to see" and prune it.
73
+ */
74
+ callerSub?: string;
75
+ /**
76
+ * When `true`, an orphan whose authorship is unknown (`createdBySub`
77
+ * undefined — a legacy entry predating author stamping, or an object
78
+ * uploaded without author metadata) is also retained rather than pruned.
79
+ * The automatic background pull sets this so a routine sync never makes a
80
+ * destructive guess about pre-stamp content; the explicit `hq sync narrow`
81
+ * ritual (which carries its own confirmation + dirty gate) leaves it off so
82
+ * a deliberately-confirmed narrow can still reclaim legacy files.
83
+ */
84
+ protectUnknownAuthors?: boolean;
65
85
  }
66
86
 
67
87
  /**
@@ -84,6 +104,7 @@ export function buildScopeShrinkPlan(
84
104
  input: BuildScopeShrinkPlanInput,
85
105
  ): ScopeShrinkPlan {
86
106
  const { journal, hqRoot, lastPrefixSet, currentPrefixSet } = input;
107
+ const { callerSub, protectUnknownAuthors } = input;
87
108
  const orphans: OrphanClassification[] = [];
88
109
 
89
110
  for (const [relPath, entry] of Object.entries(journal.files)) {
@@ -91,6 +112,14 @@ export function buildScopeShrinkPlan(
91
112
  if (entry.direction !== "down") continue;
92
113
  if (!isCoveredByAny(relPath, lastPrefixSet)) continue;
93
114
  if (isCoveredByAny(relPath, currentPrefixSet)) continue;
115
+ // Authorship guard: sync mode decides whether you mirror OTHER people's
116
+ // files — it must never disown your own. A file the caller authored is
117
+ // sacred and never orphaned, even out of the current prefix scope. When
118
+ // `protectUnknownAuthors` is set (the automatic pull path), a legacy
119
+ // entry with no recorded author is also retained — a routine background
120
+ // sync should never make a destructive guess about pre-stamp content.
121
+ if (callerSub && entry.createdBySub === callerSub) continue;
122
+ if (protectUnknownAuthors && entry.createdBySub === undefined) continue;
94
123
  orphans.push(classifyOrphan(relPath, entry, hqRoot));
95
124
  }
96
125
 
package/src/types.ts CHANGED
@@ -26,6 +26,18 @@ export interface JournalEntry {
26
26
  size: number;
27
27
  syncedAt: string;
28
28
  direction: "up" | "down";
29
+ /**
30
+ * Cognito `sub` of the file's author, captured from the object's
31
+ * `created-by-sub` S3 user-metadata at download time (zero extra network —
32
+ * the GET response already carries it). Powers the scope-shrink authorship
33
+ * guard: a scope shrink must never orphan content the caller authored, so
34
+ * sync mode only ever governs whether you ALSO mirror *other people's*
35
+ * files. Optional for backwards compatibility — entries written before this
36
+ * field existed (or uploaded without author metadata) leave it `undefined`,
37
+ * which the automatic prune path treats conservatively (never auto-delete an
38
+ * unknown-author orphan).
39
+ */
40
+ createdBySub?: string;
29
41
  /**
30
42
  * S3 ETag of the remote object as of last successful sync, normalized (no
31
43
  * surrounding quotes). Optional for backwards compatibility: entries