Skip to content

Sync active TinyMemory pin with async resolver - #49

Merged
senamakel merged 22 commits into
epic/8089-test-ownershipfrom
sec-656-active-pin-async-resolver
Oct 27, 2026
Merged

senamakel merged 22 commits into
epic/8089-test-ownershipfrom
sec-656-active-pin-async-resolver

Conversation

@senamakel

Copy link
Copy Markdown
Owner

Summary

Sync the active OpenHuman TinyMemory pin (8b919fd6) into the epic branch while preserving its later fixes and tests, and include the async EngineResolver contract from merged PR #48. This merge keeps both histories and the Tokio 1.53.3 advisory fix.

Verification

  • cargo fmt --all -- --check
  • cargo deny check all
  • cargo +1.96 check -p tinymemory-tools
  • cargo +1.96 test -p tinymemory-tools --lib (407 passed)

Refs senamakel/openhuman#656

senamakel and others added 22 commits October 22, 2026 10:13
…ership

fix(tinyredact): redact home paths in contextual file URIs
A hosted `*_PLAN_REQUIRED` refusal became `Error::Engine` in v2.0.1 so a host
stops signing the user out, but `Error::is_account_wide` only knew Off,
Unauthorized and InsufficientCredits. Every caller that asks "is this the
account, not the item?" therefore treated a plan refusal as item-scoped: the
job queue spent an attempt per run and dropped the job after MAX_ATTEMPTS,
source sync retried a refused batch item by item, the layout migration did
not pause, and a turn got no memory notice.

Add `Error::is_plan_required` and count it in `is_account_wide`, so every
caller is fixed in one place. Sync's private copy of the check and its
suffix constant are removed; cortex's `is_plan_required` delegates to the
method; the turn's refusal block names the plan.
…ccount-wide

fix(api): count a plan refusal as account-wide
…tions

An unreadable deletion store was read as empty, so the next enqueue saved
[new] over it and every deletion already owed was lost.

read() now reports the store as unreadable instead. enqueue, settle and
pending never write over it: a deletion that cannot be saved is held in
memory, counted by pending(), and merged back into the store on the next
read that succeeds.
A failed write-back during settle left the stored entries in the held
list, so a later read wrote the settled deletion back and it ran again.
Every list written already carries every held deletion except one being
settled, so a successful save now clears the held list.
…ixed credentials

A separated card run that failed Luhn as a whole (a card followed by a
CVV or preceded by a quantity) was dropped, because the greedy card regex
cannot give digits back. Such a run is now retried on windows of its
digit groups; a window must pass Luhn and be corroborated.

The credential patterns allowed no quote between the key and its
separator, so JSON-quoted credentials in prose survived, and their
leading word boundary never fired after an underscore, so DB_PASSWORD=,
*_SECRET= and *_TOKEN= survived. Both now match; the trailing word
boundary still keeps token_count, max_tokens and tokenizer clean.
redact_home_paths copied every scheme:// token whole, so a home path in
a query or fragment (?path=/Users/alice/...) was kept. Only the scheme,
authority and path are now copied as a unit; the query and fragment are
scanned like any other text.
…dable-queue

fix(deletion): never overwrite an unreadable queue; hold unsaved deletions
…d-and-credential-gaps

fix(tinyredact): redact cards next to other digits and quoted or prefixed credentials
…e-path-in-uri-query

fix(tinyredact): redact home paths in a URI's query or fragment
dedupe_overlaps dropped any hit that overlapped an earlier kept hit, so
when two detectors matched overlapping ranges (0..10 and 5..15) the
bytes 10..15 were left in clear text. Merge the overlapping hit into the
kept one instead: the earlier, longer hit keeps its token and the
combined range is redacted once.
…he scope-wide erase

cleanup only erases a legacy tree wholesale when export reports nothing
incomplete. No test covered that guard: dropping it let erase run on a
tree still holding part of a chunked item. The new test makes the legacy
engine report one incomplete item and panic on erase.
When the engine refuses a bulk store because of an item, the importer
stores the batch one item at a time. If a later item then fails with a
non-skippable error, the checkpoint must stay on the last item actually
stored. No test covered that path. The scripted engine gains a mode that
refuses every bulk store and goes unavailable after N single stores.
…ges it

On the proxied wire an erase of a tenant's user node purges the whole
tenant only when it also reaches every descendant and every kind. The
kinds case was tested; the exact-reach case was not, so dropping the
descendants check went unnoticed.
forget_events sends at most FORGET_BATCH (100) ids per request, and a
hosted retry that answers 404 means an earlier send already removed
them, which is success. Neither was tested. The new test forgets 250 ids
against a backend that fails each batch's first send with 503 and
answers its retry 404.
…ial-overlaps

fix(tinyredact): keep a partial overlap's tail redacted
…y-stored-legacy-item

test(layout_migration): pin that a partly stored legacy item blocks the scope-wide erase
…back-checkpoint

test(import): pin the checkpoint when the one-by-one fallback stops
…-reach-erase

test(cortex): pin that erasing only a proxied tenant's node never purges it
…s-and-gone-retry

test(cortex): pin forget batching and a retry that finds the events gone
@senamakel
senamakel merged commit 1033d8c into epic/8089-test-ownership Oct 27, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants