/** * Pure helpers for the contribution compliance post-check (FR-12) that the * worker runs before a guest PR opens. Each helper isolates one mechanically * verifiable rule so it can be unit-tested; `packages/ralph-worker/scripts/ * ralph-run.sh` mirrors this logic in `node` heredocs (the bash copies are not * exercised by this suite — keep the two in sync). * * Deterministic, no I/O. The caller collects the raw inputs (counts, the PR * body text, HTTP status codes, changed-file lists) and feeds them in, so these * stay pure and testable. A helper never decides pass/fail on its own — it * surfaces the evidence (reasons, offending paths, stale numbers) and the * caller maps that to pass / fail / N-A. */ /** * Counts captured before any change (the FR-11 baseline) or re-derived from the * final tree. A `null`/`undefined` field means "not measured" and is skipped by * {@link compareBaseline} — we only flag a regression we can actually prove. */ export interface ComplianceCounts { /** Passing-test count. A drop vs baseline is a regression. */ testCount?: number | null; /** Lint warning count. A rise vs baseline is a regression. */ lintWarnings?: number | null; /** Typecheck error count. A rise vs baseline is a regression. */ typecheckErrors?: number | null; /** Docs-build warning count. A rise vs baseline is a regression. */ docsWarnings?: number | null; } /** The outcome of comparing the final tree against the baseline. */ export interface BaselineComparison { /** True when at least one proven regression was found. */ regressed: boolean; /** Human-readable evidence lines, one per regressed metric. */ reasons: string[]; } /** * Compare the final-tree counts against the FR-11 baseline. Test count must not * drop; lint / typecheck / docs warning-or-error counts must not rise. A metric * that is unmeasured (null) on either side is skipped rather than guessed. */ export declare function compareBaseline(baseline: ComplianceCounts, current: ComplianceCounts): BaselineComparison; /** One numeric claim found in the PR body. */ export interface NumericClaim { /** The whole matched phrase, e.g. `142 tests`. */ text: string; /** The number claimed. */ value: number; /** Which fresh count this claim should match. */ kind: keyof ComplianceCounts; } /** Extract the numeric count claims a PR body makes about the verification run. */ export declare function extractNumericClaims(body: string): NumericClaim[]; /** The result of re-deriving a PR body's numeric claims against a fresh run. */ export interface ClaimRederivation { /** The body with every stale, re-derivable number replaced by the fresh one. */ body: string; /** Each `{from, to}` phrase that was rewritten. Empty when nothing was stale. */ replacements: Array<{ from: string; to: string; }>; } /** * Re-derive the numeric claims in `body` against the `fresh` counts from a run * at open time. A claim whose fresh count is known and differs is rewritten * in-place (FR-12 item 4: replace stale numbers rather than fail when the fresh * run is green). Claims whose metric was not measured are left untouched. */ export declare function rederiveClaims(body: string, fresh: ComplianceCounts): ClaimRederivation; /** A fenced code block the PR body presents as runnable. */ export interface RunnableBlock { /** The lowercased info-string language tag (e.g. `bash`). */ lang: string; /** The block's contents (without the fences). */ code: string; } /** Info-string tags we treat as runnable examples. */ export declare const RUNNABLE_LANGS: Set; /** * Extract the fenced code blocks a PR body presents as runnable: those tagged * with a {@link RUNNABLE_LANGS} language whose body does NOT carry a * `# not runnable` opt-out marker on its own line. Opted-out blocks are skipped * (treated N/A by the caller). */ export declare function extractRunnableBlocks(body: string): RunnableBlock[]; /** * Extract the external links a PR body (or a doc comment) cites: markdown * `[text](url)` targets, bare `http(s)://` URLs, and bare DOIs (`10.xxxx/...`, * normalised to a `https://doi.org/` URL). De-duplicated, order-preserving. */ export declare function extractLinks(text: string): string[]; /** * Classify an HTTP status for a cited link. A 2xx or 3xx (HEAD/GET) means the * link resolves; anything else — including a network failure the caller reports * as `null` — is unresolved and must be removed or flagged for the human gate. */ export declare function classifyLinkStatus(status: number | null): 'resolved' | 'unresolved'; /** * Return the body lines that carry a self-serving product/marketing phrase and * are NOT one of the `allowedLines` (the disclosure line and the guidelines * link). An empty result means the body is clean. */ export declare function findSelfServingLines(body: string, allowedLines: string[]): string[]; /** * Mechanical proxy for "every non-obvious improvement is explained in the PR * body": pass (empty result) when every commit subject already appears in the * body, otherwise return the changed files neither their path nor basename is * mentioned in the body. The caller lists any remainder as N-A for the human * gate. */ export declare function unmentionedChangedFiles(body: string, changedFiles: string[], commitSubjects?: string[]): string[]; /** * Return the changed paths that fall outside the plan's declared scope. A path * is in scope when it equals, or is nested under, one of `allowedPaths` (the * plan's "Files" list). When the caller cannot extract a Files list * (`allowedPaths` empty) this returns `[]` and the caller reports the item N-A * for the human gate rather than failing blindly. */ export declare function outOfScopePaths(changedPaths: string[], allowedPaths: string[]): string[]; //# sourceMappingURL=compliance-post-check.d.ts.map