Skip to content

feat(miner): capture bounded candidate context in eligibility-exclusion fired events#8556

Closed
kai392 wants to merge 1 commit into
JSONbored:mainfrom
kai392:fix/critical-issue-bounded-candidate-context
Closed

feat(miner): capture bounded candidate context in eligibility-exclusion fired events#8556
kai392 wants to merge 1 commit into
JSONbored:mainfrom
kai392:fix/critical-issue-bounded-candidate-context

Conversation

@kai392

@kai392 kai392 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #8544

Root cause

recordEligibilityExclusionSignals (discover-cli.ts) recorded only ruleId/targetKey/outcome, so a fired event preserved that a candidate was excluded but nothing about what it looked like. The labels/assignees/owner fields are already present at runtime on the filter's excluded entries via EligibilityExclusion<T>'s generic passthrough — they were simply dropped.

Fix approach

Widened the parameter type so each entry's candidate carries the optional fields, and passed them straight through — no new computation at the call site, and contribution-profile-filter.ts is untouched as the issue requires.

buildCandidateContextMetadata applies the exact caps: 50 labels, 25 assignees, 200 characters per string. truncated: true is added only when a cap actually fires, and is omitted otherwise.

Two deliberate details:

  • Absent fields are omitted entirely — no nulls, no empty-array placeholders. So "we captured nothing here" stays distinguishable from "this candidate genuinely had no labels". An explicitly empty array is preserved as [], which is different information, and there's a test pinning that distinction.
  • A candidate with no context at all produces no metadata key, reproducing the pre-change event shape byte-for-byte rather than emitting an empty object.

Dry-run capture and the best-effort discipline (swallowed store-init and per-write failures) are unchanged — metadata construction is pure and adds no new failure path.

Coverage

Both arms of every cap, as specified: labels at 50 vs 51, assignees at 25 vs 26, string at 200 vs 201 chars, plus an over-long owner, presence/omission of each field, the empty-vs-absent distinction, and the no-context path.

Zero uncovered lines and zero uncovered branches across the diff. While verifying that I found one of my own dead branches — routing the single owner value through the list helper left an unreachable ?? "" fallback — so I clamped it directly instead of writing a test for an impossible path.

Two things worth the reviewer's attention

1. codecov/patch will likely report 0.00% here, and it is not a real coverage gap. CI's validate-tests job runs Build miner CLI before Test with coverage, so lib/*.js exists and every root test imports the .js specifier — v8 attributes coverage to the built .js while this diff is on the .ts. Measured locally against the .ts (with the compiled output removed, reproducing CI's .js.ts resolution), the patch is fully covered. This is the same attribution defect described by #8346/#8347/#8348. I applied the #8479 root-vitest mirror precedent the issue points to — these tests already live in root test/unit/ — but that remedy fixes engine modules, which build to a separate dist/; the miner compiles .ts.js in place, so source and artifact share a path and no contributor-side import can separate them.

2. Local suite note. test/unit/miner-discover-cli.test.ts has 2 failures on my Windows checkout (discover --help and the usage-error exit) — both subprocess-spawn CLI tests. The count is identical on unmodified ec6f6e6f, verified by stashing this change and re-running, so they aren't introduced here. My 9 added tests pass; the file goes 70 → 79 passing.

Validation

  • 9/9 new tests pass; full file 79 passed / 2 pre-existing failures
  • npm run typecheck clean; oxlint clean on all changed lines
  • git diff --check upstream/main HEAD clean; branch cut from current main (ec6f6e6f)

@kai392
kai392 requested a review from JSONbored as a code owner July 24, 2026 20:36
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 24, 2026
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.62%. Comparing base (59faa47) to head (46d3f97).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
packages/loopover-miner/lib/discover-cli.ts 0.00% 30 Missing ⚠️

