fix+feat: v0.37.0 — recovery completeness, enumeration truth, provider compat, engine correctness, de-ossification#123
Conversation
…r compat, engine correctness, de-ossification Tier 1 (bugs): startup reconciler for evidence imports orphaned 'importing' by a crash; list_objects echo cap raised to the S3 page max so keys 501-1000 of a page are no longer unreachable (next_token skips the whole page); the final answer's post-processing cap is model-elastic and appends an explicit [TRUNCATED] marker instead of the codebase's one silent cut (the real slice lived in parse_agent_contract); test_conditional_get compares quote-normalized ETags so a provider ignoring If-None-Match reports "unchanged + unsupported" instead of a false "changed"; list_multipart_uploads gains a prefix (usable on prefix-scoped providers); inventory skips the storage-class-skew finding when the column is absent and keeps int64 precision in average_object_size. Security: bare AK/SK pair pastes are fully scrubbed (40-char base64 masked only when an AWS key-id shape co-occurs — ordinary 40-char strings untouched); session_messages JSON columns pass through redact() at the persistence boundary; get_object_lock_status maps InvalidRequest to "none" only in its object-lock message flavor. De-ossification (no security-floor change): completion budget bounded only by the per-model provider max-output (module-wide 32k ceiling removed); survey summary echo + deterministic session summary scale with the model window (persisted store 200, elastic echo floored at 50, digest capped at 50 with a "+N more" note); KiB/MiB labels for the 1024-based size math; duck.connect read-miss is a clean error (no stray DB) and writer lock contention gets the retryable message; session_datasets dedupe uses IS for NULL filenames; docs note for gated 1M context windows via explicit context_window. 634 tests pass (20 new in test_v0370_fixes.py); ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M3YojFPzjkfMj6YYSwvzdx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d430fa2047
ℹ️ 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".
| paired_paste = bool(_AWS_KEY_ID_HINT.search(text)) | ||
| out = text | ||
| for pattern, repl in _VALUE_PATTERNS: | ||
| out = pattern.sub(repl, out) | ||
| if paired_paste: | ||
| out = _BARE_AWS_SECRET.sub(REDACTED, out) |
There was a problem hiding this comment.
Scope bare-secret redaction to the credential pair
When one message or log contains an AWS access-key ID plus any unrelated 40-character hex/base64 value—such as a SHA-1 checksum or object identifier—paired_paste causes every such value in the entire string to be replaced. This irreversibly removes legitimate diagnostic evidence from persisted messages and reports; constrain the bare-secret match to a nearby or structurally paired value instead of globally substituting all 40-character tokens.
Useful? React with 👍 / 👎.
| return max(_MAX_OUTPUT, 4 * model_budget.completion_token_budget( | ||
| creds.get("model"), creds.get("context_window"), creds.get("max_output_tokens"))) |
There was a problem hiding this comment.
Avoid treating four characters as a hard token maximum
For completions whose tokenizer averages more than four characters per token—common with repetitive object-key prefixes, code, URLs, or whitespace—the model can legally emit an answer longer than this computed cap. _finalize_contract then truncates that valid answer despite the stated guarantee, so a requested full enumeration can still lose its tail; use a conservative tokenizer/provider-specific upper bound rather than the four-character heuristic.
Useful? React with 👍 / 👎.
What changed
The v0.37.0 batch from the four-angle mining round (persistence, S3/provider, agent de-ossification, engine math). Sixteen items; every security-floor bound untouched, one tightened.
Bugs fixed (Tier 1)
importingforever (no path back toconfirmed/planned). Startup reconciliation now fails orphaned imports + their files, mirroring the existing run reconciler.list_objectsunreachable keys. The 500-key echo cap sat below the 1000-key S3 page whilenext_tokenadvanced past the whole page — keys 501–1000 were silently lost with no way to page back. Echo cap now equals the page cap; the elastic tool-output budget still backstops it.parse_agent_contract, one layer below the visible one). The cap is now model-elastic (≥ 4 chars/token of the completion budget — it can never cut an answer the model was allowed to emit) and appends an explicit[TRUNCATED …]marker when hit.test_conditional_getfalse "changed". Providers that ignoreIf-None-Matchreturn200with the same ETag; the tool reported that as a change. It now compares quote-normalized ETags: equal on 200 → "unchanged + conditional unsupported" (rule 18).list_multipart_uploadson prefix-scoped providers. Noprefixargument meant the scope check always denied it. Now takesprefix, threaded to both the scope check and S3Prefix=.get_object_lock_statusover-broad "none".InvalidRequestmaps to "no lock" only in its object-lock message flavor; other flavors surface as errors instead of reading "cleanly deletable".average_object_sizeuses floor division (int64 precision above 2^53)..duckdb; writer lock contention gets the same retryable message readers had.session_datasetsNULL-filename dedupe (IS, not=).Security
AKIA…id survived label-anchored redaction. New narrow rule: bare 40-char base64 tokens are masked only when an AWS key-id shape co-occurs in the same text — ordinary 40-char strings without that hint are untouched (regression-tested both ways).session_messagesJSON columns (tool_activity/grounding/proposed_actions) now pass throughredact()at the persistence boundary like every sibling repo (rule-14 defense in depth).De-ossification (no security-floor change)
context_windowoverride.How to run it
Checks run
pytest -q— 634 passed (20 new intests/test_v0370_fixes.py).ruff check app— clean.stream_events_forsignature,gemini-2.5budget, KiB bucket labels, drift-sync now>=.Known gaps
parallel_tool_calls=Falsestays global (real DeepSeek workaround; provider-conditionalizing deferred).context_windowoverride (documented).🤖 Generated with Claude Code
https://claude.ai/code/session_01M3YojFPzjkfMj6YYSwvzdx
Generated by Claude Code