@amalgm/shell 0.1.86 → 0.1.88

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.
package/PURPOSE.md CHANGED
@@ -318,8 +318,17 @@ shell only assembles.
318
318
  directories need no reclassification. New or changed entries enter the
319
319
  ordinary Detect and Record path. Directory membership is reused, while
320
320
  the cheap `.git` marker classification is always observed from current
321
- ground. Repository roots still ask Git for Card + Checkpoint state because
322
- `.git` is deliberately outside the entity graph.
321
+ ground. Repository roots re-prove Card + Checkpoint state through Git,
322
+ because `.git` is deliberately outside the entity graph — but on a complete
323
+ pass Git's own records may stand in for the conversation: each accepted
324
+ capture seals a spawn-free fingerprint of HEAD, every loose ref,
325
+ packed-refs, config, the shallow boundary, and the index file's bytes and
326
+ physical identity, bound to the exact heads and identity map it certified.
327
+ Only when the current fingerprint, the stored heads, the derived identity, and every
328
+ owned entry's stat fingerprint all still match that seal is the Git
329
+ conversation skipped. Any single doubt — including a gitfile boundary or a
330
+ Git storage layout those state files do not fully describe — asks Git in
331
+ full.
323
332
 
324
333
  34. **Recovery work and evidence are root-scoped.** Each logical root reports
325
334
  its own `catching-up` or `current` state, records its own scan evidence, and
@@ -1,4 +1,16 @@
1
1
  import { type EntityType, type RepoIdentityEntry } from "@amalgm/live";
2
+ /**
3
+ * A spawn-free digest of the Git state files a capture proves: HEAD, every
4
+ * loose ref, packed-refs content, config, the shallow boundary, and both the
5
+ * index file's bytes and physical identity. Config and shallow matter because
6
+ * the Card carries remotes and the shallow boundary. Equal digests mean Git's
7
+ * own records are
8
+ * unchanged since the digest was taken, so a sealed capture bound to it still
9
+ * holds. Any doubt — a gitfile boundary, a storage layout these files do not
10
+ * fully describe (reftable, config includes), unreadable metadata — yields
11
+ * null and the caller must ask Git.
12
+ */
13
+ export declare function gitEvidenceFingerprint(repository: string): string | null;
2
14
  export interface GitRegisteredLeaf {
3
15
  readonly type: Extract<EntityType, "file.text" | "file.binary" | "link">;
4
16
  /** Git's indexed blob is the content witness; Shell does not hash it again. */
@@ -1,5 +1,111 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstatSync, readFileSync, readdirSync } from "node:fs";
3
+ import { join } from "node:path";
1
4
  import { classifyFile } from "@amalgm/live";
2
5
  import { gitText, runGit, runGitSearch, tryGitText } from "./git-command.js";
6
+ /**
7
+ * A spawn-free digest of the Git state files a capture proves: HEAD, every
8
+ * loose ref, packed-refs content, config, the shallow boundary, and both the
9
+ * index file's bytes and physical identity. Config and shallow matter because
10
+ * the Card carries remotes and the shallow boundary. Equal digests mean Git's
11
+ * own records are
12
+ * unchanged since the digest was taken, so a sealed capture bound to it still
13
+ * holds. Any doubt — a gitfile boundary, a storage layout these files do not
14
+ * fully describe (reftable, config includes), unreadable metadata — yields
15
+ * null and the caller must ask Git.
16
+ */
17
+ export function gitEvidenceFingerprint(repository) {
18
+ const gitDir = join(repository, ".git");
19
+ try {
20
+ if (!lstatSync(gitDir).isDirectory())
21
+ return null;
22
+ try {
23
+ if (lstatSync(join(gitDir, "reftable")).isDirectory())
24
+ return null;
25
+ }
26
+ catch (error) {
27
+ if (error.code !== "ENOENT")
28
+ throw error;
29
+ // No reftable directory: refs live in the files this digest reads.
30
+ }
31
+ for (const marker of [
32
+ "MERGE_HEAD",
33
+ "rebase-merge",
34
+ "rebase-apply",
35
+ "CHERRY_PICK_HEAD",
36
+ "REVERT_HEAD",
37
+ "amalgm-reveal",
38
+ ]) {
39
+ try {
40
+ lstatSync(join(gitDir, marker));
41
+ return null;
42
+ }
43
+ catch (error) {
44
+ if (error.code !== "ENOENT")
45
+ throw error;
46
+ // An absent busy marker leaves the repository eligible for a seal.
47
+ }
48
+ }
49
+ const digest = createHash("sha256");
50
+ const file = (name) => {
51
+ digest.update(name);
52
+ digest.update("\0");
53
+ try {
54
+ const bytes = readFileSync(join(gitDir, name));
55
+ digest.update(bytes);
56
+ digest.update("\0");
57
+ return bytes;
58
+ }
59
+ catch (error) {
60
+ if (error.code !== "ENOENT")
61
+ throw error;
62
+ digest.update("absent");
63
+ digest.update("\0");
64
+ return null;
65
+ }
66
+ };
67
+ file("HEAD");
68
+ file("packed-refs");
69
+ const config = file("config");
70
+ if (config !== null && /^\s*\[include/im.test(config.toString("utf8")))
71
+ return null;
72
+ file("shallow");
73
+ const walkRefs = (relativeDir) => {
74
+ let children;
75
+ try {
76
+ children = readdirSync(join(gitDir, relativeDir), { withFileTypes: true });
77
+ }
78
+ catch (error) {
79
+ if (error.code !== "ENOENT")
80
+ throw error;
81
+ return;
82
+ }
83
+ for (const child of children
84
+ .sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)) {
85
+ const relativePath = `${relativeDir}/${child.name}`;
86
+ if (child.isDirectory())
87
+ walkRefs(relativePath);
88
+ else
89
+ file(relativePath);
90
+ }
91
+ };
92
+ walkRefs("refs");
93
+ file("index");
94
+ try {
95
+ const index = lstatSync(join(gitDir, "index"));
96
+ digest.update(`index-stat:${index.mtimeMs}:${index.ctimeMs}:${index.size}:${index.ino}`);
97
+ }
98
+ catch (error) {
99
+ if (error.code !== "ENOENT")
100
+ throw error;
101
+ digest.update("index-stat:absent");
102
+ }
103
+ return digest.digest("hex");
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ }
3
109
  /**
4
110
  * Replace worktree hashes with Git object identities only where Git proves
5
111
  * the indexed leaf is clean. Dirty and untracked entries remain unchanged so
@@ -1 +1 @@
1
- {"version":3,"file":"git-registration-host.js","sourceRoot":"","sources":["../src/git-registration-host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-registration-host.js","sourceRoot":"","sources":["../src/git-registration-host.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import { existsSync, lstatSync, realpathSync, readFileSync, readdirSync, readlin
3
3
  import { open } from "node:fs/promises";
4
4
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { buildUserHomeManifest, buildUserManifest, liveMachineStateDir, scopedAmalgmDir, shippedUserHomeDeclaration, } from "@amalgm/core/identity";
6
- import { CHUNK_BYTES, CONTENT_CONTRACT, INLINE_CARGO_MAX_BYTES, ENTITY_CLOUD_CONTRACT, ENTITY_CLOUD_SCHEMA_VERSION, artifactForRecord, canonicalVersion, checkContentManifest, classifyDirectory, classifyFile, classifyRegisteredRoot, createLocalEntityRecord, createEntityRecordAuthorityPort, convergeUserGround, createUserGroundEnrollmentPolicy, isRepositoryMetadataEntry, indexRepositoryTerritory, download as downloadArtifact, encodeEntityRecord, EntityApplyRail, EntityRecordRail, membershipHash, parseSnapshot, pathIsSuspect, privateEntityResourceId, rootReplacementFromRecords, sameRecords, snapshotFromRecords, stableJson, travelingRecords, upload as uploadArtifact, userGroundRecords, } from "@amalgm/live";
6
+ import { CHUNK_BYTES, CONTENT_CONTRACT, INLINE_CARGO_MAX_BYTES, ENTITY_CLOUD_CONTRACT, ENTITY_CLOUD_SCHEMA_VERSION, artifactForRecord, canonicalVersion, checkContentManifest, classifyDirectory, classifyFile, classifyRegisteredRoot, createLocalEntityRecord, createEntityRecordAuthorityPort, convergeUserGround, createUserGroundEnrollmentPolicy, isRepositoryMetadataEntry, indexRepositoryTerritory, download as downloadArtifact, encodeEntityRecord, EntityApplyRail, EntityRecordRail, membershipHash, parseSnapshot, pathIsSuspect, privateEntityResourceId, repositoryIdentityHash, rootReplacementFromRecords, sameRecords, snapshotFromRecords, stableJson, travelingRecords, upload as uploadArtifact, userGroundRecords, } from "@amalgm/live";
7
7
  import Database from "better-sqlite3";
8
8
  import { atomicCopy, atomicWrite, ensurePrivateDir, ensureUserDir } from "./filesystem.js";
9
9
  import { emitFilesStage, } from "./files-observability.js";
@@ -18,7 +18,7 @@ import { AcceptedInboxResultIndex } from "./detection/accepted-result.js";
18
18
  import { NamedDetectRuntime } from "./detection/runtime.js";
19
19
  import { WORKSPACE_UUID as UUID, createFilesRegisterPorts, ensureWorkspaceBinding, ensureWorkspaceReference, pathExists, pathWithin, referenceWorkspaceId, selectKnownRegistrationId, workspaceBindingDir, } from "./files-register-host.js";
20
20
  import { applyRepositoryFiles, captureRepository, inspectRepositoryTransportFile, hasGitMarker, readCachedRepositoryIdentity, } from "./git-repository-host.js";
21
- import { inspectGitRegistration, sameGitIdentity, } from "./git-registration-host.js";
21
+ import { gitEvidenceFingerprint, inspectGitRegistration, sameGitIdentity, } from "./git-registration-host.js";
22
22
  import { projectMaterializedGraph } from "./materialized-graph.js";
23
23
  import { NodeWatchHost, } from "./watching/index.js";
24
24
  import { GroundCoordinator } from "./ground-coordination.js";
@@ -648,8 +648,9 @@ export class UserGroundHost {
648
648
  throw new Error("entity Record rail already started");
649
649
  await this.wire.open();
650
650
  // One floor, no per-feature gates: this shell and its gateway release
651
- // together, and the gateway ships first. 6 = whole-artifact content GET.
652
- if (this.wire.protocolVersion < 6) {
651
+ // together, and the gateway ships first. 7 = one content contract and
652
+ // deterministic manifest keys.
653
+ if (this.wire.protocolVersion < 7) {
653
654
  throw new Error("gateway speaks an older wire protocol than this shell");
654
655
  }
655
656
  const store = new EntityRecordSqliteStore(initializeDatabase(this.databasePath(identity)));
@@ -1062,7 +1063,6 @@ export class UserGroundHost {
1062
1063
  type: "private.entity-content.put",
1063
1064
  resource_id: resourceId,
1064
1065
  content_hash: artifact.contentHash,
1065
- content_contract: manifest.contract,
1066
1066
  kind: "chunk",
1067
1067
  part_index: index,
1068
1068
  part_count: manifest.chunks.length,
@@ -1092,7 +1092,6 @@ export class UserGroundHost {
1092
1092
  type: "private.entity-content.inventory",
1093
1093
  resource_id: resourceId,
1094
1094
  content_hash: artifact.contentHash,
1095
- content_contract: manifest.contract,
1096
1095
  chunks: manifest.chunks,
1097
1096
  }, ["private.entity-content.inventory-result"]));
1098
1097
  manifestPresent = frame.complete === true;
@@ -1108,7 +1107,6 @@ export class UserGroundHost {
1108
1107
  type: "private.entity-content.put-batch",
1109
1108
  resource_id: resourceId,
1110
1109
  content_hash: artifact.contentHash,
1111
- content_contract: manifest.contract,
1112
1110
  part_count: manifest.chunks.length,
1113
1111
  chunks: indexes.map((index) => ({
1114
1112
  part_index: index,
@@ -1129,7 +1127,6 @@ export class UserGroundHost {
1129
1127
  type: "private.entity-content.put",
1130
1128
  resource_id: resourceId,
1131
1129
  content_hash: artifact.contentHash,
1132
- content_contract: manifest.contract,
1133
1130
  kind: "manifest",
1134
1131
  part_index: manifest.chunks.length,
1135
1132
  part_count: manifest.chunks.length,
@@ -1231,7 +1228,6 @@ export class UserGroundHost {
1231
1228
  type: "private.entity-content.get",
1232
1229
  resource_id: resourceId,
1233
1230
  content_hash: artifact.contentHash,
1234
- content_contract: manifest.contract,
1235
1231
  kind: "chunk",
1236
1232
  part_index: index,
1237
1233
  sha256: chunk.sha256,
@@ -1287,7 +1283,6 @@ export class UserGroundHost {
1287
1283
  type: "private.entity-content.get-batch",
1288
1284
  resource_id: resourceId,
1289
1285
  content_hash: artifact.contentHash,
1290
- content_contract: manifest.contract,
1291
1286
  chunks: indexes.map((index) => ({
1292
1287
  part_index: index,
1293
1288
  sha256: manifest.chunks[index]?.sha256,
@@ -1909,12 +1904,18 @@ function assertHealthyWatch(evidence, rootId) {
1909
1904
  throw new Error(`Watch coverage is not healthy for workspace ${rootId}: ${evidence.health.reason ?? "incomplete handle evidence"}`);
1910
1905
  }
1911
1906
  }
1907
+ /** Schema migration runs once per file per process. A converge opens this
1908
+ * file over a dozen times; the file itself is never deleted by the host, so
1909
+ * every later open needs only the connection and its pragmas. */
1910
+ const migratedDatabases = new Set();
1912
1911
  function initializeDatabase(file) {
1913
1912
  ensurePrivateDir(dirname(file));
1914
1913
  const database = new Database(file);
1915
1914
  database.pragma("busy_timeout = 5000");
1916
1915
  database.pragma("journal_mode = WAL");
1917
1916
  database.pragma("synchronous = FULL");
1917
+ if (migratedDatabases.has(file))
1918
+ return database;
1918
1919
  database.exec(`
1919
1920
  CREATE TABLE IF NOT EXISTS ground_identity (
1920
1921
  singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
@@ -2012,6 +2013,13 @@ function initializeDatabase(file) {
2012
2013
  destination_path TEXT NOT NULL UNIQUE,
2013
2014
  intent_json TEXT NOT NULL
2014
2015
  );
2016
+ CREATE TABLE IF NOT EXISTS repository_git_evidence (
2017
+ uuid TEXT PRIMARY KEY,
2018
+ payload_version TEXT NOT NULL,
2019
+ transport_version TEXT NOT NULL,
2020
+ identity_hash TEXT NOT NULL,
2021
+ fingerprint TEXT NOT NULL
2022
+ );
2015
2023
  CREATE INDEX IF NOT EXISTS entities_by_absolute_path
2016
2024
  ON entities(absolute_path);
2017
2025
  CREATE INDEX IF NOT EXISTS entities_by_physical_identity
@@ -2035,6 +2043,7 @@ function initializeDatabase(file) {
2035
2043
  }
2036
2044
  database.exec("DROP INDEX IF EXISTS record_inbox_delivery");
2037
2045
  database.exec("DROP TABLE IF EXISTS mutation_journal");
2046
+ migratedDatabases.add(file);
2038
2047
  return database;
2039
2048
  }
2040
2049
  const GROUND_ROW_PROJECTION = `
@@ -2543,17 +2552,29 @@ function portableRecord(row) {
2543
2552
  transportVersion: derived ? null : row.transportVersion,
2544
2553
  };
2545
2554
  }
2546
- function readPortableRecords(file, table) {
2555
+ /** The authenticated user's core ground: the unique active root workspace
2556
+ * named by the canonical email, plus everything reachable from it by
2557
+ * parent_uuid — the exact walk Live's convergence performs. Sibling
2558
+ * workspace trees never leave SQLite; a bound root nested inside the core
2559
+ * tree is still included because the walk follows parents, not root_uuid. */
2560
+ function coreGroundRecords(file, userEmail) {
2547
2561
  if (!existsSync(file))
2548
2562
  return [];
2549
2563
  const database = initializeDatabase(file);
2550
2564
  try {
2551
2565
  return database.prepare(`
2566
+ WITH RECURSIVE core(uuid) AS (
2567
+ SELECT uuid FROM entities
2568
+ WHERE parent_uuid IS NULL AND type = 'workspace' AND status = 'active'
2569
+ AND lower(name) = lower(?)
2570
+ UNION
2571
+ SELECT entities.uuid FROM entities JOIN core ON entities.parent_uuid = core.uuid
2572
+ )
2552
2573
  SELECT uuid, type, parent_uuid AS parentUUID, name, status, version,
2553
2574
  payload_version AS payloadVersion,
2554
2575
  transport_version AS transportVersion
2555
- FROM ${table} ORDER BY uuid
2556
- `).all().map((record) => (record.type === "workspace" || record.type === "folder"
2576
+ FROM entities WHERE uuid IN (SELECT uuid FROM core) ORDER BY uuid
2577
+ `).all(userEmail).map((record) => (record.type === "workspace" || record.type === "folder"
2557
2578
  ? { ...record, payloadVersion: null, transportVersion: null }
2558
2579
  : record));
2559
2580
  }
@@ -2561,9 +2582,6 @@ function readPortableRecords(file, table) {
2561
2582
  database.close();
2562
2583
  }
2563
2584
  }
2564
- function portableRecords(file) {
2565
- return readPortableRecords(file, "entities");
2566
- }
2567
2585
  function capturedGroundRow(resourceId, rootUUID, row) {
2568
2586
  return {
2569
2587
  resourceId,
@@ -2655,6 +2673,45 @@ function runGroundUpsert(database, table, statement, row) {
2655
2673
  + `occupied by ${occupant?.uuid ?? "no retained row"} (${occupant?.absolutePath ?? "unknown"})`, { cause: error });
2656
2674
  }
2657
2675
  }
2676
+ /** The Git-evidence fingerprint proven by the last successful capture, bound
2677
+ * to the exact heads AND the exact identity map it certified. A stored
2678
+ * fingerprint only gates when the stored root row still carries the same
2679
+ * heads and the current rows still derive the same identity map, so neither a
2680
+ * capture whose detection never reached the table nor a raced base rollback
2681
+ * can silence a real change. */
2682
+ function readSealedRepositoryEvidence(file, uuid) {
2683
+ const database = initializeDatabase(file);
2684
+ try {
2685
+ return database.prepare(`
2686
+ SELECT payload_version AS payloadVersion,
2687
+ transport_version AS transportVersion,
2688
+ identity_hash AS identityHash,
2689
+ fingerprint
2690
+ FROM repository_git_evidence WHERE uuid = ?
2691
+ `).get(uuid) ?? null;
2692
+ }
2693
+ finally {
2694
+ database.close();
2695
+ }
2696
+ }
2697
+ function writeSealedRepositoryEvidence(file, uuid, evidence) {
2698
+ const database = initializeDatabase(file);
2699
+ try {
2700
+ database.prepare(`
2701
+ INSERT INTO repository_git_evidence
2702
+ (uuid, payload_version, transport_version, identity_hash, fingerprint)
2703
+ VALUES (?, ?, ?, ?, ?)
2704
+ ON CONFLICT(uuid) DO UPDATE SET
2705
+ payload_version = excluded.payload_version,
2706
+ transport_version = excluded.transport_version,
2707
+ identity_hash = excluded.identity_hash,
2708
+ fingerprint = excluded.fingerprint
2709
+ `).run(uuid, evidence.payloadVersion, evidence.transportVersion, evidence.identityHash, evidence.fingerprint);
2710
+ }
2711
+ finally {
2712
+ database.close();
2713
+ }
2714
+ }
2658
2715
  function persistRows(file, identity, resourceId, rootUUID, rows, previousRows = [], options = {}) {
2659
2716
  const database = initializeDatabase(file);
2660
2717
  try {
@@ -2768,7 +2825,7 @@ function localValue(identity, userRoot, database) {
2768
2825
  ...identity,
2769
2826
  localRoot: userRoot,
2770
2827
  sqlitePath: database,
2771
- records: portableRecords(database),
2828
+ records: coreGroundRecords(database, identity.userEmail),
2772
2829
  };
2773
2830
  }
2774
2831
  function createDeclaredHome(input) {
@@ -3125,16 +3182,25 @@ async function reconcileRoot(input) {
3125
3182
  let rootRepositoryEvidence = null;
3126
3183
  let rootRepositoryInspectionFailed = false;
3127
3184
  if (rootType === "repo.git") {
3128
- evidence && (evidence.gitInspections += 1);
3129
- try {
3130
- // A Git metadata ring can arrive before the corresponding worktree
3131
- // ring. Git already knows every dirty tracked and untracked path, so
3132
- // those paths join this observation and Card + Checkpoint cannot carry
3133
- // stale identity.
3134
- rootRepositoryEvidence = inspectGitRegistration(rootPath);
3135
- }
3136
- catch {
3137
- rootRepositoryInspectionFailed = true;
3185
+ // On a complete pass whose Git state files are unchanged since the last
3186
+ // sealed capture, the up-front dirty-path evidence would only re-prove
3187
+ // what the stored rows already hold. The walk's lazy inspection still
3188
+ // asks Git the moment any entry is actually observed.
3189
+ const sealed = suspects === null
3190
+ ? readSealedRepositoryEvidence(database, rootUUID)
3191
+ : null;
3192
+ if (sealed === null || sealed.fingerprint !== gitEvidenceFingerprint(rootPath)) {
3193
+ evidence && (evidence.gitInspections += 1);
3194
+ try {
3195
+ // A Git metadata ring can arrive before the corresponding worktree
3196
+ // ring. Git already knows every dirty tracked and untracked path, so
3197
+ // those paths join this observation and Card + Checkpoint cannot carry
3198
+ // stale identity.
3199
+ rootRepositoryEvidence = inspectGitRegistration(rootPath);
3200
+ }
3201
+ catch {
3202
+ rootRepositoryInspectionFailed = true;
3203
+ }
3138
3204
  }
3139
3205
  }
3140
3206
  const normalizedSuspects = suspects === null ? null : suspects.map((path) => {
@@ -3390,7 +3456,25 @@ async function reconcileRoot(input) {
3390
3456
  }
3391
3457
  };
3392
3458
  await visit(rootPath, rootUUID, rootType);
3393
- const resolvedIdentity = reconcileGroundUUIDs(existingRows.map((row) => ({
3459
+ // When every entry sits at its stored address with its stored type and
3460
+ // physical fingerprint (honoring any fixed UUID), path-first claiming makes
3461
+ // the multi-pass reconciliation the identity map — resolve directly. Any
3462
+ // single mismatch falls back to the full algorithm.
3463
+ const stableIdentity = () => {
3464
+ const resolved = new Map();
3465
+ for (const entry of entries) {
3466
+ const row = existingByPath.get(entry.relativePath);
3467
+ if (!row
3468
+ || row.type !== entry.type
3469
+ || row.deviceNumber !== entry.deviceNumber
3470
+ || row.inode !== entry.inode
3471
+ || (entry.fixedUUID !== undefined && entry.fixedUUID !== row.uuid))
3472
+ return null;
3473
+ resolved.set(entry.relativePath, row.uuid);
3474
+ }
3475
+ return resolved;
3476
+ };
3477
+ const resolvedIdentity = stableIdentity() ?? reconcileGroundUUIDs(existingRows.map((row) => ({
3394
3478
  uuid: row.uuid,
3395
3479
  type: row.type,
3396
3480
  relativePath: row.relativePath,
@@ -3424,22 +3508,36 @@ async function reconcileRoot(input) {
3424
3508
  group.push({ uuid: entry.uuid, name: entry.name });
3425
3509
  children.set(entry.parentUUID, group);
3426
3510
  }
3511
+ // canonicalVersion is a pure function of these identity inputs, so a stored
3512
+ // leaf row whose inputs are unchanged already holds the exact version —
3513
+ // recomputing 70k hashes on a stable restart pass proved nothing. Container
3514
+ // versions still derive from live membership, which is never persisted.
3515
+ const existingVersionByUuid = new Map(existingRows.map((row) => [row.uuid, row]));
3427
3516
  const rowsFromEntries = () => entries.map((entry) => {
3428
- const versionPayload = entry.type === "workspace" || entry.type === "folder"
3429
- ? membershipHash(children.get(entry.uuid) ?? [], sha256Hex)
3430
- : entry.payloadVersion;
3517
+ const container = entry.type === "workspace" || entry.type === "folder";
3518
+ const stored = container ? undefined : existingVersionByUuid.get(entry.uuid);
3519
+ const storedVersion = stored !== undefined
3520
+ && stored.type === entry.type
3521
+ && stored.parentUUID === entry.parentUUID
3522
+ && stored.name === entry.name
3523
+ && stored.status === "active"
3524
+ && stored.payloadVersion === entry.payloadVersion
3525
+ ? stored.version
3526
+ : null;
3431
3527
  const record = {
3432
3528
  uuid: entry.uuid,
3433
3529
  type: entry.type,
3434
3530
  parentUUID: entry.parentUUID,
3435
3531
  name: entry.name,
3436
3532
  status: "active",
3437
- version: canonicalVersion({
3533
+ version: storedVersion ?? canonicalVersion({
3438
3534
  type: entry.type,
3439
3535
  parentUUID: entry.parentUUID,
3440
3536
  name: entry.name,
3441
3537
  status: "active",
3442
- payloadVersion: versionPayload,
3538
+ payloadVersion: container
3539
+ ? membershipHash(children.get(entry.uuid) ?? [], sha256Hex)
3540
+ : entry.payloadVersion,
3443
3541
  }, sha256Hex),
3444
3542
  payloadVersion: entry.payloadVersion,
3445
3543
  transportVersion: entry.transportVersion,
@@ -3541,15 +3639,51 @@ async function reconcileRoot(input) {
3541
3639
  }))
3542
3640
  .sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
3543
3641
  };
3544
- let repoIdentity = await refreshRepositoryIdentity();
3545
- /* The rows and the transport identity are derived from the same fresh
3546
- * worktree evidence. A later Watch ring for one of these dirty paths is
3547
- * therefore ordinary equality, not a transport-only echo. */
3548
3642
  const priorRow = existingByPath.get(repository.relativePath);
3549
3643
  if (priorRow?.type === "repo.git") {
3550
3644
  repository.payloadVersion = priorRow.payloadVersion;
3551
3645
  repository.transportVersion = priorRow.transportVersion;
3552
3646
  }
3647
+ // A complete pass re-proves a repository through Git unless Git's own
3648
+ // state files still match the fingerprint sealed with the exact heads
3649
+ // the stored row carries AND every owned entry sits unchanged at its
3650
+ // stored physical identity. Both together mean capture would derive the
3651
+ // rows this scan already holds; any single doubt asks Git in full.
3652
+ const unchangedSinceSeal = (entry) => {
3653
+ const row = existingByPath.get(entry.relativePath);
3654
+ return row !== undefined
3655
+ && row.uuid === entry.uuid
3656
+ && row.type === entry.type
3657
+ && row.payloadVersion === entry.payloadVersion
3658
+ && row.deviceNumber === entry.deviceNumber
3659
+ && row.inode === entry.inode
3660
+ && row.byteSize === entry.byteSize
3661
+ && row.modifiedTimeMs === entry.modifiedTimeMs
3662
+ && row.changedTimeMs === entry.changedTimeMs
3663
+ && row.filesystemMode === entry.filesystemMode;
3664
+ };
3665
+ if (scanSuspects === null
3666
+ && priorRow?.type === "repo.git" && priorRow.payloadVersion && priorRow.transportVersion) {
3667
+ const sealed = readSealedRepositoryEvidence(database, repository.uuid);
3668
+ if (sealed !== null
3669
+ && sealed.payloadVersion === priorRow.payloadVersion
3670
+ && sealed.transportVersion === priorRow.transportVersion
3671
+ && sealed.fingerprint === gitEvidenceFingerprint(repository.absolutePath)
3672
+ && ownedEntries.every(unchangedSinceSeal)
3673
+ && sealed.identityHash === repositoryIdentityHash(ownedEntries.map((entry) => ({
3674
+ path: repositoryPath(entry),
3675
+ uuid: entry.uuid,
3676
+ type: entry.type,
3677
+ payloadVersion: entry.type === "repo.git" ? null : entry.payloadVersion,
3678
+ })), sha256Hex)) {
3679
+ continue;
3680
+ }
3681
+ }
3682
+ const fingerprintBefore = gitEvidenceFingerprint(repository.absolutePath);
3683
+ let repoIdentity = await refreshRepositoryIdentity();
3684
+ /* The rows and the transport identity are derived from the same fresh
3685
+ * worktree evidence. A later Watch ring for one of these dirty paths is
3686
+ * therefore ordinary equality, not a transport-only echo. */
3553
3687
  let prior = null;
3554
3688
  let priorLayout = null;
3555
3689
  if (priorRow?.type === "repo.git" && priorRow.payloadVersion && priorRow.transportVersion) {
@@ -3626,6 +3760,18 @@ async function reconcileRoot(input) {
3626
3760
  parentTransportVersion: currentLayout.parentTransportVersion,
3627
3761
  transportVersion: captured.transportVersion,
3628
3762
  });
3763
+ // The fingerprint is only sealed when Git's state files did not move
3764
+ // while capture ran; a concurrent ref or index write leaves no seal and
3765
+ // the next complete pass asks Git again.
3766
+ if (fingerprintBefore !== null
3767
+ && fingerprintBefore === gitEvidenceFingerprint(repository.absolutePath)) {
3768
+ writeSealedRepositoryEvidence(database, repository.uuid, {
3769
+ payloadVersion: captured.stateId,
3770
+ transportVersion: captured.transportVersion,
3771
+ identityHash: repositoryIdentityHash(repoIdentity, sha256Hex),
3772
+ fingerprint: fingerprintBefore,
3773
+ });
3774
+ }
3629
3775
  }
3630
3776
  }
3631
3777
  catch {