You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AMS's calibration capture is one-sided: the four eligibility-exclusion reasons are recorded as rule-fired signals on discovery (recordEligibilityExclusionSignals, packages/loopover-miner/lib/discover-cli.ts), but the feasibility verdict — the other deterministic gate an attempt passes through — records nothing. In packages/loopover-miner/lib/attempt-cli.ts, when buildCodingTaskSpec returns ready: false (the branch that appends an attempt_aborted attempt-log event and an attempt_blocked ledger event with reason `infeasible_${verdict}`), the verdict's reasons (codingTaskSpec.feasibility.avoidReasons / raiseReasons — values like claim_status_solved, issue_quality_do_not_use, duplicate_cluster_high, target_not_found, claim_status_claimed) are printed and dropped. Epic #8107 needs these captured so feasibility rules can be precision-scored the same way eligibility exclusions already can be.
Requirements
⚠️The capture must go through createSignalTrackingStore (packages/loopover-miner/lib/signal-tracking-store.ts) so events land in the canonical signal_rule_fired shape. This issue is NOT satisfied by: writing custom event types directly via eventLedger.appendEvent, adding capture inside coding-task-spec.ts or packages/loopover-engine/src/feasibility.ts (both are pure modules and must stay side-effect free), or capturing anything on the ready: true path.
In attempt-cli.ts, inside the existing if (!codingTaskSpec.ready) branch only: record one RuleFiredEvent per entry of codingTaskSpec.feasibility.avoidReasons and per entry of raiseReasons, with exactly: ruleId = the reason string verbatim; outcome = "avoid" for avoid-reason entries and "raise" for raise-reason entries; targetKey = `${parsed.repoFullName}#issue-${parsed.issueNumber}` (byte-identical to recordEligibilityExclusionSignals' format); occurredAt = ISO timestamp; no metadata (raw-context capture is a separate issue — do not add it here).
Store acquisition mirrors discover-cli.ts exactly: an optional initSignalTrackingStore?: () => SignalStore seam on the attempt CLI's options (same name as discover's seam), defaulting to createSignalTrackingStore({ appendEvent, readEvents }) over the shared local event ledger.
Best-effort discipline, mirrored verbatim from recordEligibilityExclusionSignals: store-init failure and each individual write failure are swallowed (try/catch around init, .catch(() => undefined) per write) and must not change the CLI's console output, JSON result shape, or exit code (the branch still returns 4).
Every ready: false occurrence records — no dedup across repeated attempts at the same issue; each attempt is a distinct decision instance.
ready: false with both avoid and raise reasons present → exact ruleId/outcome/targetKey asserted per event, counts match the reason arrays.
ready: true → zero fired events recorded.
initSignalTrackingStore throwing, and a store whose recordRuleFired rejects → exit code, console output, and JSON result identical to a run without the seam.
100% of changed lines and branches covered — both arms of every conditional introduced.
Deliverables
Capture wired in attempt-cli.ts's infeasible branch per the exact event shape above
initSignalTrackingStore seam with the discover-identical default
Tests covering the four cases above, Codecov-visible
Problem
AMS's calibration capture is one-sided: the four eligibility-exclusion reasons are recorded as rule-fired signals on discovery (
recordEligibilityExclusionSignals,packages/loopover-miner/lib/discover-cli.ts), but the feasibility verdict — the other deterministic gate an attempt passes through — records nothing. Inpackages/loopover-miner/lib/attempt-cli.ts, whenbuildCodingTaskSpecreturnsready: false(the branch that appends anattempt_abortedattempt-log event and anattempt_blockedledger event with reason`infeasible_${verdict}`), the verdict's reasons (codingTaskSpec.feasibility.avoidReasons/raiseReasons— values likeclaim_status_solved,issue_quality_do_not_use,duplicate_cluster_high,target_not_found,claim_status_claimed) are printed and dropped. Epic #8107 needs these captured so feasibility rules can be precision-scored the same way eligibility exclusions already can be.Requirements
attempt-cli.ts, inside the existingif (!codingTaskSpec.ready)branch only: record oneRuleFiredEventper entry ofcodingTaskSpec.feasibility.avoidReasonsand per entry ofraiseReasons, with exactly:ruleId= the reason string verbatim;outcome="avoid"for avoid-reason entries and"raise"for raise-reason entries;targetKey=`${parsed.repoFullName}#issue-${parsed.issueNumber}`(byte-identical torecordEligibilityExclusionSignals' format);occurredAt= ISO timestamp; nometadata(raw-context capture is a separate issue — do not add it here).discover-cli.tsexactly: an optionalinitSignalTrackingStore?: () => SignalStoreseam on the attempt CLI's options (same name as discover's seam), defaulting tocreateSignalTrackingStore({ appendEvent, readEvents })over the shared local event ledger.recordEligibilityExclusionSignals: store-init failure and each individual write failure are swallowed (try/catcharound init,.catch(() => undefined)per write) and must not change the CLI's console output, JSON result shape, or exit code (the branch still returns 4).ready: falseoccurrence records — no dedup across repeated attempts at the same issue; each attempt is a distinct decision instance.ready: falsewith both avoid and raise reasons present → exactruleId/outcome/targetKeyasserted per event, counts match the reason arrays.ready: true→ zero fired events recorded.initSignalTrackingStorethrowing, and a store whoserecordRuleFiredrejects → exit code, console output, and JSON result identical to a run without the seam.Deliverables
attempt-cli.ts's infeasible branch per the exact event shape aboveinitSignalTrackingStoreseam with the discover-identical defaultLinks & Resources
packages/loopover-miner/lib/discover-cli.ts(recordEligibilityExclusionSignals— the pattern to mirror),packages/loopover-miner/lib/attempt-cli.ts(the!codingTaskSpec.readybranch),packages/loopover-engine/src/calibration/signal-tracking.ts(RuleFiredEvent)Boundaries
attempt-cli.ts+ tests only. No pure-module changes, no override capture, no metadata, no output-format changes.