Skip to content

docs: drop numeric server error codes from notes and comments - #37

Merged
krassx merged 1 commit into
mainfrom
docs/drop-numeric-server-codes
Oct 14, 2026
Merged

krassx merged 1 commit into
mainfrom
docs/drop-numeric-server-codes

Conversation

@krassx

@krassx krassx commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #36: generalises the remaining notes and comments that quoted numeric server verdict codes (DESIGN.md, PROGRESS.md, and a few comments in the queue, runtime and transport code). Comments and notes only; no behaviour change.

🤖 Generated with Claude Code

Comments and notes only; no behaviour change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

Reviewed as a follow-up to #36: drop numeric server verdict codes from notes and comments. Diff is 10 comment/doc lines across DESIGN.md, PROGRESS.md, queue.rs, runtime.rs, and bugsee-core transport.rs. Walked the live delivery path (HttpTransport → transport::deliver → deliver_queued / memory settle → blacklist_add) rather than the patch alone.

Findings

No P0–P3 issues. No behaviour change: the protocol mapping is unchanged in crates/bugsee/src/transport.rs (12003 → DuplicateDropped, 12004 → TooManySimilar { signatures: vec![] }) and is still covered by crates/bugsee/tests/http_transport.rs. The rewritten English names match those variants and the runtime fallback to queue::signatures_of when the transport returns an empty signature list.

The 12003/12004 sweep of notes and comments is complete. Remaining numeric codes are the implementation/tests (required) and an unrelated 99006 jailbreak-validation note in environment.rs that this PR did not claim to generalise.

Verdict

  1. Overall risk: Low
  2. Merge recommendation: Approve
  3. Most important issues to fix: None
  4. Positives: Comments stay accurate after the rename (silent drop vs local blacklist vs resume-at-PUT to avoid a duplicate create). HTTP 401/429/503 are correctly left as public status codes. No executable code changed.

Did not run cargo test. CI 38598203554: MSRV, Android lint, and iOS-device lint were green at review; Ubuntu/Windows/macOS test jobs were still running.

Open in Web View Automation 

Sent by Cursor Automation: Bugsee code review

