Skip to content

fix(compression): fence WebUI with durable revisions - #6554

Merged
nesquena-hermes merged 2 commits into
nesquena:masterfrom
ruizanthony:fix/compression-durable-transcript-revision
Aug 21, 2026
Merged

fix(compression): fence WebUI with durable revisions#6554
nesquena-hermes merged 2 commits into
nesquena:masterfrom
ruizanthony:fix/compression-durable-transcript-revision

Conversation

@ruizanthony

@ruizanthony ruizanthony commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Capture WebUI history and its durable transcript revision atomically, then pass the same identity to compatible Hermes Agent versions for compression freshness checks.

This is the WebUI half of the durable fence: projection differences are valid; true concurrent SQLite mutations must block stale publication.

Changes

  • return a typed snapshot containing projected messages and the revision of the exact active rows read;
  • include active-row count, max active id, row digest and model-facing api_content digest;
  • fail closed for missing explicit profiles instead of falling back across profile boundaries;
  • centralize all three Agent invocation paths behind one rolling-compatible kwarg builder;
  • omit conversation_history_revision for strict legacy Agents and pass it to explicit/variadic compatible Agents;
  • refresh both context and revision before credential self-heal retries;
  • classify structured stale results consistently on ordinary and both retry paths;
  • retain only current-turn-owned partial output, failing closed when the current user anchor is absent or a replay is non-prefix.

Exact pairing

  • WebUI base: 320789ae596a3963d726d90f6c7f3bc86f7f2d6d;
  • WebUI head: 0f7c4cef3f38aab591ae6fa6fcfdb76a869c669a;
  • paired Agent #72806: 1bdac5d4547914d70c134f06af0435568a35159c;
  • Agent base: cb11a7e25579638c9f67e8501dd151f581c4c942.

Validation

  • exact WebUI↔Agent pair: 54 passed, 0 failed;
  • source-string call-site test replaced by an observable strict-legacy contract test;
  • Python compilation and git diff --check: passed;
  • prior head's GitHub checks were green; checks for this new exact head are required before promotion.

The complete guarantee requires both PRs. Rolling WebUI-first installations remain functional through the capability gate but do not gain the durable fence until the Agent side is upgraded.

@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from 8c0e78f to bb58255 Compare July 27, 2026 18:13
@nesquena-hermes nesquena-hermes added the size:L Large PR (>10 files or >250 LOC) label Jul 27, 2026

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes requested: keep the WebUI compatible with the pre-fence Agent contract

The current head unconditionally includes conversation_history_revision in all three AIAgent.run_conversation(...) paths:

  • api/streaming.py:9117 (ordinary turn)
  • api/streaming.py:9607-9609 (first credential self-heal retry)
  • api/streaming.py:10854-10856 (second self-heal path)

The currently deployed Agent's strict method signature (run_agent.py:6804-6814, Agent revision e6b977933e3f980a81ec5211fa2131ce8876b9cf) does not accept that keyword and has no **kwargs. The call therefore raises before the Agent body runs, including when the revision value is None. A sandboxed exact-head probe reproduced a generic apperror containing unexpected keyword argument 'conversation_history_revision', with zero entries into the Agent method. This is a WebUI-head regression: base does not pass the keyword.

The paired Agent PR is still open, and pairing does not make a WebUI-first or independently updated installation safe. The adjacent moa_config handling already demonstrates the required rolling-compatibility pattern.

Required fix

  1. Centralize a capability check for the live run_conversation callable. Add conversation_history_revision only when the signature explicitly supports it or accepts **kwargs, and use that same rule at all three invocation sites.
  2. For a pre-fence Agent, either omit the keyword and preserve the existing turn behavior, or detect an enforced minimum Agent version before accepting the turn and return an explicit actionable upgrade error. Do not let an unexpected-keyword TypeError consume the turn.
  3. Add a strict legacy-Agent fake with the deployed parameter list and no **kwargs. Cover ordinary turns and both self-heal paths, with both revision=None and a real revision.

The submitted focused files are otherwise green through the enforced sandbox: 18 passed. The WebUI-side snapshot/profile-scope work reads coherently, but the cross-repo atomic revision contract still needs paired acceptance coverage for same-ID api_content mutation and late writes around Agent compression publication.

@nesquena-hermes nesquena-hermes added the changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address label Jul 27, 2026
@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from bb58255 to 8986913 Compare July 27, 2026 19:04
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Addressed in 8986913. The WebUI now capability-gates conversation_history_revision against the live bound run_conversation signature and only passes it when explicitly supported or when **kwargs is accepted. The same helper is used by the ordinary turn and both credential self-heal paths. Added strict legacy-Agent and revision-aware tests for both None and real revision values; focused regression suite is 39/39 green and diff lint/compile checks pass.

@ruizanthony

Copy link
Copy Markdown
Contributor Author

@nesquena-hermes CI is now fully green on the compatibility fix. Re-review requested when available.

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

🔬 Gate certification — RED ⛔

Certified head: 8986913afa880288bbff9a1afc24c5181c7c1fd6 (contributor head, author @ruizanthony)
Base / merge-base: 21bdd7c1f1afe1c1a69d46e7dd2215d9020a834a
Verdict: SHIP ONLY WITH FIXES — one reproduced feature-completeness defect on the PR's own stale-snapshot path.

The prior maintainer CHANGES_REQUESTED (unconditional conversation_history_revision kwarg → TypeError on the pre-fence Agent) is fully resolved at this head. This RED is a new, narrower finding on the returned-result delivery of the stale outcome.

