feat(miner): symbol_header_prefix kwarg in chunk_text - #1508
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a symbol_header_prefix parameter to the chunk_text function in mempalace/miner.py, allowing for optional chunk enrichment by prepending a header generated by a callback. Review feedback points out that this new parameter is not yet exposed in the primary mining entry points, which limits its accessibility in standard workflows. Additionally, it was noted that the current caching mechanism does not account for changes in the enrichment logic, and a docstring update was suggested to clarify the callback's parameter names to avoid confusion with the function itself.
| content: str, | ||
| source_file: str, | ||
| *, | ||
| symbol_header_prefix=None, |
There was a problem hiding this comment.
The symbol_header_prefix parameter is added here but not yet exposed in the process_file function (line 882) or the mine entry point. This makes the enrichment feature inaccessible for the standard mining workflow without further modifications to those functions. Additionally, since file_already_mined only checks source_mtime and NORMALIZE_VERSION, changes to the logic within a provided callback will not automatically trigger a re-mine of already processed files.
There was a problem hiding this comment.
Good catch on both. Wired symbol_header_prefix through process_file and the mine entry point (mine -> _mine_impl -> process_file -> chunk_text) as an optional kwarg, default None = exactly current behavior, in 57550a6 — so it's now reachable from the standard mining workflow without forking the path. On the cache key: agreed it's out of scope to solve here, so I documented it instead — both chunk_text and process_file docstrings now note that file_already_mined keys only on source_mtime + NORMALIZE_VERSION, so changing the callback does not auto-invalidate already-mined files; a re-mine needs --force or a NORMALIZE_VERSION bump. Added tests proving the kwarg flows end-to-end and that the default path is byte-identical to the no-kwarg call.
| source_file: file path used for room/topic inference and (when | ||
| ``symbol_header_prefix`` is supplied) chunk enrichment. | ||
| symbol_header_prefix: optional callable | ||
| ``(chunk_text, source_file, chunk_index) -> str``. When |
There was a problem hiding this comment.
There was a problem hiding this comment.
Done — applied your exact wording in 57550a6. The docstring now documents the callback as (chunk, source_file, chunk_index) -> str, so the first arg no longer collides with the function name chunk_text.
|
Closing — premature on my side; want to do more local validation before opening upstream. Will revisit. Patch lives on techempower-org fork for now. |
|
Local validation landed — reopening with new data. When I closed this on 2026-05-15 I said I wanted to do more local validation before opening upstream. That validation just landed as a 2×2 encoder × chunker ablation on 48 git-derived markdown probes. Posted in the parent discussion thread at #1384 discussioncomment-16950816. The relevant numbers:
Δ (heading-aware vs paragraph), per encoder:
The kwarg is encoder-conditional: chunking-axis variance is 12.5pp at base-MiniLM and ~2pp post-FT. Symbol-header enrichment has headroom to move recall when the encoder hasn't been calibrated to the domain — which is where most projects sit until they invest in domain FT. That gives this PR a clearer value proposition than the original framing did. Concretely:
xg-gh-25's "skip chunking for code, use structured extraction + call graph" framing in #1384 is the orthogonal answer for code-specific retrieval, but it requires a substrate rewrite (entity extraction + graph traversal). This PR is the cheap lever that lets the encoder-not-yet-FT'd common case experiment with representation enrichment without forking miner. Happy to add the AST-lite example caller into a test fixture if useful, or land just the kwarg surface and let representation experiments live as separate adapters. @igorls / @milla-jovovich — would value your take on whether the encoder-conditional framing makes the kwarg compelling enough to land, or whether the better path is to keep the upstream 🫏 |
|
Quick precedent worth noting: @igorls just shipped #1519 (merged 2026-05-15) with structurally the same shape as the Cross-referenced here in case the maintainer-review takeaway from #1519 — "small kwarg surfaces are fine when the default preserves existing behavior and the sentinel is unambiguous" — is the framing this PR also fits under. Both PRs gate optional enrichment behind a kwarg the caller opts into; neither changes anything for existing call sites. 🫏 |
2686883 to
43fd508
Compare
Optional keyword-only callable ``symbol_header_prefix(chunk_text, source_file, chunk_index) -> str``. When supplied, the returned header is prepended to each chunk with a blank-line separator before storage. Default ``None`` preserves current behavior exactly — all existing callers are unaffected. Discussed in MemPalace#1384 — gives AST-lite symbol-header enrichment (and other representation-axis experiments like adaptmem's FT-Code + header stacking) a clean seam without forking ``chunk_text``. Chunk content gets ~50–200 chars longer when a header fires; the caller controls the budget. Existing miner test suite (tests/test_miner.py, 96 cases) passes unchanged on the techempower-org fork where the kwarg was first shipped. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Address Gemini review on MemPalace#1508. The kwarg was reachable only by calling chunk_text directly; wire it through the standard mining entry points so the enrichment seam is usable from mine() without forking the path: mine -> _mine_impl -> process_file -> chunk_text symbol_header_prefix is an optional kwarg (default None) at every level, fully backward-compatible — no existing call site changes behavior. Also from the review: - Document the re-mine caveat in chunk_text + process_file docstrings: file_already_mined keys only on source_mtime + NORMALIZE_VERSION, so changing the callback does not auto-invalidate already-mined files; re-mine needs --force or a NORMALIZE_VERSION bump. - Rename the documented callback arg chunk_text -> chunk in the docstring to avoid confusion with the function name: (chunk, source_file, chunk_index) -> str. Tests: prove symbol_header_prefix flows mine -> process_file -> chunk_text, that the default (no kwarg) reaches process_file as None, that a non-empty header is prepended with a blank-line separator, and that the default-None path is byte-identical to the no-kwarg call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43fd508 to
57550a6
Compare
Summary
Adds an optional keyword-only
symbol_header_prefixcallback tomempalace.miner.chunk_text. When supplied, the returned header is prepended to each chunk with a blank-line separator before storage. DefaultNonepreserves current behavior exactly — every existing call site is unaffected.Why
Discussed in #1384. Lets representation-axis experiments — AST-lite symbol headers (function name + class path + imports + decorators), encoder fine-tunes that benefit from explicit symbol disambiguation (cf. nakata-app's adaptmem FT-Code series), and any future enrichment that needs to change "what the encoder sees" — stack on the existing chunk path without forking it.
The callback signature
(chunk_text, source_file, chunk_index) -> strgives the caller everything they need to do AST inspection or per-chunk metadata lookup; returning an empty string is a per-chunk no-op.Example: AST-lite caller
Tradeoffs
Test plan
tests/test_miner.py(62 cases) passes unchanged on the techempower-org/mempalace fork where this patch first shipped.Reference: techempower-org/mempalace@0a3340e.
🤖 Generated with Claude Code