Skip to content

fix(cortex): explicit forget cascade and hosted scoped erasure - #243

Merged
senamakel merged 19 commits into
mainfrom
memory-deletion
Oct 8, 2026
Merged

senamakel merged 19 commits into
mainfrom
memory-deletion

Conversation

@senamakel

@senamakel senamakel commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Summary

Makes CortexDB deletions actually delete.

  • Every forget names its cascade. /v1/forget (and the hosted memory/forget) now sends cascade: "redact_events". CortexDB's default, derived_only, removes what was derived from the events and leaves the events in place, so a forget without a cascade did not remove anything the user wrote (memory-audit S1, docs/memory-scopes.md §7). memory-api tombstones forgets by memory_ids, which are what this crate sends.
  • The hosted engine erases a scope. A whole-tree erase still uses main's single DELETE memory. Anything narrower now erases scope by scope, as on Direct, instead of refusing with Unsupported. It goes through the backend's memory/v1/erasures passthrough of memory-api's scoped erasure (tinyhumansai/cortexdb-saas#21):
    • body is {scope, audit_note}, with no confirm_all, because memory-api refuses unknown fields
    • the call is synchronous and returns {erased: true, scope, scopes, erasure_ids}; scopes: 0 is still a success
    • a retriable 502 ERASURE_INCOMPLETE is retried up to 3 times
    • a backend without the route (404) reports Unsupported, so callers can fall back to a forget
  • The transport decodes memory/v1/* answers without the {success,data} envelope, and hosted errors also read error_code.
  • Direct erasures are polled while running. A running/pending/queued/accepted answer is polled at v1/erasures/{id} for up to 5 minutes. Any final status other than completed is an error.
  • The wire double now models the default cascade (derived_only keeps events, an unknown cascade gets a 400) and serves memory-api's scoped erasure contract unwrapped.

Depends on tinyhumansai/backend#1410 (the /memory/v1/erasures passthrough) and tinyhumansai/cortexdb-saas#21.

Tests

  • every_forget_names_the_cascade_that_removes_the_events
  • hosted:
    • the_hosted_wire_erases_a_subtree_through_the_backend_passthrough
    • the_hosted_erasure_names_only_the_fields_memory_api_accepts
    • an_incomplete_hosted_erasure_is_retried
    • a_hosted_erasure_that_stays_incomplete_is_unavailable
    • a_backend_without_the_scoped_erasure_route_is_unsupported
    • a_narrower_hosted_erase_goes_scope_by_scope_not_whole_memory
  • direct: a_running_direct_erasure_is_polled_until_it_completes, a_direct_erasure_that_does_not_complete_is_an_error
  • Without the cascade, 9 forget/conformance/hosted tests fail against the faithful double. Before this change, the hosted erase tests got Unsupported.
  • cargo test --workspace --all-features and cargo clippy --workspace --all-features --all-targets pass.

Summary by CodeRabbit

  • New Features
    • Hosted memory erasure now supports narrower, scoped requests as well as whole-tree erasure. Incomplete requests are retried, and results include erased scope details.
    • Erasure operations now wait for asynchronous jobs to finish and report errors when they fail or exceed the wait limit.
  • Bug Fixes
    • Forget requests now remove matching events and their derived data, rather than relying on a default that could retain the events.
    • Hosted API errors are handled more reliably when error codes use different field formats.

senamakel and others added 9 commits October 8, 2026 22:30
Reworked the forget log entry path to reduce duplication and make the
control flow easier to follow. Behaviour is unchanged.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The forget endpoint now reads a cascade field that defaults to derived_only, which drops beliefs derived from the named events while keeping the events themselves, and rejects any cascade other than derived_only or redact_events with a 400. This matches the documented cascade semantics so callers can remove derived beliefs without destroying their source events.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a test covering that every forget request sent by the engine
explicitly names the redact_events cascade, since CortexDB's default
derived_only cascade would leave the stored events in place.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The erase path was removing entries by their position in the log, which
shifted as soon as any earlier entry was deleted and could drop the wrong
record. It now looks entries up by id so each erase targets exactly the
entry requested.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Erase and descriptor paths now propagate transport errors rather than
treating a failed request as an empty result, so callers can distinguish
a genuine miss from an unreachable backend.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a testing module with routes that exercise the cortex integration
endpoints, giving integration tests a way to drive the cortex surface
without standing up the full stack.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace the test asserting the hosted wire refuses to erase with tests
for the new behaviour: erasure goes through the backend passthrough,
releases the write key, and polls a running erasure until it settles,
with a non-completing erasure surfacing as an error.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The Cortex integration docs now describe the hosted erasure path through the
backend's `memory/v1/erasures` passthrough, including polling a running erasure
until it settles, and note that forget always names the `redact_events` cascade
because CortexDB's default keeps the events.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the doc comment on the erasure test to note that the hosted
`memory/v1/erasures` passthrough is covered by the wire double until it is
live on the backend, rather than stating the hosted wire has no erasure
route.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper

tinysweeper Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

This revision lands hosted scoped erasure through the TinyHumans backend's `memory/v1/erasures` passthrough, explicit forget cascades, and Direct erasure polling, with a thorough wire-double test suite. Two findings from earlier pushes remain open: the hosted erasure retry loop generates a fresh idempotency key per attempt rather than reusing one across the retry of the same destructive request, and the hosted passthrough and the forget cascade are covered only against the repository's own wire double (the live backend route is not yet available, per the live test comment). One lane raised a missing overflow test for the hosted scope count, though the diff shows a `usize::try_from` guard already exists in `log/erase.rs`; no test drives it.

State: Changes requested
Priority: high
Reviewed head: ac0fabe31802
Updated: 1791485029 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 7 Active findings 18
Tests 8 Noted findings 0
Documentation 3 Resolved findings 146
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

What changed

On the TinyHumans wire, an erase narrower than the whole tree now goes scope by scope through the backend's `memory/v1/erasures` passthrough (`{scope, audit_note}` only, answered unwrapped in CortexDB's dialect) instead of refusing with `Unsupported`; the whole tree still erases in one `DELETE memory`, and a missing route (404) still surfaces as `Unsupported` so callers can fall back to `forget`. The forget body now names `cascade: "redact_events"` explicitly, since CortexDB's `derived_only` default keeps the events. `Log::erase` returns an `Erased` struct (scope count plus erasure ids) rather than a bare id, and `EraseReport` propagates the backend's counts and receipts. Direct erasures that answer `running` are polled at `v1/erasures/{id}` under a configurable `Timing::erasure` deadline with strict status validation. Responses on hosted paths under `memory/v1/` are parsed without the `{success,data}` envelope, and failure parsing falls back from `errorCode` to `error_code` when the former is unusable.

Features

  • Modified — Explicit forget cascade: Every removal body names `cascade: "redact_events"` (`FORGET_CASCADE`), so the named events and everything derived from them are removed rather than kept by CortexDB's `derived_only` default. Bodies are otherwise unchanged: batched at 100 memory_ids, no empty selector, never `confirm_all`. (crates/tinymemory-integrations/src/cortex/log/forget.rs#impl Log {, crates/tinymemory-integrations/src/cortex/testing/log.rs#impl CortexLog {, docs/architecture/cortex-wire.md#for. Both fail with `Error::Unsupported` before any request.)
  • Modified — Hosted scoped erasure via backend passthrough: On the TinyHumans wire, an erase narrower than the whole tree goes scope by scope through the backend's `memory/v1/erasures` passthrough; memory-api pins the scope under the tenant root and answers synchronously. Only `502 ERASURE_INCOMPLETE` is retried (up to three attempts with backoff); other failures surface because their outcome is unknown. A missing route is reported as `Unsupported` so a caller can fall back to `forget`. The whole tree still erases in one `DELETE memory`, and the backend's scopes/ids propagate into `EraseReport`. (crates/tinymemory-integrations/src/cortex/engine/erase.rs#impl CortexEngine {, crates/tinymemory-integrations/src/cortex/log/erase.rs#impl Log {, crates/tinymemory-integrations/src/cortex/descriptor/mod.rs#impl CortexWire {, crates/tinymemory-integrations/src/cortex/testing/routes.rs#async fn erase()
  • Internal refactor — Direct erasure polling with a configurable deadline: A Direct erasure is now a job: a `running` POST answer is polled at `v1/erasures/{id}` with exponential backoff until it settles; only `completed` counts as done, anything else (including missing or non-string statuses) is an error, and a still-running erasure times out as `Unavailable`. The deadline (`Timing::erasure`) bounds both the sleeps and the retries. (crates/tinymemory-integrations/src/cortex/log/erase.rs#impl Log {, crates/tinymemory-integrations/src/cortex/log/mod.rs#pub(crate) struct Timing {, crates/tinymemory-integrations/src/cortex/engine/engine_test_support.rs#impl CortexEngine {)
  • Internal refactor — Unwrapped dialect and error-code fallback for the hosted passthrough: Responses for hosted paths under `memory/v1/` are parsed as CortexDB dialect instead of unwrapping the backend's `{success,data}` envelope. Failure parsing falls back to `error_code` when `errorCode` is null, non-string, or cleans to empty, while `errorCode` still wins when usable. (crates/tinymemory-integrations/src/cortex/transport/mod.rs#impl HttpClient {, crates/tinymemory-integrations/src/cortex/transport/failure.rs#pub(crate) fn hosted_status_error(, crates/tinymemory-integrations/src/cortex/descriptor/mod.rs#pub enum CortexWire {)

Tests

  • unit — A hosted subtree erase posts to `memory/v1/erasures` (never `DELETE /memory`), sends only `scope` and `audit_note`, retries a `502 ERASURE_INCOMPLETE` and then completes, surfaces `Unavailable` when the erasure never completes, and a backend without the route answers `Unsupported` with data intact.: Covers the hosted scoped-erasure happy path, strict body, retry and give-up paths, and the fall-back semantics deterministically via the double. (crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs#async fn the_hosted_wire_erases_the_whole_memory_in_one_request() {, crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs#async fn the_hosted_wire_refuses_a_narrower_erase_without_a_request() {, crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs#async fn the_hosted_wire_refuses_a_narrower_erase_without_a_request() {)
  • unit — Hosted answer validation: the report reflects the scopes the backend erased (zero scopes and no receipts when the scope was emptied between listing and erasure); malformed answers (non-string or non-array `erasure_ids`, missing or string `scopes`) are errors; a hosted scope is erased by a fresh engine that never held it, using the backend's registry.: Covers strict parsing of the unwrapped passthrough answer and the not-locally-held scope case that earlier reviews flagged. (crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs#async fn the_hosted_wire_erases_the_whole_memory_in_one_request() {, crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs#async fn an_erasure_with_nothing_registered_sends_nothing() {)
  • unit — Failure parsing falls back to `error_code` when `errorCode` is null, numeric, or cleans to empty, and `errorCode` still wins when both keys are usable.: Addresses the error-code fallback for the unwrapped passthrough dialect, including primary-key precedence. (crates/tinymemory-integrations/src/cortex/transport/failure_tests.rs#fn a_write_the_indexer_has_not_reached_is_transient() {, crates/tinymemory-integrations/src/cortex/transport/failure.rs#pub(crate) fn hosted_status_error()

Findings

  • high · critique · Preserve one idempotency key across hosted erasure retries — When the backend returns `ERASURE_INCOMPLETE`, this loop sends another POST, but it does not create or pass an idempotency key. The hosted wire contract says writes claim `Idempote (crates/tinymemory\-integrations/src/cortex/log/erase\.rs:83)
  • medium · critique · Exercise hosted passthrough against a real CortexDB backend — The hosted subtree and exact-scope tests use `hosted_double`, so they only prove the client and the test double agree. They do not verify the actual `memory/v1/erasures` request, b (crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs:131)
  • medium · critique · Exercise hosted polling against a real CortexDB backend — The incomplete hosted erasure retry path is validated only by a configured double. That does not establish that a real backend returns the incomplete response shape expected by the (crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs:170)
  • medium · critique · Exercise the forget cascade against a real CortexDB — The changed hosted tests cover erasure requests through a double, but none exercises the caller's fallback from an unsupported scoped erasure into the forget cascade against a real (crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs:131)
  • medium · critique · Cover the direct erasure polling timeout path — The new deadline behavior is a user-visible failure path, but this change adds no deterministic test that exercises a job remaining in a pending status until the timeout expires. W (crates/tinymemory\-integrations/src/cortex/log/erase\.rs:204)
  • high · security · Reuse one idempotency key across hosted erasure retries — When the backend returns `ERASURE_INCOMPLETE`, this loop sends the same destructive request again, but the request carries no idempotency key. If the first request actually reached (crates/tinymemory\-integrations/src/cortex/log/erase\.rs:83)
  • medium · security · Cover hosted erasure counts outside the platform range — The malformed-answer cases cover string counts and missing receipts, but none supplies a numeric count larger than `usize`. The conversion is a platform-range boundary and needs an (crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs:546)
  • medium · tests · Exercise the hosted erasure passthrough against a real backend — The hosted passthrough's wire behaviour is asserted only against the test double: the real backend's dialect (no envelope, `error_code` in failures, the exact `502 ERASURE_INCOMPLE (crates/tinymemory\-integrations/tests/live\_cortexdb\.rs:435)
  • medium · tests · Exercise the forget cascade against a real CortexDB — The `cascade: "redact_events"` claim — that it deletes the events, unlike `derived_only` — is pinned only against the crate's own double, which was written in the same commit to mo (crates/tinymemory\-integrations/src/cortex/log/forget\.rs:28)
  • medium · description · Exercise the hosted erasure passthrough against a real backend — The hosted scoped-erasure path, its unwrapped answers, the 502 retry and the 404 fallback are all verified only against the in-repo double. A mismatch with the real memory-api cont (\(pull request description\))

Previously reported and still active

  • Exercise the hosted erasure passthrough against a real CortexDB
  • Exercise hosted erasure passthrough and polling against CortexDB
  • Exercise hosted passthrough against a real CortexDB
  • Exercise hosted polling against a real CortexDB
  • Exercise hosted passthrough against a real backend
  • Assert that hosted retries reuse one idempotency key
  • Assert that hosted retries reuse one idempotency key
  • Exercise hosted erasure passthrough against a real backend

Resolved this pass

  • Reject non-string cascade values
  • Reject polling responses without a status
  • Reject non-string erasure IDs
  • Cover malformed polled statuses
  • Cover the erasure polling timeout path
  • Cover the direct erasure polling timeout path
  • Test that a synchronous erasure answer without a status counts as completed
  • Erase the requested hosted scope even when it is not locally held
  • Always forward hosted erasures to the backend
  • Reject polling responses without a status
  • Reject polled responses without a completed status
  • Fall back when the primary error code is unusable
  • Reject non-string erasure IDs
  • Reject non-numeric hosted erasure scope counts
  • Prevent erasure-count overflow
  • Always forward hosted erasures to the backend
  • Erase the requested hosted scope even when it is not locally held
  • Reject non-string cascade values
  • Reject polling responses without a status
  • Fall back when the primary error code is unusable
  • Reject polled responses without a completed status
  • Cover the erasure polling timeout path with a test
  • Hosted erasure passthrough and polling are covered only by doubles
  • The forget cascade is never exercised against a real CortexDB
  • Reject invalid polled status responses
  • Test the direct erasure polling timeout path
  • Reject non-string erasure IDs
  • Exercise hosted erasure passthrough against a real CortexDB
  • Exercise hosted erasure polling against a real CortexDB
  • Exercise the forget cascade against a real CortexDB
  • Cover the erasure polling timeout path
  • Exercise hosted erasure against a real CortexDB backend
  • Exercise hosted erasure against a real backend
  • Reject non-string erasure scopes as invalid input
  • Prevent erasure-count overflow
  • Avoid using a wall-clock limit in the timeout test
  • Test that a synchronous erasure answer without a status counts as completed
  • Reject erasure counts that exceed the platform range
  • Cover erasure-count overflow
  • Avoid asserting a wall-clock-dependent poll count
  • Do not consume the running budget for forced statuses
  • Cover erasure counts outside the platform range
  • Cover hosted erasure counts outside the platform range
  • Make the timeout test independent of wall-clock scheduling
  • Reject non-string cascade values
  • Reject polling responses without a status
  • Fall back when the primary error code is unusable
  • Reject polled responses without a completed status
  • Cover the erasure polling timeout path with a test
  • The forget cascade is never exercised against a real CortexDB
  • high — Cover invalid polled status responses
  • Test the direct erasure polling timeout path
  • Reject non-string erasure IDs
  • Exercise hosted erasure passthrough against a real CortexDB
  • Exercise hosted erasure polling against a real CortexDB
  • Exercise the forget cascade against a real CortexDB
  • Cover the erasure polling timeout path
  • Reject non-string erasure scopes as invalid input
  • Cover malformed polled statuses
  • Exercise hosted erasure against the real backend
  • Do not consume the running budget for forced statuses
  • Test that a synchronous erasure answer without a status counts as completed
  • Reject erasure counts that exceed the platform range
  • Reject non-numeric hosted erasure scope counts
  • Exercise hosted erasure against a real CortexDB backend
  • Cover erasure counts outside the platform range
  • Always forward hosted erasures to the backend
  • Erase the requested hosted scope even when it is not locally held
  • Reject non-string cascade values
  • Reject polling responses without a status
  • Fall back when the primary error code is unusable
  • Reject polled responses without a completed status
  • Cover the erasure polling timeout path with a test
  • Reject non-string erasure IDs
  • High — Cover invalid polled status responses
  • Cover malformed polled statuses
  • Test that a synchronous erasure answer without a status counts as completed
  • Prevent erasure-count overflow
  • Cover erasure-count overflow
  • Cover erasure counts outside the platform range
  • Cover hosted erasure counts outside the platform range
  • Reject non-numeric hosted erasure scope counts
  • Erase the requested hosted scope even when it is not locally held
  • Always forward hosted erasures to the backend
  • Do not consume the running budget for forced statuses
  • Avoid using a wall-clock limit in the timeout test
  • Avoid making the timeout test depend on wall-clock scheduling
  • Avoid asserting a wall-clock-dependent poll count
  • Make the timeout test independent of wall-clock scheduling
  • Medium — Exercise hosted polling against a real CortexDB
  • Reject non-string cascade values
  • Reject polling responses without a status
  • Fall back when the primary error code is unusable
  • Reject polled responses without a completed status
  • Cover the erasure polling timeout path with a test
  • Cover invalid polled status responses
  • Test the direct erasure polling timeout path
  • Cover malformed polled statuses
  • Reject non-string erasure IDs
  • Prevent erasure-count overflow
  • Cover erasure-count overflow
  • Cover erasure counts outside the platform range
  • Reject erasure counts that exceed the platform range
  • Reject non-numeric hosted erasure scope counts
  • Erase the requested hosted scope even when it is not locally held
  • Test erasing a hosted scope that is not locally held
  • Avoid making the timeout test depend on wall-clock scheduling
  • Avoid using a wall-clock limit in the timeout test
  • Avoid asserting a wall-clock-dependent poll count
  • Make the timeout test independent of wall-clock scheduling
  • Do not consume the running budget for forced statuses
  • Test that a synchronous erasure answer without a status counts as completed
  • Cover hosted erasure counts outside the platform range
  • Reject non-string erasure scopes as invalid input
  • Reject non-string cascade values
  • Reject polling responses without a status
  • Fall back when the primary error code is unusable
  • Reject polled responses without a completed status
  • Cover the erasure polling timeout path with a test
  • Reject non-string erasure IDs
  • Cover erasure-count overflow
  • Do not consume the running budget for forced statuses
  • Erase the requested hosted scope even when it is not locally held
  • Cover malformed polled statuses
  • Test the direct erasure polling timeout path
  • Test erasing a hosted scope that is not locally held
  • Avoid using a wall-clock limit in the timeout test
  • Reject non-numeric hosted erasure scope counts
  • Prevent erasure-count overflow
  • Cover erasure counts outside the platform range
  • Cover hosted erasure counts outside the platform range
  • Reject non-string erasure scopes as invalid input
  • Reuse one idempotency key for hosted erasure retries
  • Assert that hosted erasure retries reuse one idempotency key
  • Verify that hosted retries reuse one idempotency key
  • Propagate one idempotency key across hosted retries
  • Preserve one idempotency key across hosted erasure retries
  • Always forward hosted erasures to the backend
  • Forward every hosted erasure to the backend
  • Test that a synchronous erasure answer without a status counts as completed
  • Avoid making the timeout test depend on wall-clock scheduling
  • Avoid asserting a wall-clock-dependent poll count
  • Make the timeout test independent of wall-clock scheduling
  • Avoid a wall-clock-dependent poll count
  • Reject polled responses without a status
  • Reject non-string erasure scopes as invalid input

Before merge

  • Address carried finding Exercise the hosted erasure passthrough against a real CortexDB.
  • Address carried finding Exercise hosted erasure passthrough and polling against CortexDB.
  • Address carried finding Exercise hosted passthrough against a real CortexDB.
  • Address carried finding Exercise hosted polling against a real CortexDB.
  • Address carried finding Exercise hosted passthrough against a real backend.
  • Address carried finding Assert that hosted retries reuse one idempotency key.
  • Address carried finding Assert that hosted retries reuse one idempotency key.
  • Address carried finding Exercise hosted erasure passthrough against a real backend.
  • Address Preserve one idempotency key across hosted erasure retries (crates/tinymemory\-integrations/src/cortex/log/erase\.rs).
  • Address Reuse one idempotency key across hosted erasure retries (crates/tinymemory\-integrations/src/cortex/log/erase\.rs).
Agent review details

critique

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Positive: The erasure deadline is configurable on `Timing` rather than hard-coded, letting tests tighten it from five minutes to milliseconds while production keeps 300 s.
  • Positive: Hosted retries are deliberately narrow: only an answer that proves the erasure incomplete (`ERASURE_INCOMPLETE`) is retried; other failures surface, since re-sending a destructive request whose outcome is unknown would hide it.
  • Lane summary: Reviewed 2 files; 8 findings. (3 already reported on an earlier push) (43 earlier finding(s) still open) (1 observation(s) grouped into shared inline comments) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/src/cortex/log/erase\.rs — Preserve one idempotency key across hosted erasure retries
  • Evidence: crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs — Exercise hosted passthrough against a real CortexDB backend
  • Evidence: crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs — Exercise hosted polling against a real CortexDB backend
  • Evidence: crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs — Exercise the forget cascade against a real CortexDB
  • Evidence: crates/tinymemory\-integrations/src/cortex/log/erase\.rs — Cover the direct erasure polling timeout path

security

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 2 files; 4 findings. (2 already reported on an earlier push) (20 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/src/cortex/log/erase\.rs — Reuse one idempotency key across hosted erasure retries
  • Evidence: crates/tinymemory\-integrations/src/cortex/engine/mod\_erase\_tests\.rs — Cover hosted erasure counts outside the platform range

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The wire double models real backend behaviors faithfully (unknown-field 400s, root refusal, 404 passthrough absence, incomplete-erasure 502s, invalid cascades, overridable answers, omit-status toggles), letting failure paths be exercised deterministically.
  • Lane summary: This revision lands the hosted scoped-erasure passthrough and Direct erasure polling with a strong test suite: nearly all earlier findings (non-string cascades, missing/non-terminal polled statuses, error-code fallback, timeout coverage, non-string erasure ids, scope-count overflow, erasing never-held scopes, forced-status budget) are now fixed with failing-path tests. Two earlier findings still stand: the hosted erasure retry generates a fresh idempotency key per attempt, and the new hosted passthrough and forget cascade are still exercised only against wire doubles, not a real CortexDB. (1 finding discarded for not matching a changed line) (37 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/tests/live\_cortexdb\.rs — Exercise the hosted erasure passthrough against a real backend
  • Evidence: crates/tinymemory\-integrations/src/cortex/log/forget\.rs — Exercise the forget cascade against a real CortexDB

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The revision fixes the forget cascade, malformed polled statuses, the timeout path, count/type validation of hosted erasure answers, and the fresh-engine erasure case, each with tests. What remains is the idempotency key across hosted erasure retries, which I still cannot see being preserved, and the hosted passthrough being covered only by doubles until the backend route is live. (42 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: \(pull request description\) — Exercise the hosted erasure passthrough against a real backend

e2e

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The revision adds a hosted scoped-erasure passthrough, direct erasure polling, a named forget cascade and an error-code fallback, and the new wire-double tests resolve nearly all earlier findings (non-string cascades, missing polled statuses, malformed erasure answers, count overflow, forced-status budgets, engines that never held the scope, and the retry loop that now only re-sends after a definitive ERASURE_INCOMPLETE, which makes idempotency keys unnecessary). What remains uncovered end to end: the forget cascade's real-CortexDB behaviour is asserted only against the repository's own double, and the hosted passthrough has no harness at all since the TinyHumans backend is not in the tree. Neither blocks on its own, but both are recorded. (1 already reported on an earlier push) (26 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.013064
  • Tokens: 356846 input · 33210 output · 32691 cached · 0 embedding
  • Continuity: summary cache chain restarted at the storage ceiling.
Head State Pass summary
9f438b40cae2 changes requested 14 active finding(s), 173 resolved finding(s) (at 1791483202)
5d947c0a31e2 changes requested 12 active finding(s), 106 resolved finding(s) (at 1791483743)
5bcab7038db7 changes requested 10 active finding(s), 171 resolved finding(s) (at 1791484171)
50ff48af0d4b changes requested 14 active finding(s), 120 resolved finding(s) (at 1791484657)
ac0fabe31802 changes requested 10 active finding(s), 146 resolved finding(s) (at 1791485029)

tinysweeper 0.1.0

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

  • Run on-demand review

This review includes 4 billable files and costs up to $1.00.

Or wait 25 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: aa067a9b-803e-4fdf-8da3-bb8da89034c3
📥 Commits

Reviewing files that changed from the base of the PR and between 9f438b4 and ac0fabe.

📒 Files selected for processing (4)
  • crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
  • crates/tinymemory-integrations/src/cortex/log/erase.rs
  • crates/tinymemory-integrations/src/cortex/testing/mod.rs
  • crates/tinymemory-integrations/src/cortex/testing/routes.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bdc7f256-0047-4393-bc99-6f93fe3d8c49
📥 Commits

Reviewing files that changed from the base of the PR and between fb817fe and 9f438b4.

📒 Files selected for processing (18)
  • crates/tinymemory-integrations/src/cortex/README.md
  • crates/tinymemory-integrations/src/cortex/descriptor/mod.rs
  • crates/tinymemory-integrations/src/cortex/engine/engine_test_support.rs
  • crates/tinymemory-integrations/src/cortex/engine/erase.rs
  • crates/tinymemory-integrations/src/cortex/engine/mod_direct_tests.rs
  • crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
  • crates/tinymemory-integrations/src/cortex/log/erase.rs
  • crates/tinymemory-integrations/src/cortex/log/forget.rs
  • crates/tinymemory-integrations/src/cortex/log/mod.rs
  • crates/tinymemory-integrations/src/cortex/testing/log.rs
  • crates/tinymemory-integrations/src/cortex/testing/mod.rs
  • crates/tinymemory-integrations/src/cortex/testing/routes.rs
  • crates/tinymemory-integrations/src/cortex/transport/failure.rs
  • crates/tinymemory-integrations/src/cortex/transport/failure_tests.rs
  • crates/tinymemory-integrations/src/cortex/transport/mod.rs
  • crates/tinymemory-integrations/tests/live_cortexdb.rs
  • docs/architecture/cortex-wire.md
  • docs/specs/memory-v2.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The Cortex integration now specifies the redact_events forget cascade. It supports hosted scoped erasure through memory/v1/erasures and tracks Direct erasures until completion. The test double and documentation cover these request and response behaviors.

Changes

Forget Cascade

Layer / File(s) Summary
Forget cascade requests and behavior
crates/tinymemory-integrations/src/cortex/log/forget.rs, crates/tinymemory-integrations/src/cortex/testing/log.rs, crates/tinymemory-integrations/src/cortex/engine/mod_direct_tests.rs, crates/tinymemory-integrations/src/cortex/README.md, docs/architecture/cortex-wire.md
Forget requests include cascade: "redact_events". The test double validates cascade values and models derived_only behavior. Tests check event removal and invalid cascade values.

Cortex Erasure

Layer / File(s) Summary
Erasure routes and response decoding
crates/tinymemory-integrations/src/cortex/descriptor/mod.rs, crates/tinymemory-integrations/src/cortex/transport/mod.rs, crates/tinymemory-integrations/src/cortex/transport/failure.rs, crates/tinymemory-integrations/src/cortex/transport/failure_tests.rs, docs/architecture/cortex-wire.md
The hosted erasure route maps to memory/v1/erasures. TinyHumans responses on memory/v1/ use CortexDB’s response format. Hosted error parsing checks errorCode and then error_code.
Scoped erasure and Direct polling
crates/tinymemory-integrations/src/cortex/log/erase.rs, crates/tinymemory-integrations/src/cortex/log/mod.rs, crates/tinymemory-integrations/src/cortex/engine/erase.rs, crates/tinymemory-integrations/src/cortex/README.md, docs/architecture/cortex-wire.md, docs/specs/memory-v2.md, crates/tinymemory-integrations/tests/live_cortexdb.rs
Hosted scoped erasures use the passthrough and retry ERASURE_INCOMPLETE; whole-tree erasure retains the DELETE memory path. Direct erasures poll status until completion or the configured deadline. Engine reports aggregate returned counts and IDs.
Erasure endpoint simulation and coverage
crates/tinymemory-integrations/src/cortex/testing/mod.rs, crates/tinymemory-integrations/src/cortex/testing/routes.rs, crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs, crates/tinymemory-integrations/src/cortex/engine/engine_test_support.rs
The test double adds hosted scoped-erasure and erasure-status routes, with controls for incomplete responses and status states. Tests cover request fields, retries, missing routes, malformed responses, and Direct polling outcomes.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Engine as erase_scopes
  participant Log as Log::erase
  participant Hosted as memory/v1/erasures
  participant Direct as Direct v1/erasures
  Engine->>Log: erase each scope
  alt TinyHumans wire
    Log->>Hosted: POST scope and audit_note
    Hosted-->>Log: synchronous erasure result
  else Direct wire
    Log->>Direct: POST scope with confirm_all
    Direct-->>Log: erasure ID and initial status
    opt status is running
      Log->>Direct: GET erasure status
      Direct-->>Log: updated status
    end
  end
  Log-->>Engine: scope count and erasure IDs
Loading

Suggested reviewers: m3ga-mind

Merge Risk: ⚪ Minimal · up to 9f438

The change adds hosted scoped erasure, Direct erasure polling, and an explicit forget cascade, with test coverage in the repository. No concrete merge-blocking defect was found. Live-backend verification of the hosted route remains pending until the backend ships it.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 9f438

Deletion behavior improves, but explicitly listing every memory kind permits broad hosted erasure without the documented whole-tree confirmation. Tenant isolation and recovery after partial deletion also depend on backend guarantees that could not be verified.

Retained concerns

  • Medium · reliability · observed: The new hosted scoped-erasure path exposes a whole-tree confirmation bypass. A root-and-descendants request with kinds explicitly set to Document, Conversation and Learning and whole_tree=false passes validation, then erases every discovered kind scope admitted by that reach. The base refused this hosted request. The weakness already existed for Direct, but now affects hosted destructive execution too. This bypasses an irreversible-deletion safety interlock, not a demonstrated authentication or cross-tenant authorization boundary.
Security review details

Security Blast Radius

  • inferred — The confirmed local exposure is irreversible deletion across discovered kind scopes admitted by the caller-supplied reach and layout. Broad root-scoped requests can affect multiple namespaces. Effective tenant or asset isolation depends on downstream authorization; cross-tenant reachability was not established.

Security Findings and Attack Paths

  • observed — The confirmation-bypass path is a caller-controlled root-and-descendants EraseRequest with an explicit all-kinds list: validation treats the nonempty list as not-everything, and the new hosted branch submits per-scope destructive requests. A caller still needs access to the engine and accepted backend credentials; this is not a demonstrated privilege escalation.

Trust Boundaries and Controls

  • observed — Every transport attempt resolves and attaches a bearer token. Non-success HTTP responses remain errors before the new unwrapped-response decoder runs. Scoped memory tools also constrain forget filters and resolve requested IDs under their allowed reach before invoking forget; item fingerprints retain namespace metadata.

Resilience and Maintainability Implications

  • observed — Hosted incomplete-erasure recovery makes at most three requests, each with a fresh Idempotency-Key, and returns only the final success's count and receipts. Unknown outcomes otherwise surface as errors. The local retry double returns ERASURE_INCOMPLETE before mutation, so it does not establish cumulative audit accounting or concurrency safety after a partially committed attempt.

Hardening Proposals

  • proposed — Normalize kind selections before destructive confirmation checks so an explicit complete kind set receives the same whole-tree interlock as the empty all-kinds shorthand.
  • proposed — Establish the production contract for tenant authorization, operation identity and cumulative receipts across partial erasure and retry, including concurrent writes and interruption. Validate those guarantees against the real hosted endpoint rather than relying solely on the local double.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies both main changes: the explicit forget cascade and hosted scoped erasure.
Docstring Coverage ✅ Passed Docstring coverage is 93.75% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 48 functions across 15 files. (3 skipped: 3…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit checks each scope with care,
Then sends the proper cascade there.
Hosted paths return their count,
Direct polls until results mount.
The burrow’s tests confirm the flow,
And document what callers know.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T18:36:08.523372Z 50ff48a New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 76cf658b28

ℹ️ 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 crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated

@tinysweeper tinysweeper 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.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0317 · 627,945 in / 34,682 out · 49,401 cached (8%)  · gpt-5.6-luna, glm-5.3-flash, deepseek-v4.1-flash
critique:    $0.0173 · 319,357 in / 18,249 out · 36,615 cached (11%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0138 · 244,223 in / 10,311 out · 12,530 cached (5%)  · gpt-5.6-luna
tests:       $0.0002 · 25,822 in  / 2,143 out  · 128 cached (0%)     · glm-5.3-flash
description: $0.0001 · 12,322 in  / 264 out    · 64 cached (1%)      · glm-5.3-flash
e2e:         $0.0001 · 13,718 in  / 1,150 out  · 64 cached (0%)      · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/testing/log.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/transport/failure.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/forget.rs
@tinysweeper tinysweeper Bot added the priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. label Oct 8, 2026
Keep main's whole-tree DELETE memory erase on the hosted wire and route
anything narrower through memory-api's scoped erasure passthrough
(memory/v1/erasures: {scope, audit_note}, synchronous, retried on a
retriable 502 ERASURE_INCOMPLETE, 404 reported as Unsupported).

Co-authored-by: Medulla <medulla@tinyhumans.ai>

@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: f77ef497dc

ℹ️ 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 crates/tinymemory-integrations/src/cortex/engine/erase.rs Outdated

@tinysweeper tinysweeper 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.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0368 · 722,784 in / 66,515 out · 85,646 cached (12%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0188 · 378,443 in / 29,841 out · 50,221 cached (13%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0171 · 254,358 in / 25,496 out · 32,225 cached (13%) · gpt-5.6-luna
tests:       $0.0004 · 36,042 in  / 5,575 out  · 1,600 cached (4%)   · glm-5.3-flash
description: $0.0002 · 17,001 in  / 1,593 out  · 1,408 cached (8%)   · glm-5.3-flash
e2e:         $0.0002 · 18,451 in  / 2,174 out  · 64 cached (0%)      · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs Outdated
senamakel and others added 4 commits October 8, 2026 23:23
Introduce erase operations across the cortex log and engine so stored
entries can be removed on demand. Supporting test helpers and a transport
failure path were added to exercise the new behaviour.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Cover the direct engine path, erase behaviour, and transport failure
handling with new integration tests so regressions in these areas are
caught before they reach the higher-level flows.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replaced the log_for_tests helper call with CortexLog::default in the
cascade validation test, and reformatted two long expressions in the
erase tests and testing routes to satisfy rustfmt.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@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: ed0e299027

ℹ️ 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 crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated

@tinysweeper tinysweeper 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.

Requesting changes: 2 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0413 · 787,409 in / 59,166 out · 53,801 cached (7%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0212 · 399,967 in / 23,650 out · 30,523 cached (8%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0192 · 280,786 in / 27,315 out · 23,278 cached (8%) · gpt-5.6-luna
tests:       $0.0002 · 20,980 in  / 2,170 out  · 0 cached (0%)      · glm-5.3-flash
description: $0.0002 · 20,794 in  / 1,845 out  · 0 cached (0%)      · glm-5.3-flash
e2e:         $0.0002 · 22,303 in  / 1,788 out  · 0 cached (0%)      · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/tests/live_cortexdb.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/forget.rs
Hosted erasure retries now trigger solely on the ERASURE_INCOMPLETE code, since any other failure leaves the outcome unknown and repeating a destructive request would hide it. Scope counts saturate instead of overflowing, and a Direct erasure answer that omits status is treated as completed without polling.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel

Copy link
Copy Markdown
Member Author

Correction to the thread replies of the second round: those fixes (retry only on ERASURE_INCOMPLETE, saturating erased-scope count, bounded-poll-count timeout test, synchronous-status test) landed in 9f438b4, not in the commit hash quoted there.

@tinysweeper tinysweeper 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.

Requesting changes: 2 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0278 · 566,340 in / 47,130 out · 55,097 cached (10%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0123 · 227,662 in / 17,402 out · 28,111 cached (12%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0145 · 224,643 in / 19,768 out · 26,858 cached (12%) · gpt-5.6-luna
tests:       $0.0004 · 45,922 in  / 3,979 out  · 0 cached (0%)       · glm-5.3-flash
description: $0.0002 · 21,629 in  / 1,652 out  · 64 cached (0%)      · glm-5.3-flash
e2e:         $0.0002 · 22,936 in  / 1,339 out  · 0 cached (0%)       · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
A hosted erasure answer whose `scopes` count exceeds the platform's `usize` range was silently clamped to `usize::MAX`, hiding a malformed response. It now returns an engine error naming the scope and offending count, and a test covers the string-typed count case.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@tinysweeper tinysweeper 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.

Requesting changes: 3 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0159 · 330,129 in / 27,582 out · 25,779 cached (8%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0068 · 114,151 in / 11,276 out · 13,237 cached (12%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0081 · 124,675 in / 10,596 out · 12,542 cached (10%) · gpt-5.6-luna
tests:       $0.0002 · 21,852 in  / 1,118 out  · 0 cached (0%)       · glm-5.3-flash
description: $0.0002 · 21,814 in  / 872 out    · 0 cached (0%)       · glm-5.3-flash
e2e:         $0.0002 · 23,173 in  / 368 out    · 0 cached (0%)       · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Add a test double hook that forces the status of polled Direct erasure
answers, and use it to check that a status which is not a known string
never completes the erasure. Also cover a hosted scope erased by an
engine that never held it, and relax the poll-count assertion to a lower
bound so it no longer depends on backoff timing.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel

Copy link
Copy Markdown
Member Author

Correction: the replies in the last round that cite a fix commit ('Added/Fixed in 5d947c0') refer to 5bcab70 (cross-engine erasure test, malformed polled statuses, poll-count assertion removal).

@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: 5bcab7038d

ℹ️ 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 crates/tinymemory-integrations/src/cortex/log/erase.rs

@tinysweeper tinysweeper 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.

Requesting changes: 3 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0217 · 500,180 in / 32,268 out · 45,071 cached (9%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0108 · 226,454 in / 12,217 out · 22,965 cached (10%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0098 · 155,099 in / 12,236 out · 15,898 cached (10%) · gpt-5.6-luna
tests:       $0.0004 · 47,626 in  / 1,979 out  · 3,072 cached (6%)   · glm-5.3-flash
description: $0.0002 · 22,600 in  / 789 out    · 1,408 cached (6%)   · glm-5.3-flash
e2e:         $0.0002 · 23,960 in  / 2,212 out  · 1,728 cached (7%)   · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs Outdated
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
A hosted erasure response that claims scopes were erased but returns no
erasure_ids is now treated as an incompatible answer rather than a success,
since the receipts are the audit trail of a destructive call. The test
double's forced poll status also no longer consumes the running budget, and
new malformed-answer cases cover the missing-receipt responses.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@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: 50ff48af0d

ℹ️ 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 crates/tinymemory-integrations/src/cortex/log/erase.rs

@tinysweeper tinysweeper 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.

Requesting changes: 3 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0252 · 531,932 in / 47,594 out · 44,494 cached (8%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0137 · 262,815 in / 19,549 out · 26,842 cached (10%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0103 · 145,472 in / 16,252 out · 16,116 cached (11%) · gpt-5.6-luna
tests:       $0.0005 · 50,805 in  / 8,127 out  · 0 cached (0%)       · glm-5.3-flash
description: $0.0002 · 22,910 in  / 999 out    · 1,408 cached (6%)   · glm-5.3-flash
e2e:         $0.0002 · 24,211 in  / 454 out    · 0 cached (0%)       · glm-5.3-flash

Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/testing/routes.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/erase.rs
Comment thread crates/tinymemory-integrations/src/cortex/engine/mod_erase_tests.rs
Comment thread crates/tinymemory-integrations/src/cortex/log/forget.rs
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel
senamakel merged commit 6998ce2 into main Oct 8, 2026
40 of 42 checks passed

@tinysweeper tinysweeper 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.

Requesting changes: 2 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0131 · 356,846 in / 33,210 out · 32,691 cached (9%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0050 · 83,687 in  / 9,427 out  · 9,166 cached (11%)  · gpt-5.6-luna, glm-5.3-flash
security:    $0.0065 · 102,123 in / 7,945 out  · 10,533 cached (10%) · gpt-5.6-luna
tests:       $0.0006 · 71,023 in  / 7,042 out  · 5,504 cached (8%)   · glm-5.3-flash
description: $0.0002 · 23,052 in  / 1,170 out  · 1,408 cached (6%)   · glm-5.3-flash
e2e:         $0.0005 · 51,365 in  / 5,268 out  · 5,952 cached (12%)  · glm-5.3-flash

#[tokio::test]
async fn the_hosted_wire_refuses_to_erase_without_a_request() {
async fn the_hosted_wire_erases_a_subtree_through_the_backend_passthrough() {
let (endpoint, state) = hosted_double().await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Exercise hosted passthrough against a real CortexDB backend

The hosted subtree and exact-scope tests use hosted_double, so they only prove the client and the test double agree. They do not verify the actual memory/v1/erasures request, backend scope semantics, or response parsing against CortexDB. Add an integration case using the repository's real backend harness for the hosted passthrough path.

[RULE] missing-real-backend-coverage ·


#[tokio::test]
async fn an_incomplete_hosted_erasure_is_retried() {
let (endpoint, state) = hosted_double().await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Exercise hosted polling against a real CortexDB backend

The incomplete hosted erasure retry path is validated only by a configured double. That does not establish that a real backend returns the incomplete response shape expected by the retry logic or that the eventual completion is handled correctly. Add a real-backend polling/retry integration test.

[RULE] missing-real-backend-coverage ·

#[tokio::test]
async fn the_hosted_wire_refuses_to_erase_without_a_request() {
async fn the_hosted_wire_erases_a_subtree_through_the_backend_passthrough() {
let (endpoint, state) = hosted_double().await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Exercise the forget cascade against a real CortexDB

The changed hosted tests cover erasure requests through a double, but none exercises the caller's fallback from an unsupported scoped erasure into the forget cascade against a real CortexDB. Because this behavior depends on backend route availability and the resulting deletion semantics, add an integration test using the real backend harness.

[RULE] missing-real-backend-coverage ·

};
// The deadline bounds the sleep and every retry of the request,
// not just the gap between polls.
let job = tokio::time::timeout(remaining, poll)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Cover the direct erasure polling timeout path

The new deadline behavior is a user-visible failure path, but this change adds no deterministic test that exercises a job remaining in a pending status until the timeout expires. Without one, regressions that omit the timeout, poll past the deadline, or return the wrong error can pass unnoticed. Add a paused-time test with a pending response and assert that it returns Error::Unavailable.

[RULE] missing-timeout-test ·

let mut attempt = 0;
let answer = loop {
attempt += 1;
match self

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high security confident

Reuse one idempotency key across hosted erasure retries

When the backend returns ERASURE_INCOMPLETE, this loop sends the same destructive request again, but the request carries no idempotency key. If the first request actually reached the backend and completed while its response was lost or classified as incomplete, the retry is a separate operation rather than a deduplicated replay. That can produce multiple erasure records and inconsistent audit results. Generate one idempotency key before the loop and attach it to every hosted attempt, or avoid retrying unless the transport/backend provides equivalent deduplication.


Additional critique observation

priority high likely

Preserve one idempotency key across hosted erasure retries

[RULE] idempotent-retry

When the backend returns ERASURE_INCOMPLETE, this loop sends another POST, but it does not create or pass an idempotency key. The hosted wire contract says writes claim Idempotency-Key; if the first request erased the scope but lost its response, the retry is a distinct destructive operation and can create duplicate erasure records or otherwise be processed twice. Generate one key before the loop and attach that same key to every attempt, or use the transport API that provides this guarantee.

[RULE] missing-idempotency-key ·

serde_json::json!({ "erased": true, "scopes": "1", "erasure_ids": [] }),
// Scopes erased, but no receipt for them.
serde_json::json!({ "erased": true, "scopes": 1, "erasure_ids": [] }),
serde_json::json!({ "erased": true, "scopes": 2, "erasure_ids": null }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium security confident

Cover hosted erasure counts outside the platform range

The malformed-answer cases cover string counts and missing receipts, but none supplies a numeric count larger than usize. The conversion is a platform-range boundary and needs an explicit oversized numeric response to ensure it is rejected rather than truncated or accepted inconsistently.

[RULE] missing-overflow-test ·

}

/// Direct only: the hosted wire has no erasure route.
/// Direct only for now: the hosted `memory/v1/erasures` passthrough is

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium tests likely

Exercise the hosted erasure passthrough against a real backend

The hosted passthrough's wire behaviour is asserted only against the test double: the real backend's dialect (no envelope, error_code in failures, the exact 502 ERASURE_INCOMPLETE shape, whether it truly omits confirm_all acceptance) is unverifiable from doubles. The live test file still marks erasure as Direct only. Once the route is live on the backend, extend the live test to erase a subtree through the hosted engine.

[RULE] live-coverage-gap ·

/// The cascade every removal sends: the named events go, with everything
/// derived from them. Never left to the engine's default (`derived_only`),
/// which keeps the events.
pub(crate) const FORGET_CASCADE: &str = "redact_events";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium tests likely

Exercise the forget cascade against a real CortexDB

The cascade: "redact_events" claim — that it deletes the events, unlike derived_only — is pinned only against the crate's own double, which was written in the same commit to model the desired behaviour. If real CortexDB rejects the value or spells it differently, every forget fails in production with no test having run against the real server. Extend the live CortexDB test to store an item, forget it by id, and assert it is gone.

[RULE] live-coverage-gap ·

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

Labels

priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant