Skip to content

refactor: harden silent-failure paths in tracker, modal sandbox, ask modal - #354

Closed
lfiaschi wants to merge 1 commit into
mainfrom
claude/adoring-ride-V4MYp
Closed

refactor: harden silent-failure paths in tracker, modal sandbox, ask modal#354
lfiaschi wants to merge 1 commit into
mainfrom
claude/adoring-ride-V4MYp

Conversation

@lfiaschi

Copy link
Copy Markdown
Contributor

Context

This PR is the action half of a two-step "deep review + fix" pass. The review surveyed architecture, code health, bugs, security, performance, and tests across server, client, frontend, and shared. Findings were verified against the actual code before any change was made — agent-surfaced claims that did not hold up under verification were dropped (e.g. find_audit_logs is already gated by the route handler, find_eval_run already checks user_id, useInfiniteScroll's pagination math is correct, gauntlet's entropy (?-i:...) is supported by Python 3.7+ regex). The four fixes below are the verified, high-leverage subset that fit in one focused review.

What changes

File Issue Fix
server/domain/gauntlet.py run_static_checks imported and called loguru.logger — domain functions must return or raise (CLAUDE.md) Remove the inline log; the caller in publish_pipeline already logs grade + passed and now also logs source_files count so no debug info is lost
server/domain/tracker_service.py parse_semver(manifest_version) > parse_semver(latest.semver) raised ValueError on any malformed semver, aborting the whole tracker run New _hint_is_higher helper that catches ValueError and falls back to auto-bump
server/infra/modal_client.py The bash wrapper around uv sync always exited 0 (last command was echo), so a non-zero rc was silently lost; broken deps surfaced later as a confusing "agent crashed on import" Exit the bash with uv sync's rc, raise on non-zero with a sanitized tail of stdout, trim the happy-path log to byte count
frontend/components/AskModal.tsx messages/query/error were not reset when the modal reopened — stale conversation reappeared on reopen useEffect clears state when isOpen flips to true

Concrete failing scenarios these fix

  1. Tracker run aborted by one bad manifest. Any contributor sets version_hint: "v1.2.3" (with a stray v) in their SKILL.md. The next tracker tick crashes inside the version-resolution branch with ValueError: Invalid semver, the whole batch is logged as failed, and every skill in that repo stops getting picked up until the manifest is fixed. With this PR the bad hint is logged as a warning, the version falls back to auto-bump, and the rest of the batch continues.
  2. Silent dep-install failures in the agent sandbox. A skill ships a broken pyproject.toml (typo'd dep, deleted package). uv sync returns rc=1, but the bash wrapper still exits 0. The sandbox proceeds to launch the agent, which immediately fails on import missing_package, and the eval report shows "agent crashed" with no link to the real cause. With this PR the publish/eval surfaces RuntimeError: uv sync failed with exit code 1: <tail> so the cause is obvious.
  3. Stale conversation in AskModal. A user asks a question, sees the answer, closes the modal, reopens it, and is confronted with their previous answer (and previous error if there was one). With this PR the modal opens to the empty state every time.
  4. Architecture drift. The domain layer was acquiring a logger and emitting structured log lines. CLAUDE.md mandates that logging lives at the API/infra boundary; without enforcement, this slowly bleeds I/O concerns into pure-logic modules and makes them harder to unit-test in isolation.

Tests added

  • server/tests/test_domain/test_tracker_service.py::TestHintIsHigher — 7 cases covering happy path, malformed hint, malformed current, both malformed, and the common v-prefix mistake.
  • server/tests/test_infra/test_modal_client.py::TestSandboxZipSlipProtection::test_raises_when_uv_sync_fails — patches sb.exec to return rc=1 for the uv sync invocation only; asserts RuntimeError is raised with the expected message.
  • frontend/components/AskModal.test.tsx — new "clears prior conversation, query, and error when reopened" case using rerender to toggle isOpen; asserts the previous answer, user message, and input value are all gone.

Findings deliberately left for follow-ups

The deep review surfaced more than this PR fixes. Calling them out so they aren't lost:

  • Test coverage gap. server/domain/publish_pipeline.py (848 LoC) has no dedicated test file; error paths around S3 upload, version conflicts, and eval triggers are only covered indirectly via API tests.
  • Cache eviction. server/infra/cache.py evicts the entry expiring soonest; under mixed-TTL workloads (taxonomy 10s, org metadata 30s) cold entries thrash. LRU/access-time would help but is not a clear bug today.
  • Embedding failures swallowed silently. generate_and_store_skill_embedding warns and returns; a publisher whose Gemini call failed has a skill that won't surface in semantic search and no signal in the response.
  • Tracker partial-failure SHA advance. When 2/3 skills publish and 1 fails, last_commit_sha advances and the failing skill never retries until the next push. Per-skill retry tracking is the right fix but is a larger design change.
  • Backfill scripts. backfill_*.py lack --resume and incremental flushing; a crash six hours into a 10k-skill backfill restarts from zero.
  • Inline fontSize in a few page components. Should use the --text-* scale per CLAUDE.md.

Quality gates

  • ruff check / ruff format --check: clean
  • mypy (88 source files): clean
  • frontend tsc -b + eslint: clean (one pre-existing warning in SkillDetailPage.tsx not touched here)
  • server tests: 941 passed, 34 deselected
  • frontend tests: 83 passed (incl. new AskModal regression)
  • client tests: 291 passed, 29 skipped

Test plan

  • CI green on lint, typecheck, all four test jobs, migrations, schema-drift
  • Manual: publish a skill with an intentionally broken dep in pyproject.toml against dev — confirm the eval/publish error message names uv sync instead of a downstream import error
  • Manual: open the AskModal, ask a question, close, reopen — confirm empty state
  • Manual: temporarily set a version_hint: "v1.2.3" in a tracked manifest — confirm the tracker logs a warning and the rest of the batch publishes normally

https://claude.ai/code/session_012v9S3rfspyGQKLRXY3iTKc


Generated by Claude Code

…modal

Targeted fixes from a deep codebase review. Each addresses a verified bug
or architectural violation with a concrete failing scenario; agent-surfaced
findings that did not hold up under verification (e.g. visibility checks
already gated by route handlers, infinite-scroll math, gauntlet entropy
regex flag scope) were dropped to keep this PR focused.

server/domain/gauntlet.py
  Remove the loguru import + log call that ran inside `run_static_checks`.
  Domain functions must return or raise — logging happens at the API/infra
  boundary (CLAUDE.md). The caller in publish_pipeline already logs grade
  + passed; extend that line with source_files count so no info is lost.

server/domain/tracker_service.py
  `parse_semver(manifest_version) > parse_semver(latest.semver)` raised
  ValueError on a single malformed string (e.g. a `version_hint: "v1.2.3"`
  in any tracked manifest), aborting the entire tracker run. Wrap the
  comparison in a `_hint_is_higher` helper that returns False on parse
  failure so we fall back to auto-bump. Adds 7 regression tests.

server/infra/modal_client.py
  The bash wrapper around `uv sync` always exited 0 because its last
  command was an `echo`, so `_run_in_sandbox` saw rc=0 even when deps
  failed to install. The agent later started, immediately crashed on a
  missing import, and the eval surfaced a confusing "agent crashed"
  message instead of "deps failed". Make the bash exit with the actual
  uv sync rc, raise on non-zero, and trim the success log so we don't
  ship hundreds of bytes of subprocess output to logs on the happy path.
  Adds a regression test that simulates uv sync exit=1.

frontend/components/AskModal.tsx
  `messages`, `query`, and `error` were never reset when the modal was
  reopened. Closing mid-conversation and reopening surfaced stale answers
  — confusing UX and a violation of the "reset state on context changes"
  rule in CLAUDE.md. Add a useEffect that clears state on each open.
  Adds a regression test using rerender to toggle isOpen.

Tests: 941 server / 83 frontend / 291 client all green.
Lint, typecheck, format: clean.

https://claude.ai/code/session_012v9S3rfspyGQKLRXY3iTKc
@lfiaschi

Copy link
Copy Markdown
Contributor Author

Closing as part of the 2026-08-11 open-PR consolidation. This automated review-sweep PR overlaps heavily with the retained merge queue (#449, #448, #447, #446, #405, then #438, #443, #375). Unique fixes not covered by the retained set are catalogued in #451 for a follow-up best-of PR. The branch is preserved, so nothing is lost.

@lfiaschi lfiaschi closed this Aug 12, 2026
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