Skip to content

Fix all 17 verified defects from the systematic bug scan - #34

Merged
hsliuustc0106 merged 1 commit into
mainfrom
fix/issue-33-bug-scan-fixes
Oct 2, 2026
Merged

hsliuustc0106 merged 1 commit into
mainfrom
fix/issue-33-bug-scan-fixes

Conversation

@hsliuustc0106

Copy link
Copy Markdown
Contributor

Fixes #33 — all 17 verified defects from the systematic bug scan of post-#28 main.

Full methodology and per-finding evidence are on the issue; this PR implements the fixes plus 20 new regression tests.

Medium fixes

  1. startup_failure classified as failing (core/github_eval.py) — a workflow that fails to start (e.g. invalid YAML in a PR) now emits CHECKS_FAILED instead of presenting a real failure as "required checks pending" forever.
  2. workflow_call eligible (native/github_client.py) — reusable-workflow required checks can now complete a watch instead of staying PENDING on fully green CI.
  3. IncompleteRead → ProviderError (native/inference_api.py) — truncated model responses degrade per the documented contract instead of crashing watch add --intent.
  4. Token rotation no longer kills the runner (native/secrets_file.py, native/daemon.py) — a concurrent atomic rotation is distinguished from tampering by re-inspecting the directory entry (stable regular file already opened → read it; non-regular entry → OSError, unchanged). daemon.tick survives transient store-iteration failures (warn + retry next pass) instead of terminating.
  5. config list survives damaged state (cli.py) — invalid stored values render as key=<invalid: reason>, truncated JSON fails cleanly, and legacy plaintext secret keys stay masked (an existing safety test caught a masking regression here during development).
  6. config unset/keys guarded (core/config.py) — the JSON-object contract is enforced like get/set; corrupt files produce clean errors, not tracebacks.
  7. relevant_to symmetric tokenization (core/memory.py) — one shared tokenizer for query and content, so a recorded observation for owner/repo#12 is surfaced when watching the same PR.

Low fixes

Empty memory content rejected on all write paths; memory list reports hidden older items; EOF on the watch add confirmation declines cleanly; unusable secret stores report clean errors across config/watch; config and secret read-modify-write cycles serialize through sidecar flocks with atomic config writes; the cooperative-stop window starts after startup-lock acquisition; truncated HTTP bodies classify as retryable network errors; local secret-store failures classify as accurate blockers; permanent 301/308 redirects become PRNotFoundError blockers instead of endless retries; next_check_at defaults at creation so an ACTIVE task is never persisted unschedulable.

Verification

  • 535 tests pass (515 pre-existing + 20 new regression tests).
  • The stop-deadline regression test was verified to fail against the pre-fix code and pass after.
  • examples/first_pr_watch.py e2e demo: all 8 scenarios pass.

Review notes

Two deliberate contract changes beyond bug-for-bug parity:

  • Permanent redirects (301/308) now block the watch with "update the watch target" instead of retrying; temporary redirects (302/303/307) are unchanged.
  • secrets.json.lock / config.json.lock sidecar files appear in the data home (never unlinked, matching the runner-control convention); two directory-content assertions were updated accordingly.

Medium:
- Classify GitHub's startup_failure conclusion as failing so a workflow
  that fails to start alerts instead of pending forever (github_eval)
- Allow workflow_call events as eligible required PR checks so
  reusable-workflow CI can complete a watch (github_client)
- Map http.client.HTTPException to ProviderError so truncated model
  responses degrade instead of crashing watch add --intent (inference_api)
- Treat a concurrent atomic token rotation as safe (stable regular file
  already opened) and keep the daemon alive through transient
  store-iteration failures (secrets_file, daemon)
- Make config list survive invalid stored values and truncated JSON while
  keeping legacy plaintext secrets masked; guard config unset/keys against
  non-object config.json (cli, config)
- Tokenize query and content symmetrically in relevant_to so the recorded
  PR identity matches remembered context (memory)

Low:
- Reject empty memory content; report hidden older items in memory list
- Decline the watch-add confirmation on EOF stdin; report unusable secret
  stores cleanly across config and watch commands
- Serialize config/secret read-modify-write cycles with sidecar flocks and
  write config.json atomically
- Start the cooperative-stop window after startup-lock acquisition so
  queued time is not deducted from the stop budget (runner_control)
- Classify truncated bodies as retryable network errors, local
  secret-store failures as blockers, and permanent 301/308 redirects as
  PR-not-found blockers instead of endless retries (github_client)
- Default next_check_at at creation so an ACTIVE task is never persisted
  unschedulable (tasks)

535 tests pass (20 new regression tests); the first-use e2e demo passes
all 8 scenarios.
@hsliuustc0106
hsliuustc0106 merged commit 19d16be into main Oct 2, 2026
2 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.

Systematic bug scan: 7 medium / 10 low verified defects on post-#28 main

1 participant