What I ran (isolated worktree, exact head)

  • Full pytest suite to completion (sandbox, -p no:xdist): 13,759 passed, 83 skipped, 1 xfailed, 2 xpassed, 34 subtests passed, 8 failed + 2 errors.
    • The 8 failed / 2 errors reproduce identically on an exact-master control (21bdd7c1f) run under the same sandbox: test_docs_gitignore_policy (4), test_issue609 path-traversal (2), test_5774b_atomic_config_writes::test_atomic_write_preserves_existing_group, and test_issue2695_packaged_runtime_layout (2 errors) are pre-existing sandbox-topology / git-tracking artifacts, not PR-owned.
    • test_issue1499_keyless_onboarding::test_lmstudio_keyless_chat_ready_via_full_status passes in isolation on both candidate and control — a pre-existing full-suite ordering interaction in an unrelated (lmstudio provider-detection) subsystem, not a regression from this diff.
  • Codex regression gate (GPT-5.6-sol, xhigh) → VERDICT: SHIP ONLY WITH FIXES (finding reproduced below).
  • Opus 4.8 backend gate → APPROVE / "ship it" (capability gate correct + fail-safe; atomic snapshot↔revision contract verified; no regression).
  • Digest mutation-sensitivity check: neutered _active_rows_digest()return '' in a throwaway worktree; test_state_db_reader_revision_includes_api_content_digest flipped RED as expected — the digest assertion is non-vacuous.
  • Deployed strict-Agent compat probe: the installed pre-fence AIAgent.run_conversation (no conversation_history_revision, no **kwargs) → _add_supported_run_conversation_kwarg correctly omits the kwarg (returns False, kwargs unchanged). All three call sites use the same gate; no raw bypass (grep clean).
  • Explicit-profile fail-closed: confirmed a missing/invalid explicit profile no longer falls back to the active DB (isolation property holds).
  • Ruff-forward gate CLEAN (0 new violations), py_compile OK on api/models.py + api/streaming.py, git diff --check clean.

⛔ Blocker (reproduced) — returned-result stale path is unclassified

api/streaming.py:1224_classify_provider_error recognizes the stale outcome only when CompressionSnapshotStaleError is raised. But the paired Agent's primary delivery (agent/conversation_loop.py) returns a result dict {error: "compression_snapshot_stale", compression_snapshot_stale: True, partial: True, ...} — it does not raise on that path. Reproduced at this head:

_classify_provider_error("compression_snapshot_stale", "compression_snapshot_stale")
  → type="error",   hint=""      # returned-result path: generic error, NO recovery hint
_classify_provider_error(str(exc), CompressionSnapshotStaleError(...))
  → type="compression_snapshot_stale", hint="The durable conversation changed…"  # raised path only

So on the normal (returned-result) stale outcome the user gets a bare **Error:** bubble with no "reload and reconcile" guidance — defeating the whole point of the typed compression_snapshot_stale UX this PR adds, and (since type != compression_snapshot_stale) the streaming error-path never applies the bounded public message either.

Precise fix-spec (small)

  1. In _classify_provider_error (or an equivalent pre-classification check on the agent result), classify result.get("error") == "compression_snapshot_stale" (and/or result.get("compression_snapshot_stale") is True) identically to the raised CompressionSnapshotStaleError — same type, bounded public message, and recovery hint. The classifier currently only inspects the exception/text, so plumb the result-code in at the terminal-failure classification site (~api/streaming.py:9490-9503) where result.get('error') is already read.
  2. Add a focused test whose fake Agent returns the structured stale result (not raises) and assert apperror.type == "compression_snapshot_stale", the hint is present, and no retry / no done event occurs. Keep the existing raised-exception test.

Non-blocking polish (do not gate on these)

  • test_all_agent_invocation_paths_use_revision_capability_gate asserts source-string counts rather than behavior; the strict-legacy Agent is only exercised through the unit helper, never end-to-end through _run_agent_streaming. An end-to-end strict-legacy turn test would be stronger.
  • get_state_db_session_messages switched ORDER BY timestamp ASC, id ASCORDER BY id ASC for all callers (wider than revision callers); intentional and green, but the id-less legacy-schema limit path loses tiebreaker determinism.

Recommendation to the next agent

Fix #1+#2 then re-gate. This is a small, mechanical addition (classify one result code + one test) but it needs the contributor's cross-repo contract knowledge of exactly how the Agent delivers the stale outcome — bouncing to @ruizanthony. Everything else (maintainer compat blocker, atomicity, profile isolation, digest fence, full suite) is green at this head. No merge/tag/deploy performed by this lane.

Full gate: Codex-reproduce + Opus 4.8 + full pytest suite (matched-control attribution) + digest mutation-sensitivity + deployed-strict-Agent compat probe. Head 8986913a reconfirmed live immediately before posting.

@nesquena-hermes nesquena-hermes added the gate-fail Gate found blocking issue(s); fix-spec in comment; awaiting fix/re-push label Jul 27, 2026
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Gate fix applied — head 564d4dcad5313a11daf6aed7c8b0d5d3fbf78f94

The returned-result stale-snapshot blocker from the certification above is addressed in 564d4dca.

Change

  • _classify_provider_error(..., result=...) now treats either exact structured signal
    • result["error"] == "compression_snapshot_stale", or
    • result["compression_snapshot_stale"] is True
      identically to a raised CompressionSnapshotStaleError.
  • The terminal-failure path passes the Agent result to that classifier. No broad text matching was added.
  • The existing regression test is parameterized across both delivery modes. The returned-result case uses the paired Agent contract (error, compression_snapshot_stale, partial, failed) and asserts:
    • apperror.type == "compression_snapshot_stale"
    • bounded public message + reload/reconcile hint
    • internal revision details are not exposed
    • one Agent call only, no done
    • active state cleared and partial work retained
  • The two non-blocking polish items remain intentionally untouched.

Local evidence

  • RED before production change: returned-result case produced type="error"; raised-exception case passed.
  • ./scripts/test.sh tests/test_compression_snapshot_revision.py tests/test_state_db_read_backstop.py -q26 passed
  • Adjacent terminal-state suites → 35 passed
  • ./scripts/test.sh tests/test_mcp_server.py -q50 passed
  • Ruff diff gate, py_compile, compileall, git diff --check → clean
  • Diff remains limited to api/streaming.py and tests/test_compression_snapshot_revision.py.

Current GitHub CI attribution

The new head's lint and both conversation-lifecycle jobs pass. The Python matrix fails identically on all 15 shards in unrelated tests/test_mcp_server.py imports because requirements-dev.txt specifies unpinned mcp and the runner now installs newly released mcp 2.0.0, whose Server no longer has list_tools:

AttributeError: 'Server' object has no attribute 'list_tools'

The validated local environment has mcp 1.27.0 (Server.list_tools present), where all 50 MCP tests pass. The previous certified head's CI was also fully green before this dependency release. I did not widen this PR to pin or migrate the unrelated MCP dependency. Browser smoke was cancelled by GitHub; GitHub refused a direct rerun with workflow file may be broken.

Please re-gate the blocker on 564d4dcad5313a11daf6aed7c8b0d5d3fbf78f94; the remaining red matrix is an independently evidenced repository dependency break, not owned by this two-file diff.

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes requested: classify stale results from both credential self-heal retries

The new commit correctly classifies a structured stale result from the ordinary run_conversation() attempt, and the previously approved capability gate remains intact at all three Agent call sites. One reachable part of the same contract is still unhandled: when either credential self-heal retry returns the structured stale result, WebUI never re-adjudicates _heal_result.

Reproduced at exact head 564d4dcad531

I adapted the PR's existing two-mode credential-self-heal regression so that the rebuilt Agent returns the same contract this commit now handles on the ordinary path:

{
    "error": "compression_snapshot_stale",
    "compression_snapshot_stale": True,
    "partial": True,
    "failed": False,
    "messages": [..., {"role": "assistant", "content": "partial stale"}],
}

The enforced CLEAN-scan + bubblewrap gate ran both schedules. Both failed because no stale apperror was emitted:

FAILED ...test_auth_self_heal_refreshes_revision_after_first_agent_persists_user[result]
FAILED ...test_auth_self_heal_refreshes_revision_after_first_agent_persists_user[exception]
assert apperrors and apperrors[-1]["type"] == "compression_snapshot_stale"
E assert ([])
2 failed

The code trace matches the runtime result:

  • Returned-auth path, api/streaming.py:9660-9668: _heal_result is judged only by new assistant/token state. A stale partial result can satisfy _heal_ok, enter the success merge path, and later emit success instead of the stale terminal event.
  • Raised-auth path, api/streaming.py:10910-10954: any normal _heal_result is persisted and the function returns before error emission.
  • Only the primary result is passed to _classify_provider_error(..., result=result) at api/streaming.py:9518-9523.

The submitted focused file is otherwise green through the same sandbox (19 passed), and the previous compatibility/state-db matrix remains green (35 passed, up from 34). This is a narrow incomplete-consumer defect, not a walk-back of the earlier compatibility fix.

Required fix

  1. Route every run_conversation() return through one common stale-result adjudication path. At minimum, classify _heal_result before _heal_ok in the returned-auth retry and before persistence/return in the raised-auth retry.
  2. On an exact stale marker, preserve partial assistant output once, clear/materialize pending-turn ownership, emit exactly one sanitized apperror with type compression_snapshot_stale, emit no done, and do not attempt a third Agent run.
  3. Extend test_auth_self_heal_refreshes_revision_after_first_agent_persists_user (or add an equivalent two-mode regression) so both first-attempt auth-failure forms return stale from attempt two. Assert two calls, the refreshed revision, one stale apperror, no done, and retained partial/error persistence.
  4. Exercise the accepted error-string-only and boolean-flag-only forms independently, or narrow production acceptance to the exact paired-Agent result contract.

No merge, branch write, release, production action, or screenshot was performed.

@nesquena-hermes nesquena-hermes removed the changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address label Jul 29, 2026
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Self-heal stale-result gate fixed — head 93d2832265883dab2f1074aac2724d4a396d6240

The follow-up CHANGES_REQUESTED on 564d4dca is addressed in 93d28322.

Contract now covered

  • All three run_conversation() result paths use the same exact structured stale predicate:
    • result["error"] == "compression_snapshot_stale", or
    • result["compression_snapshot_stale"] is True.
  • Both credential self-heal retries adjudicate _heal_result before success detection, merge, persistence, or return.
  • A stale second result now:
    • stops after exactly two Agent calls (no third run),
    • emits exactly one sanitized apperror with type="compression_snapshot_stale",
    • emits no done,
    • materializes/clears pending ownership,
    • preserves the partial assistant row once, even when it exists only in the structured result,
    • persists the partial followed by the recovery error.
  • A genuinely recovered second attempt retains the previous success behavior.

Regression matrix

test_auth_self_heal_refreshes_revision_after_first_agent_persists_user now covers the cross-product of:

  • first auth failure: returned structured auth error / raised exception;
  • second result: success / stale error-string-only / stale boolean-flag-only.

The four new stale variants reproduced RED before the production change; all six variants now pass.

Local evidence

  • focused snapshot + state DB matrix: 30 passed
  • adjacent terminal/cancel/error suites: 54 passed
  • MCP control suite under mcp 1.27.0: 50 passed
  • diff-scoped Ruff: 0 new violations
  • py_compile, compileall, git diff --check: clean
  • changed files remain limited to api/streaming.py and tests/test_compression_snapshot_revision.py for this follow-up commit.

GitHub checks on exact head

Green:

  • lint
  • browser smoke
  • conversation lifecycle: normal
  • conversation lifecycle: terminal-error

The 15 Python shards again fail only after installing unpinned mcp 2.0.0, at unrelated tests/test_mcp_server.py imports with:

AttributeError: 'Server' object has no attribute 'list_tools'

This is the same independently reproduced repository dependency break as on the prior head; this PR does not modify MCP code or dependency declarations.

Please re-gate 93d2832265883dab2f1074aac2724d4a396d6240 against review #pullrequestreview-4808341219.

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes requested: keep stale-retry partials scoped to the current turn

Thanks for fixing the two credential self-heal consumers. At 93d2832265883dab2f1074aac2724d4a396d6240, both retry paths now classify a returned stale snapshot before success/persistence, emit one compression_snapshot_stale apperror, emit no done, and stop after two Agent runs.

One deterministic transcript-corruption case remains in the new partial-retention path:

  • api/streaming.py::_append_result_partial_on_error() scans all of result["messages"] in reverse and takes the latest non-error assistant row.
  • If the stale retry returns partial=True with history through the newly persisted current user but no assistant row for that current turn, the scan selects the previous turn's assistant answer.
  • Both retry error consumers then append that historical answer as a new _partial for the current turn.

I reproduced this in both self-heal entry modes (the first Agent call returning a 401 result and raising a 401 exception). The sandboxed characterization passed only while asserting the unsafe behavior: one replayed prior answer _partial, one stale apperror, no done, and exactly two Agent runs. The submitted changed-file suite itself remains green: 23 passed under the mandatory no-network sandbox.

Required fix

  1. Make result-partial extraction current-turn-owned. Give _append_result_partial_on_error() the exact pre-call context (and current msg_text) and inspect only result rows added for the current call. For a self-heal result, use that retry's freshly loaded _heal_context_messages as the baseline.
  2. If the current-turn slice has no non-error assistant output, append no result-derived _partial. The independent stream-buffer snapshot can still retain output that was actually streamed.
  3. Keep _partial_marker_already_present() deduplication.
  4. Add a production-composed regression for both self-heal entry modes where retry result has partial=True, contains history through the current user, and contains no current-turn assistant row. Assert that no prior answer is replayed, exactly one stale apperror is emitted, no done is emitted, exactly two Agent runs occur, and pending/active ownership is cleared.

