fix: gate the auto-capture regex fallback behind smart extraction and admission#934
fix: gate the auto-capture regex fallback behind smart extraction and admission#934gorkem2020 wants to merge 1 commit into
Conversation
|
After #919 was merged, this PR now has merge conflicts with the latest |
537b662 to
cd3c56f
Compare
app3apps
left a comment
There was a problem hiding this comment.
Reviewed head cd3c56f. The direction is valuable and the targeted/full suites pass, but the below-threshold change introduces two blocking data-loss regressions.
- In ingress-fed sessions,
pendingIngressTextsis copied and removed and the accumulator advances, but the rollback happens only when that snapshot is empty. The function then returns before regex fallback. A below-threshold ingress turn is therefore neither persisted nor available to a later extraction. - This also removes the deterministic behavior for explicit memory requests. Two existing cases containing
请记住我的饮品偏好是乌龙茶were changed from asserting a regex capture to asserting that fallback is skipped. Persistence now requires another turn and a successful discretionary LLM extraction; a single-turn session loses the requested memory entirely.
Please retain below-threshold ingress text for the next extraction or preserve a safely admission-gated explicit-memory path, and add regressions covering real message_received ingress and a single-turn explicit remember request.
Also, admission evaluation currently fails open without storing a durable failed-open marker. Since this PR exists to close an admission bypass, please either fail closed for raw fallback text or persist provenance that makes bypassed rows auditable.
cd3c56f to
f9bf6ed
Compare
app3apps
left a comment
There was a problem hiding this comment.
Re-reviewed rebased head f9bf6ed. The rebase is clean and CI is green, but the production-path data-loss blocker remains.
In ingress-fed sessions, pendingIngressTexts is consumed and removed, the cursor advances, and the below-threshold branch returns before the fallback path. That permanently drops the ingress text, including explicit remember-style requests.
Please preserve or requeue deferred ingress text until it is actually extracted, and add production-path coverage for message_received plus a single-turn remember request. A history-carrying session that ends below threshold also needs an end-of-session case so its deferred text cannot disappear. Fail-open admission should leave durable provenance on stored rows.
Requesting changes until the ingress text is no longer lossy.
f9bf6ed to
ce16a61
Compare
Checkpoint recut of deploy/fleet-2026-07-15b (21 PRs) surfaced several merge-time regressions and stale test fixtures once the full test/tsc/build gate ran end to end: - index.ts: a plain (non-conflicted) auto-merge reintroduced CRLF into the modelRun:true block inside generateReflectionTextUnbounded; restored to LF. - index.ts: restored PR CortexReach#934's "regex fallback skipped" debug log + return in the below-threshold defer branch, dropped when PR CortexReach#951's merge took the persistence-based rollback wholesale instead of unioning both changes. - index.ts: removed a duplicate minMessages declaration left over from reconciling PR CortexReach#939's assistant-context accumulation block with PR CortexReach#951's own minMessages usage earlier in the same function. - src/admission-control.ts: hoisted the constructed-durable short-circuit from evaluateWithUtility() into evaluate() itself, so a constructed durable candidate is rejected before scoreUtility() spends an LLM call, not just before its score is blended in. - src/admission-control.ts: restored the Grounding/Conversation register fields in buildUtilityPrompt's user template (dropped during the PR CortexReach#938 split-prompt merge), since PR CortexReach#927's own admission tests depend on the judge seeing them inline. - Updated several PR CortexReach#927/CortexReach#938/CortexReach#939 test assertions that predate the split-prompt {system, user} return shape to destructure the right half instead of matching the whole object, and updated stale "## Recent Conversation" / "Evaluate whether this candidate" mock-routing strings to the current prompt text. - test/assistant-context-capture-counting-symmetry.test.mjs: gave each captureAssistant/payloadShape scenario its own directory so the new watermark sidecar file (keyed by dirname(dbPath) + sessionKey) doesn't bleed state between scenarios that previously only shared in-memory state; updated the delta-only sanity check to reflect the documented rollback characteristic where per-turn deltas below minMessages never accumulate. - test/smart-extractor-branches.mjs: updated a fixture comment/payload that had already predicted and documented this exact combination, switching to full accumulated history per turn as prescribed. Full suite (minus the environment-only Ollama port-conflict test), tsc, and build all green after these fixes.
app3apps
left a comment
There was a problem hiding this comment.
Re-reviewed head ce16a61. CI and the full suite pass, but the new expectations still codify deferral without proving eventual persistence.
For ingress-fed sessions, pendingIngressTexts is consumed and deleted, the seen cursor advances, and the below-threshold branch returns before fallback. A single-turn explicit remember request can therefore become unrecoverable. A history-backed session that ends before extractMinMessages has the same no-flush outcome.
Please preserve or requeue deferred text until extraction succeeds, or persist explicit capture through a safely gated path. Add production-path regressions using real message_received ingress, a single-turn remember request, and a session ending below threshold, proving the content is eventually stored exactly once. Admission failures that intentionally fail open should also leave durable provenance on the stored row.
Requesting changes.
|
Fixed two findings in 63eec3f, and want to be direct about how the other three relate rather than claim more than I've actually closed. Fixed: Not separately fixed:
|
|
Thanks for the update in Please rebase onto the latest |
63eec3f to
b0f05a3
Compare
|
Rebased onto current master as requested, the branch is mergeable again. New head: b0f05a3. Conflicts were limited to the test registration files (package.json test chain and scripts/ci-test-manifest.mjs), resolved by keeping both sides' entries; dist is rebuilt from the resolved sources and the PR's test suite plus typecheck pass on the new base. |
app3apps
left a comment
There was a problem hiding this comment.
Re-reviewed the current head b0f05a3. The ingress requeue and failed-open provenance fixes are useful, and the full suite passes, but two behavior gaps still block this change:
- The below-threshold branch returns before regex fallback and only preserves data for a later turn. If the session ends before
extractMinMessages, an explicit remember-style request that the legacy fallback previously persisted is silently lost. Please add an end/session-boundary flush or another exactly-once path for intentional capture, with a regression for a short session that has no later turn. - The PR body says the legitimate fallback is routed through admission when
smartExtraction=false, but the controller is obtained fromsmartExtractor?.getAdmissionController(). With smart extraction disabled that is always null, andgateRegexFallbackCaptureadmits unconditionally. Please construct/use admission independently of SmartExtractor for this configuration, or otherwise make the advertised safety boundary real and test the production configuration.
There is also an accounting edge to cover while fixing the first item: ingress cumulativeCount advances before deferral, while requeued texts are counted again and the queue is capped at six, so repeated deferrals can cross the threshold early while silently dropping older input. Add an exactly-once/count-and-cap regression around that flow.
|
Since #924 merged, GitHub now reports this branch as conflicting with the latest |
b0f05a3 to
5d3dbd3
Compare
|
Rebased onto the current master, dist rebuilt on the rebased tree, all checks green on the branch. |
app3apps
left a comment
There was a problem hiding this comment.
Re-reviewed head 5d3dbd3 after the rebase. The build, focused suites, and GitHub CI pass, but the rebase leaves the two previously requested correctness fixes unchanged:
-
In the below-threshold
agent_endpath, the consumed text is rolled back or requeued and the hook returns. There is still no session-boundary flush. If a session ends beforeextractMinMessages(including a one-turn explicit "remember this" request), there is no later turn to consume the deferred content, so a capture that previously persisted is now silently lost. Please add an exactly-once safe flush and an end-to-end short-session regression that inspects storage. -
When
smartExtraction=false, noSmartExtractororAdmissionControlleris created. The caller passesnulltogateRegexFallbackCapture, whose null-controller branch unconditionally admits the raw regex capture. Thus admission remains completely bypassed in the configuration where regex fallback is the primary capture path, despite the PR's stated admission-gating behavior. Please make the controller available independently of smart extraction (or otherwise enforce the gate) and add a production-configuration rejection test.
These are behavioral blockers, not test-infrastructure issues.
…d admission Rebuilt onto current master after the mapped-rows admission merge restructured the auto-capture hook: the original three commits replayed as one overlay (their combined delta applied at the surviving anchors) because commit-replay punts the enclosing hook body as one giant hunk. Combined content, unchanged from the reviewed branch: - below-threshold turns defer instead of falling through to the raw regex fallback; history-carrying sessions roll the watermark cursor back, ingress-fed sessions re-queue the consumed pending texts so deferred content survives to the next turn (previously it was silently discarded); - regex-fallback captures route through the same admission gate as extraction candidates (fail-open when admission control or smart extraction is disabled), with the admission audit attached to admitted rows; - the smart-extractor accessor methods the gate borrows now come from master (the mapped-rows admission merge introduced identical ones), so this branch no longer adds them.
5d3dbd3 to
c2678a7
Compare
…ves turns A below-threshold deferral keeps content alive on two independent paths: the rolling pair buffer, and the watermark rollback (or pending-ingress re-queue) whose next slice re-includes the same turns. When the deferred turn finally fires, window assembly concatenated both copies and the extraction transcript carried the same exchange twice, back to back (observed live: window inflation plus mild extraction bias toward the duplicated line). Collapse duplicates at assembly time, by user text at pair granularity: a pair-shaped copy beats a flat re-queued copy, copies of an identical exchange collapse to the latest, and a repeated user text whose replies differ is a real conversation and is kept whole. The deferral itself lives in the regex-fallback gating change (CortexReach#934); with both applied the window stays duplicate-free on every path.
Problem
When the smart extractor does not handle a turn, the auto-capture hook falls through to the legacy regex capture, which stores matching texts verbatim via
bulkStore, with no distillation, no admission, and none of the extraction pipeline's safeguards. Two trigger paths:cumulativeCount < extractMinMessages: every content-rich first message of a session is eligible for raw capture before the extractor ever gets to judge it.Observed live: the first message of a fresh session (a roleplay opener) was stored verbatim as a confirmed
factrow within seconds, bypassing the grounding and admission stack entirely. Sessions that open with a short greeting never hit this, which is why it stayed hidden; sessions that open with a rich message (how real users start conversations) hit it immediately.Fix
provenance: "auto-capture-regex-fallback". Admission disabled keeps the legacy passthrough.Tests
9 cases, 3 red-proven against the previous behavior: the below-threshold skip, deferred-text re-inclusion in the next extraction, gated boundary-skip continuation, plus pins for legacy behavior with smart extraction disabled.
Verification on a live gateway
The identical rich first message that previously produced a verbatim
factrow now produces nothing; the follow-up turn's extraction input contained the deferred first-message content, produced correctly grounded candidates, and logged "skipping regex fallback" on the empty-outcome path.