memhtml 0.5.0 → 0.5.1
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/dist/{dist-D5DlgqH2.mjs → dist-DgKlozi6.mjs} +153 -26
- package/dist/dist-DgKlozi6.mjs.map +1 -0
- package/dist/memhtml-mcp.mjs +2 -2
- package/dist/memhtml-mcp.mjs.map +1 -1
- package/dist/memhtml.mjs +2 -2
- package/dist/memhtml.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/dist-D5DlgqH2.mjs.map +0 -1
|
@@ -9021,17 +9021,42 @@ const keyMembers = (items, textOf, options) => {
|
|
|
9021
9021
|
};
|
|
9022
9022
|
};
|
|
9023
9023
|
/**
|
|
9024
|
+
* The offered key a model's answer denotes, or `undefined` when it denotes none.
|
|
9025
|
+
*
|
|
9026
|
+
* A model shown `<member_m3>` answers `member_m3` at least as readily as `m3`: the wrapper tag is
|
|
9027
|
+
* the only place most batch prompts DISPLAY a key, so the label-prefixed form is the one the prompt
|
|
9028
|
+
* itself teaches (measured live 2026-08-23: `gpt-5.6-sol` answers the prefixed form on every call,
|
|
9029
|
+
* Claude Sonnet 5 on most). So a key that does not match directly is retried once with everything
|
|
9030
|
+
* up to its last `_` stripped, and only a suffix the batch actually offered resolves — `member_m9`
|
|
9031
|
+
* in a batch of three still denotes nothing, and a path or an invented name still drops. The
|
|
9032
|
+
* canonical form is returned so two spellings of one member collapse to one key everywhere a phase
|
|
9033
|
+
* keeps per-key state.
|
|
9034
|
+
*/
|
|
9035
|
+
const offeredKeyFor = (batch, key) => {
|
|
9036
|
+
if (batch.itemForKey.has(key)) return key;
|
|
9037
|
+
const at = key.lastIndexOf("_");
|
|
9038
|
+
if (at === -1) return void 0;
|
|
9039
|
+
const suffix = key.slice(at + 1);
|
|
9040
|
+
return batch.itemForKey.has(suffix) ? suffix : void 0;
|
|
9041
|
+
};
|
|
9042
|
+
/**
|
|
9024
9043
|
* Resolve the keys a model named back to items: unknown keys are dropped, repeats collapse.
|
|
9025
9044
|
*
|
|
9026
9045
|
* A key the batch never offered is a member the model invented, and every phase on this kernel turns
|
|
9027
9046
|
* a named member into a write, so an unresolvable key must not reach that write. Dropping it leaves
|
|
9028
9047
|
* the corresponding file untouched, which is the safe outcome for every one of the five phases.
|
|
9048
|
+
* Resolution goes through {@link offeredKeyFor}, so the label-prefixed spelling of an offered key
|
|
9049
|
+
* (`member_m3` for `m3`) resolves rather than reading as an invention.
|
|
9029
9050
|
*
|
|
9030
9051
|
* The result keeps the order the model named the keys in, and a key named twice appears once.
|
|
9031
|
-
* De-duplication is on the
|
|
9032
|
-
*
|
|
9033
|
-
|
|
9034
|
-
|
|
9052
|
+
* De-duplication is on the CANONICAL key rather than on the spelling or the resolved item, so `m1`
|
|
9053
|
+
* and `member_m1` in one answer count as one member, and the count a phase gates on ("at least two
|
|
9054
|
+
* members absorbed") counts distinct offered members.
|
|
9055
|
+
*/
|
|
9056
|
+
const resolveKeys = (batch, keys) => [...new Set(keys.flatMap((key) => {
|
|
9057
|
+
const canonical = offeredKeyFor(batch, key);
|
|
9058
|
+
return canonical === void 0 ? [] : [canonical];
|
|
9059
|
+
}))].flatMap((key) => {
|
|
9035
9060
|
const item = batch.itemForKey.get(key);
|
|
9036
9061
|
return item === void 0 ? [] : [item];
|
|
9037
9062
|
});
|
|
@@ -11038,7 +11063,9 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11038
11063
|
batches: batches.length,
|
|
11039
11064
|
canonicals: 0,
|
|
11040
11065
|
archived: 0,
|
|
11041
|
-
skipped: 0
|
|
11066
|
+
skipped: 0,
|
|
11067
|
+
failed: 0,
|
|
11068
|
+
refused: 0
|
|
11042
11069
|
};
|
|
11043
11070
|
if (batches.length === 0) return emptyOutcome(counts);
|
|
11044
11071
|
if (env.dryRun) return emptyOutcome(counts);
|
|
@@ -11046,7 +11073,16 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11046
11073
|
let llmCalls = 0;
|
|
11047
11074
|
let canonicals = 0;
|
|
11048
11075
|
let archived = 0;
|
|
11076
|
+
/**
|
|
11077
|
+
* `skipped` stays the total, and `failed` + `refused` partition it. The two are different
|
|
11078
|
+
* diagnoses with different fixes — a failed call is the model or the wire (already logged by
|
|
11079
|
+
* `isolate`), a refusal is an answer the phase declined to act on (logged below) — and a night
|
|
11080
|
+
* reporting only their sum cannot say which one it had. 47 of 47 batches once skipped as
|
|
11081
|
+
* refusals with nothing on stderr, and the sum read as flaky calls.
|
|
11082
|
+
*/
|
|
11049
11083
|
let skipped = 0;
|
|
11084
|
+
let failed = 0;
|
|
11085
|
+
let refused = 0;
|
|
11050
11086
|
let lastCommit = null;
|
|
11051
11087
|
for (const batch of batches) {
|
|
11052
11088
|
/** Opaque keys again, so `absorbedKeys` cannot name a path. */
|
|
@@ -11062,12 +11098,15 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11062
11098
|
});
|
|
11063
11099
|
if (synthesis === void 0) {
|
|
11064
11100
|
skipped += 1;
|
|
11101
|
+
failed += 1;
|
|
11065
11102
|
continue;
|
|
11066
11103
|
}
|
|
11067
11104
|
/** A key the batch never offered resolves to nothing, so a fold reaches only offered files. */
|
|
11068
11105
|
const absorbed = resolveKeys(keyed, synthesis.absorbedKeys).map((entry) => entry.row.path);
|
|
11069
11106
|
if (absorbed.length < 2 || synthesis.title.trim() === "" || synthesis.claim.trim() === "") {
|
|
11070
11107
|
skipped += 1;
|
|
11108
|
+
refused += 1;
|
|
11109
|
+
yield* Effect.logWarning(`sleep.llm compress batch of ${batch.length} refused: the model absorbed ${absorbed.length} of ${synthesis.absorbedKeys.length} named keys` + (synthesis.absorbedKeys.length > 0 && absorbed.length === 0 ? ` (none of the named keys resolved: ${synthesis.absorbedKeys.slice(0, 3).join(", ")}${synthesis.absorbedKeys.length > 3 ? ", …" : ""})` : ""));
|
|
11071
11110
|
continue;
|
|
11072
11111
|
}
|
|
11073
11112
|
/**
|
|
@@ -11080,6 +11119,8 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11080
11119
|
const members = excludeSelfSupersede(canonicalPath, absorbed);
|
|
11081
11120
|
if (members.length === 0) {
|
|
11082
11121
|
skipped += 1;
|
|
11122
|
+
refused += 1;
|
|
11123
|
+
yield* Effect.logWarning(`sleep.llm compress batch of ${batch.length} refused: every absorbed member was the canonical itself`);
|
|
11083
11124
|
continue;
|
|
11084
11125
|
}
|
|
11085
11126
|
/**
|
|
@@ -11094,6 +11135,8 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11094
11135
|
}
|
|
11095
11136
|
if (archivedPaths.length === 0) {
|
|
11096
11137
|
skipped += 1;
|
|
11138
|
+
refused += 1;
|
|
11139
|
+
yield* Effect.logWarning(`sleep.llm compress batch of ${batch.length} refused: every member was already gone from the tree`);
|
|
11097
11140
|
continue;
|
|
11098
11141
|
}
|
|
11099
11142
|
yield* writeFileBytes(env, canonicalPath, renderTemplate({
|
|
@@ -11112,7 +11155,9 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11112
11155
|
...counts,
|
|
11113
11156
|
canonicals,
|
|
11114
11157
|
archived,
|
|
11115
|
-
skipped
|
|
11158
|
+
skipped,
|
|
11159
|
+
failed,
|
|
11160
|
+
refused
|
|
11116
11161
|
});
|
|
11117
11162
|
if (commitSha !== null) lastCommit = commitSha;
|
|
11118
11163
|
}
|
|
@@ -11121,7 +11166,9 @@ const compress = (env) => Effect.gen(function* () {
|
|
|
11121
11166
|
...counts,
|
|
11122
11167
|
canonicals,
|
|
11123
11168
|
archived,
|
|
11124
|
-
skipped
|
|
11169
|
+
skipped,
|
|
11170
|
+
failed,
|
|
11171
|
+
refused
|
|
11125
11172
|
},
|
|
11126
11173
|
commitSha: lastCommit,
|
|
11127
11174
|
llmCalls
|
|
@@ -12032,7 +12079,9 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
12032
12079
|
candidates: oriented.length,
|
|
12033
12080
|
components: 0,
|
|
12034
12081
|
llmGroups: 0,
|
|
12035
|
-
vetoed: oriented.length - decisions.length
|
|
12082
|
+
vetoed: oriented.length - decisions.length,
|
|
12083
|
+
skipped: 0,
|
|
12084
|
+
unresolved: 0
|
|
12036
12085
|
},
|
|
12037
12086
|
/**
|
|
12038
12087
|
* Every mined pair on this arm cleared 0.92, so a vetoed one here is a near-certain duplicate
|
|
@@ -12103,6 +12152,12 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
12103
12152
|
let llmCalls = 0;
|
|
12104
12153
|
let llmGroups = 0;
|
|
12105
12154
|
let skipped = 0;
|
|
12155
|
+
/**
|
|
12156
|
+
* Model-named member keys that resolved to no offered member, dropped unacted. The drop is the
|
|
12157
|
+
* safe outcome and stays; the count makes a systematic naming pattern visible instead of reading
|
|
12158
|
+
* as a night in which the model proposed no merges (issue #58).
|
|
12159
|
+
*/
|
|
12160
|
+
let unresolved = 0;
|
|
12106
12161
|
/** Group-implied pairs, in batch then component then group order. */
|
|
12107
12162
|
const groupPairs = [];
|
|
12108
12163
|
/** Every path a surviving group claimed, so the mined arm cannot re-propose one. */
|
|
@@ -12142,11 +12197,17 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
12142
12197
|
skipped += 1;
|
|
12143
12198
|
continue;
|
|
12144
12199
|
}
|
|
12200
|
+
/** This batch's unresolvable keys, so the warning below can name the spellings that failed. */
|
|
12201
|
+
const unresolvedKeys = [];
|
|
12145
12202
|
for (const group of partition.groups) {
|
|
12203
|
+
const dropped = group.memberKeys.filter((key) => offeredKeyFor(keyed, key) === void 0);
|
|
12204
|
+
unresolved += dropped.length;
|
|
12205
|
+
unresolvedKeys.push(...dropped);
|
|
12146
12206
|
const members = resolveKeys(keyed, group.memberKeys);
|
|
12147
12207
|
if (members.length < 2) continue;
|
|
12148
12208
|
if (new Set(group.memberKeys.flatMap((key) => {
|
|
12149
|
-
const
|
|
12209
|
+
const canonical = offeredKeyFor(keyed, key);
|
|
12210
|
+
const id = canonical === void 0 ? void 0 : componentOfKey.get(canonical);
|
|
12150
12211
|
return id === void 0 ? [] : [id];
|
|
12151
12212
|
})).size !== 1) continue;
|
|
12152
12213
|
/** The keeper is the OLDEST member: the lowest corpus offset, the same rule a pair uses. */
|
|
@@ -12172,6 +12233,7 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
12172
12233
|
}
|
|
12173
12234
|
grouped.add(keeper.path);
|
|
12174
12235
|
}
|
|
12236
|
+
if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm dedup batch of ${batch.length} components dropped ${unresolvedKeys.length} member keys naming no offered member (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
|
|
12175
12237
|
}
|
|
12176
12238
|
/**
|
|
12177
12239
|
* Groups first, then the mined pairs above the DETERMINISTIC floor that no group claimed. The
|
|
@@ -12191,7 +12253,8 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
12191
12253
|
components: components.length,
|
|
12192
12254
|
llmGroups,
|
|
12193
12255
|
vetoed: proposed.length - decisions.length,
|
|
12194
|
-
skipped
|
|
12256
|
+
skipped,
|
|
12257
|
+
unresolved
|
|
12195
12258
|
},
|
|
12196
12259
|
/**
|
|
12197
12260
|
* On this arm a vetoed pair is one the MODEL grouped as the same memory, or one that cleared
|
|
@@ -12202,11 +12265,13 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
12202
12265
|
*
|
|
12203
12266
|
* `judged` is false when a batch's call failed, because those components were never partitioned:
|
|
12204
12267
|
* their pairs reach the veto only through the mined arm, so a night that lost a call cannot say
|
|
12205
|
-
* whether a pair it did not see is still a candidate.
|
|
12268
|
+
* whether a pair it did not see is still a candidate. An unresolved member key is the same
|
|
12269
|
+
* hazard from the answer side — a group the phase could not fully map was not fully judged —
|
|
12270
|
+
* so it holds the sweep back the same way.
|
|
12206
12271
|
*/
|
|
12207
12272
|
{
|
|
12208
12273
|
vetoed: vetoedPairs(proposed),
|
|
12209
|
-
judged: skipped === 0
|
|
12274
|
+
judged: skipped === 0 && unresolved === 0
|
|
12210
12275
|
}
|
|
12211
12276
|
),
|
|
12212
12277
|
llmCalls
|
|
@@ -12631,6 +12696,7 @@ const edgeTyping = (env) => Effect.gen(function* () {
|
|
|
12631
12696
|
contradictions: 0,
|
|
12632
12697
|
promoted: 0,
|
|
12633
12698
|
skipped: 0,
|
|
12699
|
+
unresolved: 0,
|
|
12634
12700
|
capped: 0,
|
|
12635
12701
|
duplicates: 0,
|
|
12636
12702
|
tasksMinted: 0,
|
|
@@ -12697,6 +12763,13 @@ const edgeTyping = (env) => Effect.gen(function* () {
|
|
|
12697
12763
|
let capped = 0;
|
|
12698
12764
|
/** Second-and-later verdicts naming a key their batch had already answered for. */
|
|
12699
12765
|
let duplicates = 0;
|
|
12766
|
+
/**
|
|
12767
|
+
* Verdicts whose key resolved to no offered pair, so they were dropped unacted. Dropping is the
|
|
12768
|
+
* safe outcome and stays; the count is what makes a SYSTEMATIC pattern visible — a model naming
|
|
12769
|
+
* keys in a spelling the resolver refuses drops every verdict of every batch, and a night that
|
|
12770
|
+
* judged nothing looked identical to a night whose model answered nothing (issue #58).
|
|
12771
|
+
*/
|
|
12772
|
+
let unresolved = 0;
|
|
12700
12773
|
let llmCalls = 0;
|
|
12701
12774
|
/**
|
|
12702
12775
|
* Contradictions this night detected for the FIRST time, so below the promotion gate.
|
|
@@ -12737,18 +12810,27 @@ const edgeTyping = (env) => Effect.gen(function* () {
|
|
|
12737
12810
|
* rather than silently swallowed, so a model doing this is visible in a night's report.
|
|
12738
12811
|
*/
|
|
12739
12812
|
const answered = /* @__PURE__ */ new Set();
|
|
12813
|
+
/** This batch's dropped verdicts, so the warning below can name the spellings that failed. */
|
|
12814
|
+
const unresolvedKeys = [];
|
|
12740
12815
|
for (const verdict of answer.verdicts) {
|
|
12741
12816
|
/**
|
|
12742
12817
|
* The key is resolved through the kernel, so an invented key yields no candidate and no
|
|
12743
|
-
* write.
|
|
12818
|
+
* write. The CANONICAL key feeds the repeat guard, so `m1` and its label-prefixed spelling
|
|
12819
|
+
* `pair_m1` in one answer are one pair answered twice, not two pairs.
|
|
12744
12820
|
*/
|
|
12745
|
-
const
|
|
12821
|
+
const pairKey = offeredKeyFor(keyed, verdict.pairKey);
|
|
12822
|
+
if (pairKey === void 0) {
|
|
12823
|
+
unresolved += 1;
|
|
12824
|
+
unresolvedKeys.push(verdict.pairKey);
|
|
12825
|
+
continue;
|
|
12826
|
+
}
|
|
12827
|
+
const [candidate] = resolveKeys(keyed, [pairKey]);
|
|
12746
12828
|
if (candidate === void 0) continue;
|
|
12747
|
-
if (answered.has(
|
|
12829
|
+
if (answered.has(pairKey)) {
|
|
12748
12830
|
duplicates += 1;
|
|
12749
12831
|
continue;
|
|
12750
12832
|
}
|
|
12751
|
-
answered.add(
|
|
12833
|
+
answered.add(pairKey);
|
|
12752
12834
|
judged += 1;
|
|
12753
12835
|
if (!assertsEdge(verdict)) continue;
|
|
12754
12836
|
if (assertsContradiction(verdict)) {
|
|
@@ -12851,14 +12933,18 @@ const edgeTyping = (env) => Effect.gen(function* () {
|
|
|
12851
12933
|
const [subject, object] = verdict.direction === "src_to_dst" ? [candidate.pair.src, candidate.pair.dst] : [candidate.pair.dst, candidate.pair.src];
|
|
12852
12934
|
if (yield* stampFile(env, subject, [link(verdict.rel, hrefFor(object)), meta("memhtml-updated", env.at)])) typed += 1;
|
|
12853
12935
|
}
|
|
12936
|
+
if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm edge-typing batch of ${batch.length} dropped ${unresolvedKeys.length} verdicts naming no offered pair (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
|
|
12854
12937
|
}
|
|
12855
12938
|
/**
|
|
12856
12939
|
* The single-detection contradictions become tasks in the SAME commit as the promotions. The
|
|
12857
12940
|
* sweep is gated on a night that judged its whole candidate set: `skipped` counts pairs whose
|
|
12858
12941
|
* batch's call failed as well as pairs whose endpoint the tree no longer holds, and a pair the
|
|
12859
12942
|
* model was never asked about must not read as a pair the model stopped contradicting.
|
|
12943
|
+
* `unresolved` is the same hazard from the answer side — a verdict the phase could not map to a
|
|
12944
|
+
* pair is a pair that was never judged, so its held-back contradiction must not close as "no
|
|
12945
|
+
* longer detected" over a misspelled key.
|
|
12860
12946
|
*/
|
|
12861
|
-
const tasks = yield* mintContradictionTasks(env, deferred, skipped === 0);
|
|
12947
|
+
const tasks = yield* mintContradictionTasks(env, deferred, skipped === 0 && unresolved === 0);
|
|
12862
12948
|
const counts = {
|
|
12863
12949
|
candidates: candidates.length,
|
|
12864
12950
|
judged,
|
|
@@ -12866,6 +12952,7 @@ const edgeTyping = (env) => Effect.gen(function* () {
|
|
|
12866
12952
|
contradictions,
|
|
12867
12953
|
promoted,
|
|
12868
12954
|
skipped,
|
|
12955
|
+
unresolved,
|
|
12869
12956
|
capped,
|
|
12870
12957
|
duplicates,
|
|
12871
12958
|
tasksMinted: tasks.minted,
|
|
@@ -13382,6 +13469,12 @@ const entityResolution = (env) => Effect.gen(function* () {
|
|
|
13382
13469
|
/** Model calls that came back malformed. The sweep's precondition reads this; see below. */
|
|
13383
13470
|
let callsFailed = 0;
|
|
13384
13471
|
/**
|
|
13472
|
+
* Cluster member keys (or canonical keys) resolving to no offered member, dropped unacted. The
|
|
13473
|
+
* drop is the safe outcome and stays; the count makes a systematic naming pattern visible
|
|
13474
|
+
* instead of reading as a night in which the model proposed no merges (issue #58).
|
|
13475
|
+
*/
|
|
13476
|
+
let unresolved = 0;
|
|
13477
|
+
/**
|
|
13385
13478
|
* Every pair this night deferred to a human, as a value rather than only a count.
|
|
13386
13479
|
*
|
|
13387
13480
|
* This is issue #44's motivating case in one variable. The phase used to report
|
|
@@ -13493,6 +13586,8 @@ const entityResolution = (env) => Effect.gen(function* () {
|
|
|
13493
13586
|
callsFailed += 1;
|
|
13494
13587
|
continue;
|
|
13495
13588
|
}
|
|
13589
|
+
/** This shard's unresolvable keys, so the warning below names the spellings that failed. */
|
|
13590
|
+
const unresolvedKeys = [];
|
|
13496
13591
|
for (const cluster of clustering.clusters) {
|
|
13497
13592
|
/**
|
|
13498
13593
|
* A key the batch never offered resolves to nothing, so an invented member cannot become a
|
|
@@ -13500,6 +13595,9 @@ const entityResolution = (env) => Effect.gen(function* () {
|
|
|
13500
13595
|
* canonical is outside it contradicts itself, and guessing which half was meant would be
|
|
13501
13596
|
* the caller inventing a merge.
|
|
13502
13597
|
*/
|
|
13598
|
+
const droppedKeys = [...cluster.memberKeys, cluster.canonicalKey].filter((key) => offeredKeyFor(keyed, key) === void 0);
|
|
13599
|
+
unresolved += droppedKeys.length;
|
|
13600
|
+
unresolvedKeys.push(...droppedKeys);
|
|
13503
13601
|
const memberNames = resolveKeys(keyed, cluster.memberKeys).map((centroid) => centroid.name);
|
|
13504
13602
|
const [canonicalMember] = resolveKeys(keyed, [cluster.canonicalKey]);
|
|
13505
13603
|
if (canonicalMember === void 0 || !memberNames.includes(canonicalMember.name)) continue;
|
|
@@ -13558,6 +13656,7 @@ const entityResolution = (env) => Effect.gen(function* () {
|
|
|
13558
13656
|
});
|
|
13559
13657
|
}
|
|
13560
13658
|
}
|
|
13659
|
+
if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm entity-resolution ${entityType} batch of ${shard.length} dropped ${unresolvedKeys.length} cluster keys naming no offered member (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
|
|
13561
13660
|
}
|
|
13562
13661
|
}
|
|
13563
13662
|
/**
|
|
@@ -13595,6 +13694,8 @@ const entityResolution = (env) => Effect.gen(function* () {
|
|
|
13595
13694
|
aliasMerges,
|
|
13596
13695
|
pendingCorroboration,
|
|
13597
13696
|
reviewCandidates,
|
|
13697
|
+
callsFailed,
|
|
13698
|
+
unresolved,
|
|
13598
13699
|
tasksMinted: 0,
|
|
13599
13700
|
tasksFramed: 0,
|
|
13600
13701
|
tasksDismissed: 0,
|
|
@@ -13620,7 +13721,12 @@ const entityResolution = (env) => Effect.gen(function* () {
|
|
|
13620
13721
|
* 1. The old early return on `rewrites.size === 0` would have skipped exactly the night this
|
|
13621
13722
|
* feature exists for: a night whose only outcome was deferrals is a night with no rewrites.
|
|
13622
13723
|
*/
|
|
13623
|
-
|
|
13724
|
+
/**
|
|
13725
|
+
* `unresolved === 0` joins the sweep gate for the reason `callsFailed === 0` is already in it: a
|
|
13726
|
+
* cluster key the phase could not map to a member is a name that was never judged, and sweeping
|
|
13727
|
+
* against a night that lost part of an answer closes reviews over a misspelling.
|
|
13728
|
+
*/
|
|
13729
|
+
const tasks = yield* mintReviewTasks(env, deferred, model !== void 0 && callsFailed === 0 && unresolved === 0);
|
|
13624
13730
|
let rewritten = 0;
|
|
13625
13731
|
for (const [path, pairs] of [...rewrites.entries()].sort(([left], [right]) => left < right ? -1 : 1)) {
|
|
13626
13732
|
const html = yield* readFileBytes(env, path);
|
|
@@ -14617,6 +14723,12 @@ const taskDetection = (env) => Effect.gen(function* () {
|
|
|
14617
14723
|
let dismissed = 0;
|
|
14618
14724
|
let skipped = 0;
|
|
14619
14725
|
/**
|
|
14726
|
+
* Findings whose key resolved to no offered member, dropped unacted. The drop is the safe
|
|
14727
|
+
* outcome and stays; the count makes a systematic pattern visible, because a night whose every
|
|
14728
|
+
* finding named an unresolvable key otherwise reads as a night with no open work (issue #58).
|
|
14729
|
+
*/
|
|
14730
|
+
let unresolved = 0;
|
|
14731
|
+
/**
|
|
14620
14732
|
* Every key this night's scan SAW, whether or not it minted and whether or not it cleared the floor.
|
|
14621
14733
|
* The sweep's input; see the `liveKeys.add` below for why the floor is not a filter here.
|
|
14622
14734
|
*/
|
|
@@ -14644,11 +14756,20 @@ const taskDetection = (env) => Effect.gen(function* () {
|
|
|
14644
14756
|
* because it is called one key at a time here — a finding names one member.
|
|
14645
14757
|
*/
|
|
14646
14758
|
const answered = /* @__PURE__ */ new Set();
|
|
14759
|
+
/** This batch's dropped findings, so the warning below can name the spellings that failed. */
|
|
14760
|
+
const unresolvedKeys = [];
|
|
14647
14761
|
for (const finding of answer.findings) {
|
|
14648
|
-
|
|
14762
|
+
/** The CANONICAL key feeds the repeat guard, same as edge-typing's, and for the same reason. */
|
|
14763
|
+
const memberKey = offeredKeyFor(keyed, finding.memberKey);
|
|
14764
|
+
if (memberKey === void 0) {
|
|
14765
|
+
unresolved += 1;
|
|
14766
|
+
unresolvedKeys.push(finding.memberKey);
|
|
14767
|
+
continue;
|
|
14768
|
+
}
|
|
14769
|
+
const [row] = resolveKeys(keyed, [memberKey]);
|
|
14649
14770
|
if (row === void 0) continue;
|
|
14650
|
-
if (answered.has(
|
|
14651
|
-
answered.add(
|
|
14771
|
+
if (answered.has(memberKey)) continue;
|
|
14772
|
+
answered.add(memberKey);
|
|
14652
14773
|
findings += 1;
|
|
14653
14774
|
/**
|
|
14654
14775
|
* The key is the SOURCE PATH plus the normalized sentence, so the same commitment found again
|
|
@@ -14694,13 +14815,17 @@ const taskDetection = (env) => Effect.gen(function* () {
|
|
|
14694
14815
|
else if (outcome === "framed") framed += 1;
|
|
14695
14816
|
else if (outcome === "dismissed") dismissed += 1;
|
|
14696
14817
|
}
|
|
14818
|
+
if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm task-detection batch of ${batch.length} dropped ${unresolvedKeys.length} findings naming no offered member (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
|
|
14697
14819
|
}
|
|
14698
14820
|
/**
|
|
14699
14821
|
* The sweep, only from a full-strength scan. `skipped > 0` means at least one batch's memories
|
|
14700
14822
|
* went unread, so a finding of theirs is missing from `liveKeys` because the phase could not look
|
|
14701
|
-
* rather than because it is gone.
|
|
14823
|
+
* rather than because it is gone. `unresolved > 0` is the same hazard from the answer side: the
|
|
14824
|
+
* model reported a finding the phase could not map to a member, so its detection key was never
|
|
14825
|
+
* constructed, and sweeping against that would close a live task because the model misspelled a
|
|
14826
|
+
* key rather than because the finding vanished.
|
|
14702
14827
|
*/
|
|
14703
|
-
const closed = skipped === 0 ? yield* closeVanishedDetections(env, TASK_DETECT_DETECTOR, liveKeys) : 0;
|
|
14828
|
+
const closed = skipped === 0 && unresolved === 0 ? yield* closeVanishedDetections(env, TASK_DETECT_DETECTOR, liveKeys) : 0;
|
|
14704
14829
|
const counts = {
|
|
14705
14830
|
candidates: candidates.length,
|
|
14706
14831
|
batches: batches.length,
|
|
@@ -14712,7 +14837,8 @@ const taskDetection = (env) => Effect.gen(function* () {
|
|
|
14712
14837
|
dismissed,
|
|
14713
14838
|
closed,
|
|
14714
14839
|
capped: budget.overflow,
|
|
14715
|
-
skipped
|
|
14840
|
+
skipped,
|
|
14841
|
+
unresolved
|
|
14716
14842
|
};
|
|
14717
14843
|
/**
|
|
14718
14844
|
* A refresh writes a `memhtml-updated` stamp, which is a staged file, so it commits — the queue's
|
|
@@ -14748,7 +14874,8 @@ const ZERO = {
|
|
|
14748
14874
|
dismissed: 0,
|
|
14749
14875
|
closed: 0,
|
|
14750
14876
|
capped: 0,
|
|
14751
|
-
skipped: 0
|
|
14877
|
+
skipped: 0,
|
|
14878
|
+
unresolved: 0
|
|
14752
14879
|
};
|
|
14753
14880
|
|
|
14754
14881
|
//#endregion
|
|
@@ -16861,4 +16988,4 @@ const latest = (left, right) => left === null ? right : right === null ? left :
|
|
|
16861
16988
|
|
|
16862
16989
|
//#endregion
|
|
16863
16990
|
export { STATE_DB_PATH as $, IndexRecorder as A, IndexGit as B, ModelClient as C, EmbeddingsLive as D, Embeddings as E, makeRetrieval as F, MIGRATIONS_DIR as G, sanitizeFtsQuery as H, reinforce as I, Store as J, STATE_MIGRATIONS_DIR as K, Indexer as L, persistScanned as M, readWatermark as N, EMBED_DIM as O, Retrieval as P, SLEEP_REPORTS_DIR as Q, makeIndexer as R, runDiscrimination as S, wrapAsData as T, DatabaseService as U, makeGitPort as V, makeDatabase as W, makeStore as X, expandRoot as Y, INDEX_DB_PATH as Z, meta as _, parseSidecar as a, makeGit as at, isSleepPhase as b, generateArtifacts as c, setMeta as ct, allPaths as d, fenceOpeningOf as dt, STATE_SIDECAR_PATH as et, danglingEdges as f, REINFORCE_SIGNALS as ft, link as g, hrefFor as h, makeSleep as i, Git as it, makeIndexRecorder as j, EMBED_WATERMARK as k, DETECTION_PREFIX as l, isValidDatetime as lt, applyHeadEdits as m, scanTraceRoot as n, initRepo as nt, renderSidecar as o, commitSubject as ot, publishRows as p, frameKeyOf as pt, STATE_SCHEMA as q, Sleep as r, readFileOrNull as rt, archivedFormOf as s, checkMemory as st, mergeTailExtract as t, attemptIo as tt, accessRows as u, closesFence as ut, unlink as v, ModelClientLive as w, discriminationGate as x, SLEEP_PHASES as y, readIndexState as z };
|
|
16864
|
-
//# sourceMappingURL=dist-
|
|
16991
|
+
//# sourceMappingURL=dist-DgKlozi6.mjs.map
|