This is a current-head changes request. The previously requested stale-result adjudication is resolved; the blocker is the new current-turn ownership defect introduced by the partial-retention helper.

@ruizanthony

ruizanthony commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Current-turn partial ownership fixed — head 25f503c1d4e844428f8f05597dd2c829009acf02

The transcript-corruption blocker from review #pullrequestreview-4810322349 is addressed in 25f503c1.

Change

  • _append_result_partial_on_error() now receives:
    • the copied pre-call context baseline;
    • the current msg_text.
  • Every Agent invocation captures that baseline immediately before run_conversation().
  • Both credential self-heal consumers use their retry's freshly loaded _heal_context_messages, not the original-turn context.
  • Result inspection is limited to rows beyond the baseline and, when the baseline does not already end with the current user, only rows after the matching current-user boundary.
  • If that current-turn slice contains no non-error assistant row, no result-derived _partial is appended.
  • The independent stream-buffer snapshot remains unchanged.
  • _partial_marker_already_present() remains the final deduplication guard.

Production-composed regression

The existing production-composed self-heal test now covers both entry modes:

  • first Agent call returns a 401 result;
  • first Agent call raises a 401 exception.

In both new cases, retry returns partial=True, history through new webui turn, and no current-turn assistant row.

Assertions cover:

  • historical prior answer is never replayed as _partial;
  • no result-derived partial is added;
  • exactly one compression_snapshot_stale apperror;
  • no done;
  • exactly two Agent runs;
  • refreshed retry revision;
  • active_stream_id, pending_user_message, and pending_attachments are cleared.

Both variants reproduced RED before the production change with:

AssertionError: assert not [{'role': 'assistant', 'content': 'prior answer', '_partial': True, ...}]
2 failed

They pass after the fix.

Local evidence

  • focused compression/state DB suite: 32 passed
  • aggregate focused + adjacent terminal/cancel/error suite: 86 passed
  • MCP control suite under local mcp 1.27.0: 50 passed
  • diff-scoped Ruff: 0 new violations
  • py_compile, compileall, git diff --check: clean
  • commit diff limited to api/streaming.py and tests/test_compression_snapshot_revision.py

GitHub checks on exact head

Green:

  • lint
  • browser smoke
  • conversation lifecycle: normal
  • conversation lifecycle: terminal-error

All 15 Python matrix shards install unpinned mcp 2.0.0 and fail in unrelated tests/test_mcp_server.py setup with:

AttributeError: 'Server' object has no attribute 'list_tools'

The final Python 3.13 shard also shows the compression regression tests passing before that MCP setup failure. This is the same independent repository dependency break already evidenced on the preceding heads; no MCP file or dependency declaration is changed here.

Please re-gate 25f503c1d4e844428f8f05597dd2c829009acf02 against review #pullrequestreview-4810322349.

@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from 25f503c to 96fd952 Compare July 29, 2026 17:52
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Rebased onto current master at head 96fd9520693296a88f9899fb18c36d75d6038ddb. Local targeted regression gate: 32 passed (test_compression_snapshot_revision.py, test_state_db_read_backstop.py); git diff --check clean. The current-turn stale-partial ownership fix is retained. Re-review requested on the rebased exact head when CI completes.

@ruizanthony

Copy link
Copy Markdown
Contributor Author

CI shard-4 compatibility failure fixed at head 7a3c54c085a12205a8a5b313ed5f31f8a1d47598: the adjacent provider-classifier spy now accepts and forwards the new result keyword. Local combined gate: 50 passed (test_issue5121_provider_auth_terminal_error.py, test_compression_snapshot_revision.py, test_state_db_read_backstop.py); git diff --check clean. Re-review requested on this exact head after CI.

@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from 7a3c54c to 144e376 Compare July 29, 2026 18:01
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Final rebase after upstream advanced: exact head 144e376ba24d82f75ce5e073620e2dae71197459. Combined targeted gate remains 50 passed; git diff --check clean. Please certify this exact head.

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes requested: non-prefix stale results can still replay the prior turn

Thanks for scoping result-derived partials to a pre-call baseline. The submitted append-prefix cases now pass for both credential self-heal entry modes, and the refreshed retry baselines plus deduplication are present at exact head 144e376ba24d82f75ce5e073620e2dae71197459.

One deterministic transcript-attribution defect remains in the same current-turn ownership path.

api/streaming.py::_append_result_partial_on_error() uses only len(messages) >= len(pre_call_context) before slicing messages[len(pre_call_context):]. It does not verify that the returned messages actually have pre_call_context as a prefix. When a supported compacted/replayed result replaces rather than appends to the baseline, a historical assistant row can shift into that numeric suffix. Because the refreshed baseline already ends with the current user, the fallback current-user search is skipped, and the historical answer is appended as this turn's _partial.

This result shape is part of the code's existing contract: the same module already notes that compacted/replayed results are not always append-only, and _assistant_reply_added_after_current_turn() handles it with _messages_have_prefix(...) plus _find_current_user_turn(...).

I reproduced the residual through the mandatory CLEAN threat scan and no-network bubblewrap gate: a non-prefix compacted/replayed stale result with no assistant after the current user appended the historical prior answer once as _partial. Dedup correctly suppressed a second append. The contributor's focused tests remain green, including both new append-prefix no-replay cases.

Required fix

  1. In _append_result_partial_on_error(), use the established boundary rule:
    • if _messages_have_prefix(messages, pre_call_context), inspect only the appended suffix;
    • otherwise locate the current user with _find_current_user_turn(messages, msg_text), return None if no current-user anchor exists, and inspect only rows after that anchor.
  2. Preserve the refreshed per-self-heal baselines and _partial_marker_already_present() deduplication.
  3. Extend the production-composed self-heal regression with a non-prefix compacted/replayed stale result containing historical assistant rows before the last current-user row and no assistant after it, crossed with both first-entry modes. Assert zero partial replay, one compression_snapshot_stale apperror, no done, two Agent calls, and cleared ownership.

Targeted sandbox evidence at this exact head: the focused contributor/tip-spy gate passed 11 tests, and the changed/neighbor file slice passed 57 tests. This is still-red partial rework on the existing current-turn ownership blocker, not a walk-back of the earlier stale-result adjudication fixes.

No merge, branch write, release, production action, or screenshot was performed.

@nesquena-hermes nesquena-hermes added changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address and removed changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address labels Jul 29, 2026
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Reviewer defect addressed (non-prefix partial replay in _append_result_partial_on_error()).

