@yagni-app/code-staging 1.2.10-staging.2105.1 → 1.2.10-staging.2111.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,8 +36,9 @@
36
36
  * failures (connection refused, missing env, DB/auth, command not found) and
37
37
  * anything UNCERTAIN fail OPEN with an honest note, never a never-clearable
38
38
  * critical. A cloud session's gate (`unreadTestFailureIsFinding`) makes an
39
- * UNCERTAIN failure a finding carrying the output tail, unless the clean tree
40
- * failed the same command. On a build that named the repository's toolchain
39
+ * UNCERTAIN failure a finding carrying the output tail: it names nothing the
40
+ * unchanged code could already have, so it is never excused. On a build that
41
+ * named the repository's toolchain
41
42
  * (`YAGNI_TOOLCHAIN_FILE`, a sandbox) both halves run on it, as the model's
42
43
  * shell and the approved checks do ({@link buildGateVerifyEnv},
43
44
  * {@link buildGateTestEnv}).
@@ -52,6 +53,7 @@
52
53
  * findings, handoffs, or run records (§0.9).
53
54
  */
54
55
  import { type ToolchainFile } from "../toolchain/spawnHook.js";
56
+ import { canonicalCheckCommand, type BaseMeasurement, type FailureAttribution } from "./checkAttribution.js";
55
57
  import { type FailedCheckResult, type MissionChecksFile } from "./missionChecks.js";
56
58
  import type { Finding } from "./types.js";
57
59
  /**
@@ -112,17 +114,13 @@ export interface VerifyOutcome {
112
114
  /** An approved check's name on the report: its command, cut at 80 characters. */
113
115
  export declare function checkLabel(command: string): string;
114
116
  /**
115
- * A command as the gate compares two: the same words, whatever spaces sit
116
- * between them, and a package manager's script named the one way it runs,
117
- * so `yarn test` and `yarn run test`, `npm test` and `npm run test`, `pnpm
118
- * lint` and `pnpm run lint` are one check, run once (staging bench
119
- * 2026-10-25: the gate's own `test` script and two approved twins ran one
120
- * suite three times). Only the leading form: a manager's flags before the
121
- * script leave the command as it is. The same rule as
122
- * `canonicalCheckCommand` in the backend's attempts/inputs.ts; both test
123
- * files read one corpus, test/fixtures/equivalentCheckCommands.json. Pure.
117
+ * A command as the gate compares two (staging bench 2026-10-25: the gate's
118
+ * own `test` script and two approved twins ran one suite three times):
119
+ * `checkAttribution.ts`, the one rule the host's attempts/inputs.ts keeps
120
+ * too; both test files read one corpus,
121
+ * test/fixtures/equivalentCheckCommands.json.
124
122
  */
125
- export declare function canonicalCheckCommand(command: string): string;
123
+ export { canonicalCheckCommand };
126
124
  /**
127
125
  * True when a command changes the checkout's git state: a commit, a branch
128
126
  * created or switched, a reset, a stash, a push. `git branch`, `git remote`
@@ -367,7 +365,8 @@ export type TestFailureClassification = {
367
365
  * prerequisite ({@link classifyMissingPrerequisite}, given the `env` the
368
366
  * command ran under) is `infra` with `needs` and the cause "needs <it>".
369
367
  * - recognisable failing-test lines (pnpm-wrapped vitest / jest / node:test
370
- * TAP + spec reporters) → `failures` with located `critical` findings
368
+ * TAP + spec reporters, pytest, Pest, PHPUnit, go test) → `failures` with
369
+ * located `critical` findings
371
370
  * (capped at 25, deduped, locations attached when the runner printed them).
372
371
  * - a failure summary with no parseable per-test lines → one capped tail
373
372
  * finding (still real evidence tests ran and failed).
@@ -404,33 +403,36 @@ export declare function parseVerifyFailures(output: string, exitCode: number, la
404
403
  */
405
404
  export declare function toRepoRelativePath(file: string, repoRoot: string, commandCwd: string): string;
