Commit c3a7a4a
committed
feat(layers): select L1 wake-up drawers by salience
Issue #1629 asked why wake-up did not read like the essential story it
promises. Ordering was half the answer and is fixed. The other half is
what gets in: L1 has room for about 15 lines, and it filled them with
whatever sorted highest, including harness injection blocks, raw tool
output, markdown tables, bare timestamp lines, three near-identical
chunks of one transcript, and snippets that opened mid-word. On a
149k-drawer palace the result read as fragment soup.
Selection now happens between sorting and rendering.
_l1_salience(text) scores a candidate. Negative means junk and drops it.
Exclusion is deliberately narrow and structural, never lexical:
- a harness wrapper *opening* the drawer (<system-reminder>,
<command-message>, <local-command-caveat>, <task-notification>,
[SYSTEM NOTIFICATION), matched with startswith after normalization
- a timestamp-only or rule-only drawer
- text below a 20-character floor
- pipe/dash density above 0.18, which is a table, a diff or an ASCII rule
- a prose ratio below 0.78, the fraction of characters that are letters
or spaces
The prose ratio is the load-bearing rule and the general form of a
marker list: JSON, ls output, env dumps, URL lists, log lines and bare
code fences all fail it without any marker being named, while an
engineering sentence quoting a path, a version pin or a fence passes.
Measured over the 21-item corpus in
test_l1_salience_drops_soup_without_markers, soup lands in 0.40 to 0.82
and prose in 0.84 to 0.99. The floor sits at 0.78, deliberately below
the gap: a false drop loses a real memory forever, a false keep costs
one wake-up line. The residue that clears it, word-heavy tracebacks and
diffs, is demoted rather than excluded.
Nothing is excluded for merely mentioning tooling. tool_use, tool_result,
fences, "Exit code:" and "cwd was reset" cost a ranking point and nothing
more, because engineering writing quotes those constantly. Positive
scoring is outcome wording (2 points), a clean sentence or heading start
(1), and freedom from tool noise (1). Outcome is worth strictly more than
both presentation signals, otherwise a drawer that is both an outcome and
a little noisy ties with background chatter that merely reads cleanly:
outcome + clean 4 chatter + clean 2
outcome + noisy 3 chatter + noisy 1
Anchoring rather than substring matching is the whole correctness
argument here. An earlier revision also dropped any body that *repeated*
a wrapper, reasoning that a repeat means concatenated injections. That
rule was unanchored and re-created the same defect: an engineer writing
about why a reminder fired twice names the tag twice. It is gone.
Genuine concatenated soup is already caught by density and the prose
floor, neither of which needs a marker named.
_l1_select applies the caps. At most L1_MAX_PER_SOURCE (2) lines from one
source file, so a single long transcript cannot own the story. Drawers
with no source_file are uncapped, because the cap exists to stop one
known file dominating and lumping unattributed drawers under one empty
key would do the opposite. Near-duplicates collapse on whole-body word
overlap at 0.8, not on a leading slice: mined session summaries routinely
share a templated opening, and matching the first 80 characters collapsed
three summaries reporting a migration, a revert and an RTL fix into one
and lost two outcomes silently. Whole-body overlap scores that case at
0.27 and keeps all three, while genuine restatements stay above 0.84.
The comparison list never exceeds max_drawers, so selection stays linear:
measured on this machine at 8.7 ms for 500 candidates, 16.9 ms for 1,000
and 34.2 ms for 2,000, which is the MAX_SCAN ceiling, against the repo's
100 ms startup-injection budget.
Rendering groups rooms in the order the ranked list arrives, not
alphabetically. Grouping by room and then sorting room names before the
MAX_CHARS truncation undid the ranking at the last step: a salience-4
outcome in a room named zzz_outcomes was cut while salience-2 chatter in
aaa_trivia rendered.
_l1_snippet composes the line: start after the next sentence boundary
when a chunk opens mid-sentence, cut on a word boundary. The result is
always a contiguous substring of the drawer, never a paraphrase, so the
verbatim promise holds. Filtered drawers are untouched in the palace and
still returned by L2 and L3.
When every candidate scores as junk, L1 renders exactly what it rendered
before the filter. An empty wake-up is the worse failure.
No LLM call, no embedding, no I/O: a few passes over text already in
memory, because L1 runs inside the wake-up hook's latency budget.
Two details for non-English palaces. The clean-start point tests "not
lowercase" rather than "is uppercase", so Arabic, Hebrew and CJK are not
permanently denied a point that every English drawer collects. And
L1_OUTCOME_KEYWORDS is English, which its docstring says along with the
real two-step for extending it: the regex is compiled once at import, so
appending to the tuple alone does nothing, and _l1_compile_outcome_re is
exposed for that reason. The junk, cap, duplicate and boundary rules are
language-neutral.
Known gap, left for a follow-up to keep this in scope: the outcome
keyword list has no failure vocabulary. "died", "crashed", "OOM", "timed
out" and "regressed" are absent, so a drawer reporting a failure ranks as
chatter unless the sentence happens to also say something passed.
Orthogonal to PR #1950 (per-drawer salience from the dynamics model plus
retrieval potentiation). That work scores drawers at retrieval time in
dynamics.py/searcher.py/service.py/mcp_server.py; this is snippet-level
composition inside layers.py and touches none of those files. If #1950
lands, its per-drawer signal can feed the importance key L1 already sorts
on, and this filter keeps doing the part it does.
Tests: salience edges (anchored wrapper, prose naming a wrapper twice,
date-only, table soup, short text, outcome boost, fragment vs whole
thought, the ISO-designator false positive, non-Latin prose scoring like
Latin), a marker-free soup corpus, noise demotion ordering, snippet
boundaries (sentence start, no-boundary passthrough, word-boundary cut,
newline collapse), selection (per-source cap, unattributed drawers
uncapped, templated-lead summaries kept, near-duplicate suppression, tier
order, all-junk empty), render order under the character cap, and end to
end through Layer1.generate including the fallback and a
verbatim-substring assertion.1 parent e73e75b commit c3a7a4a
4 files changed
Lines changed: 803 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
11 | 15 | | |
12 | 16 | | |
13 | 17 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
77 | 78 | | |
78 | 79 | | |
79 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
80 | 378 | | |
81 | 379 | | |
82 | 380 | | |
| |||
156 | 454 | | |
157 | 455 | | |
158 | 456 | | |
159 | | - | |
| 457 | + | |
160 | 458 | | |
161 | | - | |
162 | | - | |
163 | | - | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
164 | 477 | | |
165 | 478 | | |
166 | 479 | | |
| |||
170 | 483 | | |
171 | 484 | | |
172 | 485 | | |
173 | | - | |
| 486 | + | |
174 | 487 | | |
175 | 488 | | |
176 | 489 | | |
177 | 490 | | |
178 | 491 | | |
179 | 492 | | |
180 | 493 | | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
| 494 | + | |
185 | 495 | | |
186 | 496 | | |
187 | 497 | | |
| |||
0 commit comments