Defect: the error-path partial recovery still sliced messages[len(pre_call_context):] numerically without any prefix check. For compacted/replayed results that REPLACE the pre-call baseline instead of appending to it, that suffix can expose a historical assistant row from before the in-flight call — including the documented dedupe/move_last case — and replay it as the current turn's _partial_response.

Fix: before assigning, the result is verified with the existing _messages_have_prefix(...) helper. When the prefix holds, the previous append-only logic is unchanged. When it does not, the current user turn is located via the existing _find_current_user_turn(...) helper (the same boundary rule used by _assistant_reply_added_after_current_turn) and only rows after it are scanned for an assistant partial; the function fails closed (returns None) when no current-user anchor exists.

Regression coverage: new stale_non_prefix_compacted scenario in the auth self-heal parametrization — a compacted result whose numeric suffix contains historical assistant rows ("prior answer" etc.) and no current-turn assistant row — asserting no _partial row is persisted and no historical content is replayed.

Tests: python3 -m pytest tests/test_gateway_sync.py tests/test_compression_snapshot_revision.py -q -o addopts= -p no:cacheprovider93 passed (was 68+ baseline, now includes the new non-prefix parametrizations).

New head: da209652ee80a4574f15d7922fc55fc9587b5c60

@nesquena-hermes could you please re-review?

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes requested: fail closed when the current user turn is absent

Thanks for adding the prefix check and the non-prefix compacted regression. The exact numeric-suffix case from the prior review is fixed at da209652ee80, but the same historical-partial attribution blocker remains reachable through the helper reused by the new fallback.

Reproduced at exact head da209652ee80

In the non-prefix branch, _append_result_partial_on_error() calls _find_current_user_turn(messages, msg_text) and treats only None as “no current-user anchor.” That helper does not return None when the requested current turn is absent. It falls back to the last arbitrary user row:

fallback = idx
...
return fallback

I ran a production-helper characterization through the mandatory CLEAN threat scan and no-network bubblewrap sandbox. The result had partial=True, an unrelated historical user/assistant pair, no row matching the actual current prompt, and a mismatching pre-call baseline. The safety invariant failed:

assert appended is None
E AssertionError: assert {
  '_partial': True,
  'content': 'historical answer',
  'role': 'assistant',
  ...
} is None
1 failed

So the new comment says “fail closed when no current-user anchor exists,” but the called helper converts that no-match state into an unrelated historical anchor. The following historical assistant is then appended and persisted as this turn's _partial.

The submitted regression is useful and passes for both first-attempt modes. It contains a matching final new webui turn, so it cannot exercise this no-match branch.

Required fix

  1. In _append_result_partial_on_error(), use a safety-specific current-turn lookup that returns None unless it positively matches the actual current user text. Do not reuse _find_current_user_turn()'s arbitrary-user fallback in this persistence path.
  2. Keep workspace-prefix normalization, but require a strong/exact normalized match here. If the current turn cannot be proven, retain no result-derived partial. The independent stream buffer remains the safe source for output actually observed during this turn.
  3. Add a production-composed regression, crossed with both credential self-heal entry modes, where the non-prefix stale result contains an unrelated historical user followed by a historical assistant and contains no current-prompt row. Assert zero _partial replay, one sanitized compression_snapshot_stale apperror, no done, two Agent calls, and cleared ownership.
  4. Preserve the new prefix-vs-non-prefix split, refreshed retry baselines, and final partial deduplication.

Targeted sandbox evidence at this head: the contributor's four-file regression slice is green (59 passed), and the exact new non-prefix cases are green (2 passed). The blocker is the uncovered no-anchor branch above, not a walk-back of those fixes.

No merge, branch write, release, screenshot, server, or production action was performed.

@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from da20965 to 29229bf Compare August 3, 2026 10:00
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Corrections de la dernière revue publiées sur le head exact 29229bffc6d341a8ccce89d7f8f65b480b7347a6.

  • L’extraction des partiels échoue désormais fermée lorsque le tour utilisateur courant est absent, au lieu de retomber sur un tour historique.
  • La régression production-composed couvre les deux chemins d’auto-réparation.
  • Le rebase sur origin/master conserve désormais explicitement la projection owner/context requise par le nouveau settlement amont.
  • Validation post-rebase : 120 tests ciblés/adjacents réussis, compilation Python et git diff --check propres.

Merci de re-review ce SHA exact.

@ruizanthony

Copy link
Copy Markdown
Contributor Author

Exact review target updated to 0e2bad0e2622b40647b884f1c499083867ebf0d5, paired with Agent #72806 1bdac5d4547914d70c134f06af0435568a35159c. The final delta centralizes all three Agent invocation paths behind one compatibility chokepoint and replaces the source-count test with observable strict-legacy behavior. Exact coupled gate: 54/54 passed. Please certify this exact SHA.

@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from 0e2bad0 to 0f7c4ce Compare August 3, 2026 13:11
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Superseding the immediately previous review request: the tree is unchanged, but the final commit was republished with the repository-required verified author/committer identity. Exact WebUI review target: 0f7c4cef3f38aab591ae6fa6fcfdb76a869c669a, paired Agent #72806: 1bdac5d4547914d70c134f06af0435568a35159c. Exact coupled gate remains 54/54 green. Please certify this SHA.

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

🔬 Gate certification — RED ⛔

Certified contributor head: a2c75eac4c6256eba8ec3cf56828ea865670090e
Base / merge-base: 320789ae596a3963d726d90f6c7f3bc86f7f2d6d
Verdict: SHIP ONLY WITH FIXES — two exact-head streaming/data-integrity defects reproduce in production-shaped tests.

What I ran

  • Threat scan: CLEAN, score 0.
  • Codex regression gate: SHIP ONLY WITH FIXES. It reproduced both blockers below against the exact head.
  • Fable backend correctness gate: SHIP ONLY WITH FIXES. It independently reproduced blocker 1 in both credential-self-heal lanes.
  • Five real CI pytest shards, sandboxed: 13,851 passed, 100 skipped, 3 xpassed; 8 failed and 2 errored. The same command on clean current master produced the exact same 10 failing/error nodes, so those nodes are environmental attribution evidence, not PR findings and not a passing local suite. The exact contributor head also has 22/22 hosted checks green, including all 15 Python-version/shard jobs, lint, browser smoke, changes, and all three lifecycle jobs.
  • Private/static checks: git diff --check, py_compile, exact five-file diff-scope assertion, and Ruff forward gate all clean.
  • Independent bite test: the current no-anchor guard passed both self-heal lanes; restoring only the prohibited arbitrary historical fallback made both fail by persisting historical answer as _partial.
  • Cross-layer parity: WebUI's revision mapping matched the latest live Agent #72806 head 9a2237ec6dfd… under a production-composed sandbox probe for empty, append-only, in-place api_content mutation, and digest-clear states.
  • Independent blocker reproductions: production-shaped self-heal success failed in both returned-error and raised-exception lanes; exact-once partial persistence failed only in the returned-result lane with two copies.

