Repository navigation
feat: redirect ignore-pattern drops into the lossless sidecar (WS1.5 PR-2) - #163
100yenadmin wants to merge 11 commits into
Conversation
Groundwork for storing ignore_message_patterns drops losslessly instead of discarding them. Adds an additive ignored_messages child table plus the store read/write API, with no ingest behavior change yet: no drop path is redirected here, so replay, FTS, token counts, and cursor reconciliation are untouched. The sidecar is deliberately separate from the messages table. Keeping ignored content out of the parent means the ~10 'stored row == replay row' reconciliation assumptions and the external-content FTS rebuild never see it, so lossless capture needs no changes to those fragile subsystems (the reason a messages.ignored column was rejected). Migration is version-fenceless: ensure_ignored_messages_table runs unconditionally in run_versioned_migrations and does not bump SCHEMA_VERSION, so an older build simply ignores the table and keeps dropping -- downgrades stay safe. append_ignored_batch routes rows through the same ingest protection as append_batch (redaction / externalization before persist). Session rebind and delete keep the sidecar bound to its parent session. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…PR-2) Builds on the ignored_messages sidecar (PR-1). When the new lossless_ignored_enabled flag is set, messages that match ignore_message_patterns are persisted into the sidecar instead of being discarded outright; they still stay out of replay, FTS, token counts, and cursor reconciliation exactly as before, so only their durable audit/recall value is added. Both drop sites are covered: the main _ingest_messages raw-pattern drop and the late session-end suffix drop. Persistence is best-effort and fully decoupled from the active path -- a sidecar write failure is swallowed (audit-only) and never breaks ingest. The existing _ignore_pattern_dropped_count is preserved (augmented, not replaced), and get_status surfaces lossless_ignored_enabled plus a per-session ignored_sidecar_count when enabled. The flag defaults off, so the drop path is byte-identical to today unless an operator opts in (LCM_LOSSLESS_IGNORED_ENABLED). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both sides added independent pre-scan blocks at the top of _find_reconciled_cursor_for_store_tail (ignored-prefix cursor gating from this PR, fresh-tail boundary counting from main); keep both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Imported upstream pr-conversation
@codex review current head d60a884. Rebuilt cleanly on repaired #362 head b22be578; capture-only diff remains scoped to config.py, engine.py, and tests/test_lossless_ignored_capture.py. Validation on exact stacked head: 1622 passed, 12 xfailed; ruff and hygiene gates passed. Imported upstream pr-conversation
Stack re-gate evidence for current head
@codex please review this exact stacked head. Imported upstream pr-conversation
@codex Please review rebuilt stacked head This branch is rebuilt directly on repaired #362 head Fresh local evidence: focused 20 passed; full suite 1623 passed / 12 xfailed; ruff, compileall, py_compile, shell syntax, and Please review #362 first, then the capture delta in this stacked PR. Imported upstream pr-conversation
@codex review\n\nCurrent rebuilt child head: Imported upstream pr-conversation
@codex review — head moved to Imported upstream pr-conversation
Moved to draft to reduce the size of the open review queue, as requested. Nothing is closed and no work is lost: the branch and its history stay intact. This will be reopened once the corresponding workstream base has clear review direction. Queue context: #416. Imported upstream pr-review-commented
💡 Codex ReviewHere are some automated review suggestions for this pull request. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". Imported upstream pr-review-commented
💡 Codex ReviewHere are some automated review suggestions for this pull request. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". Imported upstream pr-review-commented
💡 Codex ReviewHere are some automated review suggestions for this pull request. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". Imported upstream pr-review-comment
When lossless capture is enabled and a session contains only messages matching Useful? React with 👍 / 👎. Imported upstream pr-review-comment
When lossless capture is enabled for an ignored-only session, this guard only advances if the entire incoming batch is ignored and the whole Useful? React with 👍 / 👎. Imported upstream pr-review-comment
This identity comparison uses the raw incoming ignored message, but Useful? React with 👍 / 👎. Imported upstream pr-review-comment
When an existing long session already has earlier ignored sidecar rows, a restarted gateway can replay only the durable tail. This code compares the first ignored message in that tail against Useful? React with 👍 / 👎. |
|
Triage: your red CI is stale, not broken — and here is the actual blocker. This PR shows a failing check, but the failure is a CodeQL infrastructure error from 2026-08-16, not a problem with your code: This is a Python repo, so that extractor found nothing to analyse and aborted. The job has passed on every PR landed since, so the configuration is already fixed and this PR is simply carrying an old red. It needs a re-run, not repair. Twelve of the sixteen "failing" PRs in this repo are in the same position — detail and recommendation in #241. The real blocker is the rebase. This branch is ~40 commits behind and conflicts against current Recorded disposition: NEEDS-REBASE. Not closed, not abandoned — it is a feature branch whose capability I verified is still absent from If you want it prioritised sooner, say so on the PR and I will pick it up next. |
|
Thank you @ai-ag2026. This draft mirrors upstream hermes-lcm#363, which was closed upstream without being merged. Its preservation record (#100) is closed. It depends on #162 and targets engine/reconcile code that has been largely rewritten since, through v0.24.0 and v0.24.1. Closing as a stale mirror. If a lossless sidecar for ignore-pattern drops is still wanted, please refile it against current main together with the sidecar substrate. |
Important
This executable LCM-X PR was recreated by the migration operator from the exact upstream commit head. GitHub did not transfer the original PR actor, dates, review objects, or approval state.
Source and attribution
821ef86e221e2fee022a6c698ca8894f4a4561f9ai-ag2026/hermes-lcm:pr/ws1.5-ignored-capturemainupstream/pr-363Truedraft(a maintainer can mark it ready when current-head review is wanted)@coderabbitai ignore
Original commit authorship and history remain in the commits. Historical discussion and review text are imported below as attributed ordinary comments; they are not new approvals or change requests.
Original upstream PR description
Summary
Second WS1.5 step, stacked on #362: preserve messages matched by
ignore_message_patternsin the losslessignored_messagessidecar while keeping them out of the active LCM path.This update keeps
lossless_ignored_enableddefault-off and covers both raw drop sites. It also reconciles restart replay against the protected/normalized stored identity: only a contiguous, identity-proven ignored prefix is advanced, while unrelated or newly arrived ignored rows remain available for capture. Ignored-only and mixed ignored/active restarts therefore avoid duplicates without feeding ignored rows back into active context.Why
Previously, matching messages were dropped permanently. The sidecar provides an audit-only durable path, but restart reconciliation must distinguish already persisted ignored rows from fresh input. Comparing raw input or advancing an unmatched tail can either duplicate protected rows or skip fresh rows.
The repaired flow protects the candidate row before identity comparison, advances only the matched ignored prefix, preserves fresh/unrelated rows, and retains the existing pattern timeout/error fail-safe. With the feature disabled, active behavior remains byte-identical; with it enabled, ignored rows are captured once and never enter replay, FTS, active token counts, or cursor feedback.
Validation
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=/tmp/t_a1dc5f84-generated python3 -m pytest -q -p no:cacheprovider tests/test_lossless_ignored_capture.py tests/test_ignored_sidecar.py tests/test_lcm_command.py tests/test_lcm_core.py—393 passed in 9.83sPYTHONPATH=/tmp/t_a1dc5f84-generated python3 -m pytest -q—1638 passed, 12 xfailed in 32.15spython3 -m py_compile reconcile.py tests/test_lossless_ignored_capture.py— passedgit diff --check HEAD^ HEAD— passed482cd905d7e47adf5c56b175b74d57470c78d601— ACCEPT, no blocking findingsNotes
2 failed, 9 passed: protected stored identity duplicated, and mixed restart skipped a fresh ignored row.config.py,engine.py,reconcile.py, andtests/test_lossless_ignored_capture.py; the final repair commit changes onlyreconcile.pyand its focused tests.lintcheck is the authoritative lint result for this exact head.Refs
7121b565f5da3caa77ef766272d312b2a1a2c243482cd905d7e47adf5c56b175b74d57470c78d601engine.py::_ingest_messages,engine.py::_append_off_current_session_end_suffixreconcile.py