406
405
  /**
407
- * What the gate's own checks already failed on before the build changed
408
- * anything (YAG-1003): per command, how many times each failure key was seen
409
- * on the clean tree. A command with no entry was not run there (or could not
410
- * run), and its failures all count, as before.
411
- */
412
- export type VerifyBaseline = ReadonlyMap<string, ReadonlyMap<string, number>>;
413
- /** One command's identity across the baseline run and the build's runs: where it runs and what it runs. */
414
- export declare function verifyCommandKey(command: Pick<VerifyCommand, "cwd" | "argv">): string;
415
- /**
416
- * One failure's key, the shape #2601's `failureKeyOf` gives a CI failure: the
417
- * repo-relative file and the message, never the line, since a change above a
418
- * failure moves it. A failure that is only the output's tail names nothing
419
- * stable, so it has no key and is never excused. Pure.
420
- */
421
- export declare function verifyFailureKey(finding: Finding): string | null;
422
- /** How many times each failure key occurs. Pure. */
423
- export declare function failureKeyCounts(findings: readonly Finding[]): Map<string, number>;
424
- /**
425
- * The failures this change caused: each failure key is excused at most as many
426
- * times as the clean tree had it, so a second copy of an old error is new. A
427
- * failure in a file the build did not touch still counts when the baseline did
428
- * not have it, since a change can break another file's types. No baseline for
429
- * the command leaves every failure in place. Pure.
430
- */
431
- export declare function subtractBaseline(findings: readonly Finding[], baseline: ReadonlyMap<string, number> | undefined): {
406
+ * What the gate's checks did on the unchanged code before the build changed
407
+ * anything (YAG-1003), by check id (`checkId`: the command and the folder it
408
+ * runs in): each that passed there, and each that failed with its failure
409
+ * keys. A check with no entry was not measured there (or gave no verdict),
410
+ * and its failures all count. The session measures each check once per
411
+ * attempt and base commit ({@link makeMeasureOnBase}); `checks.json` carries
412
+ * what the attempt's earlier sessions measured.
413
+ */
414
+ export type BaseMeasurements = ReadonlyMap<string, Omit<BaseMeasurement, "id">>;
415
+ /** A detected command's id, as the base measurement and the gate both key it. */
416
+ export declare function commandCheckId(repoRoot: string, command: Pick<VerifyCommand, "cwd" | "argv">): string;
417
+ /**
418
+ * One finding's failure key, in `checkAttribution.ts`'s shapes: a failing
419
+ * test's name, or a located diagnostic's repo-relative file and message,
420
+ * never its line, since a change above a failure moves it. A finding that is
421
+ * only the output's tail names nothing stable: null, and never excused. Read
422
+ * before the finding is prefixed with what ran. Pure.
423
+ */
424
+ export declare function findingKey(finding: Finding): string | null;
425
+ /**
426
+ * The failures this change caused, by `attributeFailure`: each failure the
427
+ * unchanged code already had is excused once, so a second copy of an old
428
+ * error is new, and a failure that names nothing never is. No measurement on
429
+ * the base leaves every failure in place. `keys` is index for index with
430
+ * `findings`. Pure.
431
+ */
432
+ export declare function attributeFindings(findings: readonly Finding[], keys: ReadonlyArray<string | null>, base: Omit<BaseMeasurement, "id"> | undefined): {
432
433
  findings: Finding[];
433
434
  excused: number;
435
+ verdict: FailureAttribution;
434
436
  };
435
437
  /** The note for failures the clean tree already had, by command label. Pure. */
436
438
  export declare function preexistingNote(byLabel: ReadonlyMap<string, number>): string | null;
@@ -579,23 +581,18 @@ export interface MakeRunVerifyOpts {
579
581
  /** Undo what the half wrote into the tree (default: `git clean` / `git checkout` of exactly those paths). */
580
582
  undoTreeWrites?: (cwd: string, entries: TreeEntry[]) => Promise<void>;
581
583
  /**
582
- * What the typecheck and test halves already failed on before the build
583
- * (YAG-1003, {@link makeTakeVerifyBaseline}). Those failures are a note, not
584
- * findings. Absent: every failure is a finding, as before.
585
- */
586
- baseline?: VerifyBaseline | null;
587
- /**
588
- * What the approved checks `checks.json` marks `measureOnBase` did on the
589
- * unchanged code ({@link makeMeasureChecksOnBase}). It stands over each
590
- * one's `status`: one that passed there must pass, and one that failed
591
- * there is the change's only where it fails anew. Absent: `status` alone.
584
+ * What the gate's checks did on the unchanged code ({@link makeMeasureOnBase},
585
+ * and what `checks.json` carried from the attempt's earlier sessions). A
586
+ * failure is the change's unless `attributeFailure` finds the base already
587
+ * had it; a check with no measurement counts every failure, whatever label
588
+ * `checks.json` gave it. Absent: every failure is a finding.
592
589
  */
593
- checksOnBase?: ChecksOnBase | null;
590
+ onBase?: BaseMeasurements | null;
594
591
  /**
595
592
  * The cloud session's rule (spec decision 3): a test run that exits
596
593
  * non-zero with output no parser reads is a finding carrying its output
597
- * tail, unless the baseline saw the clean tree fail the same command, which
598
- * is a note. Absent (mission mode): it fails open with a note, as before.
594
+ * tail. It names nothing the base could already have, so it is never
595
+ * excused. Absent (mission mode): it fails open with a note, as before.
599
596
  */
600
597
  unreadTestFailureIsFinding?: boolean;
601
598
  /**
@@ -646,8 +643,8 @@ export interface MakeWorkstreamCheckOpts {
646
643
  detect?: (cwd: string, claimDirs: string[]) => VerifyCommand[];
647
644
  exec?: VerifyExec;
648
645
  timeoutMs?: number;
649
- /** What the clean tree already failed on (YAG-1003): those failures are not a workstream's. */
650
- baseline?: VerifyBaseline | null;
646
+ /** What the unchanged code already failed on (YAG-1003): those failures are not a workstream's. */
647
+ onBase?: BaseMeasurements | null;
651
648
  /**
652
649
  * The toolchain the checks run on, as the full gate's do (default:
653
650
  * `YAGNI_TOOLCHAIN_FILE`, when it reads).
@@ -680,6 +677,27 @@ export interface MakeWorkstreamCheckOpts {
680
677
  * and produces no findings.
681
678
  */
682
679
  export declare function makeWorkstreamCheck(opts?: MakeWorkstreamCheckOpts): (cwd: string, targets: WorkstreamCheckTarget[], signal?: AbortSignal) => Promise<WorkstreamCheckResult[]>;
680
+ /**
681
+ * A failing repository command's findings, located from the folder it ran in
682
+ * and prefixed with what ran, each with its failure key ({@link findingKey},
683
+ * index for index): the gate's on the build's tree, and the unchanged code's
684
+ * measurement ({@link makeMeasureOnBase}), so a failure keys the same on
685
+ * both. Pure.
686
+ */
687
+ export declare function repoCommandFindings(failure: {
688
+ output: string;
689
+ code: number;
690
+ env?: NodeJS.ProcessEnv;
691
+ }, at: {
692
+ label: string;
693
+ prefix: string;
694
+ repoRoot: string;
695
+ dir: string;
696
+ limit?: number;
697
+ }): {
698
+ findings: Finding[];
699
+ keys: Array<string | null>;
700
+ };
683
701
  /**
684
702
  * Build the runVerify function injected into the orchestrator. It discovers the
685
703
  * changed package(s) (scoped to this run's diff via `baselinePaths`), detects a
@@ -690,109 +708,90 @@ export declare function makeWorkstreamCheck(opts?: MakeWorkstreamCheckOpts): (cw
690
708
  * blocks a real change on its own failure.
691
709
  */
692
710
  export declare function makeRunVerify(opts?: MakeRunVerifyOpts): (cwd: string, signal?: AbortSignal, baselinePaths?: string[]) => Promise<VerifyOutcome>;
693
- /** The whole baseline run's cap, before the build starts: it costs minutes at most. */
694
- export declare const VERIFY_BASELINE_BUDGET_MS: number;
695
- export interface MakeTakeVerifyBaselineOpts {
696
- detect?: (cwd: string, dirs: string[]) => VerifyCommand[];
697
- detectTests?: (cwd: string, dirs: string[]) => VerifyCommand[];
711
+ /** The whole base measurement's cap, before the build starts: it costs minutes at most. */
712
+ export declare const BASE_MEASUREMENT_BUDGET_MS: number;
713
+ /**
714
+ * One check to run once on the unchanged code: an approved check from
715
+ * `checks.json` (at the repository root, as the gate runs it), or one of the
716
+ * gate's own typecheck and test commands in a package the build will
717
+ * change, keyed (`id`) as the gate keys its run.
718
+ */
719
+ export interface BaseTarget {
720
+ id: string;
721
+ label: string;
722
+ kind: "check" | "typecheck" | "test";
723
+ /** The command line, as the stream hears it. */
724
+ command: string;
725
+ argv: string[];
726
+ /** Where it runs (absolute). */
727
+ dir: string;
728
+ }
729
+ /**
730
+ * What the gate will judge, in the order it is measured: the approved
731
+ * checks `checks.json` marks `measureOnBase` (every one it can run with
732
+ * `allChecks`, a resumed session's rule: the record's green is what went
733
+ * stale), then the gate's own typecheck and test commands in `dirs`, the
734
+ * packages the build will change. Each once, by id; a check that changes the
735
+ * checkout's git state or that the sandbox cannot run is never one. Read on
736
+ * the tree as it is: the gate detects its commands on the build's tree, so
737
+ * these are the ids it will look up.
738
+ */
739
+ export declare function baseTargets(cwd: string, input: {
740
+ dirs: string[];
741
+ checks: MissionChecksFile | null;
742
+ allChecks?: boolean;
743
+ }, opts?: Pick<MakeRunVerifyOpts, "detect" | "detectTests">): BaseTarget[];
744
+ export interface MakeMeasureOnBaseOpts {
698
745
  exec?: VerifyExec;
746
+ /** One typecheck's cap (default {@link VERIFY_TIMEOUT_MS}). */
699
747
  timeoutMs?: number;
748
+ /** One test run's cap (default {@link VERIFY_TEST_TIMEOUT_MS}). */
700
749
  testTimeoutMs?: number;
750
+ /** One approved check's cap (default {@link REPO_CHECK_TIMEOUT_MS}). */
751
+ repoCheckTimeoutMs?: number;
752
+ /** Env overrides for determinism in tests (default: the gate's own, per kind). */
701
753
  testEnv?: NodeJS.ProcessEnv;
702
- /**
703
- * The toolchain the commands run on, as the gate's do (default:
704
- * `YAGNI_TOOLCHAIN_FILE`, when it reads).
705
- */
754
+ repoChecksEnv?: NodeJS.ProcessEnv;
755
+ /** The toolchain the commands run on, as the gate's do (default: `YAGNI_TOOLCHAIN_FILE`, when it reads). */
706
756
  toolchain?: () => ToolchainFile | null;
707
757
  budgetMs?: number;
708
758
  now?: () => number;
709
759
  treeStatus?: (cwd: string, signal?: AbortSignal) => Promise<string>;
710
760
  undoTreeWrites?: (cwd: string, entries: TreeEntry[]) => Promise<void>;
711
- /** Told as each command starts and ends on the clean tree (the session's stream). */
761
+ /** Told as each command starts and ends on the unchanged code (the session's stream). */
712
762
  onCheck?: (event: VerifyCheckEvent) => void;
713
763
  }
714
- /** What the baseline run found, for the gate and for the run's log. */
715
- export interface VerifyBaselineResult {
716
- baseline: VerifyBaseline;
717
- /** Commands that gave a verdict on the clean tree, by label. */
764
+ /** What one measurement found, for the gate and for the run's log. */
765
+ export interface BaseMeasurementResult {
766
+ /** Each target that gave a verdict, by id: it passed, or failed with these keys. */
767
+ measured: Map<string, Omit<BaseMeasurement, "id">>;
768
+ /** The labels of the targets that gave a verdict. */
718
769
  ran: string[];
719
- /** Keyed failures the clean tree already had, across those commands. */
770
+ /** Keyed failures the unchanged code had, across them. */
720
771
  failures: number;
721
- /** Commands that gave no verdict, and why: their failures all count later. */
722
- notes: string[];
723
- }
724
- /**
725
- * Run the gate's own typecheck and test commands ONCE on the clean tree,
726
- * before the build changes anything (YAG-1003), in the package dirs the
727
- * approved plan names, and keep each command's failure keys. The build's gate
728
- * then counts only the failures this change added ({@link subtractBaseline}).
729
- *
730
- * The same detection, exec seam and environments as {@link makeRunVerify}, so
731
- * a command's key and its failures' keys match the build's runs. Fail-open per
732
- * command: one that cannot run, times out, or is not reached in the budget
733
- * has no baseline, and its failures all count, as before. What the commands
734
- * write into the tree is undone, so none of it reaches the candidate.
735
- */
736
- export declare function makeTakeVerifyBaseline(opts?: MakeTakeVerifyBaselineOpts): (cwd: string, dirs: string[], signal?: AbortSignal, budgetOverrideMs?: number) => Promise<VerifyBaselineResult>;
737
- /**
738
- * What the approved checks marked `measureOnBase` did on the unchanged code,
739
- * by command (trimmed): each that passed there, and each that failed there
740
- * with failures the gate reads, with how often each failure key was seen
741
- * (none for a failure only a summary line names). A command in neither gave
742
- * no verdict there, and keeps the status `checks.json` gave it.
743
- */
744
- export interface ChecksOnBase {
745
- passed: ReadonlySet<string>;
746
- failed: ReadonlyMap<string, ReadonlyMap<string, number>>;
747
- }
748
- /** {@link ChecksOnBase}, with what ran and why the rest gave no verdict, for the run's log. */
749
- export interface ChecksOnBaseResult extends ChecksOnBase {
750
- ran: string[];
772
+ /** Targets that gave no verdict, and why: their failures all count later. */
751
773
  notes: string[];
752
774
  /**
753
- * What the checks wrote into the tree was undone (or they wrote nothing).
754
- * False when the tree could not be read before them or the undo failed:
755
- * the build then starts on a tree the checks may have dirtied.
775
+ * What the commands wrote into the tree was undone (or they wrote
776
+ * nothing). False when the tree could not be read before them or the undo
777
+ * failed: the build then starts on a tree they may have dirtied.
756
778
  */
757
779
  treeUndone: boolean;
758
780
  }
759
781
  /**
760
- * The whole measurement's cap, before the build starts: each check marked to
761
- * measure, once, the plan's first.
762
- */
763
- export declare const CHECKS_ON_BASE_BUDGET_MS: number;
764
- export interface MakeMeasureChecksOnBaseOpts {
765
- exec?: VerifyExec;
766
- /** Repository-checks env override for determinism in tests (default: the gate's own). */
767
- repoChecksEnv?: NodeJS.ProcessEnv;
768
- toolchain?: () => ToolchainFile | null;
769
- /** One check's cap (default {@link REPO_CHECK_TIMEOUT_MS}). */
770
- timeoutMs?: number;
771
- budgetMs?: number;
772
- now?: () => number;
773
- treeStatus?: (cwd: string, signal?: AbortSignal) => Promise<string>;
774
- undoTreeWrites?: (cwd: string, entries: TreeEntry[]) => Promise<void>;
775
- /** Told as each check starts and ends on the unchanged code (the session's stream). */
776
- onCheck?: (event: VerifyCheckEvent) => void;
777
- }
778
- /**
779
- * Run each approved check `checks.json` marks `measureOnBase` once on the
780
- * unchanged code, before the build changes anything: a plan's check the
781
- * host has not seen pass there (none of the record's, or a red one the
782
- * record may hold from long ago), and a command the repository's CI runs
783
- * when the record names no check of its own. A check the plan wrote for the
784
- * change often fails there by design (its test file is not written yet), and a
785
- * failure that says only that (a file not found, no tests to run, output no
786
- * parser reads) is no verdict: its failures all count after the build, as
787
- * before. A failure the gate reads (failing tests, located diagnostics, a
788
- * test runner's failure summary) is one the unchanged code already has.
782
+ * Run each target ({@link baseTargets}) once on the unchanged code, before
783
+ * the build changes anything (YAG-1003), and keep what it did: passed, or
784
+ * failed with its failure keys ({@link findingKey}). The build's gate then
785
+ * counts only the failures the change added ({@link attributeFindings}).
789
786
  *
790
- * Run as the gate runs the check ({@link makeRunVerify}): the same command
791
- * line, environment and toolchain, from the repository root, so a failure
792
- * keys the same on both trees. Bounded: each check by its cap, the whole by
793
- * the budget, and one not reached in it has no verdict. What the checks
794
- * write into the tree is undone.
795
- */
796
- export declare function makeMeasureChecksOnBase(opts?: MakeMeasureChecksOnBaseOpts): (cwd: string, file: MissionChecksFile, signal?: AbortSignal, budgetOverrideMs?: number) => Promise<ChecksOnBaseResult>;
797
- export {};
787
+ * Each runs as the gate runs it, with the same command line, environment
788
+ * and toolchain, so a failure keys the same on both trees. A run that says
789
+ * only that it could not run (an infra failure, a path it reads not there,
790
+ * a command not found) gives no verdict, and its failures all count after
791
+ * the build. A test run or check whose output no parser reads failed there
792
+ * with no keys: nothing after the build is excused by it. Bounded: each by
793
+ * its cap, the whole by the budget, and a target not reached in it gives no
794
+ * verdict. What the commands write into the tree is undone.
795
+ */
796
+ export declare function makeMeasureOnBase(opts?: MakeMeasureOnBaseOpts): (cwd: string, targets: readonly BaseTarget[], signal?: AbortSignal, budgetOverrideMs?: number) => Promise<BaseMeasurementResult>;
798
797
  //# sourceMappingURL=verify.d.ts.map