Reproduced blockers

  1. Successful credential self-heal is rejected with the real Agent result shape (api/streaming.py:6672-6725, callers at 10361-10365 and 11627-11631).

    _self_heal_result_succeeded() treats a prefix result's suffix as current-turn rows, then cuts at the first user row before searching for a final assistant. WebUI's pre-call context deliberately omits the checkpointed current user, while Agent appends that current user before its assistant. A valid suffix is therefore [user(current), assistant(recovered)]; the helper truncates it to empty and returns False. The retry actually succeeds, but WebUI emits auth_mismatch and does not settle the recovered answer.

    Independent reproduction: after changing only the existing success fake to the production shape history + [current user, recovered assistant], both failure_mode=result and failure_mode=exception failed with an authentication error. The direct helper probe returned False for the same valid result.

    Fix: pass current-turn text/authority into the helper and anchor the prefix suffix on the exact normalized current user before slicing after it, as _append_result_partial_on_error() already does. Keep non-prefix handling fail-closed unless it has real current-run authority. Make all success fakes use the real Agent shape and cover both retry entry modes.

  2. A returned stale/partial result persists identical assistant content twice (api/streaming.py:10021-10029 and 10484-10492).

    The ordinary returned result is first settled into s.messages as a normal assistant row. The terminal error path then calls _append_result_partial_on_error() on the same result. Its duplicate guard checks only an existing _partial marker, so it appends the same content again as _partial.

    Independent reproduction: tightening the existing returned/exception stale-snapshot test to require one persisted copy produced 2 == 1 only for delivery=result: one normal assistant row plus an identical _partial row. The exception lane remained green.

    Fix: skip result-derived partial insertion when that result has already been settled, or deduplicate against equivalent current-turn assistant content while preserving insertion for genuinely unsettled retry results. Add an exact-once returned-partial regression.

What is closed

The prior revision-capability, stale-result classification, no-current-anchor, repeated-prompt ownership, owner-context settlement, profile scope, and revision/digest parity findings are closed at this head. The mutation bite and latest Agent companion parity probe specifically defend those repairs.

Recommendation

Do not merge this head. @ruizanthony, fix the two bounded streaming defects above and re-request certification on the new exact head. A fresh full gate is required because this is an L-sized persistence/streaming path, but the next focused reproduction can be narrow: both production-shaped self-heal lanes must recover without apperror, and returned stale/partial content must persist exactly once.

@nesquena-hermes nesquena-hermes added the changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address label Aug 4, 2026
@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from a2c75ea to a399327 Compare August 12, 2026 08:56
@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Captures state.db history with a durable revision and propagates that fence through compatible Agent calls.

  • Adds typed message snapshots with active-row revision metadata.
  • Refreshes context and revision together on credential-recovery retries.
  • Consolidates live and result-derived partial output within the authoritative current turn.
  • Adds regression coverage for revision compatibility, stale results, profile isolation, and partial settlement.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains, and the previously reported prior-turn mutation and duplicate current-turn partial issues are addressed by turn-bounded authority checks and exact-once consolidation.

Important Files Changed

Filename Overview
api/models.py Adds typed state.db snapshots, durable active-row revision calculation, profile-scoped reads, and revision-preserving reconciliation.
api/streaming.py Centralizes Agent invocation compatibility, propagates refreshed revisions, classifies stale results, and bounds partial recovery to the current turn.
tests/test_compression_snapshot_revision.py Adds extensive coverage for revision construction, Agent compatibility, retries, stale settlement, repeated prompts, and exact-once partial recovery.
tests/test_issue5121_provider_auth_terminal_error.py Extends terminal provider-error tests to cover successful and stale credential-recovery results.
tests/test_state_db_read_backstop.py Extends state.db backstop tests for durable ordering and snapshot-return compatibility.

Sequence Diagram

sequenceDiagram
  participant DB as state.db
  participant WebUI as WebUI streaming worker
  participant Agent as Hermes Agent
  DB->>WebUI: messages + durable revision
  WebUI->>WebUI: reconcile and sanitize context
  WebUI->>Agent: conversation history + compatible revision kwarg
  Agent-->>WebUI: result or stale-snapshot marker
  WebUI->>WebUI: settle only current-turn-owned output
  WebUI-->>DB: persist terminal transcript
Loading

Reviews (7): Last reviewed commit: "Merge branch 'master' into fix/compressi..." | Re-trigger Greptile

Comment thread api/streaming.py Outdated
@nesquena-hermes nesquena-hermes removed the changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address label Aug 12, 2026
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

🔬 Gate certification — RED ⛔

Certified contributor head: a0bbda98b4c4c16748315a9f7ba8ab2048af7d80
Frozen base / merge-base: 483772b44b585b3185c2420a80f05ce268f47d2d
Tested integration: contributor-exact head a0bbda98b4c4c16748315a9f7ba8ab2048af7d80 (the frozen base is its ancestor; no synthetic rebase commit was needed)
Paired Agent contract reviewed: NousResearch/hermes-agent#72806 at 1bdac5d4547914d70c134f06af0435568a35159c

Verdict: SHIP ONLY WITH FIXES. Two current-turn settlement defects remain on the exact paired-Agent non-prefix result shape.

What I ran

  • Threat scan: CLEAN, score 0.
  • Codex regression gate: SHIP ONLY WITH FIXES. It inspected all five changed files and the exact paired Agent source, then identified the two cross-layer defects below.
  • Opus 4.8 crown-jewel review: SHIP for the ordinary valid-token/plain-content path, with a conditional exact-once fix for degraded authority. That broader approval does not cover the exact paired-Agent non-prefix result contract reproduced below.
  • Full serial sandbox suite: 14,277 passed, 92 skipped, 1 xfailed, 2 xpassed, 34 subtests passed, with 9 failed + 2 errors. All raw residuals are shared controls rather than the RED basis: the same-box frozen-master control reproduced the atomic-config, SSE lifecycle, keyless-provider, two path-policy, and two packaged-layout nodes; a frozen-master worktree control reproduced all four docs/gitignore nodes.
  • Focused sandbox tests: 69/69 passed across compression revision, credential-terminal recovery, state-db backstop, and partial dedupe; the five parametrized real-SSE terminal callback items also passed 5/5.
  • Hosted checks: 23/23 completed successfully, including hosted lint.
  • Static checks: git diff --check, Python compilation, and the exact five-file scope assertion passed. Local Ruff was unavailable inside the no-network sandbox, so I am not presenting the fallback skip as a local Ruff pass.
  • Independent production-helper reproduction: 2/2 assertions failed on the paired-Agent non-prefix shape, reproducing both blockers below. The temporary gate-only test was removed and the exact-head worktree is clean.

Reproduced blockers

  1. A valid non-prefix credential self-heal result is rejected (api/streaming.py:6978).

    Agent 1bdac5d… can compact/rebuild messages and return [compacted context, current user, recovered assistant]. The returned rows do not carry WebUI's _active_turn_token, and the result dictionary does not export current_turn_user_idx or turn_id; those authorities remain on the Agent instance. Even when WebUI resolves the real index/turn authority, _self_heal_result_succeeded() still requires the token to appear on the rebuilt user row. The production helper returned False for a completed result containing the valid recovered answer, so the successful retry is misclassified and the UI can emit auth_mismatch instead of settling it.

    Reproduction: test_nonprefix_paired_agent_success_uses_resolved_turn_authority expected True; the exact helper returned False.

  2. A non-prefix stale result silently drops its owned current-turn partial (api/streaming.py:7595).

    _append_result_partial_on_error() uses the same unavailable row token before scanning the rebuilt current-turn assistant rows. With paired-Agent messages containing the current user plus owned partial, it returned None; no partial was persisted even though the resolved Agent authority identifies the current turn.

    Reproduction: test_nonprefix_paired_agent_stale_partial_uses_resolved_turn_authority expected an appended partial; the exact helper returned None.

These are reachable cross-layer states, not advisor-only hypotheticals: the paired Agent reanchors its current-turn index after compaction but returns ordinary/stale result dictionaries with messages and without the WebUI-only row token. The independent probe used that exact row shape and WebUI's production settlement helpers.

Required repair

  • Make _self_heal_result_succeeded() consume the resolved Agent turn boundary for non-prefix results, validating the resolved index/turn against normalized current-user text rather than requiring a WebUI-only token on rebuilt Agent rows.
  • Apply the same validated authority to _append_result_partial_on_error() so it retains only the owned assistant rows after the current user and stops at the next user.
  • Replace the current token-injected non-prefix fixture with the real paired-Agent result shape. Cover returned-auth and raised-auth successful self-heal plus stale-partial retention, and include bite checks proving historical/repeated-prompt rows cannot be selected.

Recommendation

Do not merge this head. @ruizanthony, repair the paired-Agent non-prefix authority handoff above and request a fresh exact-head gate. The ordinary revision fence, profile isolation, capability gate, hosted matrix, and focused suites are otherwise in good shape.

No merge, tag, deploy, close, or contributor-branch push was performed by this lane.

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-gate: turn-boundary fallback can select historical same-text output

Thanks for the substantive response. I re-gated exact head cdfa1b5e2e6e0a800fad29b1ecb77a79d2410ffa against the two non-prefix Agent-boundary findings on a0bbda98b4c4c16748315a9f7ba8ab2048af7d80.

The original token-only false rejection and partial drop are improved, but the replacement introduces one deterministic historical-row authority flaw.

Must fix

api/streaming.py::_find_active_turn_checkpoint_index() treats one resolved Agent index as two different projection domains. For non-prefix results it tests:

  1. current_turn_user_idx - len(previous_context), then
  2. current_turn_user_idx.

It accepts the first user row whose normalized text matches. With a repeated prompt, both positions can be matching user rows. The shifted historical row wins, so _self_heal_result_succeeded() can accept historical assistant prose as the successful retry, and _append_result_partial_on_error() can persist that historical prose as the current turn's partial.

Use exactly one declared index domain. If the Agent index addresses result["messages"], validate only that exact index. If a shifted projection is genuinely supported, carry an explicit projection-origin/base-length discriminator from the Agent rather than probing both positions.

Required regressions

Add a repeated-prompt case where both candidate positions are same-text users, historical assistant output follows only the shifted row, and current output follows only the exact row. Prove the historical row is never accepted or persisted. Compose it through both production self-heal entries, returned auth failure and raised 401, and assert exact-once settlement, persistence, done, and apperror behavior.

The new terminal=[returned, raised] direct-helper parameterization does not execute either production self-heal arm; the parameter changes only assistant text.

Verification

Threat scan CLEAN. Mandatory Layer-3 sandbox runs completed at this exact head:

  • tests/test_compression_snapshot_revision.py: 44 passed
  • adjacent authority/self-heal slice: 11 passed, 48 deselected

Those green tests omit the dual-matching-user collision above. No bare PR-code execution, merge, branch write, release, screenshot, server, or production action was performed.

@nesquena-hermes nesquena-hermes added changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address and removed changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address labels Aug 13, 2026
Comment thread api/streaming.py
@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from 3d08764 to 18342ad Compare August 20, 2026 23:24
@ruizanthony

Copy link
Copy Markdown
Contributor Author

Rebuilt the PR as one focused commit on current master (1f5e45527ac8eb14230a9f5720664d0867e74035) and force-pushed with an explicit lease. Exact review target: 18342ad6039104aae3beeba4da187d733ec92e8a.

The rebuild preserves the five-file durable revision/profile/capability contract and repairs the remaining turn-authority and exact-once gaps: paired-Agent non-prefix boundaries are consumed as one coherent index/turn domain and validated against normalized current-user text; current-turn partial selection stops at the next user; repeated prompts cannot select historical output; live-buffer/result snapshots consolidate into one _partial while retaining a newer suffix.

Local evidence on the exact tree:

  • ./scripts/test.sh tests/test_compression_snapshot_revision.py tests/test_issue5121_provider_auth_terminal_error.py tests/test_state_db_read_backstop.py tests/test_issue2592_partial_dedupe.py tests/test_issue5567_profile_home_override.py tests/test_run_journal_routes.py -q120 passed, 1 skipped
  • focused compression suite — 53 passed
  • python3 scripts/ruff_lint.py --diff origin/master — 0 findings on added/modified lines
  • py_compile, compileall, and git diff --check — clean