@krassx
krassx merged commit bf90a57 into main Oct 14, 2026
9 checks passed
krassx added a commit that referenced this pull request Oct 14, 2026
Tree unchanged here; the clean-up from #37 is already included by the parent merge or applied next.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
krassx added a commit that referenced this pull request Oct 14, 2026
Comments and notes only; no behaviour change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
krassx added a commit that referenced this pull request Oct 14, 2026
* feat: degrade to in-memory reporting on read-only/ephemeral file systems (#9)

Resolve the data directory as explicit option, BUGSEE_DATA_DIR, platform
default, then temp dir, taking the first that is actually writable. If none is,
or the disk fails mid-run (full, read-only, removed), launch still succeeds and
handled errors / manual reports are assembled without capture context and
delivered from a bounded in-memory backlog. Native crash handler and panic
snapshots are skipped in memory mode. Adds Bugsee::storage_status() so a host
can check crash recovery is available and whether the dir may be ephemeral.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: address review of data-directory fallback (#9)

- memory backlog: entries stay queued while in flight so the cap is real; cache
  the presigned endpoint (no duplicate issue on a retried PUT); honour the flush
  deadline; clear the backlog in fork children
- a requested data_dir / BUGSEE_DATA_DIR is final: unusable means memory mode
  (explicit_rejected), never another disk location
- temp fallback is bugsee-<uid>/<token>, 0700, symlink/owner checked; probe uses
  create_new with a random name
- recover and deliver leftovers from the previous default location once
- mid-run degradation is visible (StorageStatus::degraded); fork child falls
  back to memory instead of failing; warn_once per message, never panics
- #[non_exhaustive] on the new public types; ffi test no longer writes to the
  real data directory

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: second review round for data-directory fallback (#9)

- fork child that falls back to memory clears the panic snapshot path and
  updates the published storage resolution (dir None, source None)
- legacy location is adopted only if <temp>/bugsee and the token dir are real
  directories owned by us and not our own directory (canonicalised compare)
- legacy queue is included in flush, gc'd for orphans, and retired from polling
  once recovery has run and its queue is empty
- do not resolve temp_dir() unless a default location is actually needed
- tests: fork memory-fallback, symlinked/aliased legacy dir, end-to-end legacy
  crashed session + queued report delivered once and cleaned up

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* feat(bugsee): populate utc_offset, hardware model and Windows locale

Adds crates/bugsee/src/hostinfo.rs with per-platform lookups (libc on unix,
hand-declared Win32 calls on Windows; no new dependencies) and threads the
results through HostFacts into platform.utc_offset and hardware.model.

Closes #16

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(bugsee): address review of hostinfo (iOS model, tm_gmtoff gating, locale)

Closes #16

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): exactly-once recovery and queue draining across processes sharing a data dir

Several processes on one data directory could double-deliver (or lose) reports:

- A session was recovered twice: a peer that listed it before another finished
  claimed it after the winner had discarded it, producing a phantom report. The
  marker is now re-checked after the claim is won.
- Stale-claim takeover was remove-then-create, so two takers could each remove the
  other's fresh claim and both hold it. Takeover is now serialised by a guard file
  and re-validated under it; release only removes the claim's own content.
- Claims and session markers identified owners by bare pid: a recycled pid (or a
  restarted container's pid 1) kept a dead owner's work blocked forever. Owners
  now carry a process start time (Linux /proc, macOS proc_pidinfo, Windows
  GetProcessTimes), with a 30 minute lease as a backstop.
- On Windows process liveness always answered "dead", so live peers' claims and
  markers were taken over. Implemented via OpenProcess/GetExitCodeProcess.
- queue::gc_orphans at a peer's launch reaped another process's in-flight enqueue
  (sidecars before the bundle rename), stranding the bundle and losing the report.
  Only files untouched for 60 s are reaped now.
- Leftover claims of discarded sessions are swept.

Adds tests/multiprocess.rs (real child processes racing; SIGKILLed holder) plus unit
tests for claims, process identity and queue gc.

Closes #14

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* feat: define the shutdown/flush contract; opt-in SIGTERM/SIGINT flush

- Document per exit path what is persisted, delivered and recovered
  (Bugsee::stop docs, DESIGN.md section 8).
- Bugsee::shutdown(timeout) = flush then stop. A stop during a flush now
  aborts the flush so the clean-stop acknowledgement bound holds.
- Bugsee::install_termination_flush: opt-in, chaining SIGTERM/SIGINT hook
  (self-pipe; flush on a normal thread; re-raises with the default
  disposition so the exit status is unchanged) and a Windows console
  control handler.
- LaunchOptions::flush_at_exit: atexit-based clean stop for deliberate
  process::exit.
- Subprocess tests for every exit path.

Closes #8

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* feat: general PII scrubber and report rate limiting

Add a regex-free scrubber (emails, token shapes, keyed secrets, card-like
numbers, home-dir usernames; allow/deny/sensitive_keys; off switch) applied
at report assembly over every JSON section after before_send, and token
bucket rate limiting (per-signature + global, crash floor, bounded memory)
applied before the durable queue, surfaced via DropReason::RateLimited and
a bugsee.reports_suppressed attribute. Both on by default, opt-out via
LaunchOptions::disable_scrubbing / disable_rate_limiting.

Closes #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): arbitrate cross-process claims and session liveness with OS file locks

Review of the pid/start-time claim scheme found it unsound where #14 matters most:
containers with separate pid namespaces sharing a volume (both apps pid 1) cannot
compare pids or start times, so a peer's live claim was judged stale and its live
session reported as a crash. Pid-in-file schemes also needed a lease, a takeover
guard with a timer, and identity checks, each with its own race.

Replace them with kernel locks: fcntl(F_SETLK) on unix (per process, released on
death, not inherited by fork) and LockFileEx on Windows, on dedicated *.lock files
(queue/<bundle>.lock, sessions/<gen>.recover.lock, and sessions/<gen>.lock held
for a session's life). Nothing can go stale, so there is no lease, takeover or
start-time logic. An in-process registry (pid-keyed, spin-locked with the holder's
pid so a fork child cannot inherit a held lock) excludes threads and keeps a
process from ever opening one lock file twice, which POSIX would punish by
dropping the lock.

- .alive stays a bare pid and lock files are new names, so older builds sharing a
  directory keep working (no exactly-once between old and new; documented).
  Markers with no .lock beside them still use the pid probe.
- Liveness probe: zombies count as dead (Linux /proc state, macOS proc_pidinfo);
  Windows uses WaitForSingleObject.
- Leftover lock files of finished items and dead sessions are swept when free.
- Tests: a live peer whose marker names a colliding pid (parent's, init's) is not
  recovered until it really dies, then exactly once; concurrent claimers; probing
  never drops a held lock; zombie probe.

Closes #14

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: harden the termination hook and shutdown after review

- Detect a handler installed after ours (tokio, signal-hook) by asking the
  kernel what is in force; flush only, never terminate the host.
- A stop no longer waits on the uploader to end the session cleanly (an HTTP
  call cannot be interrupted); delivery is documented at-least-once.
- Fork-child re-install ordering, SIG_IGN left alone, watcher-alive and
  pending-signal tracking, host sa_mask/SA_ONSTACK/SA_NODEFER/SA_RESETHAND
  carried over, fork-aware install lock, pipe2, clean rollback on failure.
- flush_at_exit is unix only and skipped in fork children.
- Flush aborts between deliveries on stop (memory and every queue dir).
- Tests: late/SA_SIGINFO/ignored handlers, SIGINT, double signal, fork child,
  hanging transport; no fixed sleeps; temp dirs cleaned.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: keep draining existing data dirs that cannot take new files (#9)

- an existing directory that fails the write probe / session open is still
  recovered from and drained (read + delete only); claims are lenient there and
  a crash that cannot be re-queued on disk is delivered from memory; delivered
  but undeletable bundles are remembered so they are not resent every drain
- in-memory TooManySimilar blacklist (cleared in fork children)
- a clean stop gives the in-memory backlog a last bounded delivery attempt
- legacy temp location adopted whenever it exists and is trusted, even if no
  new default directory was usable
- rotation tick rewrites a missing liveness marker after a wipe and marks the
  recorder degraded
- DESIGN.md: failure table, legacy/flush wording

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(scrub): second-review hardening of the PII scrubber

Numeric secrets under secret keys and integer card numbers are redacted;
colon-form prose ("invalid token: expected ident") and "my_app::token:"
are left alone; Cookie headers take the whole line; escaped quotes inside
quoted values are honoured; the "signatures" exemption moves out of the
shared key matcher into crash.json handling; tighter token shapes (AWS,
hf_, sk-, prose after Bearer); contextual stem exclusions (author,
tokenizer, session_state, method_signature); exact key/sig only redact
credential-looking strings; request.json no longer double-scrubs
metadata; file names (icon@2x.png) and /Users/Shared are not PII; the
pre-check handles \u escapes and separated key stems. Test secrets are
assembled from halves for push protection.

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): harden the file-lock claims (second review)

- A launch that cannot hold <gen>.lock removes the file instead of leaving an
  unheld one, which every peer read as "that session died" and recovered (and
  deleted) the live session. Contended claims are retried briefly; an empty,
  fresh marker with a free lock is skipped (the pid is written after locking);
  on unix a probe uses F_GETLK and never takes the lock.
- Filesystems that reject locks (ENOLCK, EOPNOTSUPP, ENOSYS, EINVAL) degrade to
  thread-only claims with a one-time message, and probes report unknown so
  recovery falls back to the marker pid, instead of blocking the queue forever.
- An unclean shutdown (detached worker/uploader) keeps the session lock until the
  process exits so peers cannot recover a session still being written.
- Registry keys are canonicalised; a fork child resets the registry from the fork
  hook; old-scheme .claim/.claim.takeover files are swept.
- Tests: the real pid-namespace hazard (marker pid that does not exist here,
  reaped pid), crashed sessions with free lock files, the lock-race launch,
  unsupported-lock injection, and the probe/launch ordering cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: keep the scheduled memory drain independent of the stop flag

The stop-time memory drain relies on the scheduled pass having had its one
attempt; only an explicit flush aborts on stop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* test: gate unix-only helpers so Windows clippy stays clean (#9)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* feat(native): best-effort flush of in-flight events at crash time

A producer only queues an entry; the capture worker appends it later, so the
last events before a fault (still in the channel) were lost. Measured: a
1500-event burst followed by SIGSEGV recovered ~50-60 events.

After the marker is complete, the fatal-crash handler now does one atomic
ticket, one non-blocking write(2) (Windows: SetEvent) to a pre-created wake
handle and polls an atomic for at most 50 ms. A helper thread made at launch
posts a Flush through the normal FIFO channel and publishes the worker's ack.
No allocation or lock on the crashing thread; a stuck worker costs only the
budget. A main-thread panic nothing will catch runs the same bounded flush.

Tests: core handshake/stuck-worker/deregistration, torn part-tail recovery,
and subprocess crash tests (burst then SIGSEGV recovers every event; wedged
worker still dies promptly and reports). fork_safety's FileTransport now
writes atomically since a dying worker can linger mid-upload.

Closes #13

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): queue the previous crash on the launch path before launch returns

A host that crashes again right after launch (crash loop) could die before the
worker thread recovered the previous crash. launch now runs a bounded,
newest-first recovery pass (8 sessions, 500 ms budget via
LaunchOptions::launch_recovery_budget, 4096-entry scan cap) that enqueues the
reports durably before returning; upload stays async and the worker's pass picks
up the rest, skipping what the launch pass attempted.

Closes #10

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: drain every trusted unwritable default tree, not just one; stale unlinkable claims proceed (#9)

- recovery_dirs: all rejected existing candidates (incl. the private temp tree)
  are drained/recovered even when a later default wins; core takes extra_data_dirs
- a stale claim that cannot be unlinked is Unavailable, not Taken
- seed the in-memory blacklist from the on-disk one

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(scrub,runtime): second re-review fixes

Stem exclusions for cancellation_token, www-authenticate/authentication,
token_endpoint/url/uri/expiry/ttl; the colon-prose leniency applies only to
bare 'token', so password/passwd/secret/api_key values are always redacted;
the rate limiter now runs before the on-disk blacklist read so a denied
storm is lock + hash only (test counts disk reads).

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: PR #31 review and CI fixes

- Android: errno via libc::__errno (and the BSD variants), not __errno_location.
- Gate the flush_at_exit statics and import on unix (Windows clippy).
- SA_RESETHAND: the handler decides "terminate" before emulating the reset
  and ships it in the pipe byte; the watcher no longer re-reads the slot.
  New test with a one-shot host handler.
- Windows Ctrl+C/Break now run shutdown like close/logoff/shutdown; document
  that a host which swallows the event registers its handler after ours.
- DESIGN section 6 no longer says guard Drop flushes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): run launch-path recovery on a bounded helper, after the crash handlers

Address review of the launch-path recovery pass:
- the pass runs on a helper thread and launch waits at most the budget, so a
  blocked before_send cannot stall or deadlock launch; the worker holds its own
  recovery until the pass is done (bounded) and skips what the pass claimed
- Recorder::recover_on_launch_path is called by launch_with after the native
  handler and panic hook are installed, outside all locks
- dedup repeated identical recovered crashes against the queue and cap it
- recovered crashes carry no scope on either path; claimed-only attempted set;
  scan cap counts session markers only; docs, latency numbers, deterministic
  tests, facade test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(native): harden in-flight crash flush (review feedback, #13)

- One process-wide wake pipe/event and ONE helper thread, created once and
  re-created in a fork child; the flush target is swapped under a fork-aware
  lock (last registered wins). Handles are never closed, so no descriptor-reuse
  race and no SIGPIPE for C hosts; shared ticket counters are now coherent.
- Dying flag raised by the crash handler before waking the helper: claims and
  recoveries start nothing in the window, so a report is never half-delivered
  (removes the 5 s UNOWNED_GRACE stall in fork_safety; test-helper workaround
  reverted).
- Skip the wait when the crashing thread is the worker or helper.
- Handler waits with poll (Unix) / ack event + QPC (Windows) instead of
  nanosleep / Sleep(1); pipe2(O_CLOEXEC) on Linux/Android; parent's fds closed
  in a fork child; unpublish-then-republish ordering.
- Panic hook shares DEFAULT_BUDGET; docs cover host-caught panics, ordering,
  Windows filter order and last-registered-wins.
- crash_inflight runs on Windows too (cfg any(unix, windows)); a hidden budget
  setter lets the burst test use a long budget deterministically, a small burst
  covers the real 50 ms budget, and the wedged test now requires the handler to
  wait the budget and no longer (all three fail without the feature).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): review round 3 on lock claims

- A leftover <gen>.lock that cannot be opened (0444, read-only volume) or whose
  lock call errors probes as Unknown, not Held, and the probe opens read-only, so
  it can no longer hide a crash forever.
- Lock-less sessions (filesystem rejects locks) keep a <gen>.beat heartbeat file,
  touched every 2 s by the worker; a beat younger than 60 s means alive whatever
  pid the marker names, so a peer in another pid namespace is never mistaken for a
  crash. Without a beat the pid is probed as before.
- claim_pending re-runs the liveness decision under the recovery claim, so a
  session that finished locking since the scan is not torn down.
- Windows maps ERROR_INVALID_FUNCTION/NOT_SUPPORTED/CALL_NOT_IMPLEMENTED to
  Unsupported, so the documented degrade exists there; the dead-code allow is gone.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* feat(health): local session health records for release health (#12)

Records how each session ends (ok/errored/crashed/abnormal) behind an
off-by-default option. Recovered crashes settle their session exactly once.
Nothing is sent: the backend has no session-health ingest endpoint.

Refs #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): make the lock-less heartbeat robust to clock skew and slow launches

- A heartbeat whose mtime is in the future (file server clock ahead) counts as
  fresh, like marker_is_fresh; only a demonstrably quiet beat condemns a session.
  The staleness window is 3 minutes, above NFS attribute-cache lifetimes.
- Launch-time recovery (before the worker loop starts) now keeps the beat going.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): keep unique crashes the launch pass cannot queue; scan newest-first without a cap; keep attempts progressing

- Admission::Full no longer discards the session; it is left to the worker
- find_pending_bounded reads all marker names, sorts, then probes (no capped
  readdir), and includes sessions with prior attempts so a fault during recovery
  still reaches MAX_RECOVERY_ATTEMPTS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(health): address review of release health (#12)

Register the backend session eagerly at launch when release_health is on, finish
records on any non-panicking stop, ignore stale panic snapshots, memory-mode and
empty-dir guards, ack tombstones, generation floor, no file I/O under the facade
lock, gc, monotonic durations, unstable/hidden API, docs moved to section 10.

Refs #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): tried sessions first, and a queue-cap refusal is not an attempt

- find_pending_bounded returns sessions with prior attempts before newer ones, so
  MAX_RECOVERY_ATTEMPTS progresses even if recovering the newest keeps faulting
- Admission::Full gives the attempt back (undo_attempt)
- make the full-queue test race-free

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(native): address review of the in-flight flush (#13)

- P1: a dying process skips the worker's recovery scan, orphan GC and legacy
  drains and reaches worker_loop at once, so the queued Flush is answered.
- P2: the flush target stays registered until the worker has acked Stop, so a
  crash during shutdown still waits for queued entries.
- P2: Windows wait uses integer QPC math (no floating point in the filter).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: never recover the same directory twice in one launch (#9)

- legacy_is_adoptable compares against the chosen dir AND recovery_dirs by
  canonical path (Windows: temp fallback is the legacy location)
- spawn path dedups legacy/extra dirs against the data dir and each other
- seed the in-memory blacklist from legacy/extra dirs too
- test: an existing temp tree is offered in exactly one role

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): a lock file that vanishes under a scan is not evidence of a crash

probe returned Free both for an unheld lock and for a file that disappeared
between a caller's exists() and the open. A session without kernel locks unlinks
its <gen>.lock before writing its heartbeat, so a peer that saw the file could
classify that live session as crashed. probe now reports Probe::Vanished for a
missing file (no pre-check), and session_is_crashed treats it like Unknown and
falls through to the heartbeat/pid decision. Test injects the vanish between the
existence check and the probe's open.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: a stop during a flush's memory pass must not start a disk upload

Re-check `stopping` after the memory drain and after each claim, so the
uploader reaches its stop arm and the stop-time memory drain runs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(health): keep panic.info for abort correlation, no eager registration in memory mode

Address review on #35: the worker-thread snapshot is expired by a detached
thread after the process survived 1 s instead of deleted in the hook, and the
eager session registration requires a disk session.

Refs #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): a failed enqueue write is not a recovery attempt

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(health): do not expire panic.info from a hook timer

Address re-review on #35: leave the worker-thread snapshot alone (abort
correlation) and rule out a surviving process's leftover at recovery with a
5 s tail. Adds a worker-thread aborting-panic case to the crash matrix.

Refs #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): a session the launch pass defers is picked up even if the pass outlived the worker's wait

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(health): mark a panicking drop so a slow unwind is still a crash

Address re-review on #35: panic_is_recent no longer guesses from the clock when
the recorder was dropped while unwinding; empty rotation directories no longer
count as capture activity.

Refs #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): deferred launch-pass recovery uses the recovery directory, not only the capture tree

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(scrub): do not redact public OIDC/OAuth metadata keys

authorization_endpoint/url/uri, oauth* names (oauth_token and
oauth_client_secret still hit the token/secret stems), auth_method and
token_endpoint_auth_* are not secrets. Tests in bugsee-core and
bugsee-reqwest (query params and headers).

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: remember every undeletable retired bundle, not just delivered ones (#9)

One retire_queued helper for all arms (delivered, TooManySimilar, duplicate,
permanent, retries exhausted); recovered crashes consult the in-memory
blacklist. Test: terminal verdicts on a read-only queue are sent once.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* test(core): wait on an observable condition in the full-queue test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(scrub): narrow the oauth exclusion to public metadata

oauth_verifier, oauth_pin and a bare oauth key stay redacted again;
oauth_client_id/redirect/scope/issuer/endpoint/... and auth_url/uri/endpoint
are public. Tests in bugsee-core and bugsee-reqwest.

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* Merge origin/fix/issue-9 into fix/issue-11

Adapt the new storage_failures test to assemble_docs' scrubber argument.

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): declare kernel32 calls once (clashing_extern_declarations on Windows)

process.rs and crash_flush.rs declared WaitForSingleObject with different handle types. Both now use one win32 module; no other duplicate extern declarations exist in bugsee-core, bugsee-native or bugsee. Verified with a standalone windows-msvc clippy of the affected modules.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(scrub): free-text oauth_verifier/oauth_pin and short pin/otp codes

Free-text keyed matching now follows the structured matcher for the OAuth
1.0a verifier/PIN and redacts 4-10 digit pin=/otp= values.

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(scrub): structured matching redacts code_verifier (PKCE)

Refs #11

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* docs: keep the corrected native feature comment from main

* fix: de-duplicate the unix libc dependency after merging main (#27's optional form vs the unconditional one)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix(core): make the crash-flush handshake robust on slow runners

Root cause of the windows flake in a_stuck_worker_costs_only_the_budget: the helper's ack wait (250 ms) was shorter than the 5 s budget the test asked for. After un-wedging, the worker had to drain a backlog (file creation on Windows is slow) and the helper gave up before the ack, never retrying, so the handler waited out its whole budget. The helper now waits 10 s (it only bounds a permanently wedged worker). The test also stopped assuming a 150 ms sleep wedges the worker (it waits for the sampler to report entry), uses generous budgets and bounds, and no longer relies on sleeps.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* docs: describe backend behaviour generically in release-health notes

Refs #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* docs: keep design notes generic (no private-component references) (#36)

Generalise the mobile native capture and out-of-process monitor design
notes, the FFI audit and a few code comments so they describe behaviour in
generic terms (the backend, the ingestion pipeline, existing report
variants) instead of naming components of other projects. No behaviour
change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* docs: drop numeric server error codes from notes and comments (#37)

Comments and notes only; no behaviour change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant