@ricsam/r5d-worker 0.0.136 → 0.0.137

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.
@@ -1,33 +1,64 @@
1
+ import type { ProjectedWorkingTreeEntry } from "./working-tree-mirror";
1
2
  /**
2
- * Blob ids of the bytes merge hydration replaced in a checkout, kept in
3
- * memory per mount incarnation until a later hydration of the same path
4
- * replaces them or the mount is hydrated outside a cycle (recovery, reset,
5
- * configuration), which rewrites the checkout without recording anything.
3
+ * What a merge hydration replaced at one checkout path
4
+ * (docs/merge-hydration-design.md §3.1): the blob that was there before
5
+ * (`preBlob`), the blob hydration wrote (`postBlob`, null when it removed the
6
+ * path), the `lstat` it left behind (`stat`, null when removed), and whether
7
+ * a worker-tracked process or PTY was alive across that hydration.
6
8
  *
7
- * The projection reads it as the stale-rewrite detector
8
- * (docs/merge-hydration-design.md §3.3): a process that read a file before a
9
- * hydration and re-emits the same bytes afterwards would otherwise publish a
10
- * revert of the inbound change as an ordinary local edit. A changed file whose
11
- * content hashes to the blob hydration replaced is exactly that, so the mount
12
- * is pinned instead of published, loudly.
13
- *
14
- * Deliberately not persisted: a restart loses the entries and the detector is
15
- * best effort. Phase 2 of the design turns this into a durable ledger if
16
- * telemetry warrants it.
9
+ * At the next projection a path whose stat moved is treated by that flag: a
10
+ * process alive across the hydration may have read the file before it and
11
+ * written it afterwards, so its bytes are merged against `preBlob` (what it
12
+ * read) with `postBlob` as the other side, which turns a stale-read revert
13
+ * into the inbound change plus the process's own delta, or a visible
14
+ * conflict. Without a live process the change is a plain edit on top of
15
+ * `postBlob`; the exact re-emission of `preBlob` is still refused as a stale
16
+ * rewrite (§3.3).
17
+ */
18
+ export type WorkspaceHydrationLedgerEntry = {
19
+ preBlob: string;
20
+ postBlob: string | null;
21
+ stat: Extract<ProjectedWorkingTreeEntry, {
22
+ kind: "file";
23
+ }> | null;
24
+ processLiveAcrossHydration: boolean;
25
+ };
26
+ /**
27
+ * In memory, per mount incarnation and clone. Not persisted: every process
28
+ * and PTY the flag refers to is a child of the worker, so a restart ends
29
+ * them all and no entry could still merge; the detector half is best effort.
17
30
  */
18
- export declare class WorkspaceHydrationPreBlobLedger {
31
+ export declare class WorkspaceHydrationLedger {
19
32
  private readonly mounts;
20
33
  private static key;
21
- /** Blob ids by mount-relative path for the mount, or an empty map. */
34
+ /** Entries by mount-relative path for the mount, or an empty map. */
35
+ entries(mount: {
36
+ id: string;
37
+ hydrationIncarnationKey: string;
38
+ }): ReadonlyMap<string, WorkspaceHydrationLedgerEntry>;
39
+ /** Blob ids by mount-relative path for the mount (the §3.3 detector's input), or an empty map. */
22
40
  preBlobs(mount: {
23
41
  id: string;
24
42
  hydrationIncarnationKey: string;
25
43
  }): ReadonlyMap<string, string>;
26
- /** Record the pre-hydration blob of every path a merge hydration replaced; earlier entries for other paths are kept. */
44
+ /**
45
+ * Record what a merge hydration replaced; earlier entries for other paths
46
+ * are kept. A path that already carries a live entry keeps its `preBlob`
47
+ * while the new hydration also ran across a live process: the process's
48
+ * read predates both hydrations, so what it read is still the first blob.
49
+ */
27
50
  record(mount: {
28
51
  id: string;
29
52
  hydrationIncarnationKey: string;
30
- }, preBlobs: ReadonlyMap<string, string> | Readonly<Record<string, string>>): void;
53
+ }, entries: ReadonlyMap<string, WorkspaceHydrationLedgerEntry> | Readonly<Record<string, WorkspaceHydrationLedgerEntry>>, options?: {
54
+ /**
55
+ * Paths whose new `preBlob` is taken even over a live entry: the
56
+ * hydration followed a projection that merged the process's own write
57
+ * at that path, so the bytes it wrote (not what it originally read)
58
+ * are the base its next write derives from.
59
+ */
60
+ replacePreBlobFor?: readonly string[];
61
+ }): void;
31
62
  /** Forget the mount: its checkout was rewritten by something this ledger did not observe. */
32
63
  clearMount(mount: {
33
64
  id: string;
@@ -41,3 +72,5 @@ export declare class WorkspaceHydrationPreBlobLedger {
41
72
  clear(): void;
42
73
  get size(): number;
43
74
  }
75
+ /** The name the first version of this module exported; kept for callers that still use it. */
76
+ export declare const WorkspaceHydrationPreBlobLedger: typeof WorkspaceHydrationLedger;
@@ -54,6 +54,14 @@ export type WorkspaceHydrationMergeDecision = {
54
54
  expectations: Map<string, fs.Stats | null>;
55
55
  /** Blob of the bytes each written or removed path held before hydration; the stale-rewrite detector's input. */
56
56
  preBlobs: Map<string, string>;
57
+ /** Blob each path in `preBlobs` holds after hydration (null: removed); with `preBlobs`, the hydration ledger's record. */
58
+ postBlobs: Map<string, string | null>;
59
+ /**
60
+ * Bytes the ledger names that no commit holds (a merged file's previous
61
+ * and merged content), keyed by blob id, for the job to write into the
62
+ * clone's object store so a later projection can read them back.
63
+ */
64
+ blobsToStore: Map<string, Buffer>;
57
65
  /** Paths whose content was three-way merged. */
58
66
  mergedPaths: string[];
59
67
  /** Paths the checkout changed since projection that hydration leaves as they are. */
@@ -1,4 +1,5 @@
1
1
  import { type ProjectedWorkingTreeEntry, type WorkingTreeSourceMode } from "./working-tree-mirror";
2
+ import type { WorkspaceHydrationLedgerEntry } from "./workspace-hydration-ledger";
2
3
  export type WorkspaceMergeProjectionSupport = {
3
4
  supported: true;
4
5
  } | {
@@ -25,6 +26,13 @@ export type WorkspaceMergeProjectionResult = {
25
26
  readAtMs: number;
26
27
  /** Ledger paths whose checkout content moved on from both the replaced and the basis bytes (or that are gone). */
27
28
  staleRewriteCleared: string[];
29
+ /**
30
+ * Ledger paths a process alive across their hydration rewrote, merged
31
+ * here against what that process read (docs/merge-hydration-design.md
32
+ * §3.1): the checkout still holds the process's bytes, so the mount must
33
+ * be hydrated from the merged result even where its receipt is current.
34
+ */
35
+ ledgerMergedPaths: string[];
28
36
  } | {
29
37
  kind: "conflict";
30
38
  oursCommit: string;
@@ -33,6 +41,7 @@ export type WorkspaceMergeProjectionResult = {
33
41
  projectedFiles: Record<string, ProjectedWorkingTreeEntry>;
34
42
  readAtMs: number;
35
43
  staleRewriteCleared: string[];
44
+ ledgerMergedPaths: string[];
36
45
  } | {
37
46
  kind: "stale_rewrite";
38
47
  paths: string[];
@@ -46,7 +55,7 @@ export declare function mergeWorkspaceProjectionMount(input: {
46
55
  basisHead: string;
47
56
  currentHead: string;
48
57
  attemptId: string;
49
- staleRewriteBlobs?: Readonly<Record<string, string>>;
58
+ hydrationLedger?: Readonly<Record<string, WorkspaceHydrationLedgerEntry>>;
50
59
  }): WorkspaceMergeProjectionResult;
51
60
  export declare function materializeWorkspaceProjectionTree(input: {
52
61
  workspacePath: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.136",
3
+ "version": "0.0.137",
4
4
  "type": "module",
5
5
  "main": "./dist/cjs/main.cjs",
6
6
  "module": "./dist/mjs/main.mjs",
@@ -21,7 +21,7 @@
21
21
  "r5d-worker": "dist/cjs/main.cjs"
22
22
  },
23
23
  "dependencies": {
24
- "@ricsam/r5d-api": "^0.0.136",
24
+ "@ricsam/r5d-api": "^0.0.137",
25
25
  "node-pty": "^1.1.0",
26
26
  "picomatch": "^4.0.3"
27
27
  },