The two inline P1 findings have been answered with the exact fix SHA. Hosted checks are now running against that SHA.

@ruizanthony
ruizanthony force-pushed the fix/compression-durable-transcript-revision branch from 18342ad to c8bd54f Compare August 20, 2026 23:57
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

🔬 Gate certification — GREEN ✅ (durable revision fencing converged; legacy Agent lane remains safe)

Certified contributor head: c8bd54fcd4ad7b6cea5b0f361b5d8f633812d278
Pinned live master/base: 069a55db58830631bc312509d6bd4fc27bc4c13f (no rebase needed)

Verdict: exact-head gate-pass. The prior tokenless/non-prefix answer and partial losses are closed, current-turn authority no longer reuses shifted historical indices, stale snapshot outcomes settle terminally without automatic retry, and the not-yet-capable installed Agent follows an unchanged legacy lane because the new revision kwarg is omitted by signature detection.

Authoritative gate

Gate Result
Exact-head threat scan CLEAN, score 0
Rebase/current-base Already based exactly on pinned master 069a55db; clean worktree
Focused compression/auth/state-db slices 81/81 passed in sandbox
Reviewer prefix-branch probes 2/2 passed: production-shape previous_context + [current_user, assistant] accepted; error-only current turn with later-user assistant rejected
Full serial sandbox suite 14,858 passed, 95 skipped, 1 xfailed, 2 xpassed, 45 subtests; 9 failed + 2 errors
Exact pinned-base control, same wrapper/box 14,803 passed with identical 9 failures + 2 errors → zero PR-owned suite residuals, 55 candidate-only passes
Codex exact integration SAFE TO SHIP; all five files, installed legacy-Agent path, companion shape, and 310 focused checks verified
Senior advisor (OPUS_GATE_MODEL=claude-opus-4-8) APPROVE / GREEN; 79 PR-file + 175 neighboring checks passed
Static gates Ruff-forward CLEAN, ESLint runtime CLEAN, scope-undef CLEAN, git diff --check clean

The shared 9 failures + 2 errors are the established sandbox/env baseline, byte-for-byte identical on candidate and pinned control.

Installed-runtime compatibility

  • Installed Agent authority is commit dd859ee9725c4c4dabde4d5a999c78ec045bef24; it has no conversation_history_revision, CompressionSnapshotStaleError, or active_rows_digest.
  • Companion Agent PR #72806 (9a2237ec) is still open/unmerged.
  • WebUI checks the real bound run_conversation signature and omits conversation_history_revision for the installed legacy Agent. Codex executed that installed lane and found no current send/stream regression.
  • The durable revision fence is therefore dormant, not emulated, until the companion Agent capability ships. WebUI-first rollout is backward-compatible. The Agent's future count/digest/current-user reconciliation remains #72806's contract and needs its own gate.

Prior RED closure

  1. _resolve_active_turn_authority accepts one coherent Agent-owned (current_turn_user_idx, turn_id) pair and clears stale provenance.
  2. Non-prefix results use the Agent index directly against result messages; shifted WebUI-history arithmetic is no longer result authority.
  3. Partial extraction is bounded after the exact current user and before the next user; historical equal prose cannot be mutated.
  4. Returned-auth and raised-401 self-heal retry once, refresh context+revision together, settle exactly once, and preserve successor ownership.
  5. State-db messages/revision/digest come from one ordered explicit-profile snapshot; ambiguous/legacy/unbounded reads withhold the fence.
  6. Returned/raised compression_snapshot_stale settles as terminal apperror with no done and no auto-retry.

Non-blocking follow-up

Coordinate exact digest/count semantics when Agent PR #72806 lands. That future runtime boundary cannot be exercised by today's installed Agent, but its absence does not regress the current product lane.

Recommendation

Gate-pass / Tier 1. Safe for release-agent current-head validation and normal merge/release mechanics. Preserve @ruizanthony attribution. This gate does not merge, tag, deploy, close, or write the contributor branch.


Valid only for exact contributor head c8bd54fcd4ad7b6cea5b0f361b5d8f633812d278.

@nesquena-hermes nesquena-hermes added gate-pass Full gate passed (Codex+Opus+suite+browser); queued Tier 1 for release agent and removed gate-fail Gate found blocking issue(s); fix-spec in comment; awaiting fix/re-push labels Aug 21, 2026

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Independent release-manager re-gate at exact head c8bd54fc — GREEN, autonomous-ship (crown-jewel backend, no screenshot surface). Clears the stale CHANGES_REQUESTED (the gate-cert + this re-gate both post-date it).

  • Codex regression gate: SAFE TO SHIP, and it reproduced the load-bearing backward-compat: the installed AIAgent.run_conversation lacks conversation_history_revision, so api/streaming.py:8295-8350 omits it (retaining persist_user_timestamp); a full strict-legacy send completed with done — no apperror, no TypeError — and persisted the answer. Stale snapshots settle once as terminal errors (no retry loop); partial output stays with the authoritative current turn; compression rotation preserves the parent snapshot + continuation transcript. The future paired-Agent fence is dormant (kwarg omitted) until the companion Agent PR ships, and is covered by capable-Agent contract tests.
  • Full serial suite (my box): 14,914 passed. The 52 non-passing (16 fail + 36 error) are pre-existing same-box environment artifacts (test_mcp_server mcp-SDK version mismatch + test_issue1699 model-cache-fingerprint flake) — proven by a same-box clean-master control reproducing the identical set; this PR touches neither file and has zero compression/streaming/models/state failures.
  • Consistent with the 2026-08-21 02:33 gate-cert (Codex SAFE + senior GREEN + 81/81 focused + zero PR-owned residuals in its own sandbox baseline).

Approving to clear the stale review state. Thanks @ruizanthony.

@nesquena-hermes
nesquena-hermes merged commit c27f3d6 into nesquena:master Aug 21, 2026
23 checks passed
nesquena-hermes added a commit that referenced this pull request Aug 21, 2026
…sions (#6554, @ruizanthony) (#7194)

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Shipped in exp-v0.52.257 🎉 — WebUI now fences the transcript with a durable revision so cancelled/interrupted compression can't lose or misattribute work. Live on the experimental channel. The paired-Agent fence stays dormant on current Agent builds (WebUI omits the new revision kwarg via signature detection) and activates once the companion Agent build ships — existing installs are unaffected. Thanks @ruizanthony!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gate-pass Full gate passed (Codex+Opus+suite+browser); queued Tier 1 for release agent size:L Large PR (>10 files or >250 LOC)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants