Skip to content

feat(miner): wire claim-conflict resolution end-to-end - #5480

Merged
JSONbored merged 1 commit into
mainfrom
feat/claim-conflict-resolution-4848
Jul 12, 2026
Merged

feat(miner): wire claim-conflict resolution end-to-end#5480
JSONbored merged 1 commit into
mainfrom
feat/claim-conflict-resolution-4848

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #4848

Summary

  • claim-adjudication.js's adjudicateSoftClaim (wrapping the engine's isDuplicateClusterWinnerByClaim) was correct and well-tested in isolation but had no real caller assembling a competing-claims set from GitHub -- a genuine duplicate claim had no automated resolution path.
  • checkSubmissionFreshness already catches the common pre-submission case (aborts before open_pr if another author's PR already references the issue), but that's a point-in-time check -- it can't see a competing PR that doesn't exist yet. Two miners racing closely enough that both pass their own freshness check before either's PR exists is a genuine TOCTOU window freshness cannot close.
  • New claim-conflict-resolver.js is the post-submission reconciliation for exactly that window: once this miner's own PR is real and public, it fetches the live issue snapshot, assembles every OTHER open PR referencing the issue (excluding this miner's own), and adjudicates via the existing, unchanged claim-adjudication.js. When this miner's claim loses, it closes its own just-opened PR (never anyone else's) via a new close_pr local-write spec, citing the winner. Fails open (never closes anything) when the live snapshot can't be fetched.
  • Wired into attempt-cli.js, only on a real outcome === "submitted". Uses the miner's own real claim-ledger claimedAt for its side of the election; each competing PR's real GitHub createdAt stands in for the competing side (documented asymmetry -- the maintainer gate's own "first observed" election needs a continuous server-side observation history this stateless client-side tool doesn't have for a PR it doesn't own).
  • Extended fetchLiveIssueSnapshot's GraphQL query with each referencing PR's createdAt.
  • Added buildClosePrSpec to the engine's local-write-tools.ts, mirroring the existing buildOpenPrSpec pattern.
  • Extracted the shared PR-number-from-exec-result parser (previously private to loop-cli.js) into pr-number-parse.js so both call sites agree on one implementation.

Test plan

  • tsc --noEmit --incremental false clean (root + packages/gittensory-engine)
  • npm run build --workspace @jsonbored/gittensory-miner clean (new files added to the check-list)
  • npx vitest run test/unit test/contract -- all passing (one unrelated, pre-existing macOS-only symlink-resolution test failure in miner-coding-task-spec.test.ts, from an already-merged, unrelated PR -- not touched by this diff, and Linux CI runners don't hit it; will file/fix separately)
  • Acceptance criteria covered directly: resolveClaimConflict has dedicated tests for two simulated competing claims, both a win and a loss, verifying the losing claim's PR is really closed with a real close_pr write citing the winner
  • Per-file patch coverage verified line-by-line against the diff: 100% on every new/changed line across claim-conflict-resolver.js, pr-number-parse.js, local-write-tools.ts, live-issue-snapshot.js, and the new block in attempt-cli.js
  • npm run docs:drift-check / manifest:drift-check / engine-parity:drift-check all clean
  • npm audit --audit-level=moderate -- 0 vulnerabilities
  • git diff --check clean

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 12, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
gittensory-ui 007aae3 Commit Preview URL

Branch Preview URL
Jul 12 2026, 10:54 PM

@superagent-security

Copy link
Copy Markdown
Contributor

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

Closes #4848

claim-adjudication.js's isDuplicateClusterWinnerByClaim wrapper was correct and well-tested in isolation but had no caller that assembled a real competing-claims set from GitHub -- a genuine duplicate claim had no automated resolution path.

checkSubmissionFreshness already catches the common pre-submission case (aborting before open_pr if another author's PR already references the issue), but that check can only see what's public at the moment it runs. Two miners racing closely enough that both pass their own freshness check before either's PR exists yet is a genuine TOCTOU window freshness cannot close.

claim-conflict-resolver.js is the post-submission reconciliation for exactly that window: once this miner's PR is real and public, it fetches the live issue snapshot, assembles the real competing-claims set (every other OPEN PR referencing the issue, excluding this miner's own), and adjudicates via the existing claim-adjudication.js. When this miner's claim loses, it closes its own just-opened PR (never anyone else's) via a new close_pr local-write spec, citing the winner. Fails open (never closes anything) when the live snapshot can't be fetched.

Wired into attempt-cli.js right after a real "submitted" outcome, using the miner's own real claim-ledger claimedAt for its side of the election and each competing PR's real GitHub createdAt as the best publicly-observable proxy for a third-party PR (documented asymmetry -- the maintainer gate's own "first observed" semantics need a continuous server-side observation history this stateless client-side tool doesn't have).

Extracted the shared PR-number-from-exec-result parser (previously private to loop-cli.js) into pr-number-parse.js so both call sites agree on exactly one implementation.
@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.74%. Comparing base (849e11e) to head (007aae3).
⚠️ Report is 3 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5480   +/-   ##
=======================================
  Coverage   94.73%   94.74%           
=======================================
  Files         561      563    +2     
  Lines       44794    44823   +29     
  Branches    14667    14669    +2     
=======================================
+ Hits        42437    42467   +30     
+ Misses       1622     1621    -1     
  Partials      735      735           
Flag Coverage Δ
shard-1 44.34% <55.26%> (+0.05%) ⬆️
shard-2 35.32% <65.78%> (+0.03%) ⬆️
shard-3 32.01% <15.78%> (-0.01%) ⬇️
shard-4 31.23% <18.42%> (-0.16%) ⬇️
shard-5 33.29% <0.00%> (+0.06%) ⬆️
shard-6 43.62% <15.78%> (+0.03%) ⬆️

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

Files with missing lines Coverage Δ
...s/gittensory-engine/src/miner/local-write-tools.ts 100.00% <100.00%> (ø)
packages/gittensory-miner/lib/attempt-cli.js 96.81% <100.00%> (+0.10%) ⬆️
...es/gittensory-miner/lib/claim-conflict-resolver.js 100.00% <100.00%> (ø)
...ckages/gittensory-miner/lib/live-issue-snapshot.js 100.00% <100.00%> (ø)
packages/gittensory-miner/lib/loop-cli.js 93.65% <ø> (+0.26%) ⬆️
packages/gittensory-miner/lib/pr-number-parse.js 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

loopover-orb Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Warning

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏸️ Gittensory review result - manual review recommended

Review updated: 2026-07-12 23:00:40 UTC

19 files · 2 AI reviewers · no blockers · readiness 100/100 · CI green · clean

⏸️ Suggested Action - Manual Review

  • Touches a guarded path — held for manual review: This PR changes guardrail-protected path(s): packages/gittensory-engine/src/index.ts (matched packages/gittensory-engine/**), packages/gittensory-engine/src/miner/local-write-tools.ts (matched packages/gittensory-engine/**).

Review summary
This PR wires post-submission claim-conflict resolution end-to-end: a new claim-conflict-resolver.js assembles competing claims from the live issue snapshot and adjudicates via the existing, unchanged claim-adjudication.js, closing the miner's own PR via a new buildClosePrSpec when it loses. It's gated correctly (only on a real submitted outcome with a recoverable PR number), fails open on fetch failure, and never touches another PR by construction (filters by selfPrNumber/author). The pr-number-parse extraction and live-issue-snapshot createdAt addition are clean, mechanically-threaded changes with corresponding tests, and the PR closes its stated issue #4848.

Nits — 7 non-blocking
  • claim-conflict-resolver.js's competing-claim filter (packages/gittensory-miner/lib/claim-conflict-resolver.js) excludes any open PR by the same minerLogin, which means if the SAME miner process/account opens two competing PRs referencing the same issue (e.g. a retry after a crash), neither is treated as competing — worth confirming this is intentional rather than an edge case slipping through.
  • buildClosePrSpec's close+comment command (packages/gittensory-engine/src/miner/local-write-tools.ts) chains two `gh` calls with `&&` in a single shell string; if `gh pr comment` fails (e.g. transient network) the close never runs, silently leaving a losing PR open — consider making the close unconditional or documenting the tradeoff.
  • attempt-cli.js has grown to ~442 lines per the size-smell note; the new claim-conflict block is small but adds another sequential concern to an already-large function — consider whether the submitted-outcome branch (PR-number parse + conflict resolution + result merging) could be factored into a small helper for readability, though this is not required for this PR.
  • Consider a short doc/comment note on why same-author competing PRs are excluded from assembleCompetingClaims, since it's a non-obvious policy choice.
  • In buildClosePrSpec, consider running the comment as best-effort (e.g. `; ` instead of `&&`, or two separate write actions) so a failed comment never blocks the close.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.
  • Touches a guarded path — held for manual review — A maintainer must review and merge this change.
Signal Result Evidence
Code review ✅ No blockers 2 reviewers, synthesized
Linked issue ✅ Linked #4848
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: 44 registered-repo PR(s), 36 merged, 424 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 44 PR(s), 424 issue(s).
Gate result ⚠️ Not blocking Advisory; not blocking this PR.
Improvement ✅ Minor risk: clean · value: minor — Code changes are accompanied by test evidence. LLM value judgment: moderate — This closes a real end-to-end wiring gap for the narrow post-submission race that the existing freshness check cannot observe, while reusing the existing adjudicator and local-write boundaries.
Linked issue satisfaction

Addressed
The PR adds claim-conflict-resolver.js which assembles the real competing-claims set from a live GitHub issue snapshot and calls the existing adjudicator, wires it into attempt-cli.js on a real submitted outcome, and surfaces the decision (including closing the losing PR via a new close_pr spec) in the CLI's JSON result. Included unit tests simulate two competing claims and verify correct adjudica

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, JavaScript, MDX, Shell, Solidity
  • Official Gittensor activity: 44 PR(s), 424 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
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.
[BETA] Chat with Gittensory

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

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

Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands

🟩 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 Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 12, 2026
@JSONbored
JSONbored merged commit 7109bf2 into main Jul 12, 2026
19 checks passed
@JSONbored
JSONbored deleted the feat/claim-conflict-resolution-4848 branch July 12, 2026 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire claim-conflict resolution end-to-end

1 participant