Improve tracker fidelity (B11, B12, B17, F2) - #368
Merged
Conversation
…ip, Jira pagination, config-aware retry, 4xx fast-fail
Fixes a group of tracker-fidelity audit findings:
- B11: Jira blocker "done" detection now uses the statusCategory key
("done") instead of comparing the human-readable status name against a
hardcoded Done/Closed/Resolved list, so dependents aren't starved when
the blocker's done status has a custom name. Mirrors LinearTracker's
canonical state-type check.
- B17: findIssueByIdentifier reverse-maps the raw Jira status name back to
the internal critter status via statusMap, so the webhook trigger compare
(issueMatchesTrigger -> statusName === trigger.status) agrees with the
poll path, which queries by the forward-mapped name.
- F2: Jira findIssues now paginates through nextPageToken until isLast
(capped at MAX_PAGINATED_ISSUES, mirroring Linear), adds a stable
ORDER BY created ASC, and logs when the cap is hit.
- B12: single-issue runRetry is now config-aware — it identifies the
matching critter type by trigger label and uses that type's provider,
trigger.status, and outcomes.failure?.status instead of hardcoding "Todo"
and the default-provider tracker, mirroring runRetryAllFailed.
- 4xx fast-fail: findIssues (Jira + Linear) passes a shouldRetry predicate
(isTransientTaskError) so non-retryable 4xx errors fail fast instead of
burning the full retry budget.
Adds src/__tests__/audit-trackers.test.ts covering statusCategory-based
blocker detection, the statusMap webhook round-trip, Jira pagination/ORDER
BY, 4xx fast-fail, and config-aware retry target selection.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
resolvePhaseMcpConfig expands ~ via node:os homedir(); the test compared it to process.env.HOME. Bun caches homedir() on first call and ignores later process.env.HOME mutations, so when a sibling test changes HOME they diverge on Linux CI and this test fails (works on macOS by execution-order luck). Assert against the same homedir() the implementation uses. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The 4xx fast-fail change used isTransientTaskError (a whitelist written
for git/subprocess errors) as the shouldRetry predicate, which silently
dropped retries for real transient failures: Bun/undici network errors
("Unable to connect...", "fetch failed") and Linear SDK 5xx messages
("Graphql error (code: 502)") match nothing in that regex, so three
transient blips could open the circuit breaker and pause a provider.
Invert to a blacklist: fail fast only on definitive 4xx, retry
everything else. Adds regression tests asserting network-style and
5xx messages are retried and 400/401/403/404/422 fail fast.
Co-Authored-By: Claude Fable 5 <[email protected]>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Jira-specific divergences from the Linear-shaped assumptions in the tracker layer.
statusCategory.key === "done"findIssueByIdentifierreturned the raw Jira name with no reversestatusMap, so webhook trigger compares never matchedfindIssuesprocessed only the first ~50 issues, non-deterministicallynextPageTokento a cap with stable ordering (mirrors Linear'sfetchAllNodes)retryhardcoded "Todo"/Linear names and the default providertrigger.status/outcomes.failurefindIssuesretried non-retryable 4xxshouldRetryfast-fails auth/validation errorsTests
audit-trackers.test.ts(12) — statusCategory blockers, statusMap round-trip, config-aware retry target.Verification
typecheck clean · lint exit 0 ·
bun test854 pass / 0 fail.🤖 Generated with Claude Code