Skip to content

[R2 mono] wave-1 + scaling fixes + citable delivery — fork review rounds - #175

Merged
100yenadmin merged 65 commits into
mainfrom
bench/w3b-on-wave1
Jul 29, 2026
Merged

100yenadmin merged 65 commits into
mainfrom
bench/w3b-on-wave1

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Jul 29, 2026 •

Copy link
Copy Markdown
Owner

The R2 consolidated train, opened for the fork's multi-bot review rounds (gate 5 of the consolidation checklist)

Head: 2edb8fc — wave-1 (V2 trajectory subsystem) + the Phase-1A scaling fixes (#167 batched full scan, #168 in-product FTS5-safe sanitization with the allow_operators mode split) + #164a summary-hit store_id + the citable-delivery engine (PR #174: reference-strict delivery, entry-lifecycle ledger, derived resume — 8 review rounds, 15 findings closed, property-tested).

Measured so far (full provenance in bench/ on docs/program-architecture):

  • Phase 1B scaling re-run (F34): recall cliff eliminated — the index out-recalls file-scan at every rung of the 389× ladder; raw NL queries 100%-empty → 0%-empty. Full-scan latency cost published (5.6s at 20k sessions); ANN successor filed (R3: ANN index (or persistent matrix residency) for large-store recall latency — mandated by F34's pre-registered criterion #171).
  • Gate-4 slice (F36): harness fail-closes 16 → 0; 62/100 on the failure-enriched slice vs banked 44 (p=4.0e-05), with the gain proven stable across the delivery-engine rebuild (net −1 on common rows).
  • The full-500 confirm run is executing now — its paired result vs the banked 444 is the release's V1 number and will be posted here when it lands. No /500 claim is made from the slice (enriched-slice discipline).

Review guide: highest-leverage areas are search_query.py (sanitizer; adversarially reviewed ×2), vector_store.py (batched scan + cache semantics), tools.py recall paths (the citable-delivery ledger — the 8-round review history with per-finding commits is on PR #174), and the lcm_trajectory_* subsystem. Known open items tracked separately: #171 (ANN), #172 (FTS-arm NL rescue), summary-lineage-at-ingest (unfiled — nested provenance data gap).

Requesting review rounds from the configured bots (Codex / CodeRabbit / evaOS Code Review Bot). Merge is gated on: clean rounds per the checklist (min 2, cap 5) + the full-500 confirm number landing in the release notes. Do not merge before both.

Summary by CodeRabbit

  • New Features
    • Added bounded full-corpus scanning controls (row cap, time budget, optional deadline) to KNN/recall retrieval flows.
    • Added resumable state embedding backfill tooling; enhanced recall modes (state-semantic and adjacency expansion, diversity/title boosting, adaptive/sharp excerpting).
  • Bug Fixes
    • Improved FTS/LIKE sanitization and operator handling; tightened strict reference verification and evidence digesting to prevent stale/ambiguous results.
  • Documentation
    • Updated all version references and “Verify”/plugin output examples to v0.20.0.
  • Tests
    • Expanded regression/replay coverage for scan bounds, strict verification, and query fallback correctness.

Fork main CI has been red since the R1 merge: 4 trajectory-stack tests
failed in clean CI while appearing to pass in dev environments —
test_registered_tool_uses_the_product_compiler_path,
test_code_owns_host_envelope_and_selector_proposes_semantics_only,
test_named_facet_delta_is_selected_before_the_only_semantic_call, and
test_pre_llm_hook_selective_compiler_uses_existing_auxiliary_seam_and_fails_open.

Root cause (corrected from the earlier provider-gate hypothesis): these
fixtures pin question_date="2026-07-20" but append their source messages
WITHOUT a timestamp, so the store records observation at wall-clock "now".
reasoning._ground_one enforces the as_of boundary (falling back to
ingested_at when observed_at is absent), so once the clock passed
2026-07-20 every grounding call rejected with "source was observed after
the question-date boundary" -> operand_grounding_failed -> status
"fallback" / state "unknown" / the pre-llm hook failing open without the
lcm-selective-evidence block. A time bomb, not a provider gate: with
question_date moved past today the same paths compile fine in a clean
pytest+numpy venv with no embedding/LLM provider at all.

Fix: pin observed_at/timestamp to 2026-07-19T09:00Z (before the pinned
question_date) on the appended sources, exactly the idiom the passing
tests in the same files already use (e.g.
test_exact_span_entity_date_value_unit_role_and_key_are_product_validated).
This keeps the real code path exercised — grounding now validates the
observation boundary instead of short-circuiting — and stays
deterministic forever. No provider fixtures were needed (the selectors
and retrieval in these tests are already deterministic fixtures) and no
skip markers were added: nothing in these paths requires a provider.

Verified in a CI-faithful venv (pytest+numpy only, agent stub, no
provider env): the 4 tests pass both with VOYAGE_API_KEY/OPENAI_API_KEY/
ANTHROPIC_API_KEY unset and with dummy values set; full-suite failure set
is byte-identical to the pre-fix baseline minus exactly these 4; ruff
clean.
MessageStore.search()'s FTS-path SQL still SELECTed the old 12 message
columns + rank + snippet, while _row_to_dict() grew to expect 15 message
columns (..., ingested_at, observed_at, observed_at_source). The zip()
truncation misread the FTS row's rank as ingested_at and snippet as
observed_at, and silently dropped observed_at_source. The LIKE fallback
path was unaffected.

Add the three sidecar columns to the FTS SELECT and derive the
rank/snippet column offset from _MESSAGE_SELECT_COLUMNS instead of a
hardcoded 12, so a future column addition can't silently desync the two
again.

Regression: tests/test_runtime_time_contract.py::test_fts_search_preserves_time_contract_fields
(fails on 0cb7f37, passes after this fix).

Codex finding: stephenschoettler#436 discussion_r3641730742
In _persist_compiled_view(), claim_build() could succeed and then
publish_ready() could still raise (e.g. a rejected manifest). The
generic `except Exception:` handler only recorded
query_view_publish_failed in the result payload and never called
mark_failed() on the claimed token, so the row stayed status='building'
for the full 300s lease. An immediate, correct retry for the same
identity got query_view_build_in_progress ("busy") instead of
rebuilding.

Track the token outside the try block and call store.mark_failed(token,
str(exc)) in the except-Exception branch, mirroring the pattern already
used in adaptive_retrieval.py's _persist_view().

Regression: tests/test_evidence_compiler.py::test_persist_compiled_view_releases_lease_on_publish_failure
(fails on 0cb7f37 -- row stays 'building' and the retry reports busy;
passes after this fix).

Codex finding: stephenschoettler#436 discussion_r3641730749
classify_version_mismatch() treats any extra table not matching a known
feature-family prefix as a genuinely-newer-build signature. The prefix
list stopped at lcm_assertion, so a profile with an interim schema_version
stamp whose only extras are the new query-view (lcm_query_*) or
trajectory (lcm_trajectory_*) sidecar tables was misclassified as
genuinely_newer instead of an interim stamp -- sending
`/lcm doctor repair schema-stamp` down the refusal path even though these
are opt-in, marker-gated features that don't bump the core schema.

Add "lcm_query" and "lcm_trajectory" to _KNOWN_FEATURE_TABLE_PREFIXES.
Both families are new in this PR with no prior deployed shape to drift
from, so (like the existing prefix-only families before their own
verifiers existed) they intentionally get no early-variant verifier yet --
that stays a separate, future addition if these tables ever need
drop-and-rebuild remediation.

Regression: tests/test_schema_stamp_remediation.py::test_classify_interim_stamp_with_query_view_and_trajectory_marker_tables
(fails on 0cb7f37 -- classifies genuinely_newer; passes after this fix).

Codex finding: stephenschoettler#436 discussion_r3641730753
LCM_COMPILE_EVIDENCE's public proposal schema required "operation", but
_validate_proposal() rejects any proposal containing an "operation" key
(_PROPOSAL_KEYS deliberately excludes it) because operation is a
deterministic, code-derived value computed from the question in
prepare_evidence_selector() and only ever surfaced to the selector as
input (selector_request["operation"]) -- it is never a selector output.
A caller who honestly followed the schema's required-field list got
selector_schema_invalid on every call; the proposal-mode path was only
reachable by silently violating the advertised contract.

Remove "operation" from the proposal object's required list and
properties -- the schema's additionalProperties:false now correctly
rejects it too, matching the runtime exactly.

Regression: tests/test_evidence_compiler.py::test_public_proposal_schema_does_not_require_code_derived_operation
(fails on 0cb7f37 -- a schema-compliant proposal is rejected with
selector_schema_invalid; passes after this fix).

Codex finding: stephenschoettler#436 discussion_r3641730756
requirements_digest() hashed only slot_id and minimum_refs, omitting the
requirement description that defines what evidence a slot is supposed to
satisfy. Two unrelated questions sharing a QueryViewIdentity (same
subject/predicate/scope, plausible for a coarse-grained intent bucket)
and the same slot_id/minimum_refs -- but a different description --
produced an identical digest, so start() treated a cached view built for
one meaning as a hit for the other and pre-filled the new requirement
with unrelated cached evidence. Confirmed end to end: a "Who is the CFO
of Acme?" retrieval was served the CEO's cached citation.

Fold the (already whitespace-normalized) description into the hashed
identity alongside slot_id/minimum_refs.

This intentionally narrows one existing warm-reuse case:
test_exact_slot_closure_compute_finish_and_warm_reuse previously varied
both the literal question text AND the requirement description on its
"warm" call and still asserted a hit. That was exercising the exact gap
being closed here. Updated it to keep the description constant while
still rewording the question, which is what that test is actually meant
to demonstrate (warm reuse survives rephrasing, not a description
change); the description-varies case now has its own dedicated coverage.

Regressions:
- tests/test_adaptive_retrieval.py::test_requirements_digest_distinguishes_descriptions
- tests/test_adaptive_retrieval.py::test_cached_view_is_not_reused_across_different_requirement_descriptions
(both fail on 0cb7f37 -- digests collide and the CFO retrieval reuses the
CEO's evidence; pass after this fix).

Codex finding: stephenschoettler#436 discussion_r3641730764
Add lexical_floor:int=0 kwarg to TrajectoryStore.query(). When >0, reserve
K nucleus slots for the top pure-BM25 states (via _select_with_floor) before
filling the rest from the fused order, honouring the same 5/trajectory cap.
Default 0 reproduces the historical fused-only selection byte-for-byte
(candidate-composition repair for the semantic-magnet SOURCE_MISS bucket).
Add arm_quota:tuple|None=None kwarg to TrajectoryStore.query(). When set,
_merge_arms round-robins a pure-BM25 arm and the semantic/fused arm into the
nucleus by a q_lex:q_sem quota (dedup + backfill, arm order as tie-break),
strictly generalising Policy A. Default None reproduces the historical
selection byte-for-byte.
Component instrument for the candidate-composition repair. Injects the frozen
H1.3 semantic source ranks into TrajectoryStore.query() (no provider/model
call), replays from read-only frozen DB copies, and:
  - GOLDEN GATE: defaults reproduce recorded delivered_evidence_refs byte-for-byte;
  - RECOVERY: vanished genuine-loss refs re-admitted (by h2 bucket);
  - CEILING: vanished refs absent from global_rows top-128 (un-recoverable at seam);
  - PRESERVATION: stable-correct delivered refs dropped (ref-level + source-level);
  - latency p95 over a 50-query replay.
Emits the full A/K + D/quota sweep table + JSON; does not pick a shipping knob.
Reproduce the semantic-magnet SOURCE_MISS displacement synthetically and assert:
default byte-compat (magnet displacement preserved), Policy A/D re-admit the
displaced lexical winner, _merge_arms dedup+backfill order, and both policies
no-op without semantic ranks.
… from scored path per #127 (2nd powered fail +7 vs ≥+8); preserved default-off; golden 451/451 byte-identical
Promote adjacency from a delivery-only ±1 backfill to a POOL-stage
expansion: for every lexical seed hit in the candidate pool, the states at
sequence_ordinal ±1..adjacency_radius within the same source are admitted
as a QUOTA-CAPPED ADDITIVE arm through the existing _merge_arms machinery
(q_lex=len(rows), q_sem=adjacency_quota), giving a non-lexical recall path
for states that carry no query term of their own.

Controls (anti-magnet, per H5-design-options option (b) + SPEC-H5b):
- strictly additive tail: expanded neighbors earn NO semantic boost and no
  BM25 rank; nucleus selection -- and therefore delivery -- changes only
  when the ranked pool cannot fill the nucleus (gate (ii) additive proof);
- deterministic distance-major / seed-pool-rank / ordinal arm order;
- 5-per-trajectory diversity cap at selection untouched;
- adjacency_radius=0 / adjacency_quota=0 defaults skip the path entirely
  (current bytes; telemetry key present only when active);
- batched row-value IN lookups on the (source_id, sequence_ordinal) index.

tests: synthetic invisible-neighbor corpus -- default byte-identity incl.
half-open knobs, pool entry, radius bound + arm order, quota cap, pool
dedup, delivery-unchanged on a full (magnet) pool, selection cap, tail-only
placement. Full suite: failure set identical to base 65f679b under the
same invocation (pre-existing env-dependent failures only).
…135)

The arm probe is now index-only (state_id/source_id/sequence_ordinal); the
candidate-shaped full rows (large state text) are fetched solely for the
<=quota admitted states. Measured on the frozen enterprise corpus: ~400-pair
full-row probe cost ~63ms/chunk vs 0.07ms light probe + ~5ms admitted fetch
-- keeps the knob inside the p95 +10% latency gate (iv). Behavior unchanged
(41 trajectory-suite tests green; golden 451/451 re-verified).
Extends the H3.1 composition replay instrument: same frozen assets, same
injected semantic ranks, same mandatory golden gate (451/451 before any
sweep). Sweeps adjacency radius x quota under TWO compositions (base +
quarantined hybrid lexical_floor=1/arm_quota=(7,4)) and reports per knob:
pool-entry recovery over the 30 verified H32 targets (h5-targets.json;
EXACT pool membership, not 64-truncated telemetry), Delivered-Recall@16 vs
the same composition's no-adjacency delivery, the 8 loss-ids' delivered-set
anti-filler check, preservation disturbance over the 154 stable-correct
questions, and paired-pass p95 latency (external-drive I/O variance makes
unpaired reads incomparable). Also emits the zero/weak-seed split of the 30.
The component gate is FROZEN: this instrument does not pick the knob.
#142)

Add an additive per-STATE embedding space (the existing lcm_trajectory_embeddings
is per-SOURCE / one coarse vector per trajectory, which cannot surface a
lexically-invisible answer state). New idempotent tables
lcm_trajectory_state_embedding{_profiles,s} created lazily via
_ensure_state_semantic_schema (mirrors _ensure_semantic_schema; no existing-table
change), a resumable build_state_semantic_index backfill (32-item/72K-token
packing, chunked mean-pool path for over-cap states, skip-embedded resume,
progress ledger callback), and a default-off state_semantic_quota query arm that
admits the query's semantic nearest-neighbour states as a STRICTLY ADDITIVE
_merge_arms tail (no boost, 5/traj cap intact, telemetry only when active).
Defaults reproduce current bytes. 10 tests mirror the 8 adjacency tests + backfill
resume/chunk/inert cases.
state_embedding_backfill.py: resumable metered CLI over a working-copy lcm.db
(32-item/72K packing via build_state_semantic_index, JSONL spend ledger,
projected-cost cost-cap abort, 50%% checkpoint). h5_state_semantic_replay.py:
sibling of the adjacency sweep -- opens the BACKFILLED copies with a cached real
Voyage query provider (source ranks still injected -> golden byte-identical),
sweeps state_semantic_quota and reports the four frozen #142 gate metrics
(pool-entry/30, delivered-recall@16, loss8 preservation, 154-set preservation,
p95). Query embeds cached off the timed path so the latency delta isolates the
arm's added cost.
Bootstrap the hermes_lcm package before constructing the query provider (the
provider import needs it), and disable the interactive per-minute call-rate guard
on the sweep's query embedder (the 451-query warm pass is the bulk pattern
for_backfill exempts, and tripped ProviderRateLimited otherwise). Sweep runs
clean end-to-end: golden 451/451, quotas 4-64.
…trieval knobs (#143)

Knob G (HERMES_LCM_ANTIBOILERPLATE, default-off): inside C1's per-trajectory
MMR survivor selection, penalize a candidate by its mean lexical similarity to
the other pooled states of its own trajectory and reward query-term density, so
a trajectory's seats go to query-relevant states not repeated task headers.

Knob H (HERMES_LCM_TITLE_BOOST, default-off): at the lexical candidate stage,
stable-reorder states whose title/heading/field-label text contains an exact
(case/punct-normalized) 2-4 gram question phrase ahead of same-band peers.

Both deterministic, no model calls, omitted from query() when off. Golden
451/451 byte-identical on base and W3a stores; full-suite failure-set parity
(+3 new passing tests, identical 60 pre-existing bad node ids); ruff clean.
FTS5 barewords accept only alphanumerics, so a natural-language question
(`?`, apostrophes, commas, `&`, `$`) was a syntax error at MATCH. The
query fell through to the LIKE full-scan, which blows recall_query_timeout_s
at scale and returns EMPTY -- 100% of queries at 8,000+ sessions
(FINDING-F31 §3). The sanitization belonged in the product, not in a
benchmark harness that happened to know the trick.

sanitize_fts5_query now maps every non-alphanumeric character outside a
balanced phrase quote to a separator (the transform the Phase 1A A3 arm
used), matching how the default unicode61 tokenizer splits the INDEXED
text -- so no term is lost. LIKE stays the fallback for what FTS cannot
express (CJK/emoji/compound tokens) and for a query with nothing left
after sanitization; that path now scores punctuation-only queries on the
raw text so its literal substring behavior is unchanged.
…ndow (#167)

recall_scan_rows was a HARD bound on the brute-force scan, so at 185,175
vectors lcm_recall scored only the 25,000 most-recent and 86% of memory was
invisible to semantic retrieval. All-gold recall@25 collapsed 0.82 -> 0.00
across the ladder exactly as gold content aged out of the window, and the
no-deadline arm reproduced it: coverage, not time (FINDING-F31 §2). The
"all conversations, all time" promise was false at scale.

The scan now covers the WHOLE corpus in batches with a running top-k across
them. recall_scan_rows becomes the BATCH SIZE, so it bounds vectors resident
per batch (peak memory) instead of the corpus reached; the arithmetic is
trivial either way (185k x 384-dim is ~0.14 GFLOPs). No ANN index here --
that is deferred until profiling shows the full scan too slow.

lcm_grep is untouched: full_scan is off by default, and a single batch of
bounded_scan_rows candidates is byte-for-byte the previous behavior.

The degraded/degraded_reason machinery is preserved and now means what it
says: coverage degrades to 'bounded' only when an explicit bound truncates
the scan -- recall_scan_max_rows (0 = unlimited, for a pathological corpus)
or recall_scan_budget_s (0 = no early stop). Both default to no early stop,
so a default recall discloses nothing because nothing is hidden.
… the raw one

requires_like_fallback() tested the RAW query, so a compound token still forced
the full-table LIKE scan even though sanitization turns it into ordinary terms
the index answers: requires_like_fallback("art-related") was True while
sanitize_fts5_query("art-related") == "art related". Six of the fifty fixed
Phase 1B questions carry a hyphen, so 12% of the rerun would have taken the
same full-scan path this branch exists to remove.

The predicate now asks what sanitization LOSES, not what the FTS5 query grammar
cannot spell. Compounds ride the index. The genuine losses still route to LIKE
and are tested against the RAW query, because sanitization is exactly what
removes them: unicode61 does not segment CJK and drops emoji from the index, and
a query that sanitizes to nothing has no term left to match.

Four existing tests used a hyphen purely as their LIKE trigger; they now trigger
on an emoji and keep the hyphen in the raw query, so the SQL-limit, conversational
-vs-tool ranking, and risky-ASCII repetition collapse each still assert exactly
what they did before.
The 4-entry matrix cache and a sequential batch sweep are actively hostile to
each other. The 185,175-vector corpus needs eight 25k batches; after a sweep the
cache holds batches 4-7, and the next sweep starts at batch 0 and evicts each
entry before reaching it — zero hits on every measured repetition, pure reload
cost. Worse, it RETAINED four float32 matrices (153.6MB on the chunk arm alone),
which is exactly the peak-memory bound the batching was introduced to provide.

A sweep that needs more than one batch now loads each batch straight through
(_load_matrix / _load_chunk_matrix, no cache interaction), so peak memory really
is one batch. A single-batch scan — every lcm_grep call, and any corpus under
the batch size — takes the cached path unchanged, so the pooled-store warm path
keeps its F2-matrix-cache behavior byte for byte.

Cache semantics for the Phase 1B curve, so F34 can read it: rungs whose corpus
fits one batch are WARM across repetitions; any rung above the batch size is
DETERMINISTICALLY COLD. At the default 25k batch that is the 19,829-session rung
(185k vectors) cold and the rest warm.
…path too

A fully-synced binary-prescreen identity returned coverage='full_approx' before
_scan_limits() was ever consulted, so recall_scan_max_rows and
recall_scan_budget_s were silently ignored on those profiles — on both the
summary and chunk arms. An operator capping a pathological corpus got an
uncapped scan and no disclosure that the cap did nothing.

The two-stage path can honor neither knob: it is one matmul over the whole
binary mirror, with no candidate window to cap and no batch boundary to stop at.
So a requested bound now declines that path and takes the exact batched scan,
which enforces the bound and reports the bounded coverage with scanned/total.
Both knobs default to 0, so an unbounded recall keeps the two-stage path and its
full_approx disclosure byte for byte.
Sharing the FTS term form with the LIKE fallback deleted the very characters
that fallback exists to find. `launch 🚀` routes to LIKE precisely BECAUSE
unicode61 does not index the emoji — and then sanitized to `launch`, searching
only %launch%. A row containing just 🚀 stopped matching. Regression against the
base sanitizer, on both message and summary search.

The LIKE path now has its own weaker sanitizer (sanitize_like_query), which
strips only genuine FTS5 query-syntax operators — the punctuation a user typed
FOR the index — and preserves every other character, because a character the
index cannot spell is still a character a substring match can find. That is the
pre-Phase-1B behavior, restored for the one path that wants it, while MATCH
keeps the strict term form. Both walk the same quote-preserving scanner.

This also retires the `or query` empty-sanitize workaround: sanitize_like_query
never empties a punctuation-only query in the first place.
…query

Uppercase AND/OR/NOT/NEAR survived sanitization, so a raw question silently
ACQUIRED boolean semantics it never asked for. `Portland, OR hotel` sanitized to
`Portland OR hotel` and broadened into a disjunction; a leading `NOT ready` was
an outright FTS syntax error that dumped the query onto the LIKE full-scan —
the exact failure mode this branch exists to close.

Raw and deliberate queries share one unmarked entry point, so the raw reading
has to be the safe one: bare operators outside quoted phrases are lowercased,
which turns them back into ordinary barewords (FTS5 operators are operators only
in uppercase). An explicit "NEAR" phrase is already a literal and is untouched.

The two hyphenated-operator tests asserted the OLD contract, where a stray OR
broadened the query. They now assert the new one — the messy query resolves
conjunctively with no syntax error and no full-table fallback — plus a positive
check that the hyphenated compounds themselves reach the target through the
index, which is what finding 1 bought.
str.isalnum() is not unicode61's token boundary. A combining mark is not
alphanumeric, so a decomposed "naïve" (nai + U+0308) sanitized to "nai ve" while
unicode61 folds and indexes the word as "naive" — zero rows for a query that
matched raw. That directly contradicted the tokenizer-parity invariant this
sanitizer is justified by.

sanitize_fts5_query now composes to NFC first, so a decomposed accent is the one
alphanumeric character the tokenizer folds, and any mark that does NOT compose
(a virama, stacked diacritics) is kept inside its token rather than treated as a
separator. The LIKE path deliberately does not normalize: it is a literal
substring match against stored bytes and must not re-spell the query.
…ad of guessing

Neutralizing bare operators broke the ONE in-repo caller that composes FTS5
syntax on purpose: benchmarking/longmemeval.build_fts_query joins its barewords
with OR, and lowercasing them turned the harness's disjunction into a
conjunction that also required the literal word "or" — the FTS arm's recall@10
fell from 1.0 to 0.0. That is the Phase 1B instrument itself, so leaving it
broken would have silently gutted the rerun this branch exists to enable.

The reviewer named the real defect: raw and deliberate queries shared one
unmarked mode. So mark it. search() and sanitize_fts5_query() take an explicit
allow_operators flag, default False — raw prose keeps the safe reading from the
previous commit — and the harness, which knows it wrote operator syntax, opts
in. Caught by tests/test_longmemeval_harness.py, which is why the arm assertion
is worth keeping.
…d scan

cache=False kept NEW batches out of the LRU but did nothing about what was
already in it, and the retrieval-core pool keeps a store alive for the whole
process. The delta-review probe measured cache_before=4 / cache_after=4 across a
two-batch scan: four matrices warmed by earlier calls — ~192MB of summary
float32 at a 25k batch, before the separate chunk cache — sitting resident
alongside the streamed batch. The one-batch peak claim was false in exactly the
long-lived-process case that motivates it.

A multi-batch sweep now releases every cached matrix before allocating its first
batch. All four caches go: both float32 LRUs and both binary-prescreen caches,
since all of them are retained scan state and the binary ones are additive to
the same peak. Same probe after the fix: cache_before=4, cache_after=0, and 0
resident at EVERY batch allocation.

Safe on a shared pooled store: clearing only drops dict entries. A caller
mid-scan holds its own reference to the tuple it was handed, so its matrix stays
alive until it returns and is freed normally after. Single-batch scans are
untouched and keep their warm-cache behavior, pinned by the existing test.
Phase 1B: full-corpus batched recall scan + in-product FTS5 query sanitization (#167, #168)
@evaos-code-review-bot

evaos-code-review-bot Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

evaOS review status: completed

PR: #175 - [R2 mono] wave-1 + scaling fixes + citable delivery — fork review rounds
Head: 060a0df5824a741b9c7cfde5f6c9b5acffb549e2
Updated: 2026-07-29T07:57:35.740Z

evaOS review completed for this PR head.

Automation note: agents should wait for this comment to reach completed, stale_head, closed_or_merged_before_review, skipped, or failed before treating evaOS review as settled for this head. provider_deferred means evaOS still intends to retry.

PR URL: #175

Review URL: #175 (review)

@evaos-code-review-bot evaos-code-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

PR: #175 - [R2 mono] wave-1 + scaling fixes + citable delivery — fork review rounds
Head: 060a0df5824a741b9c7cfde5f6c9b5acffb549e2 into main. Review event: COMMENT.
Provider: GLM/Z.ai through ZCode (zcode-glm, zcode, model GLM-5.2).

Estimated review effort: 5/5 (~70 min)

Changed Files

File Status Churn Purpose Risk
.github/ISSUE_TEMPLATE/bug_report.yml modified +1/-1 Changed file Low
CHANGELOG.md modified +8/-0 Documentation Low
DELTA-REVIEW-PACKET.md added +24/-0 Documentation Low
FINDINGS-VERDICTS-R2.md added +19/-0 Documentation Low
FINDINGS-VERDICTS-R3.md added +21/-0 Documentation Low
FINDINGS-VERDICTS-R4.md added +17/-0 Documentation Low
FINDINGS-VERDICTS-R4B.md added +19/-0 Documentation Low
FINDINGS-VERDICTS-R6.md added +8/-0 Documentation Low
FINDINGS-VERDICTS.md added +22/-0 Documentation Low
README.md modified +1/-1 Documentation Low
REGRESSION-REPORT.md added +56/-0 Documentation Low
REVIEW-PACKET.md added +47/-0 Documentation Low
adaptive_retrieval.py modified +47/-7 Changed file Low
benchmarking/h3_composition_replay.py added +462/-0 Changed file Elevated: large change
benchmarking/h5_recall_replay.py added +425/-0 Changed file Elevated: large change
benchmarking/h5_state_semantic_replay.py added +291/-0 Changed file Elevated: large change
benchmarking/longmemeval.py modified +5/-1 Changed file Low
benchmarking/state_embedding_backfill.py added +266/-0 Changed file Elevated: large change
benchmarking/stress.py modified +45/-13 Changed file Low
benchmarking/w3b_diversity_replay.py added +456/-0 Changed file Elevated: large change
benchmarking/w3b_it4_replay.py added +188/-0 Changed file Low
config.py modified +32/-5 Configuration Low
dag.py modified +52/-2 Changed file Low
db_bootstrap.py modified +32/-2 Changed file Low
docs/operator-guide.md modified +1/-1 Documentation Low

32 additional changed files omitted from this walkthrough.

Review Signal

No validated inline findings.
Dropped findings before posting: 0. High-severity findings: 0.

Risk Taxonomy

No finding categories.

Validation and Proof

No required validation recommendation selected; rely on existing GitHub checks and human review.
Proof status: not_applicable - No required behavior proof selected for this changed surface.
Profile validation hints: Prefer correctness, security, data-loss, release, and regression findings over style-only feedback.
Profile proof expectations: Look for focused validation, rollback notes, and evidence appropriate to the changed surface.

Related Context

Related issues/PRs: #167, #168, #164, #174, #171, #172.
Suggested labels: docs, tests.
Suggested reviewers: none from current metadata.

Review Settings Preview

  • Profile: assertive
  • Enabled sections: Review summary (inline_review); Walkthrough (inline_review); Changed-files table (walkthrough); Effort estimate (walkthrough); Related issues/PRs (walkthrough); Review status comment (sticky_status)
  • Path instructions: none
  • Label suggestions: none
  • Reviewer suggestions: none
  • Suggestion behavior: suggestions only; labels and reviewers are not auto-applied.
  • Roadmap-only settings: auto-apply labels; auto-request reviewers; required status checks

Pre-merge checklist

  • Inline comments target current RIGHT-side diff lines.
  • No secret-like content survived into posted inline comments.
  • REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
  • Required behavior proof is present or not applicable.
  • Labels and reviewers are suggestions only; the bot did not auto-apply them.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
trajectory_store.py (1)

3233-3301: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Skip the source-semantic embed for termless queries

  • scoped_rows is always [] when expression is empty, so _semantic_source_ranks(query) can only affect telemetry here while still billing tokens under an active embedding provider. Gate it behind if expression: and keep the state-semantic path unchanged.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trajectory_store.py` around lines 3233 - 3301, Update the semantic
source-ranking block around _semantic_source_ranks so it is invoked only when
expression is non-empty; use empty semantic ranks and skip related
embedding/telemetry work for termless queries. Preserve the existing
state-semantic path and the current scoped_rows behavior for queries with an
expression.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@adaptive_retrieval.py`:
- Around line 176-183: Update EvidenceRequirement.parse() validation to reject
descriptions containing surrogate code points, including lone surrogates, before
constructing the requirement; preserve the existing length and empty-description
checks, and add a regression test covering the rejected input.

In `@tests/test_h5_state_semantic_replay.py`:
- Around line 8-19: Add an explicit assertion in
test_output_parent_exists_before_provider_work that CachedVoyageQueryProvider is
not constructed, such as monkeypatching its constructor with a failing spy
before invoking h5_state_semantic_replay.main. Preserve the existing exit-code,
parent-directory, and absent-output assertions.

---

Outside diff comments:
In `@trajectory_store.py`:
- Around line 3233-3301: Update the semantic source-ranking block around
_semantic_source_ranks so it is invoked only when expression is non-empty; use
empty semantic ranks and skip related embedding/telemetry work for termless
queries. Preserve the existing state-semantic path and the current scoped_rows
behavior for queries with an expression.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1f634614-3d43-44d6-8e6d-79baa24a9897

📥 Commits

Reviewing files that changed from the base of the PR and between 4b684c9 and 060a0df.

📒 Files selected for processing (7)
  • FINDINGS-VERDICTS-R6.md
  • adaptive_retrieval.py
  • benchmarking/h5_state_semantic_replay.py
  • tests/test_adaptive_retrieval.py
  • tests/test_h5_state_semantic_replay.py
  • tests/test_trajectory_state_semantic_expansion.py
  • trajectory_store.py
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.14)
  • GitHub Check: test (3.12)
🧰 Additional context used
🪛 ast-grep (0.45.0)
adaptive_retrieval.py

[warning] 47-49: Regex pattern passed to re is built from a non-literal (variable, call, concatenation, or f-string) value. If that value is attacker-controlled it can introduce a malicious pattern with catastrophic backtracking (ReDoS). Use a hardcoded literal pattern, or validate/escape untrusted input with re.escape() and bound the regex complexity before compiling.
Context: re.compile(
rf"^[a-z][a-z0-9_.-]{{0,{MAX_REQUIREMENT_SLOT_ID_CHARS - 1}}}$"
)
Note: [CWE-1333] Inefficient Regular Expression Complexity.

(redos-non-literal-regex-python)


[info] 110-120: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"slot_id": "s" * MAX_REQUIREMENT_SLOT_ID_CHARS,
"description": "\0" * MAX_REQUIREMENT_DESCRIPTION_CHARS,
"minimum_refs": MAX_CANDIDATE_REFS,
},
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (6)
FINDINGS-VERDICTS-R6.md (1)

1-8: LGTM!

tests/test_adaptive_retrieval.py (1)

14-17: LGTM!

Also applies to: 244-254, 275-356

adaptive_retrieval.py (1)

39-50: LGTM!

Also applies to: 107-130

trajectory_store.py (1)

1808-1827: Spend ledgered before failure-prone persistence — matches Round-6 intent.

Moving stats["provider_calls"]/billed_tokens accounting and _emit_progress() to immediately after embed_documents() (before the vector-count check and _persist()) correctly ensures the ledger reflects real spend even if persistence later fails. Verified against test_normal_batch_persist_failure_still_ledgers_spend.

tests/test_trajectory_state_semantic_expansion.py (1)

19-19: LGTM!

Also applies to: 263-281, 717-760

benchmarking/h5_state_semantic_replay.py (1)

149-149: LGTM!

Comment thread adaptive_retrieval.py
Comment thread tests/test_h5_state_semantic_replay.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 060a0df582

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread trajectory_store.py
Comment on lines +1830 to +1835
if batch_docs and (
len(batch_docs) >= batch_max_items
or batch_tokens + tokens > batch_token_budget
):
_flush_normal()
batch_ids.append(state_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Split documents to honor the request token budget

When a caller configures batch_token_budget below document_token_budget, a normal document can be larger than the batch budget, but this condition only flushes an already-populated batch and then appends the oversized document unchanged. The subsequent embed_documents() request therefore exceeds the explicitly configured request cap and may be rejected by the provider; classify or split documents using the smaller of the two budgets, or reject this parameter combination.

Useful? React with 👍 / 👎.

Comment thread trajectory_store.py
Comment on lines +1737 to +1739
"SELECT state_id FROM lcm_trajectory_state_embeddings "
"WHERE profile_digest = ?",
(profile_digest,),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Clear prior rows before a forced same-profile rebuild

When resume=False forces a rebuild using the same provider/model/profile digest as an existing complete index, the old rows are left in place while batches overwrite them. If that rebuild is interrupted or intentionally stopped by the cost cap, a subsequent default resume selects every old and newly written row here as already embedded, performs zero remaining provider work, passes the row-count completeness check, and reactivates a stale or mixed index. Delete or generation-scope the same-profile rows when starting a forced rebuild so a later resume can distinguish unfinished work.

Useful? React with 👍 / 👎.

Comment thread benchmarking/h3_composition_replay.py Outdated
Comment on lines +284 to +287
top = ctx.global_top_state_ids(qid, 128)
for ref in info["vanished"]:
state_id = ctx.ref_to_state_id(qid, ref)
per_ref.setdefault(qid, {})[ref] = state_id is not None and state_id in top

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include scoped semantic rows in Policy D's ceiling

For an arm_quota sweep cell, Policy D selects its semantic arm from the fused rows pool, which includes FTS hits scoped to the injected semantic-top trajectories, but this ceiling labels a vanished reference recoverable only when it is in the global FTS top 128. A target present only in the scoped pool is therefore excluded from the denominator and evaluate_knob() skips it even if Policy D actually delivers it, under-reporting recovery and potentially invalidating the composition experiment's conclusion. Compute a policy-appropriate ceiling from the same fused candidate pool used by the arm.

Useful? React with 👍 / 👎.

@100yenadmin

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- trajectory: forced same-profile rebuild (resume=False) clears prior
  rows before refill — no stale vectors from an earlier fill survive
- trajectory: document chunk-routing honors the SMALLER of document/
  request token budgets
- trajectory: termless queries skip the source-semantic embed (scoped
  rows are structurally empty there); state-semantic seeding intact
- adaptive_retrieval: requirement descriptions reject surrogate code
  points before canonical UTF-8 digesting
- h3 replay: Policy D arm-quota cells measure recoverability from their
  fused candidate pool (scoped semantic rows included)
- h5 test: out-dir contract now proves provider construction is skipped

All items quota-gated / bench-side / test-side — no delivery-path change.
Author: codex sol-high (R7); review: orchestrator. Full-suite exact-name
parity; 6 focused regressions green.

STOPPING RULE (declared): this closes the in-train fix cycle. Subsequent
non-delivery-path findings are filed as next-train issues.
@100yenadmin

Copy link
Copy Markdown
Owner Author

Round 7 response — 6/6 closed at 93a3ade; the in-train fix cycle CLOSES here

All six round-7 findings fixed surgically (verdicts in FINDINGS-VERDICTS-R7.md): forced same-profile rebuilds clear prior rows, chunk routing honors the smaller token budget, termless queries skip the structurally-useless source-semantic embed, surrogate code points rejected before digesting, Policy D ceilings computed from the fused pool, and the out-dir test now proves provider construction is skipped. Full-suite exact-name parity, 6 focused regressions green.

Stopping rule, declared: seven rounds are complete (finding decay 35 → 11 → 6 → 8 → 3 → 4 → 6, every finding fixed, refuted in writing, or deferred to a filed issue — #172, #176, #177, #178, #179). The delivery path has produced no findings since round 3; rounds 4–7 lived entirely in the default-off state-semantic subsystem, bench tooling, and tests. From this point, further findings in non-delivery code are welcomed as filed issues for the next train; only a HIGH+ finding on a delivery path reopens in-train fixes. This PR proceeds to consolidation per the release plan.

@evaos-code-review-bot

evaos-code-review-bot Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

evaOS review status: completed

PR: #175 - [R2 mono] wave-1 + scaling fixes + citable delivery — fork review rounds
Head: 93a3adefcab8b0a3cf7bda3196586694f1fea71f
Updated: 2026-07-29T08:33:48.014Z

evaOS review completed for this PR head.

Automation note: agents should wait for this comment to reach completed, stale_head, closed_or_merged_before_review, skipped, or failed before treating evaOS review as settled for this head. provider_deferred means evaOS still intends to retry.

PR URL: #175

Review URL: #175 (review)

@evaos-code-review-bot evaos-code-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

PR: #175 - [R2 mono] wave-1 + scaling fixes + citable delivery — fork review rounds
Head: 93a3adefcab8b0a3cf7bda3196586694f1fea71f into main. Review event: COMMENT.
Provider: GLM/Z.ai through ZCode (zcode-glm, zcode, model GLM-5.2).

Estimated review effort: 5/5 (~70 min)

Changed Files

File Status Churn Purpose Risk
.github/ISSUE_TEMPLATE/bug_report.yml modified +1/-1 Changed file Low
CHANGELOG.md modified +8/-0 Documentation Low
DELTA-REVIEW-PACKET.md added +24/-0 Documentation Low
FINDINGS-VERDICTS-R2.md added +19/-0 Documentation Low
FINDINGS-VERDICTS-R3.md added +21/-0 Documentation Low
FINDINGS-VERDICTS-R4.md added +17/-0 Documentation Low
FINDINGS-VERDICTS-R4B.md added +19/-0 Documentation Low
FINDINGS-VERDICTS-R6.md added +8/-0 Documentation Low
FINDINGS-VERDICTS-R7.md added +13/-0 Documentation Low
FINDINGS-VERDICTS.md added +22/-0 Documentation Low
README.md modified +1/-1 Documentation Low
REGRESSION-REPORT.md added +56/-0 Documentation Low
REVIEW-PACKET.md added +47/-0 Documentation Low
adaptive_retrieval.py modified +51/-7 Changed file Low
benchmarking/h3_composition_replay.py added +493/-0 Changed file Elevated: large change
benchmarking/h5_recall_replay.py added +425/-0 Changed file Elevated: large change
benchmarking/h5_state_semantic_replay.py added +291/-0 Changed file Elevated: large change
benchmarking/longmemeval.py modified +5/-1 Changed file Low
benchmarking/state_embedding_backfill.py added +266/-0 Changed file Elevated: large change
benchmarking/stress.py modified +45/-13 Changed file Low
benchmarking/w3b_diversity_replay.py added +456/-0 Changed file Elevated: large change
benchmarking/w3b_it4_replay.py added +188/-0 Changed file Low
config.py modified +32/-5 Configuration Low
dag.py modified +52/-2 Changed file Low
db_bootstrap.py modified +32/-2 Changed file Low

34 additional changed files omitted from this walkthrough.

Review Signal

No validated inline findings.
Dropped findings before posting: 0. High-severity findings: 0.

Risk Taxonomy

No finding categories.

Validation and Proof

No required validation recommendation selected; rely on existing GitHub checks and human review.
Proof status: not_applicable - No required behavior proof selected for this changed surface.
Profile validation hints: Prefer correctness, security, data-loss, release, and regression findings over style-only feedback.
Profile proof expectations: Look for focused validation, rollback notes, and evidence appropriate to the changed surface.

Related Context

Related issues/PRs: #167, #168, #164, #174, #171, #172.
Suggested labels: docs, tests.
Suggested reviewers: none from current metadata.

Review Settings Preview

  • Profile: assertive
  • Enabled sections: Review summary (inline_review); Walkthrough (inline_review); Changed-files table (walkthrough); Effort estimate (walkthrough); Related issues/PRs (walkthrough); Review status comment (sticky_status)
  • Path instructions: none
  • Label suggestions: none
  • Reviewer suggestions: none
  • Suggestion behavior: suggestions only; labels and reviewers are not auto-applied.
  • Roadmap-only settings: auto-apply labels; auto-request reviewers; required status checks

Pre-merge checklist

  • Inline comments target current RIGHT-side diff lines.
  • No secret-like content survived into posted inline comments.
  • REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
  • Required behavior proof is present or not applicable.
  • Labels and reviewers are suggestions only; the bot did not auto-apply them.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
benchmarking/h3_composition_replay.py (1)

190-224: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

deliver() and fused_candidate_state_ids() duplicate the query-and-inject boilerplate.

Both methods build store.injected and call store.query(...) with identical kwargs, only diverging in what they extract from telemetry afterward. Extract a private _run(qid, **kwargs) that performs the injection + query call once, and have both public methods pull their respective telemetry field from the result.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarking/h3_composition_replay.py` around lines 190 - 224, Extract the
shared injection and query logic from deliver() and fused_candidate_state_ids()
into a private _run(qid, **kwargs) helper that returns the query telemetry.
Update both public methods to call _run and extract only their respective
telemetry fields, preserving the existing query arguments and result
conversions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmarking/h3_composition_replay.py`:
- Around line 210-224: The fused candidate lookup in fused_candidate_state_ids
currently reads the truncated state_candidate_pool; update the query telemetry
usage to retrieve the uncapped state_candidate_pool_ids list, following the
existing diversity_cap pattern. Preserve integer state-ID conversion and return
the full candidate-limit pool so measure_ceiling can evaluate every arm_quota
cell.

---

Outside diff comments:
In `@benchmarking/h3_composition_replay.py`:
- Around line 190-224: Extract the shared injection and query logic from
deliver() and fused_candidate_state_ids() into a private _run(qid, **kwargs)
helper that returns the query telemetry. Update both public methods to call _run
and extract only their respective telemetry fields, preserving the existing
query arguments and result conversions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 653540e6-c0ad-4e37-a381-680bbc87dfe6

📥 Commits

Reviewing files that changed from the base of the PR and between 060a0df and 93a3ade.

📒 Files selected for processing (8)
  • FINDINGS-VERDICTS-R7.md
  • adaptive_retrieval.py
  • benchmarking/h3_composition_replay.py
  • tests/test_adaptive_retrieval.py
  • tests/test_h3_composition_replay.py
  • tests/test_h5_state_semantic_replay.py
  • tests/test_trajectory_state_semantic_expansion.py
  • trajectory_store.py
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.14)
🧰 Additional context used
🪛 markdownlint-cli2 (0.23.1)
FINDINGS-VERDICTS-R7.md

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🔇 Additional comments (8)
trajectory_store.py (1)

1727-1737: LGTM!

Also applies to: 1771-1785, 1852-1854, 3273-3308

tests/test_trajectory_state_semantic_expansion.py (1)

263-283: LGTM!

Also applies to: 566-611, 723-753

tests/test_h3_composition_replay.py (1)

1-39: LGTM!

adaptive_retrieval.py (2)

176-187: LGTM!


107-130: 🎯 Functional Correctness

No issue: _REQUIREMENTS_DIGEST_MAX_CHARS is derived from the max canonical item length, including description, and covers the 12-item payload with one-item headroom.

tests/test_adaptive_retrieval.py (1)

288-295: LGTM!

tests/test_h5_state_semantic_replay.py (1)

8-28: LGTM!

FINDINGS-VERDICTS-R7.md (1)

1-14: LGTM!

Comment on lines +210 to +224
def fused_candidate_state_ids(
self, qid: str, **kwargs: Any
) -> set[int]:
domain, text = self.questions[qid]
store = self.stores[domain]
store.injected = self._injected_ranks(qid)
store.query(
text, candidate_limit=128, limit=16, image_limit=0,
include_adjacent=True, text_char_limit=2000, **kwargs,
)
return {
int(row["state_id"])
for row in store.last_query_telemetry()["state_candidate_pool"]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant files and inspect the surrounding code.
git ls-files | rg '(^|/)(benchmarking/h3_composition_replay.py|trajectory_store\.py|.*diversity_cap.*|.*trajectory.*)$'

echo '--- benchmarking/h3_composition_replay.py (around fused_candidate_state_ids and measure_ceiling) ---'
sed -n '180,340p' benchmarking/h3_composition_replay.py

echo '--- trajectory_store.py (search for state_candidate_pool / survivor_state_ids / telemetry) ---'
rg -n -A8 -B8 'state_candidate_pool|survivor_state_ids|last_query_telemetry|candidate_limit|include_adjacent' trajectory_store.py

Repository: 100yenadmin/hermes-lcm

Length of output: 22497


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- trajectory_store.py (around candidate selection and telemetry) ---'
sed -n '3440,3665p' trajectory_store.py

echo '--- tests touching diversity_cap / candidate telemetry ---'
rg -n -A6 -B6 'diversity_cap|survivor_state_ids|state_candidate_pool|fused_candidate_state_ids|arm_quota' tests benchmarking

Repository: 100yenadmin/hermes-lcm

Length of output: 50378


Expose an uncapped fused candidate-id list for the ceiling sweep.

state_candidate_pool is truncated to 64 rows, so fused_candidate_state_ids() can miss state IDs that are present in the full candidate_limit=128 pool. That makes measure_ceiling() undercount recoverable vanished refs for every arm_quota cell. Reuse the same pattern as diversity_cap and return a full state_candidate_pool_ids list instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarking/h3_composition_replay.py` around lines 210 - 224, The fused
candidate lookup in fused_candidate_state_ids currently reads the truncated
state_candidate_pool; update the query telemetry usage to retrieve the uncapped
state_candidate_pool_ids list, following the existing diversity_cap pattern.
Preserve integer state-ID conversion and return the full candidate-limit pool so
measure_ceiling can evaluate every arm_quota cell.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 93a3adefca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment on lines +178 to +180
embedded = max(1, stats["states_embedded"])
pending = max(1, stats["pending"])
projected_tokens = stats["billed_tokens"] / embedded * pending

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use dispatched batch size in cost projections

When the first normal embedding request contains multiple states, build_state_semantic_index() invokes the callback before persisting them, so states_embedded is still zero and this denominator becomes 1. A 32-document first batch is therefore projected as though its billed tokens covered one state, inflating the estimated total by roughly 32×; a valid --cost-cap can abort the backfill after a paid request even when the true projected run cost is below the cap. Track documents dispatched in the current request or defer the projection until that batch's completed-state count is available.

Useful? React with 👍 / 👎.

Comment thread trajectory_store.py
Comment on lines +1869 to +1872
if len(vectors) != len(sub):
raise ValueError("chunk embedding count does not match batch size")
for vector in vectors:
chunk_vectors.append(_normalized_vector(vector, expected_dim=dim))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for chunk requests before validating vectors

When an oversized-state embed_documents() call returns a malformed vector count or a vector with the wrong dimension, these validations raise before provider_calls, billed_tokens, and the progress ledger are updated. The provider request was still dispatched and may be billable, so the CLI loses it from its audit trail and cost-cap accounting; record and emit the request usage immediately after the provider returns, before failure-prone validation, as the normal path now does.

Useful? React with 👍 / 👎.

for k, v in _COMPOSITIONS.items()},
"sweep": results,
}
args.out.write_text(json.dumps(payload, indent=2))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Create the H5 replay output directory before sweeping

When --out names a file in a directory that does not already exist, this final write raises FileNotFoundError only after the golden gate, baseline measurements, and every radius/quota replay have completed. The experiment then consumes its full runtime without producing an artifact; create args.out.parent before starting the sweep, as the sibling replay drivers do.

Useful? React with 👍 / 👎.

Comment thread trajectory_store.py
Comment on lines +1652 to +1661
source_profile = self._semantic_profile()
dim: int | None = None
probe_provider_calls = 0
probe_billed_tokens = 0
if (
source_profile is not None
and str(source_profile["provider"]) == provider_name
and str(source_profile["model_name"]) == model_name
):
dim = int(source_profile["dim"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reuse the completed state profile before probing

When a state-only index is already complete but no source-level semantic profile exists, a default resume still reaches the dimension probe because this lookup consults only _semantic_profile(), not the matching active state profile. The rerun then pays for embed_query() even though every state is skipped, contradicting the zero-provider-call idempotency contract and allowing a tight cost cap to abort an otherwise no-op resume; reuse the dimension from a matching state profile after checking its provider, model, document version, and manifest.

Useful? React with 👍 / 👎.

Comment on lines +156 to +159
_bootstrap_package(_REPO_ROOT)
provider = CachedVoyageQueryProvider()
ctx = StateReplayContext(
args.run_root, args.h1_artifacts, args.h31_artifacts, args.db_dir, provider

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate the replay provider against the state profile

When --db-dir points to copies backfilled with any supported model other than voyage-4, this hard-coded provider identity does not match the active state profile. _semantic_state_ranks() then silently returns no candidates, while the knob-off golden gate still passes and the script writes an apparently valid sweep reporting zero state-semantic recovery. Resolve the model from the active profiles or fail before the golden gate when both database copies do not match the requested provider identity.

Useful? React with 👍 / 👎.

@100yenadmin
100yenadmin merged commit cb92bf4 into main Jul 29, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant