Uh oh!
There was an error while loading. Please reload this page.
Follow-up: carry PR #701's stranded review fixes (skip the wasted resettle scan, MaintenanceReport symmetry, span visibility, LLP gloss) - #706
Conversation
… MaintenanceReport symmetry, span visibility, LLP gloss PR #701 was squash-merged at head 287b67b, before the round-2 review fixes in cc82d6f were pushed, so four verified fixes never reached master. - Hoist a cheap `compactionDue` check above the `hasResettleCandidate` row scan and gate the scan on `!compactionDue`. Recognition of a foreign sorted `replace` outranks the resettle check, so the first tick after each foreign replace paid a complete single-column scan of the day purely to discard the answer. - Add `totalRebaselined` to `MaintenanceReport` beside `totalCompacted`, and let `query.js` read it instead of re-deriving the count. - Tag the enclosing `maintenance.partition` span with `rebaselined`; the `hyp_rebaselines` counter carries only the dataset, not the partition. - Give LLP 0199's bare `Extended-by: LLP 0207` the corpus's linked and glossed form. Co-Authored-By: Claude <noreply@anthropic.com>
Round-1 review of #706 approved the carry but flagged that none of the four stranded fixes was pinned by a committed test, plus two @ref nits. - Add three tests to test/core/cache-retention-maintenance.test.js, in the foreign-sorted-replace block: - `totalRebaselined === 1` on a re-baselining run, and `=== 0` once converged (pins the MaintenanceReport symmetry fix). - a capturing TracerProvider asserting the maintenance.partition span carries `rebaselined: true` (pins the span-attribute fix). - a partition already due for compaction: assert the resettle candidate's data file is read once, not twice, by spying on `fs.readFileSync` (pins the scan-skip fix). hasResettleCandidate's return value is otherwise unobservable once compactionDue is true (it's discarded via `||`), so this is the cheapest honest signal available; each new test was verified to fail when its corresponding fix is reverted. - Retarget the scan-skip gate's @ref from LLP 0207#foreign-replace to #outranks-resettle: the gloss ("recognition ... still outranks it") is that anchor's actual subject, not the recognition test's. - Drop the @ref on the span-attribute comment: #re-baseline settles the cursor-write shape, not telemetry, so citing it was close to mechanical. The prose rationale stays; it's the useful part. - Amend the PR body's claim about item 1: `needsCompaction` (pure, read-only) is now evaluated unconditionally in the re-settle path where the old `||` short-circuited past it, so more moved than "only the scan's side effect is skipped." Co-Authored-By: Claude <noreply@anthropic.com>
philcunliffe
commented
Aug 11, 2026
Review round 1 - head |
- test/core/cache-retention-maintenance.test.js: the resettle-scan-skip test asserted a global .parquet readFileSync count of 1 for the whole maintainCache tick, not just reads the gate governs. Any future second legitimate read elsewhere in the tick would break it with a message that misdirects the next reader. Switch to capturing a stack trace per .parquet read and asserting none pass through hasResettleCandidate, attributing each read to its caller instead of counting tick-wide. Verified both directions: passes at this head (3x, no flake), and fails with the expected message when the !compactionDue && gate in src/core/cache/maintenance.js is reverted, showing hasResettleCandidate in the offending stack. - PR body: item 2's exemplar list cited llp/0012:9, 0017:9, 0036:9, 0041:8, 0191:9 as using the linked-and-glossed Extended-by form, but only 0191 actually carries a link; the other four are gloss-only. Replaced with docs confirmed to use the linked form: llp/0106:9, 0129:9, 0158:9, 0180:9, 0182:9, 0188:9, 0190:9, 0191:9. (0201, also suggested, only has a backward "Extends" pointer, not "Extended-by", so it was excluded.) Co-Authored-By: Claude <noreply@anthropic.com>
philcunliffe
commented
Aug 11, 2026
Review round 2 - head |
philcunliffe
commented
Aug 11, 2026
Neutral triage at head |
# Conflicts: # llp/0199-maintenance-compaction-convergence.decision.md
The conflict resolution replaced the 0207 gloss that landed on master with this branch's alternative wording. Both describe LLP 0207 accurately, but rewording a gloss already on an Accepted doc is a content edit, where adding the link is the permitted mechanical one. Keeping master's text also matches how PR #706 resolved the same line, so the two open PRs no longer diverge and whichever merges second will not re-conflict here.
philcunliffe
commented
Aug 11, 2026
Triage (head |
| finding | round | state at b86c642 |
|---|---|---|
| None of the four carried fixes was test-pinned | 1 | resolved - pins at cache-retention-maintenance.test.js:891/901/913 (totalRebaselined), :1039-1070 (span attribute), :1080-1131 (scan-skip) |
@ref targeted #foreign-replace while glossing #outranks-resettle | 1 | resolved - maintenance.js:314 now carries 0207#outranks-resettle [constrained-by]; both anchors exist in LLP 0207 |
Mechanical #re-baseline@ref on the span-attribute site | 1 | resolved - removed; the sole 0207#re-baseline ref is the [implements] on rebaselineCursor, which is correct |
| PR body overstated item 1 | 1 | resolved - body now names the needsCompaction evaluation change explicitly |
| Scan-skip assertion was a global read count, not attribution | 2 | resolved - now captures a stack per .parquet read and asserts no frame contains hasResettleCandidate, with a stacks.length > 0 sanity check |
Attribution test's discriminating frame sits near V8's default 10-frame Error.stackTraceLimit, so a deeper call chain could silently blind it | triage note | unresolved, preference |
Why the residual finding does not block
Confirmed real: grep stackTraceLimit over the test file at this head returns 0 matches, so the hazard stands. But the worst case is a regression test going blind, not a production defect: no wrong behaviour, no data loss, no crash, no perf regression.
It is also not being dropped. It is recorded in open issue #707, and PR #708 (Fixes #707) is in flight right now and adds precisely the missing guard (Error.stackTraceLimit raised while the mock is installed and restored afterwards, test/core/cache-retention-maintenance.test.js:1094-1112 on that branch). So the deferral has a named owner and a live fix rather than an open-ended promise. No new follow-up issue is warranted, and filing one would duplicate #707.
Shippability, independently checked
The specific risk here was the merge with master: #698 reworked the same cache-maintenance path this PR changes the gate logic around, and the files auto-merged with no conflict, which is exactly where a change disappears silently.
- Both sides coexist.Follow-up: carry PR #701's stranded review fixes (skip the wasted resettle scan, MaintenanceReport symmetry, span visibility, LLP gloss) #706's gate (
compactionDue:303,hasResettle:317,shouldCompact:320) feeds the branch where Cache compaction sizes files by bytes written, not the in-memory batch estimate #698's sizing lands (r.compactedBytesWritten = result.bytesWritten:351,openStreamingAppend:20/:657,bytesWritten:752), and Cache compaction sizes files by bytes written, not the in-memory batch estimate #698'sbytes_writtenspan attribute (:167-168) tags the samemaintenance.partitionspan as Follow-up: carry PR #701's stranded review fixes (skip the wasted resettle scan, MaintenanceReport symmetry, span visibility, LLP gloss) #706'srebaselinedattribute (:337). Neither displaced the other. - All four carried fixes present: the gate trio;
totalRebaselinedat all three sites (maintenance.jsdeclared :122, incremented :177, returned :188;types.d.ts:304;commands/query.js:330); the span attribute atmaintenance.js:337. llp/0199Extended-by:line carries both forward-refs as working links with master's landed gloss text verbatim (diffed againstorigin/master; only the link wrapping and the;separator differ). That is the permitted mechanical edit on anAccepteddoc, not a rewrite of settled prose.
Gates, as observed on the merged tree
npm test3943 pass / 0 fail / 1 skipped (3944 tests), exit 0 - including master's new cache-compaction-file-size.test.js from #698 alongside this PR's three new pins, so both PRs' suites pass on the combined code. npm run typecheck clean. Cache smokes on the merged tree: cache_lifecycle_maintenance, incremental_sink_compaction, cache_roundtrip all ok.
Not verified
The revert-discrimination claims (each new test failing individually when its target is reverted) were not re-reproduced this round; they were checked twice previously, and this round confirmed only that the tests are present and passing. Issue #707's body was not read beyond its title and open state.
Nothing blocks this. The PR is being flipped out of draft state as needed and held for you to merge.
Uh oh!
There was an error while loading. Please reload this page.
master landed PR #706 (815b999), which carried the same maintenance.js / types.d.ts / query.js / LLP 0199 changes this branch had. Those files are byte-identical on both sides and merged cleanly. The one conflict is the scan-skip test, where master has PR #706's version and this branch has the #707 fix on top of it (raise Error.stackTraceLimit around the readFileSync mock, restore it in finally, and assert positively that some captured stack names compactGeneration so the negative assertion cannot pass vacuously on a truncated stack). Kept this branch's version: it is master's test plus those guards.
* Carry PR #701's stranded review fixes: skip the wasted resettle scan, MaintenanceReport symmetry, span visibility, LLP gloss PR #701 was squash-merged at head 287b67b, before the round-2 review fixes in cc82d6f were pushed, so four verified fixes never reached master. - Hoist a cheap `compactionDue` check above the `hasResettleCandidate` row scan and gate the scan on `!compactionDue`. Recognition of a foreign sorted `replace` outranks the resettle check, so the first tick after each foreign replace paid a complete single-column scan of the day purely to discard the answer. - Add `totalRebaselined` to `MaintenanceReport` beside `totalCompacted`, and let `query.js` read it instead of re-deriving the count. - Tag the enclosing `maintenance.partition` span with `rebaselined`; the `hyp_rebaselines` counter carries only the dataset, not the partition. - Give LLP 0199's bare `Extended-by: LLP 0207` the corpus's linked and glossed form. Co-Authored-By: Claude <noreply@anthropic.com> * Pin PR #706's carried fixes with tests; sharpen two @ref citations Round-1 review of #706 approved the carry but flagged that none of the four stranded fixes was pinned by a committed test, plus two @ref nits. - Add three tests to test/core/cache-retention-maintenance.test.js, in the foreign-sorted-replace block: - `totalRebaselined === 1` on a re-baselining run, and `=== 0` once converged (pins the MaintenanceReport symmetry fix). - a capturing TracerProvider asserting the maintenance.partition span carries `rebaselined: true` (pins the span-attribute fix). - a partition already due for compaction: assert the resettle candidate's data file is read once, not twice, by spying on `fs.readFileSync` (pins the scan-skip fix). hasResettleCandidate's return value is otherwise unobservable once compactionDue is true (it's discarded via `||`), so this is the cheapest honest signal available; each new test was verified to fail when its corresponding fix is reverted. - Retarget the scan-skip gate's @ref from LLP 0207#foreign-replace to #outranks-resettle: the gloss ("recognition ... still outranks it") is that anchor's actual subject, not the recognition test's. - Drop the @ref on the span-attribute comment: #re-baseline settles the cursor-write shape, not telemetry, so citing it was close to mechanical. The prose rationale stays; it's the useful part. - Amend the PR body's claim about item 1: `needsCompaction` (pure, read-only) is now evaluated unconditionally in the re-settle path where the old `||` short-circuited past it, so more moved than "only the scan's side effect is skipped." Co-Authored-By: Claude <noreply@anthropic.com> * Sharpen scan-skip test to stack attribution; fix PR #706 body citations - test/core/cache-retention-maintenance.test.js: the resettle-scan-skip test asserted a global .parquet readFileSync count of 1 for the whole maintainCache tick, not just reads the gate governs. Any future second legitimate read elsewhere in the tick would break it with a message that misdirects the next reader. Switch to capturing a stack trace per .parquet read and asserting none pass through hasResettleCandidate, attributing each read to its caller instead of counting tick-wide. Verified both directions: passes at this head (3x, no flake), and fails with the expected message when the !compactionDue && gate in src/core/cache/maintenance.js is reverted, showing hasResettleCandidate in the offending stack. - PR body: item 2's exemplar list cited llp/0012:9, 0017:9, 0036:9, 0041:8, 0191:9 as using the linked-and-glossed Extended-by form, but only 0191 actually carries a link; the other four are gloss-only. Replaced with docs confirmed to use the linked form: llp/0106:9, 0129:9, 0158:9, 0180:9, 0182:9, 0188:9, 0190:9, 0191:9. (0201, also suggested, only has a backward "Extends" pointer, not "Extended-by", so it was excluded.) Co-Authored-By: Claude <noreply@anthropic.com> * Scan-skip test goes blind if the call chain grows 3 frames (#707) `a partition already due for compaction skips the resettle-candidate row scan` attributes each `.parquet` read to its caller by capturing `new Error().stack` inside a `readFileSync` mock and asserting no stack passes through `hasResettleCandidate`. The discriminating frame sits at frame 8 of 10, and `Error.stackTraceLimit` defaults to 10. Three more frames anywhere between the mock and the caller (an icebird refactor, extra node:test mock internals, a wrapper in `resolver.js`) drop that frame, and a negative "no stack mentions X" assertion then passes vacuously: the test stays green even with the `!compactionDue &&` gate reverted. The `stacks.length > 0` sanity check only proved a read happened, not that the stacks were attributable, and the `new Error().stack ?? ''` fallback would store an unattributable empty string without complaint. Demonstrated by running with `Error.stackTraceLimit = 7` (standing in for the three extra frames) and the gate reverted: the old test passed. Two guards, because they cover different routes to the same blindness: 1. Raise `Error.stackTraceLimit` to 50 while the mock is installed, restoring the previous value in the existing `finally` so it is put back even if the test throws. This removes the practical hazard. 2. Assert positively that some captured stack names `compactGeneration`, the legitimate reader. It calls `scanRowsFromTable` from exactly the same depth as `hasResettleCandidate` does, so any truncation deep enough to hide the frame the negative assertion hunts for also hides this one and fails the test loudly. Asserting on `scanRowsFromTable` itself would not work: it sits one frame shallower and survives truncation that has already blinded the real check. This guard also catches the empty-string fallback. Under the same truncation with the gate still reverted, the hardened test fails; with the gate restored it passes, truncated or not. No production code changed. Co-Authored-By: Claude <noreply@anthropic.com> * LLP 0199: keep master's landed 0207 gloss, add only the link The conflict resolution replaced the 0207 gloss that landed on master with this branch's alternative wording. Both describe LLP 0207 accurately, but rewording a gloss already on an Accepted doc is a content edit, where adding the link is the permitted mechanical one. Keeping master's text also matches how PR #706 resolved the same line, so the two open PRs no longer diverge and whichever merges second will not re-conflict here. --------- Co-authored-by: test <test@test.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: neutral <neutral@hyparam.com>
Why this exists
PR #701 went through review, a fix worker applied four round-1 items and pushed
cc82d6ffd96e2216f4c219f349c107d06a046ee2, and then #701 was squash-merged athead
287b67bb- beforecc82d6flanded. #701 is nowMERGEDand closed,so its branch is invisible to the reconciler and the four verified fixes would
be silently lost.
Evidence that they never reached master:
git merge-base --is-ancestor cc82d6f origin/master-> falseorigin/master:src/core/cache/maintenance.jscontains zero occurrences ofcompactionDueorigin/master:src/core/cache/maintenance.jscontains zero occurrences ofsetAttribute('rebaselined'origin/master:src/core/cache/types.d.tscontains zero occurrences oftotalRebaselinedAll four files
cc82d6ftouches are byte-identical between287b67bandcurrent
origin/master, so each fix is carried over unchanged in intent.The four fixes
1. Skip the wasted re-settle scan (
src/core/cache/maintenance.js)Hoist a cheap
const compactionDue = opts.force || (grewSinceCompaction && needsCompaction(liveDir, cfg))above the
hasResettleCandidaterow scan, gate the scan on!compactionDue && settle,and set
shouldCompact = compactionDue || hasResettle.Recognition of a foreign sorted
replaceoutranks the re-settle check, so onthe first tick after each foreign replace a partition with no fallback row paid
a complete single-column scan of the day purely to discard the answer. The
boolean is unchanged (
compactionDue || hasResettleis the same disjunction asbefore); the row scan is skipped when its answer cannot matter. In exchange,
the cheap
needsCompactionstat-walk is now evaluated in the re-settle pathwhere the old
||short-circuited past it:needsCompactiononly reads(
readdirSync/statSync), so this trades a warm stat-walk for a fullsingle-column row scan with no semantic change.
Empirical verification (instrumented
hasResettleCandidatewith a callcounter, then reverted before committing):
test/core/cache-retention-maintenance.test.jstest/core/cache-resettle-sweep.test.jsThe 4 remaining calls are exactly the cases where the fallback-row scan is the
only possible trigger for compaction, so the sweep keeps working; the 4
eliminated calls are scans whose answer was discarded.
2. LLP 0199
Extended-bygloss (llp/0199-maintenance-compaction-convergence.decision.md)Give the bare
**Extended-by:** LLP 0207the corpus's usual linked + glossedform, matching
llp/0106:9,llp/0129:9,llp/0158:9,llp/0180:9,llp/0182:9,llp/0188:9,llp/0190:9,llp/0191:9.3.
MaintenanceReportsymmetry (types.d.ts,maintenance.js,commands/query.js)Add
totalRebaselined: numbertoMaintenanceReportand increment it besidetotalCompacted, soquery.jsreads the total the report already knows insteadof re-deriving it by filtering
report.partitions.maintainCacheis the onlyproducer of a
MaintenanceReport, so the new required field has one writer.4.
rebaselinedspan attribute (src/core/cache/maintenance.js)The
hyp_rebaselinescounter was the only in-daemon signal that a re-baselinehappened, and it carries only the dataset, not the partition. Tag the enclosing
maintenance.partitionspan so a trace query can find which day re-baselined.Note on PR #698
Open PR #698 (
fix/issue-697) rewrites this file heavily (streaming row groups,descriptor parking) and adds its own
span.setAttributeblock inmaintainCache, converting thewithSpancallback toasync (span) =>. Toavoid a needless conflict, item 4 here is deliberately not the original
cc82d6fshape (which restructured that same callback intoconst result = ... ; span.setAttribute(...) ; return result). Instead it is asingle line at the re-baseline site itself, using the repo's existing
getActiveSpan()helper (already used insrc/core/commands/policy.js):withSpanruns its callback undertracer.startActiveSpan, so the enclosingmaintenance.partitionspan is the active span there; instrumentation confirmedgetActiveSpan()resolves to a real span in all 4 re-baseline paths exercised bythe suite. This leaves the exact block #698 rewrites untouched.
Verified:
git merge origin/fix/issue-697into this branch auto-mergessrc/core/cache/maintenance.js,src/core/cache/types.d.tsandsrc/core/commands/query.jscleanly. The only conflict is the one-line**Extended-by:**metadata field inllp/0199, which #698 also rewrites (itadds a gloss for 0207 and 0209 but no link); resolving it is a union of the two
glosses.
Gate
npm test: 3901 pass, 0 fail, 6 skippednpm run typecheck: cleantest/core/llp-ref-hygiene.test.js: 11 pass, 0 failhyp smoke cache_lifecycle_maintenance: okhyp smoke incremental_sink_compaction: okhyp smoke cache_roundtrip: okIssue #700 was already closed by #701; this PR deliberately carries no
Fixes #...trailer.🤖 Generated with Claude Code