import { type BacktestCommit, type BacktestReport, type CoverageRatioStats, type ModelRef } from "../../query/backtest.js"; /** Post-filter window size (Proposal issue #23 判据 A): how many `.ts`/`.tsx`-touching * commits to collect. Matches the issue's original repro script's N=50. */ export declare const DEFAULT_BACKTEST_WINDOW = 50; /** * Upper bound on RAW commits walked while collecting the window. Without a * cap, a repo whose recent history is mostly non-TS (docs/infra churn) could * make this walk arbitrarily far back looking for a window that never fills. * `formatBacktest`'s "scanCapped" line is how a reader is told the shortfall * is a cap artifact rather than "this repo really only has 12 TS commits ever". */ export declare const BACKTEST_SCAN_CAP = 500; interface RawLogCommit { sha: string; files: string[]; } /** * Parses `git log --format=%H --name-only` output into per-commit * file lists. Pure (string in, structure out) so the parsing itself is * unit-testable without a git subprocess. Each chunk after splitting on the * sentinel is `\n\n\n\n...` (git emits a blank separator * line between the hash and the file list, and again before the next * commit's sentinel) — blank lines are simply filtered out of the file list, * so that layout detail doesn't need to be asserted on. */ export declare function parseLogOutput(stdout: string): RawLogCommit[]; export interface CollectedCommits { /** qualifying commits only (>=1 `.ts`/`.tsx` file changed), most-recent-first, length <= windowRequested. */ commits: BacktestCommit[]; /** raw commits walked (>= commits.length) to collect them. */ commitsScanned: number; scanCapped: boolean; } /** * Walks `ref`'s history (`--no-merges`) collecting up to `windowRequested` * commits that changed >=1 `.ts`/`.tsx` file. This "changed a .ts/.tsx file" * test IS the doc/chore-commit filter — issue #23's repro script achieves * "skip non-code commits" exactly this way (grep -E "\.tsx?$" on the changed * file list), not via a second commit-message-based filter layered on top. * Stacking a message-based filter here would change the measured percentage * away from the already-verified 36%/18-of-50 baseline for no stated reason. * * A SINGLE `git log --name-only` call fetches everything, not one `git show` * per commit (which would be O(window) subprocesses on a 500-commit walk). * * Returns undefined when the ref/repo can't be resolved at all (bad ref / * not a git checkout), so the caller can report a clean skip rather than an * exception. */ export declare function collectBacktestCommits(gitRoot: string, ref: string, windowRequested: number, scanCap?: number): Promise; export interface BacktestOptions { /** git repo to scan. Defaults to `targetDir` (self-hosted: model dir IS the repo root). */ repoRoot?: string | undefined; /** git ref to walk history from. Defaults to "HEAD". */ ref?: string | undefined; /** post-filter window size. Defaults to DEFAULT_BACKTEST_WINDOW (50). */ window?: number | undefined; } export type BacktestResult = { ran: true; report: BacktestReport; coverageRatio: CoverageRatioStats; modelRef: ModelRef; } | { ran: false; skippedReason: string; coverageRatio?: CoverageRatioStats; modelRef?: ModelRef; }; /** * `loopgraph backtest`: 判据 A end to end — load the model, resolve the repo, * walk history for the window, and compute the hit rate. Advisory/read-only * (like `coverage`/`graph`/`overview`): never throws on a resolvable failure, * always returns a reportable `ran: false` instead. * * `coverageRatio` (判据 C) and `modelRef` are attached whenever the model * itself loaded — even on a `ran: false` result caused by a LATER failure * (bad ref, not a git checkout, broken components config). Both need only * the model (graph / working-tree git state), no commit-window scan at all, * so a git-log failure must not also hide them: a nightly consumer watching * all three would otherwise lose C and the model stamp on exactly the nights * A's git scan has trouble, which is backwards. They are absent only when * the model itself failed to load/parse (the two `return`s before * component/git resolution below). */ export declare function runBacktest(targetDir: string, options?: BacktestOptions): Promise; export {}; //# sourceMappingURL=backtest.d.ts.map