Skip to content

feat(miner-discovery-plane): define the public-data-only discovery-index API contract - #4436

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
jeffrey701:feat/discovery-index-contract
Jul 9, 2026
Merged

feat(miner-discovery-plane): define the public-data-only discovery-index API contract#4436
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
jeffrey701:feat/discovery-index-contract

Conversation

@jeffrey701

Copy link
Copy Markdown
Contributor

Closes #4300

What

Defines the client-side discovery-index API contract — the typed request/response shape a miner uses to query the optional hosted discovery-index service. The server-side counterpart (#4250, maintainer-only) is explicitly blocked on this contract being defined first; this issue is that contract, scoped to schema/shape only — no server, no deployed endpoint, no client HTTP (those are #4250 and the sibling soft-claim-coordination issue).

The plane exists to mitigate the rate-limit incident already fixed once for the review stack (#1936): one shared GitHub-metadata crawler across the fleet instead of every miner instance independently hammering the same repos' search/listing endpoints.

Design

Lives in @jsonbored/gittensory-engine (shared by both sides) and follows the tolerant-parser convention already established by miner-goal-spec.ts / fleet-run-manifest.ts — every field optional, malformed input degrades to a documented default with a warning rather than throwing.

  • Request (DiscoveryIndexQuery) — repos (owner/repo), orgs (owner), searchTerms, a limit floored+clamped to [1,200], and an opaque forward cursor. Invalid entries skipped, deduped, capped at 200; normalizeDiscoveryIndexRequest never throws.
  • Response (DiscoveryIndexResponse) — a candidates list plus a forward nextCursor. Each DiscoveryIndexCandidate is field-for-field compatible with opportunity-ranker.js's normalizeCandidate (owner, repo, repoFullName, issueNumber, title, labels, commentsCount, createdAt, updatedAt, htmlUrl, aiPolicyAllowed, aiPolicySource), so rankCandidateIssues consumes hosted results exactly like a local fan-out — a miner can swap a local fan-out for a hosted query without the ranker changing.

Boundary enforced in code

The Phase 1 boundary (cross-repo-discovery-phase1.md:13-14,54 — metadata-only, GET/list-only, no raw scores/rewards/wallet/hotkey/source data) is enforced, not just documented:

  • discoveryIndexBoundaryViolations(raw) returns any forbidden field present on a raw object (DISCOVERY_INDEX_FORBIDDEN_FIELDS: score, reward, wallet, hotkey, coldkey, mnemonic, payout, ranking, rawtrust, trustscore, sourcecontent, diff, patch).
  • normalizeDiscoveryIndexCandidate rejects (returns null) — rather than silently trimming — any candidate carrying one, so a misbehaving server can't smuggle economic/identity/source data past the contract.

Files

  • packages/gittensory-engine/src/discovery-index-contract.ts — the contract + normalizers.
  • packages/gittensory-engine/src/index.ts — barrel re-export.
  • packages/gittensory-miner/docs/discovery-index-contract.md — field reference (mirrors miner-goal-spec.md).
  • test/unit/discovery-index-contract.test.ts — tests.

Testing

npx vitest run test/unit/discovery-index-contract.test.ts
npm run typecheck

16/16 tests pass; typecheck clean. New engine file at 100% line + branch coverage (75/75, 108/108, 13/13).

…dex API contract

The optional hosted discovery-index plane (JSONbored#4250, maintainer-only, explicitly
blocked on this contract) exists to mitigate the rate-limit incident already
fixed once for the review stack (JSONbored#1936): one shared GitHub-metadata crawler
across the miner fleet instead of every miner independently hammering the same
repos' search/listing endpoints. This defines the client-side request/response
contract both sides build against — schema/shape only, no server, no deployed
endpoint, no client HTTP (those are JSONbored#4250 and the sibling soft-claim issue).

- packages/gittensory-engine/src/discovery-index-contract.ts:
  * DiscoveryIndexQuery / DiscoveryIndexRequest — scope (repos/orgs/searchTerms)
    plus clamped limit + opaque cursor, via a tolerant normalizer.
  * DiscoveryIndexCandidate — metadata-only, field-for-field compatible with
    opportunity-ranker.js's normalizeCandidate, so rankCandidateIssues consumes
    hosted results exactly like a local fan-out.
  * DiscoveryIndexResponse — candidate list + forward nextCursor + version.
  * The Phase 1 boundary is enforced in code, not just documented:
    discoveryIndexBoundaryViolations lists any forbidden field, and
    normalizeDiscoveryIndexCandidate rejects (returns null) — rather than
    silently trimming — any candidate carrying score/reward/wallet/hotkey/
    source-content fields, so a misbehaving server can't smuggle raw
    economic/identity/source data past the contract.
- packages/gittensory-engine/src/index.ts: barrel re-export of the contract.
- packages/gittensory-miner/docs/discovery-index-contract.md: field reference,
  mirroring the miner-goal-spec.md style, for this repo's future JSONbored#4250 server
  and any third-party consumer.
- test/unit/discovery-index-contract.test.ts: full coverage of the normalizers
  and the boundary enforcement.

Closes JSONbored#4300
@jeffrey701
jeffrey701 requested a review from JSONbored as a code owner July 9, 2026 18:22
@superagent-security

Copy link
Copy Markdown
Contributor

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

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.96%. Comparing base (fb7b5c7) to head (92eac0d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4436      +/-   ##
==========================================
+ Coverage   93.95%   93.96%   +0.01%     
==========================================
  Files         412      413       +1     
  Lines       37212    37292      +80     
  Branches    13591    13624      +33     
==========================================
+ Hits        34963    35043      +80     
  Misses       1594     1594              
  Partials      655      655              
Files with missing lines Coverage Δ
.../gittensory-engine/src/discovery-index-contract.ts 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 9, 2026
@loopover-orb

loopover-orb Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ Gittensory review result - approve/merge recommended

Review updated: 2026-07-09 18:39:00 UTC

4 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
The AI review returned non-blocking notes for this change but did not include a separate narrative summary. Review the nits below before deciding this PR.

Nits — 5 non-blocking
  • `discoveryIndexBoundaryViolations` (discovery-index-contract.ts:97-105) matches forbidden fragments as a raw substring of the lower-cased key, so a legitimate future field like `resourceContent` or `outsourceContent` would false-positive against the `sourcecontent` fragment — consider word-boundary or exact-suffix matching if the candidate shape ever grows.
  • `commentsCount` (discovery-index-contract.ts:200) accepts any finite number including negatives; a `>= 0` guard would match the implicit non-negative invariant on a GitHub comment count.
  • The PR claims field-for-field compatibility with `opportunity-ranker.js`'s `normalizeCandidate`, but that file isn't in the diff/context, so the compatibility claim isn't independently verifiable here — worth a cross-reference test or comment pointing at the exact fields being mirrored.
  • Add a test asserting `discoveryIndexBoundaryViolations` doesn't false-positive on a plausible legitimate field name that happens to contain a forbidden fragment as a substring, to lock in intended matching behavior either way.
  • Consider clamping `commentsCount` to `>= 0` in `normalizeDiscoveryIndexCandidate` (discovery-index-contract.ts:200) for consistency with the rest of the tolerant-normalization style.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #4300
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: 97 registered-repo PR(s), 40 merged, 4 issue(s).
Contributor context ✅ Confirmed Gittensor contributor jeffrey701; Gittensor profile; 97 PR(s), 4 issue(s).
Gate result ✅ Passing No configured blocker found.
Review context
  • Author: jeffrey701
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 97 PR(s), 4 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.

🟩 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 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Gittensory approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit e021f2a into JSONbored:main Jul 9, 2026
10 checks passed
@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 9, 2026
@JSONbored JSONbored added gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. and removed gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. labels Jul 9, 2026
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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(miner-discovery-plane): define the public-data-only discovery-index API contract

2 participants