@smthrs/engine-store 1.0.0-rc.6 → 1.0.0-rc.7

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.
@@ -496,12 +496,14 @@ export interface FileSystemOptions {
496
496
  */
497
497
  readonly maxTotalInlineBytes?: number | undefined
498
498
  /**
499
- * The workspace root cache replay confines its writes, removals, and prune
500
- * walk to. A filesystem already confined to a root (the kernel-guarded
501
- * layer's service, or a `confined` view) keeps its own root and ignores
502
- * this. Otherwise it defaults to the process working directory, the root a
503
- * path-based host resolves `prepare` and `settle` against. {@link layer}
504
- * passes the kernel `Workspace` root when one is in context.
499
+ * The workspace root every declared path resolves against: `prepare` and
500
+ * `settle` measure under it, and cache replay confines its writes, removals,
501
+ * and prune walk to it. A filesystem already confined to a root (the
502
+ * kernel-guarded layer's service, or a `confined` view) keeps its own root
503
+ * and ignores this. Otherwise it defaults to the process working directory,
504
+ * the root a path-based host resolves a relative path against. {@link layer}
505
+ * passes the kernel `Workspace` root when one is in context, which is the
506
+ * root a step's own FileSystem resolves against (issue #3911).
505
507
  */
506
508
  readonly root?: string | undefined
507
509
  }
@@ -573,7 +575,16 @@ export const makeFileSystem = (
573
575
  const digest = yield* Schema.decodeUnknownEffect(Sha256)(bytes).pipe(Effect.orDie)
574
576
  return { digest, bytes } satisfies MeasuredDigest
575
577
  })
576
- const readDigest = (path: string) => readDigestFrom(fs, path)
578
+ // Declared paths are workspace-relative. A confined filesystem resolves them
579
+ // against its own root, but a path-based host resolves them against the
580
+ // process working directory, where a same-named file would answer the dirty
581
+ // check and let a stale declaration serve a cache hit (issue #3911). Such a
582
+ // host is handed each path resolved against the configured root; results
583
+ // stay keyed by the declared path.
584
+ const readRoot = KernelFileSystem.confinedRoot(fs) === undefined ? options.root : undefined
585
+ const hostPath = (path: string): string => readRoot === undefined ? path : platformPath.resolve(readRoot, path)
586
+ const enumeration: FileEnumeration.EnumerationOptions = readRoot === undefined ? {} : { resolve: hostPath }
587
+ const readDigest = (path: string) => readDigestFrom(fs, hostPath(path))
577
588
  const batch = KernelFileSystem.batch(fs)
578
589
  const measurements = Effect.fn("StepBoundary.measurements")(
579
590
  function*(paths: ReadonlyArray<string>, content: boolean) {
@@ -594,7 +605,7 @@ export const makeFileSystem = (
594
605
  const response = yield* batch.execute(
595
606
  paths.slice(offset, offset + batch.maxSize).map((path) => ({
596
607
  operation: "digest",
597
- path,
608
+ path: hostPath(path),
598
609
  content
599
610
  }))
600
611
  ).pipe(Effect.mapError(hostFailure))
@@ -636,10 +647,14 @@ export const makeFileSystem = (
636
647
  // workspace-relative expansion and let a tree replay delete dotfiles the
637
648
  // producer wrote.
638
649
  const expandGlob = Effect.fn("StepBoundary.expandGlob")(function*(glob: FileSet.Glob) {
639
- return yield* FileEnumeration.expandGlob(fs, glob).pipe(Effect.mapError(hostFailure))
650
+ return yield* FileEnumeration.expandGlob(fs, glob, enumeration).pipe(Effect.mapError(hostFailure))
640
651
  })
641
- const treeEntries = Effect.fn("StepBoundary.treeEntries")(function*(host: FileSystem.FileSystem, path: string) {
642
- return yield* FileEnumeration.entriesUnder(host, path).pipe(Effect.mapError(hostFailure))
652
+ const treeEntries = Effect.fn("StepBoundary.treeEntries")(function*(
653
+ host: FileSystem.FileSystem,
654
+ path: string,
655
+ resolution: FileEnumeration.EnumerationOptions
656
+ ) {
657
+ return yield* FileEnumeration.entriesUnder(host, path, resolution).pipe(Effect.mapError(hostFailure))
643
658
  })
644
659
  // Replay writes and deletes what evidence names, so the lexical check alone
645
660
  // is not a boundary: a symlink planted on a lexically valid path would carry
@@ -647,7 +662,7 @@ export const makeFileSystem = (
647
662
  // its prune walk go through a view pinned to the root, where each call is
648
663
  // one descriptor-relative, no-follow request and a symlink anywhere on the
649
664
  // path is refused rather than followed. `prepare` and `settle` only read,
650
- // and keep the caller's filesystem.
665
+ // and keep the caller's filesystem, rooted through `hostPath`.
651
666
  const replayRoot = KernelFileSystem.confinedRoot(fs) ?? options.root ?? "."
652
667
  const replayHost: Effect.Effect<FileSystem.FileSystem, UnsupportedBoundary> = KernelFileSystem.isConfinable(fs)
653
668
  ? KernelFileSystem.confined(fs, replayRoot).pipe(
@@ -849,7 +864,7 @@ export const makeFileSystem = (
849
864
  if (typeof entry === "string") outputPaths.push(entry)
850
865
  else if (entry._tag === "Glob") outputPaths.push(...yield* expandGlob(entry))
851
866
  else {
852
- const files = (yield* treeEntries(fs, entry.path)).files
867
+ const files = (yield* treeEntries(fs, entry.path, enumeration)).files
853
868
  outputPaths.push(...files)
854
869
  treeMembers.push({ path: entry.path, files })
855
870
  }
@@ -1007,7 +1022,7 @@ export const makeFileSystem = (
1007
1022
  .map((output) => output.path)
1008
1023
  .filter((path) => path.startsWith(prefix))
1009
1024
  )
1010
- const entries = yield* treeEntries(host, tree.path)
1025
+ const entries = yield* treeEntries(host, tree.path, {})
1011
1026
  for (const path of entries.files) {
1012
1027
  if (!recorded.has(path)) yield* host.remove(path).pipe(Effect.mapError(hostFailure))
1013
1028
  }