memhtml 0.7.1 → 0.7.2

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.
@@ -4346,6 +4346,18 @@ const parseLsTree = (output) => output.split("\0").filter((row) => row !== "").f
4346
4346
  path: row.slice(tab + 1)
4347
4347
  }];
4348
4348
  });
4349
+ /**
4350
+ * A bare NUL-terminated path list, which is what every `-z` path-only git output is.
4351
+ *
4352
+ * One function for the shape rather than one `split` per call site, because the trailing NUL is what
4353
+ * makes the naive read wrong: `"a\0b\0"` splits into three fields, the last empty, so a caller that
4354
+ * forgets the filter gets an empty string in its path set. `diff-tree --name-only -z` and
4355
+ * `diff --name-only --diff-filter=U -z` are both this shape.
4356
+ *
4357
+ * `-z` is also what removes the escaping question: under newline framing git applies `core.quotePath`
4358
+ * and a path holding a non-ASCII byte arrives as `"caf\303\251.html"`, quotes included.
4359
+ */
4360
+ const parseNulPathList = (output) => output.split("\0").filter((path) => path !== "");
4349
4361
  /** The status letters git emits, mapped to the names this package uses. */
4350
4362
  const CHANGE_KINDS = {
4351
4363
  A: "added",
@@ -4639,10 +4651,15 @@ var GitFailure = class extends Schema.TaggedError()("GitFailure", {
4639
4651
  }) {};
4640
4652
  const Git = Context.Service("memhtml/Git");
4641
4653
  /**
4642
- * Environment for every git call. The three `GIT_CONFIG_*` variables suppress any
4643
- * `~/.gitconfig` alias, hook path, or template dir that would otherwise change what these
4644
- * commands do on a developer's machine but not in CI. `GIT_TERMINAL_PROMPT=0` is what keeps a
4645
- * credential prompt from hanging a headless indexer forever.
4654
+ * Environment for every git call. `GIT_TERMINAL_PROMPT=0` keeps a credential prompt from hanging a
4655
+ * headless indexer forever, `GIT_OPTIONAL_LOCKS=0` stops a read from taking the index lock, and
4656
+ * `LC_ALL=C` pins the message locale so a parsed word is the same word everywhere.
4657
+ *
4658
+ * **A user's own config IS read.** Nothing here neutralizes `~/.gitconfig`, so every call whose output
4659
+ * a caller parses states its format with explicit flags rather than inheriting a default: `-z` against
4660
+ * `core.quotePath`, `-M` and `--no-renames` against `diff.renames`, `--porcelain=v2` against every
4661
+ * status shorthand. A format a developer's machine and CI could disagree about is a format this
4662
+ * service does not rely on.
4646
4663
  */
4647
4664
  const GIT_ENV = {
4648
4665
  GIT_TERMINAL_PROMPT: "0",
@@ -4651,6 +4668,8 @@ const GIT_ENV = {
4651
4668
  };
4652
4669
  /** 64 MiB. A `cat-file --batch` over a whole corpus is the one call with a large stdout. */
4653
4670
  const MAX_BUFFER = 67108864;
4671
+ /** A full 40-hex object name, which is the only form {@link GitShape.diffTreeNames} accepts. */
4672
+ const FULL_OBJECT_NAME = /^[0-9a-f]{40}$/;
4654
4673
  /**
4655
4674
  * Spawn git and collect its output as bytes.
4656
4675
  *
@@ -4735,6 +4754,50 @@ const makeGit = (root) => ({
4735
4754
  from,
4736
4755
  to
4737
4756
  ]).pipe(Effect.map((result) => parseDiffNameStatus(text$1(result)))),
4757
+ /**
4758
+ * Dropping any of the first five flags makes the answer SILENTLY smaller or dirtier rather than an
4759
+ * error, which is why each has its own case in `git.test.ts`. Measured against git 2.50.1 on
4760
+ * 2026-08-26:
4761
+ *
4762
+ * - `--stdin`, so a range of hundreds of commits costs one process;
4763
+ * - `-r`, or the answer is the changed TREE (`areas`) instead of the blobs under it;
4764
+ * - `-m`, or a merge commit reports ZERO paths (empty without, its paths with, and byte-identical
4765
+ * on a single-parent commit, so it is free);
4766
+ * - `--root`, or a root commit reports ZERO paths (0 without, its whole tree with);
4767
+ * - `--no-commit-id`, or each commit's own 40-hex sha arrives as a line among the paths;
4768
+ * - `-z`, which frames on NUL and disables `core.quotePath` — under newline framing a path
4769
+ * holding a non-ASCII byte arrives as `"areas/x/caf\303\251.html"`, quoted and escaped, and
4770
+ * equals nothing a caller compares it to.
4771
+ *
4772
+ * `--no-renames` is INERT here and is declared anyway. `diff-tree` detects no renames in this form
4773
+ * whatever the config says — probed under `diff.renames` unset, `true`, and `copies`, all three
4774
+ * reporting both paths of a `git mv` — so the flag pins that default rather than producing it, the
4775
+ * same reason the calls above spell `-z` and `--porcelain=v2`. What holds the behavior is the test,
4776
+ * not the flag: a caller unioning paths needs the path that went away as much as the one that
4777
+ * arrived, and `git diff --name-only` (which DOES detect renames) reports only the destination.
4778
+ *
4779
+ * **An abbreviated sha is refused rather than passed through**, because git echoes the short name
4780
+ * as its own output line and reports no diff at all — with `--no-commit-id` set, a caller would
4781
+ * receive one bogus path and no real ones, at exit 0. `%H` from `logTrailers` is already full, so
4782
+ * the check costs nothing and closes the one input that fails quietly.
4783
+ */
4784
+ diffTreeNames: (commits) => {
4785
+ if (commits.find((sha) => !FULL_OBJECT_NAME.test(sha)) !== void 0) return Effect.fail(GitFailure.make({
4786
+ command: "diff-tree",
4787
+ exitCode: null
4788
+ }));
4789
+ return commits.length === 0 ? Effect.succeed([]) : git(root, "diff-tree", [
4790
+ "diff-tree",
4791
+ "-r",
4792
+ "-m",
4793
+ "--root",
4794
+ "--stdin",
4795
+ "--no-commit-id",
4796
+ "--name-only",
4797
+ "-z",
4798
+ "--no-renames"
4799
+ ], { stdin: `${commits.join("\n")}\n` }).pipe(Effect.map((result) => parseNulPathList(text$1(result))));
4800
+ },
4738
4801
  statusPorcelainV2: () => git(root, "status", [
4739
4802
  "status",
4740
4803
  "--porcelain=v2",
@@ -4811,7 +4874,7 @@ const makeGit = (root) => ({
4811
4874
  ]);
4812
4875
  return {
4813
4876
  merged: false,
4814
- conflicted: text$1(unmerged).split("\0").filter((path) => path !== "")
4877
+ conflicted: parseNulPathList(text$1(unmerged))
4815
4878
  };
4816
4879
  }),
4817
4880
  mergeAbort: () => git(root, "merge-abort", ["merge", "--abort"]).pipe(Effect.asVoid),
@@ -10009,6 +10072,47 @@ const TRAILER_RUN = "Memhtml-Run";
10009
10072
  const TRAILER_PHASE = "Memhtml-Phase";
10010
10073
  const TRAILER_COUNTS = "Memhtml-Counts";
10011
10074
  /**
10075
+ * Phases whose commit is a UNIFORM SWEEP: one head stamp applied to every eligible file by a rule,
10076
+ * carrying no per-file decision and authoring no edge.
10077
+ *
10078
+ * This is the distinction `placement-triage`'s this-run guard turns on. That guard refuses to move a
10079
+ * file another phase wrote on this branch, because a move would fold that phase's edit into a rename
10080
+ * a reviewer reads somewhere else. A sweep has no edit to fold: `confidence-decay` restamps
10081
+ * `memhtml-confidence` and `memhtml-updated` on every eligible active file, and its value is a
10082
+ * mechanical function of the value already in the file (`decayConfidence`), so nothing about it is
10083
+ * invalidated by the file being at a different path afterwards. It is also the WIDEST commit in a
10084
+ * run, so a guard that counts it pins essentially the whole corpus and the phase downstream refuses
10085
+ * essentially everything (issue #81).
10086
+ *
10087
+ * **The list enumerates the sweeps, so a phase absent from it PINS.** The two mistakes cost
10088
+ * different amounts. A phase wrongly treated as a sweep lets placement move a file it just wrote —
10089
+ * a committed href that dangles, or a decision folded into a rename — while a phase wrongly pinning
10090
+ * costs one night's yield on a file that is still a candidate tomorrow. So membership is an explicit
10091
+ * claim and the default is the recoverable side.
10092
+ *
10093
+ * A phase that calls a model is never a member: a model answer is a per-file decision. The two lists
10094
+ * are asserted disjoint in `units.test.ts`.
10095
+ *
10096
+ * The near-misses, because the absences carry the rule:
10097
+ *
10098
+ * - `reprieve` writes only head metas too, and is still out. `memhtml-valid-until` plus
10099
+ * `memhtml-reprieves` IS a per-file retention decision, and a reviewer reads it at the path it was
10100
+ * decided on. Its volume is bounded to the files whose TTL passed, so membership would buy almost
10101
+ * no reach against that.
10102
+ * - `person-links` and `edge-typing` splice `<link>` elements, which leave the article's bytes — and
10103
+ * therefore its content hash — identical. So the meaning of a change, not its width, is what
10104
+ * decides membership: a hash-based rule would release exactly these two, and placement's inbound
10105
+ * href rewrite reads the INDEX, which no phase refreshes mid-run, so an edge authored this run is
10106
+ * invisible to it and the move would leave the href dangling.
10107
+ * - `preflight` and `relationship-mining` are in {@link NON_COMMITTING_PHASES}, so no commit of
10108
+ * theirs can appear in a range; `integrity`, `state-export`, and `report` run after
10109
+ * `placement-triage`, so theirs cannot either. Membership for any of the five would be a claim
10110
+ * nothing can exercise.
10111
+ */
10112
+ const SWEEP_PHASES = ["confidence-decay"];
10113
+ /** True when a phase's commit is a uniform sweep. See {@link SWEEP_PHASES}. */
10114
+ const isSweepPhase = (phase) => SWEEP_PHASES.includes(phase);
10115
+ /**
10012
10116
  * Where a run's ledger lives: beside its report, under the same run-id-to-filename rule.
10013
10117
  *
10014
10118
  * `/` is not legal in a filename and a run id is `sleep/<date>`, so the separator becomes a hyphen —
@@ -15743,6 +15847,84 @@ const personLinks = (env) => Effect.gen(function* () {
15743
15847
  };
15744
15848
  });
15745
15849
 
15850
+ //#endregion
15851
+ //#region packages/sleep/dist/touched.js
15852
+ /**
15853
+ * True when a commit's `Memhtml-Phase` trailer says every phase that made it is a sweep.
15854
+ *
15855
+ * **A missing, empty, or unrecognized value pins.** The trailer is what identifies a sweep, so the
15856
+ * absence of the identification cannot grant the exemption — an operator's own mid-run commit, a
15857
+ * commit stamped with a phase name this version does not know, and a forged value that is not a phase
15858
+ * all land on the conservative side. `every` rather than `some` for the same reason: a commit
15859
+ * claiming two phases is exempt only if neither of them decided anything.
15860
+ */
15861
+ const isSweepCommit = (values) => values.length > 0 && values.every((value) => isSleepPhase(value) && isSweepPhase(value));
15862
+ /**
15863
+ * The paths this run wrote, excluding the sweeps.
15864
+ *
15865
+ * **Paths come back exactly as git spells them, with no normalization, and that is deliberate.**
15866
+ * `diff-tree --name-only -z` emits repo-root-relative, `/`-separated, unquoted paths with no leading
15867
+ * slash — the same spelling the `files` table holds, because the indexer derived those from
15868
+ * `git ls-tree`. `normalizePath` strips leading slashes, collapses doubled ones, and trims a trailing
15869
+ * one, so against this output it is a no-op, and a no-op called for its name reads as a guarantee
15870
+ * nobody checks. What holds the two spellings in agreement is a test that moves a real file after a
15871
+ * real phase wrote it.
15872
+ *
15873
+ * The set legitimately holds paths that are not memories — `edge-typing` stages its pending-marks
15874
+ * ledger into its own commit — and they are inert, because a caller only ever asks whether a
15875
+ * candidate's own path is in it.
15876
+ *
15877
+ * `baseSha === ""` is an empty set rather than a scan of all of `HEAD`. Over `HEAD` a previously
15878
+ * merged run's trailers name every phase, so the set would become every file every past sleep ever
15879
+ * touched: the same over-pinning, one release further back. With no base there is no run to bound, and
15880
+ * production always has one because `preflight` requires a commit and a clean tree.
15881
+ */
15882
+ const touchedThisRun = (git, baseSha) => Effect.gen(function* () {
15883
+ if (baseSha === "") return {
15884
+ kind: "scoped",
15885
+ paths: /* @__PURE__ */ new Set(),
15886
+ commits: 0,
15887
+ sweeps: 0
15888
+ };
15889
+ const range = `${baseSha}..HEAD`;
15890
+ const read = yield* Effect.result(git.logTrailers(range, TRAILER_PHASE));
15891
+ if (Result.isFailure(read)) {
15892
+ yield* Effect.logWarning(`sleep.touched could not read ${TRAILER_PHASE} over ${range}; pinning the whole range`);
15893
+ return yield* widen(git, baseSha);
15894
+ }
15895
+ const records = read.success;
15896
+ const semantic = records.flatMap((record) => isSweepCommit(record.values) ? [] : [record.sha]);
15897
+ const diffed = yield* Effect.result(git.diffTreeNames(semantic));
15898
+ if (Result.isFailure(diffed)) {
15899
+ yield* Effect.logWarning(`sleep.touched could not diff ${String(semantic.length)} commit(s) of ${range}; pinning the whole range`);
15900
+ return yield* widen(git, baseSha);
15901
+ }
15902
+ return {
15903
+ kind: "scoped",
15904
+ paths: new Set(diffed.success),
15905
+ commits: semantic.length,
15906
+ sweeps: records.length - semantic.length
15907
+ };
15908
+ });
15909
+ /**
15910
+ * Every path the range touched, as the fallback when the scoped read could not be made.
15911
+ *
15912
+ * Through `diffNameStatus`, which detects renames and reports the pre-move path in `fromPath`. BOTH
15913
+ * sides go in: this set exists to be conservative, and a `git mv`'s source is a path a phase wrote as
15914
+ * surely as its destination is.
15915
+ */
15916
+ const widen = (git, baseSha) => git.diffNameStatus(baseSha, "HEAD").pipe(Effect.map((changes) => {
15917
+ const paths = /* @__PURE__ */ new Set();
15918
+ for (const change of changes) {
15919
+ paths.add(change.path);
15920
+ if (change.fromPath !== null) paths.add(change.fromPath);
15921
+ }
15922
+ return {
15923
+ kind: "widened",
15924
+ paths
15925
+ };
15926
+ }), Effect.orElseSucceed(() => ({ kind: "unknown" })));
15927
+
15746
15928
  //#endregion
15747
15929
  //#region packages/sleep/dist/phases/placement-triage.js
15748
15930
  /**
@@ -15768,12 +15950,22 @@ const personLinks = (env) => Effect.gen(function* () {
15768
15950
  * `archive/`, and any path outside the PARA buckets;
15769
15951
  * - tasks never move (excluded from the scan AND re-checked per row, matching the double guard
15770
15952
  * task-detection carries);
15771
- * - a file another phase already touched this run never moves, read from `git diff --name-only
15772
- * base..HEAD` a `mv` of a path compress just archived would fail, and one of a path an earlier
15773
- * phase stamped would tear that phase's edit out of its own commit's diff;
15953
+ * - a file a phase whose write carries a DECISION already touched this run never moves, read from
15954
+ * the diffs of the run's own commits whose `Memhtml-Phase` trailer is not in `SWEEP_PHASES` a
15955
+ * `mv` of a path compress just archived would fail, and one of a path a phase stamped a link into
15956
+ * would tear that phase's edit out of the commit a reviewer reads it in. A SWEEP is exempt:
15957
+ * `confidence-decay` restamps every eligible file in the corpus by a rule, so counting it pins
15958
+ * essentially every candidate and this phase refuses essentially everything (issue #81). An
15959
+ * unreadable trailer or diff widens the set to the whole range instead of emptying it, and a
15960
+ * set that cannot be read at all returns before a single model call;
15774
15961
  * - `keep-inbox`, an unknown key, a below-floor confidence, and an omitted member all leave the
15775
15962
  * file where it is.
15776
15963
  *
15964
+ * **Every refusal is its own count**, one key per class beside the `refused` total
15965
+ * ({@link PLACEMENT_REFUSALS}). Nine classes pooled into one number make a night where the phase
15966
+ * applied nothing unreadable without a log grep, which is exactly how issue #81's mechanism stayed
15967
+ * hidden for two runs.
15968
+ *
15777
15969
  * **Inbound hrefs are rewritten in the same commit.** Integrity's dangling-href repair chases a
15778
15970
  * target into the ARCHIVE by deriving `archivePathFor`; a placement move is not an archive, so this
15779
15971
  * phase rewrites `<link>` elements in the files that point at each moved path itself, the same
@@ -15792,6 +15984,30 @@ const PLACEMENT_MEMBER_CHARS = 600;
15792
15984
  * thirty new topics should earn them over several reviewed runs, not one.
15793
15985
  */
15794
15986
  const PLACEMENT_NEW_DIR_CAP = 5;
15987
+ /**
15988
+ * Every refusal class, as its count key and the prose it logs. The keys ARE the partition of
15989
+ * `refused`, which stays the total.
15990
+ *
15991
+ * One map rather than a prose string per guard, so the count and the log line cannot name different
15992
+ * things and a class cannot exist without a count. `refused` keeps its meaning exactly — an existing
15993
+ * reader is unaffected — and every case in `deep.test.ts`'s guard g asserts the parts sum to it.
15994
+ *
15995
+ * `refusedTouched` and `refusedAlreadyMoved` are separate because they are separate facts: the first
15996
+ * is another phase's write, the second is THIS phase having already moved the file in an earlier row
15997
+ * of the same run. One key covering both would report a duplicate model answer as cross-phase
15998
+ * contamination, and an operator reading the count would go looking for a phase that wrote nothing.
15999
+ */
16000
+ const PLACEMENT_REFUSALS = {
16001
+ refusedLowConfidence: "below the confidence floor",
16002
+ refusedDestination: "not a placeable directory",
16003
+ refusedTask: "tasks never move",
16004
+ refusedTouched: "a phase that decides wrote this file this run",
16005
+ refusedAlreadyMoved: "this run already moved this file",
16006
+ refusedNewDirCap: "the new-directory cap for this run is spent",
16007
+ refusedInvalidPath: "the destination path is not a valid memory path",
16008
+ refusedCollision: "the destination already holds a file by that name",
16009
+ refusedSourceGone: "the source file is already gone from the tree"
16010
+ };
15795
16011
  const placementTriage = (env) => Effect.gen(function* () {
15796
16012
  if (env.deep === void 0) return {
15797
16013
  ...emptyOutcome({ candidates: 0 }),
@@ -15828,12 +16044,12 @@ const placementTriage = (env) => Effect.gen(function* () {
15828
16044
  PEOPLE_DIR
15829
16045
  ]);
15830
16046
  const existingDirs = [...new Set(corpus.map((row) => row.path.slice(0, row.path.lastIndexOf("/"))).filter((dir) => (dir.startsWith("areas/") || dir.startsWith("resources/")) && !managed.has(dir)))].sort();
15831
- /** Paths this run already touched. A move of one would cross-contaminate another phase's diff. */
15832
- const touched = new Set(env.baseSha === "" ? [] : yield* env.deps.git.run([
15833
- "diff",
15834
- "--name-only",
15835
- `${env.baseSha}..HEAD`
15836
- ]).pipe(Effect.map((out) => out.split("\n").map((line) => line.trim()).filter(Boolean)), Effect.orElseSucceed(() => [])));
16047
+ /**
16048
+ * Paths a phase whose write carries a decision already touched this run. A move of one would
16049
+ * fold that phase's edit into a rename a reviewer reads elsewhere; a SWEEP has no such edit.
16050
+ * Read BEFORE the batch loop, so a set that cannot be read costs no model call.
16051
+ */
16052
+ const touched = yield* touchedThisRun(env.deps.git, env.baseSha);
15837
16053
  const batches = assembleBatches([candidates], { maxMembers: 16 });
15838
16054
  const counts = {
15839
16055
  candidates: candidates.length,
@@ -15844,7 +16060,22 @@ const placementTriage = (env) => Effect.gen(function* () {
15844
16060
  keptInbox: 0,
15845
16061
  newDirs: 0,
15846
16062
  budgetSkipped: 0,
15847
- failed: 0
16063
+ failed: 0,
16064
+ existingDirs: existingDirs.length,
16065
+ touchedFiles: touched.kind === "unknown" ? 0 : touched.paths.size,
16066
+ touchedCommits: touched.kind === "scoped" ? touched.commits : 0,
16067
+ sweepCommits: touched.kind === "scoped" ? touched.sweeps : 0,
16068
+ touchedWidened: touched.kind === "widened" ? 1 : 0,
16069
+ ...Object.fromEntries(Object.keys(PLACEMENT_REFUSALS).map((key) => [key, 0]))
16070
+ };
16071
+ /**
16072
+ * A touched set neither read could establish is a degradation, reported the way an absent model
16073
+ * is: a reason, nothing written, nothing committed. Moving under it would be moving without the
16074
+ * guard, and the corpus is still there tomorrow.
16075
+ */
16076
+ if (touched.kind === "unknown") return {
16077
+ ...emptyOutcome(counts),
16078
+ detail: "the run's touched set could not be read"
15848
16079
  };
15849
16080
  if (batches.length === 0 || env.dryRun) return emptyOutcome(counts);
15850
16081
  const modelKey = modelFor(env.deps, "placement-triage");
@@ -15887,41 +16118,46 @@ const placementTriage = (env) => Effect.gen(function* () {
15887
16118
  }
15888
16119
  const refuse = (reason) => {
15889
16120
  counts.refused = (counts.refused ?? 0) + 1;
15890
- return Effect.logWarning(`sleep.placement refused ${row.path} -> ${destination}: ${reason}`);
16121
+ counts[reason] = (counts[reason] ?? 0) + 1;
16122
+ return Effect.logWarning(`sleep.placement refused ${row.path} -> ${destination}: ${PLACEMENT_REFUSALS[reason]}`);
15891
16123
  };
15892
16124
  if (placement.confidence < .7) {
15893
- yield* refuse("below the confidence floor");
16125
+ yield* refuse("refusedLowConfidence");
15894
16126
  continue;
15895
16127
  }
15896
16128
  const bucket = paraBucketOf(destination);
15897
16129
  if (bucket !== "areas" && bucket !== "resources" || managed.has(destination) || destination === row.path.slice(0, row.path.lastIndexOf("/")) || destination.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
15898
- yield* refuse("not a placeable directory");
16130
+ yield* refuse("refusedDestination");
15899
16131
  continue;
15900
16132
  }
15901
16133
  if (isSleepExcluded(row.memory_type)) {
15902
- yield* refuse("tasks never move");
16134
+ yield* refuse("refusedTask");
16135
+ continue;
16136
+ }
16137
+ if (touched.paths.has(row.path)) {
16138
+ yield* refuse("refusedTouched");
15903
16139
  continue;
15904
16140
  }
15905
- if (touched.has(row.path) || movedFrom.has(row.path)) {
15906
- yield* refuse("another phase touched this file this run");
16141
+ if (movedFrom.has(row.path)) {
16142
+ yield* refuse("refusedAlreadyMoved");
15907
16143
  continue;
15908
16144
  }
15909
16145
  const isNew = !existingDirs.includes(destination) && !mintedDirs.has(destination);
15910
16146
  if (isNew && mintedDirs.size >= 5) {
15911
- yield* refuse("the new-directory cap for this run is spent");
16147
+ yield* refuse("refusedNewDirCap");
15912
16148
  continue;
15913
16149
  }
15914
16150
  const target = `${destination}/${row.path.slice(row.path.lastIndexOf("/") + 1)}`;
15915
16151
  if (!isValidMemoryPath(target)) {
15916
- yield* refuse("the destination path is not a valid memory path");
16152
+ yield* refuse("refusedInvalidPath");
15917
16153
  continue;
15918
16154
  }
15919
16155
  if ((yield* readFileBytes(env, target)) !== void 0) {
15920
- yield* refuse("the destination already holds a file by that name");
16156
+ yield* refuse("refusedCollision");
15921
16157
  continue;
15922
16158
  }
15923
16159
  if ((yield* readFileBytes(env, row.path)) === void 0) {
15924
- yield* refuse("the source file is already gone from the tree");
16160
+ yield* refuse("refusedSourceGone");
15925
16161
  continue;
15926
16162
  }
15927
16163
  yield* attemptIo(`sleep.placement.mkdir:${target}`, async () => {
@@ -19440,4 +19676,4 @@ const latest = (left, right) => left === null ? right : right === null ? left :
19440
19676
 
19441
19677
  //#endregion
19442
19678
  export { expandRoot as $, EMBED_DIM as A, reinforce as B, discriminationGate as C, wrapAsData as D, ModelClientLive as E, readWatermark as F, makeGitPort as G, makeIndexer as H, Retrieval as I, makeDatabase as J, sanitizeFtsQuery as K, makeRetrieval as L, IndexRecorder as M, makeIndexRecorder as N, Embeddings as O, persistScanned as P, Store as Q, facetConditions as R, DiscriminationFailed as S, ModelClient as T, readIndexState as U, Indexer as V, IndexGit as W, STATE_MIGRATIONS_DIR as X, MIGRATIONS_DIR as Y, STATE_SCHEMA as Z, link as _, REINFORCE_SIGNALS as _t, parseSidecar as a, attemptIo as at, SLEEP_PHASES as b, archivedFormOf as c, Git as ct, accessRows as d, checkMemory as dt, makeStore as et, allPaths as f, parseMemory as ft, hrefFor as g, fenceOpeningOf as gt, applyHeadEdits as h, closesFence as ht, makeSleep as i, STATE_SIDECAR_PATH as it, EMBED_WATERMARK as j, EmbeddingsLive as k, generateArtifacts as l, makeGit as lt, publishRows as m, isValidDatetime as mt, scanTraceRoot as n, SLEEP_REPORTS_DIR as nt, renderSidecar as o, initRepo as ot, danglingEdges as p, setMeta as pt, DatabaseService as q, Sleep as r, STATE_DB_PATH as rt, reportFilename as s, readFileOrNull as st, mergeTailExtract as t, INDEX_DB_PATH as tt, DETECTION_PREFIX as u, commitSubject as ut, meta as v, frameKeyOf as vt, runDiscrimination as w, isSleepPhase as x, unlink as y, parseFacetFilters as z };
19443
- //# sourceMappingURL=dist-D1wH0oJ0.mjs.map
19679
+ //# sourceMappingURL=dist-xlKgJuWn.mjs.map