/**
 * Compose the shipped slice-2/3/4 stages into the certifying corpus (5c-ii).
 *
 * Runs Extract → Classify → Compile over the train slice via the injected ports
 * (REPLAY for the certifying run — zero LLM, zero network; RECORD wraps the live
 * adapters), then assembles the `CertifyingCorpus`:
 *  - **rules + provenanceByRule** from the compiled candidates;
 *  - **binding-2 (carried)**: archived (Stage-4 out-of-scope) rules are EXCLUDED
 *    from the scored set (archived ≠ wind-tunnel FP — `buildFirings`/fold-F would
 *    throw if one leaked); their provenance is dropped with them.
 *  - **fold-I (FM-h)**: the API-usage ledger's held-out-fetch-count MUST be 0 —
 *    a non-zero count means mining touched the held-out slice, which voids the
 *    run, so we fail loud here.
 *  - **prDiffs + groundTruth** are passed through from the (fixture or resolved)
 *    inputs; firing/scoring is the deterministic 5c-i engine's job downstream.
 *
 * Returns the corpus + the fold-I ledgers (emitted for §7 observability). Pure of
 * its own IO — all IO is behind the injected ports/deps, so it is fully testable
 * with fakes (no LLM, no network, no real git).
 */
export async function buildCertifyingCorpus(deps) {
    const { runExtractStage, runClassifyStage, runCompileStage, assembleMinerLedgers, TotemError } = await import('@mmnto/totem');
    // Stage 1 — Extract (REPLAY or LIVE via the injected ports).
    const extract = await runExtractStage(deps.split, {
        source: deps.source,
        extractor: deps.extractor,
        seedClassesProvided: deps.seedClassesProvided,
    });
    // fold-I (FM-h): the held-out slice must NEVER be fetched during mining.
    if (extract.apiUsageLedger.heldOutFetchCount !== 0) {
        throw new TotemError('CONFIG_INVALID', `Held-out fetch count is ${extract.apiUsageLedger.heldOutFetchCount}, must be 0 ` +
            `(fold-I / FM-h): mining touched the held-out slice, which voids the certifying run.`, 'The extract stage fetched a held-out PR. Verify the split + fetch loop honor the train-only boundary.');
    }
    // Stage 2 — Classify; Stage 3/4 — Compile + Stage-4 verify.
    const classify = await runClassifyStage(extract, deps.splitLedger, {
        classifier: deps.classifier,
    });
    const compileResult = await runCompileStage(classify, { stage4: deps.stage4, now: deps.now });
    // binding-2 (carried): exclude Stage-4 out-of-scope (archived) rules from the
    // scored set — archived ≠ wind-tunnel FP; fold-F throws if one reaches firing.
    const scored = compileResult.compiled.filter((c) => c.rule.status !== 'archived');
    const rules = scored.map((c) => c.rule);
    const provenanceByRule = new Map(scored.map((c) => [c.rule.lessonHash, c.provenance]));
    // fold-I ledgers — emitted + CI-observable (§7), never asserted-on beyond FM-h.
    const ledgers = assembleMinerLedgers(deps.splitLedger, extract, classify);
    return {
        corpus: { rules, prDiffs: deps.prDiffs, groundTruth: deps.groundTruth, provenanceByRule },
        ledgers,
    };
}
//# sourceMappingURL=spine-cert-corpus.js.map