Skip to content

fix(notifications): wire the maintainer-recap's calibration/gate-outcomes/per-repo section builders into the actual digest output #8372

Description

@JSONbored

Context

The maintainer recap digest (RecapReport, #1963) has four dedicated "content slice" section builders,
each shipped in its own file with a doc comment explicitly describing itself as a slice of the composed
digest:

All three fields these first three sections need (totals.merged/closed/reversals/blocked/ gateFalsePositives/gateOverrides, and repos) are already present on every RecapReport produced by
buildMaintainerRecap in src/services/maintainer-recap.ts — no new data sourcing is required to wire
them in.

Despite this, formatMaintainerRecap (src/services/maintainer-recap.ts, the function that actually
renders a RecapReport into the digest body posted to Discord/Slack) never calls any of them:

  • buildCalibrationRecapSection and buildGateOutcomesRecapSection are never called anywhere in src/**
    outside their own unit tests (test/unit/maintainer-recap-calibration.test.ts,
    test/unit/maintainer-recap-gate-outcomes.test.ts) — confirmed by repo-wide grep. Fully implemented,
    fully tested, never composed into the real output.
  • buildPerRepoRecapSection is also never called in production; formatMaintainerRecap instead inlines
    its own simpler, duplicate per-repo line format (the perRepoLines map at
    src/services/maintainer-recap.ts around line 168) that has no cap, no "(+N more)" remainder handling,
    and no sort — a second, drifted implementation of the same section sitting next to the unused dedicated
    one.
  • buildDriftRecapSection's output IS renderable — formatMaintainerRecap accepts an optional
    options.configDrift: DriftRecapSection parameter and appends it when present (added for calibration: config-drift section in the maintainer recap #8214) — but
    runMaintainerRecap (the only production caller of formatMaintainerRecap, same file, around line 241)
    calls formatMaintainerRecap(report) with no options argument at all. The config-drift section is
    therefore never rendered in a real, delivered digest either; it is only exercised via
    test/unit/maintainer-recap-format.test.ts calling formatMaintainerRecap directly with a hand-built
    configDrift value.

This repo already has a recorded instance of exactly this bug shape (closed issue #6636:
"resolveDispositionReason is fully implemented and tested but never called from production code") — this
issue is the same pattern recurring across four sibling section builders in one feature area.

Net effect: a maintainer running the live recap digest today only ever sees the ad-hoc "Summary / Totals /
(duplicate, uncapped) Per-repo" text formatMaintainerRecap hand-rolls — never the calibration section, the
gate-outcomes section, the properly-capped per-repo section, or the config-drift section, even though all
four were separately scoped, built, and merged specifically to be part of this digest.

Requirements

  1. In formatMaintainerRecap (src/services/maintainer-recap.ts), replace the inline perRepoLines
    block with a call to buildPerRepoRecapSection({ windowDays: report.windowDays, repos: report.repos })
    (imported from ./maintainer-recap-per-repo), rendering its .lines the same way the existing
    ## Per-repo section already renders (through recapSectionLines/redactRecapLine). Preserve the ## Per-repo header.
  2. Add a ## Calibration section to formatMaintainerRecap's output, built by calling
    buildCalibrationRecapSection({ windowDays: report.windowDays, totals: report.totals }) (imported from
    ./maintainer-recap-calibration) and rendering its .lines through the same recapSectionLines/
    redactRecapLine path as every other section. This section is unconditional (not behind an optional
    options flag) since its inputs are always present on any RecapReport.
  3. Add a ## Gate outcomes section the same way, via buildGateOutcomesRecapSection({ windowDays: report.windowDays, totals: report.totals }) (imported from ./maintainer-recap-gate-outcomes).
    Unconditional, same reasoning as point 2.
  4. In runMaintainerRecap, pass a configDrift option through to formatMaintainerRecap whenever the
    caller supplied one. Add an optional configDrift?: DriftRecapSection field to
    runMaintainerRecap's own options parameter and forward it as
    formatMaintainerRecap(report, { configDrift: options.configDrift }). Do NOT attempt to source live
    drift data inside runMaintainerRecap itself (that requires querying the knob-loosening sentinel state
    in src/services/loosening-knobs.ts, which is a separate, larger concern with its own data-sourcing
    design) — this issue only needs the plumbing to exist so a caller that already has a DriftRecapSection
    (or a future caller that builds one) can pass it through and have it actually render. Leave a code
    comment noting that src/review/maintainer-recap-wire.ts (the real cron caller) does not yet supply one.
  5. Keep the section ORDER as: Summary, Totals, Per-repo, Calibration, Gate outcomes, Config drift
    (optional, last) — Totals stays as-is (it is not one of the four dormant section builders and is
    already correct).
  6. Do not change buildMaintainerRecap's RecapReport shape, and do not touch
    buildTopContributorsRecapSection (src/services/maintainer-recap-top-contributors.ts) — that section
    needs a contributors: TopContributor[] list that is NOT present on RecapReport today, so wiring it in
    requires a separate data-sourcing decision outside this issue's scope.

Deliverables

  • formatMaintainerRecap renders ## Per-repo via buildPerRepoRecapSection instead of its own inline
    duplicate.
  • formatMaintainerRecap renders a new, unconditional ## Calibration section via
    buildCalibrationRecapSection.
  • formatMaintainerRecap renders a new, unconditional ## Gate outcomes section via
    buildGateOutcomesRecapSection.
  • runMaintainerRecap accepts and forwards an optional configDrift option to formatMaintainerRecap.

Test Coverage Requirements

99%+ Codecov patch coverage, branch-counted, on every changed line in src/**. At minimum:

  • formatMaintainerRecap: a report with populated repos/totals renders all three new/replaced sections
    with the same content the standalone section-builder unit tests already assert (cross-check against
    test/unit/maintainer-recap-calibration.test.ts / -gate-outcomes.test.ts / -per-repo.test.ts fixtures
    so the wired output matches the already-tested builder output exactly).
  • An empty RecapReport (zero repos, zero totals) still renders all sections with their documented
    zero/empty-case text (each builder already has its own zero-case branch — assert the composed output
    reaches it).
  • runMaintainerRecap forwards a supplied configDrift through to the rendered output, and omits the
    ## Config drift section entirely when none is supplied (existing behavior, must not regress).
  • Update test/unit/maintainer-recap.test.ts and test/unit/maintainer-recap-format.test.ts for the new
    section content; do not delete existing assertions about Summary/Totals.

Expected Outcome

The live maintainer recap digest delivered to Discord/Slack actually contains the calibration,
gate-outcomes, and properly-capped per-repo sections that were separately scoped and shipped for exactly
this purpose (#2241, #2242, #2243), instead of silently omitting them in favor of ad-hoc inline text — and
a caller that supplies config-drift data can have it rendered without needing to bypass
runMaintainerRecap.

Links & Resources

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions