Skip to content

feat(orb): export a signed, anonymized federated calibration bundle (opt-in) - #6505

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
reyanthony062001-ops:feat/6478-federated-bundle-export
Jul 16, 2026
Merged

feat(orb): export a signed, anonymized federated calibration bundle (opt-in)#6505
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
reyanthony062001-ops:feat/6478-federated-bundle-export

Conversation

@reyanthony062001-ops

@reyanthony062001-ops reyanthony062001-ops commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Closes #6478. Export side of federated fleet intelligence (#1970).

buildFederatedBundle (src/orb/federated-bundle.ts) packages this instance's own calibration signals into a signed, anonymized bundle an operator can choose to hand to a peer. Export only — transport is #6479, import/trust-gating is #6480.

Not a duplicate of the Orb export (#1255)

exportOrbBatch (src/selfhost/orb-collector.ts:155) also "exports calibration", so to be explicit — this is distinct on five axes, and none of them can be retrofitted onto that path:

Orb export (#1255) This (#1970)
Trigger always on once the App is configured — "there is no opt-out flag" (orb-collector.ts:6-7); only ORB_AIR_GAP suppresses it (:157) opt-in via .loopover.yml, default off
Destination central hosted collector (:168, https://api.loopover.ai/v1/orb/ingest) a peer / an operator's own collector — no central service assumed
Granularity watermark-paginated per-PR event stream one aggregate snapshot over a window
Privacy floor still carries HMAC'd repo_hash/pr_hash per event (:187-188) zero identifiers, not even hashed
Content raw per-PR verdict/outcome/reversal aggregate precision + bucketed slop/copycat rates

Enumerated bundle fields (auditable, per the issue's requirement)

Aggregate-only. No source, diffs, logins, repo names, PR ids, commit SHAs, raw gate reason text, or per-PR rows.

field type notes
schemaVersion int so #6480 can reject/upgrade rather than misread
instanceId string the existing opaque HMAC-derived handle (orb-collector.ts:59) — reused, not a second identity
generatedAt ISO string
windowDays number so peers only median equal-length windows
decided number resolved PRs in-window
mergePrecision / closePrecision number|null null below MIN_DECIDED
fpRate / fnRate number|null null below MIN_DECIDED
reversalRate number
cycleP50Ms / cycleP95Ms number|null
slopRate / copycatRate number bucketed rates only
signature hex string HMAC-SHA256 over the canonical body

The privacy floor is structural, not a filtering step: LOCAL_CALIBRATION_QUERY joins on project/target_id but never SELECTs them, so no identifier can reach a bundle even by mistake. A test asserts the exact key set, so a new field cannot land without review.

Choices worth flagging

Verification

  • typecheck (whole repo), docs:drift-check, engine-parity:drift-check, manifest:drift-check, command-reference:check, selfhost:env-reference:check, ui:openapi:check — all pass.
  • 795 tests pass across the touched suites (18 new in federated-bundle.test.ts, 8 new config cases in focus-manifest.test.ts).
  • Patch coverage measured, not assumed: src/orb/federated-bundle.ts 33/33 statements, 41/41 branches; every added line in analytics.ts, orb-collector.ts, and the engine focus-manifest.ts covered. Branches covered include opted-out, opted-in, the sub-MIN_DECIDED null arm, zero-decided, reverted vs reopened vs none, window default/clamp/reject, and the fail-safe error path.
  • Covered by tests: opted-out reads no DB (a proxy DB throws if touched) and makes no network call; the signature verifies against an independently recomputed HMAC; no identifier leaks; a DB failure returns null instead of throwing.

Rebased onto current main (2caac30). The earlier red shards were a transiently-red base, not this diff: backfill.test.ts, queue-5.test.ts and api.test.ts failed on untouched main at the previous base and all pass on 2caac30 both with and without this change (364/364).

@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 16, 2026
…opt-in)

Adds the export side of federated fleet intelligence (JSONbored#1970): buildFederatedBundle packages this instance's
own calibration signals into a signed, anonymized bundle an operator can hand to a peer.

Opt-in via a new .loopover.yml federatedIntelligence: block, cloning the draftFlow/upstreamDriftIssues
config-as-code pattern (JSONbored#6275). Absent or disabled => the builder returns null having read no database and
made no network call, so an instance that has not opted in is byte-identical to before.

The bundle carries aggregate figures only -- gate precision, fp/fn, reversal/slop/copycat rates and cycle
percentiles over a window. The privacy floor is structural rather than a filtering step: the aggregate query
never SELECTs project or target_id, so no identifier can reach a bundle even by mistake. Below MIN_DECIDED the
precision figures publish as null rather than as a number the fleet would refuse to count.

Reuses the existing pipeline rather than reimplementing it: foldInstance for the confusion matrix (so a
bundle's precision is defined identically to the peer median JSONbored#6481 compares it against), instanceId for the
opaque handle, bucketReasonCode, cycleTimeMs, and the createHmac signing idiom.

Export side only -- transport is JSONbored#6479, import/trust-gating is JSONbored#6480. The signing key is a documented
TODO(JSONbored#6477) placeholder rather than an invented peer-trust scheme.

Closes JSONbored#6478
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.57%. Comparing base (2caac30) to head (f8cadb3).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6505   +/-   ##
=======================================
  Coverage   95.56%   95.57%           
=======================================
  Files         589      590    +1     
  Lines       47121    47170   +49     
  Branches    14989    15007   +18     
=======================================
+ Hits        45032    45081   +49     
  Misses       1297     1297           
  Partials      792      792           
Flag Coverage Δ
shard-1 43.92% <6.00%> (-0.15%) ⬇️
shard-2 36.88% <6.00%> (+0.17%) ⬆️
shard-3 32.46% <10.00%> (+0.11%) ⬆️
shard-4 34.57% <6.00%> (-0.68%) ⬇️
shard-5 31.11% <84.00%> (+0.13%) ⬆️
shard-6 45.36% <22.00%> (-0.03%) ⬇️

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

Files with missing lines Coverage Δ
packages/loopover-engine/src/focus-manifest.ts 98.99% <100.00%> (+<0.01%) ⬆️
src/orb/analytics.ts 100.00% <100.00%> (ø)
src/orb/federated-bundle.ts 100.00% <100.00%> (ø)
src/selfhost/orb-collector.ts 100.00% <ø> (ø)
src/signals/focus-manifest-loader.ts 96.03% <ø> (ø)
src/signals/focus-manifest.ts 99.58% <ø> (ø)

@loopover-orb

loopover-orb Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-16 11:58:47 UTC

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

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This adds a scoped, opt-in export-only module (buildFederatedBundle) that packages this instance's own aggregate calibration signals into a signed, anonymized bundle, wired through the existing .loopover.yml focus-manifest config-as-code pattern (mirroring upstreamDriftIssues exactly: parse fn, EMPTY config, present-flag inclusion, index.ts re-exports, focus-manifest-loader.ts round-trip). The privacy floor is structural — the SQL query never selects project/target_id, so no identifier can reach a bundle even by mistake — and precision math is correctly reused from analytics.ts's foldInstance/percentile/MIN_DECIDED rather than reimplemented, keeping the comparison definition consistent with the fleet median it will be compared against. The signing key is explicitly a documented placeholder pending #6477's key-trust design, and the whole build is wrapped in try/catch so a failure here can never affect gate behavior — both are reasonable, called-out scope boundaries rather than hidden gaps.

Nits — 5 non-blocking
  • src/orb/federated-bundle.ts:165 — the TODO(Design: trust-gating/anti-poisoning scoring rules for federated signal-bundle import #6477) placeholder signing key (getOrCreateAnonSecret) is fine as a stopgap, but confirm Implement signature-bundle import + trust-gating validation for federated fleet intelligence #6480's import side will hard-fail rather than silently trust a bundle signed this way once Design: trust-gating/anti-poisoning scoring rules for federated signal-bundle import #6477 lands.
  • src/orb/federated-bundle.ts LOCAL_CALIBRATION_QUERY only filters the window on `po.outcome_at`, not `gd.decided_at`, so a PR decided long before the window but resolved inside it is counted — confirm this matches FLEET_QUERY's semantics intentionally rather than by omission.
  • src/orb/federated-bundle.ts:207/251/252/259 — several magic numbers (86_400_000, percentile args 50/95, the 200-char error truncation) could be named constants for readability, though none are load-bearing enough to require it.
  • Consider a short comment on the JOIN in LOCAL_CALIBRATION_QUERY clarifying that decided_at is deliberately unfiltered, to prevent a future contributor from 'fixing' it into an AND clause without checking FLEET_QUERY parity.
  • The 'carries only the enumerated fields' test in federated-bundle.test.ts is a good pattern (fails on any new field) — worth calling out in review as the right way to gate privacy-sensitive schemas.

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 #6478
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: 34 registered-repo PR(s), 21 merged, 1 issue(s).
Contributor context ✅ Confirmed Gittensor contributor reyanthony062001-ops; Gittensor profile; 34 PR(s), 1 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: significant
Review context
  • Author: reyanthony062001-ops
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Cuda, HTML, JavaScript, Python, TypeScript
  • Official Gittensor activity: 34 PR(s), 1 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 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.

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

@loopover-orb
loopover-orb Bot merged commit 53ce7b2 into JSONbored:main Jul 16, 2026
17 checks passed
This was referenced Jul 16, 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.

Implement signed, anonymized signature-bundle export for federated fleet intelligence

1 participant