❌ Your patch status has failed because the patch coverage (0.00%) is below the target coverage (99.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8556      +/-   ##
==========================================
- Coverage   92.50%   88.62%   -3.89%     
==========================================
  Files         794       98     -696     
  Lines       79557    22952   -56605     
  Branches    24037     3957   -20080     
==========================================
- Hits        73597    20341   -53256     
+ Misses       4800     2433    -2367     
+ Partials     1160      178     -982     
Flag Coverage Δ
backend 0.00% <0.00%> (-93.68%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-miner/lib/discover-cli.ts 0.00% <0.00%> (-99.54%) ⬇️

... and 696 files with indirect coverage changes

Eligibility-exclusion fired events recorded only ruleId/targetKey/outcome,
so a later backtest had no way to reconstruct why a candidate was excluded.

Adds bounded labels/assignees/owner metadata (50/25 entries, 200 chars each)
with a truncated flag when a cap fires. Absent fields are omitted entirely so
"not captured" stays distinguishable from "genuinely empty", and a candidate
with no context reproduces the pre-change event shape exactly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JSONbored
JSONbored force-pushed the fix/critical-issue-bounded-candidate-context branch from 7f96136 to 46d3f97 Compare July 24, 2026 20:40
@loopover-orb

loopover-orb Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Caution

🛑 LoopOver review result - fixes required

Review updated: 2026-07-24 20:46:52 UTC

2 files · 1 AI reviewer · no blockers · CI failing · unstable

🛑 Suggested Action - Fix Blockers

Review summary
This PR widens `recordEligibilityExclusionSignals`'s candidate type to carry through labels/assignees/owner and adds `buildCandidateContextMetadata`/`boundStringList` to cap and truncate that context (50 labels, 25 assignees, 200 chars/string) before writing it into fired-rule events. The implementation correctly distinguishes absent-vs-empty fields, omits `metadata` entirely when there's no context (preserving the pre-#8544 event shape), and only sets `truncated: true` when a cap actually fires — the owner field is clamped directly rather than routed through `boundStringList` to avoid an unreachable `?? ""` fallback, which is a legitimate dead-branch avoidance. Tests exercise both arms of every cap plus the empty-vs-absent and no-context-at-all distinctions, matching the stated coverage claims for this diff.

Nits — 5 non-blocking

CI checks failing

  • codecov/patch — 0.00% of diff hit (target 99.00%)

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8544
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 148 registered-repo PR(s), 75 merged, 10 issue(s).
Contributor context ✅ Confirmed Gittensor contributor kai392; Gittensor profile; 148 PR(s), 10 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The diff widens recordEligibilityExclusionSignals' parameter type to pass through labels/assignees/owner and adds buildCandidateContextMetadata that applies the exact caps (50 labels, 25 assignees, 200 chars) with truncated flags added only when clamping fires and omitted otherwise, matching the issue's requirements while leaving contribution-profile-filter.ts untouched and dry-run capture unchang

Review context
  • Author: kai392
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, Cuda, JavaScript, Kotlin, Perl, TypeScript, Vue
  • Official Gittensor activity: 148 PR(s), 10 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb

loopover-orb Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

LoopOver is closing this pull request on the maintainer's behalf (CI is failing (codecov/patch)). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed.

@loopover-orb loopover-orb Bot closed this Jul 24, 2026
@JSONbored

Copy link
Copy Markdown
Owner

Investigating what's happening with codecov/patch showing 0%/99% on the past few PR closures. No need to reopen, will re-review shortly.

@JSONbored

Copy link
Copy Markdown
Owner

Reopening: this PR was auto-closed on a phantom codecov/patch (0%/99%) failure — a CI bug (in-place package build output shadowing the .ts sources during the coverage run), not a problem with this PR. Fixed in #8564; updating the branch now to get a fresh run under the fixed workflow.

@JSONbored JSONbored reopened this Jul 24, 2026

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue was solved already, closing.

@JSONbored JSONbored closed this Jul 24, 2026
@loopover-orb loopover-orb Bot added gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. and removed gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. labels Jul 24, 2026
@JSONbored

Copy link
Copy Markdown
Owner

Closing note: the original auto-close was the CI bug fixed in #8564, not a fault in this PR — but while that was being resolved, a competing implementation of #8544 (#8561) was reviewed and merged, and the issue is now closed. Standard one-shot competition outcome; the branch conflict with main is that landed change. #8543, #8320, and the other open calibration issues are still up for grabs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

miner: capture bounded candidate context (labels/assignees/owner) in eligibility-exclusion fired-event metadata

3 participants