autor3search-typescript 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/benchproto/types.d.ts +32 -0
- package/dist/benchproto/types.js +28 -0
- package/dist/benchproto/types.js.map +1 -0
- package/dist/benchrun/child.d.ts +1 -0
- package/dist/benchrun/child.js +222 -0
- package/dist/benchrun/child.js.map +1 -0
- package/dist/benchrun/invoke.d.ts +61 -0
- package/dist/benchrun/invoke.js +152 -0
- package/dist/benchrun/invoke.js.map +1 -0
- package/dist/cli/cmd-baseline.d.ts +15 -0
- package/dist/cli/cmd-baseline.js +292 -0
- package/dist/cli/cmd-baseline.js.map +1 -0
- package/dist/cli/cmd-doctor.d.ts +11 -0
- package/dist/cli/cmd-doctor.js +26 -0
- package/dist/cli/cmd-doctor.js.map +1 -0
- package/dist/cli/cmd-eval.d.ts +30 -0
- package/dist/cli/cmd-eval.js +173 -0
- package/dist/cli/cmd-eval.js.map +1 -0
- package/dist/cli/cmd-init.d.ts +16 -0
- package/dist/cli/cmd-init.js +343 -0
- package/dist/cli/cmd-init.js.map +1 -0
- package/dist/cli/cmd-profile.d.ts +11 -0
- package/dist/cli/cmd-profile.js +140 -0
- package/dist/cli/cmd-profile.js.map +1 -0
- package/dist/cli/cmd-report.d.ts +15 -0
- package/dist/cli/cmd-report.js +70 -0
- package/dist/cli/cmd-report.js.map +1 -0
- package/dist/cli/cmd-status.d.ts +11 -0
- package/dist/cli/cmd-status.js +143 -0
- package/dist/cli/cmd-status.js.map +1 -0
- package/dist/cli/cmd-stop.d.ts +15 -0
- package/dist/cli/cmd-stop.js +143 -0
- package/dist/cli/cmd-stop.js.map +1 -0
- package/dist/cli/main.d.ts +31 -0
- package/dist/cli/main.js +133 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/runctx.d.ts +29 -0
- package/dist/cli/runctx.js +49 -0
- package/dist/cli/runctx.js.map +1 -0
- package/dist/cli/speedup.d.ts +14 -0
- package/dist/cli/speedup.js +25 -0
- package/dist/cli/speedup.js.map +1 -0
- package/dist/config/load.d.ts +6 -0
- package/dist/config/load.js +172 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/schema.d.ts +42 -0
- package/dist/config/schema.js +25 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/discover/benchmarks.d.ts +26 -0
- package/dist/discover/benchmarks.js +88 -0
- package/dist/discover/benchmarks.js.map +1 -0
- package/dist/discover/files.d.ts +23 -0
- package/dist/discover/files.js +82 -0
- package/dist/discover/files.js.map +1 -0
- package/dist/doctor/doctor.d.ts +56 -0
- package/dist/doctor/doctor.js +255 -0
- package/dist/doctor/doctor.js.map +1 -0
- package/dist/freeze/freeze.d.ts +23 -0
- package/dist/freeze/freeze.js +107 -0
- package/dist/freeze/freeze.js.map +1 -0
- package/dist/freeze/manifest.d.ts +6 -0
- package/dist/freeze/manifest.js +9 -0
- package/dist/freeze/manifest.js.map +1 -0
- package/dist/freeze/safepath.d.ts +8 -0
- package/dist/freeze/safepath.js +22 -0
- package/dist/freeze/safepath.js.map +1 -0
- package/dist/gitx/git.d.ts +87 -0
- package/dist/gitx/git.js +235 -0
- package/dist/gitx/git.js.map +1 -0
- package/dist/measure/interleave.d.ts +32 -0
- package/dist/measure/interleave.js +42 -0
- package/dist/measure/interleave.js.map +1 -0
- package/dist/pipeline/eval.d.ts +67 -0
- package/dist/pipeline/eval.js +495 -0
- package/dist/pipeline/eval.js.map +1 -0
- package/dist/pm/detect.d.ts +17 -0
- package/dist/pm/detect.js +131 -0
- package/dist/pm/detect.js.map +1 -0
- package/dist/profile/profile.d.ts +53 -0
- package/dist/profile/profile.js +105 -0
- package/dist/profile/profile.js.map +1 -0
- package/dist/results/results.d.ts +65 -0
- package/dist/results/results.js +214 -0
- package/dist/results/results.js.map +1 -0
- package/dist/runner/exec.d.ts +69 -0
- package/dist/runner/exec.js +185 -0
- package/dist/runner/exec.js.map +1 -0
- package/dist/scope/scope.d.ts +20 -0
- package/dist/scope/scope.js +70 -0
- package/dist/scope/scope.js.map +1 -0
- package/dist/state/baseline.d.ts +35 -0
- package/dist/state/baseline.js +38 -0
- package/dist/state/baseline.js.map +1 -0
- package/dist/state/home.d.ts +9 -0
- package/dist/state/home.js +72 -0
- package/dist/state/home.js.map +1 -0
- package/dist/state/lock.d.ts +11 -0
- package/dist/state/lock.js +89 -0
- package/dist/state/lock.js.map +1 -0
- package/dist/state/runnaming.d.ts +27 -0
- package/dist/state/runnaming.js +47 -0
- package/dist/state/runnaming.js.map +1 -0
- package/dist/state/stop.d.ts +28 -0
- package/dist/state/stop.js +59 -0
- package/dist/state/stop.js.map +1 -0
- package/dist/stats/delta.d.ts +29 -0
- package/dist/stats/delta.js +41 -0
- package/dist/stats/delta.js.map +1 -0
- package/dist/stats/geomean.d.ts +4 -0
- package/dist/stats/geomean.js +21 -0
- package/dist/stats/geomean.js.map +1 -0
- package/dist/stats/mannwhitney.d.ts +27 -0
- package/dist/stats/mannwhitney.js +158 -0
- package/dist/stats/mannwhitney.js.map +1 -0
- package/dist/verdict/verdict.d.ts +46 -0
- package/dist/verdict/verdict.js +102 -0
- package/dist/verdict/verdict.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +35 -0
- package/templates/program.md +131 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export declare function repoRoot(dir: string): Promise<string>;
|
|
2
|
+
export declare function headCommit(root: string): Promise<string>;
|
|
3
|
+
export declare function shortSha(sha: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* A tree is clean only if it has no modifications AND no untracked files.
|
|
6
|
+
* `--porcelain` lists untracked entries too (respecting .gitignore, so an
|
|
7
|
+
* untracked file inside an ignored directory does not count): a baseline
|
|
8
|
+
* pinned against what is on disk rather than what is in git is not
|
|
9
|
+
* reproducible, so a stray untracked file must make the tree dirty.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isClean(root: string): Promise<boolean>;
|
|
12
|
+
/**
|
|
13
|
+
* Repo-relative POSIX paths touched since `sinceRef`: everything the scope
|
|
14
|
+
* gate (and gate 8's clean-tree check) must treat as "changed," whether or
|
|
15
|
+
* not it was ever `git add`-ed, committed, or hidden from git's own normal
|
|
16
|
+
* views.
|
|
17
|
+
*
|
|
18
|
+
* This is the union of several views, because no one of them alone answers
|
|
19
|
+
* the question:
|
|
20
|
+
*
|
|
21
|
+
* - `diff --name-only <ref>` (ref vs. the *working tree*, not `HEAD`) --
|
|
22
|
+
* catches committed changes, uncommitted edits to tracked files, and
|
|
23
|
+
* files the agent deleted. Blind to a brand-new file never `git add`-ed,
|
|
24
|
+
* and to a tracked file flagged assume-unchanged/skip-worktree (below).
|
|
25
|
+
* - `ls-files --others --exclude-standard` -- untracked files, respecting
|
|
26
|
+
* `.gitignore`. Safe to trust here ONLY because `untrustedGitignores`
|
|
27
|
+
* (above) is checked first and separately: this function does NOT
|
|
28
|
+
* re-derive an ignore-immune untracked-file list of its own (an earlier
|
|
29
|
+
* version did, and it made the tool refuse on a repository's own
|
|
30
|
+
* ordinary `dist/`, `.env` or `*.log` entries -- the opposite failure).
|
|
31
|
+
* - `untrustedGitignores` -- an untracked or modified `.gitignore` is
|
|
32
|
+
* itself reported as a change, so `--exclude-standard`'s output for
|
|
33
|
+
* THIS invocation is never trusted while the rules it depends on are in
|
|
34
|
+
* an unverified state.
|
|
35
|
+
* - `listSymlinks` minus git's tracked set -- an untracked symlink is
|
|
36
|
+
* invisible to the ordinary file walk `walkRepo` uses (by design; see
|
|
37
|
+
* its own doc comment) and to `--exclude-standard` only if it happens to
|
|
38
|
+
* be gitignored, but it is exactly what Node and `tsc` resolve at
|
|
39
|
+
* measure time. Reported unconditionally, gitignored or not: a symlink
|
|
40
|
+
* is content indirection, and hiding a NEW one behind an ignore rule is
|
|
41
|
+
* not a legitimate use this gate needs to accommodate the way `dist/`
|
|
42
|
+
* or `.env` are.
|
|
43
|
+
* - `tamperedIndexEntries` -- see its own doc comment: a complete bypass
|
|
44
|
+
* of `diff` for a tracked file, detected directly.
|
|
45
|
+
*
|
|
46
|
+
* `diff` and every `ls-files` call use `-z`: a path with a space or
|
|
47
|
+
* embedded newline would otherwise be able to split into extra entries
|
|
48
|
+
* under the default newline-separated, C-quoted output, and a scope gate
|
|
49
|
+
* that mis-parses a filename is one an agent can bypass by naming a file
|
|
50
|
+
* carefully. This is a security property, not formatting.
|
|
51
|
+
*/
|
|
52
|
+
export declare function changedFiles(root: string, sinceRef: string): Promise<string[]>;
|
|
53
|
+
export declare function currentBranch(root: string): Promise<string>;
|
|
54
|
+
export declare function branchExists(root: string, name: string): Promise<boolean>;
|
|
55
|
+
export declare function createBranch(root: string, name: string): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Deletes a local branch, force (`-D`) rather than `-d`: this exists for the
|
|
58
|
+
* `baseline` unwind path, where a run that fails partway must delete the run
|
|
59
|
+
* branch it just created so a retry does not die on "branch already
|
|
60
|
+
* exists." A branch created moments ago for a fresh run is never something
|
|
61
|
+
* the merge-safety check behind `-d` needs to protect. Fails (does not
|
|
62
|
+
* silently succeed) if the branch does not exist, since a caller unwinding
|
|
63
|
+
* a partial failure needs to know its assumption about what it created was
|
|
64
|
+
* wrong.
|
|
65
|
+
*/
|
|
66
|
+
export declare function deleteBranch(root: string, name: string): Promise<void>;
|
|
67
|
+
export declare function addWorktree(root: string, dir: string, commit: string): Promise<void>;
|
|
68
|
+
export declare function removeWorktree(root: string, dir: string): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Moves an existing detached worktree to another commit.
|
|
71
|
+
*
|
|
72
|
+
* This is how the MEASUREMENT commit advances after a KEEP. It must never be
|
|
73
|
+
* used on the frozen-test snapshot: moving the measurement point must not move
|
|
74
|
+
* the success criteria.
|
|
75
|
+
*
|
|
76
|
+
* `--force` (in addition to `-q --detach`): this is also how `eval` gate 8
|
|
77
|
+
* self-heals a worktree merely left at the wrong commit (e.g. by a crash
|
|
78
|
+
* between recording an advanced `measureCommit` and repointing the
|
|
79
|
+
* worktree to match it -- see `pipeline/eval.ts`). That worktree's own
|
|
80
|
+
* frozen files were restored on a previous run and may still differ from
|
|
81
|
+
* the target commit's tree; a plain `checkout --detach` would refuse to
|
|
82
|
+
* discard those local changes, which the self-heal must not depend on a
|
|
83
|
+
* human clearing first. Safe to discard unconditionally: the worktree
|
|
84
|
+
* holds nothing this tool did not itself put there, and `restore` runs
|
|
85
|
+
* again immediately after this to reassert the frozen bytes regardless.
|
|
86
|
+
*/
|
|
87
|
+
export declare function repointWorktree(worktreeDir: string, commit: string): Promise<void>;
|
package/dist/gitx/git.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { listSymlinks, walkRepo } from '../discover/files.js';
|
|
3
|
+
import { ok, run } from '../runner/exec.js';
|
|
4
|
+
const TIMEOUT_MS = 60_000;
|
|
5
|
+
async function git(cwd, args) {
|
|
6
|
+
const r = await run('git', args, { cwd, timeoutMs: TIMEOUT_MS });
|
|
7
|
+
if (!ok(r)) {
|
|
8
|
+
throw new Error(`git ${args.join(' ')} failed in ${cwd} (exit ${r.exitCode}): ${r.stderr.trim()}`);
|
|
9
|
+
}
|
|
10
|
+
return r.stdout.trim();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Like `git`, but returns stdout untrimmed.
|
|
14
|
+
*
|
|
15
|
+
* `.trim()` is safe for the scalar callers (`repoRoot`, `headCommit`,
|
|
16
|
+
* `currentBranch`, ...), which only ever get one shell-wrapped value back.
|
|
17
|
+
* It is NOT safe for a `-z` NUL-separated list: `String.prototype.trim`
|
|
18
|
+
* strips leading ASCII whitespace, and a leading space (0x20) sorts before
|
|
19
|
+
* any letter in git's output — so a repo-relative path that legitimately
|
|
20
|
+
* starts with a space (e.g. a directory named `" src"`) would have that
|
|
21
|
+
* space clipped from the *first* entry every time, silently turning
|
|
22
|
+
* `" src/evil.ts"` into `"src/evil.ts"`. Under a scope gate that allowlists
|
|
23
|
+
* `src/**`, that reported path is in scope while the real file is not —
|
|
24
|
+
* the same "name a file to bypass the gate" class `-z` itself exists to
|
|
25
|
+
* prevent, reintroduced one layer up by an over-eager trim. `-z` and NUL
|
|
26
|
+
* splitting still take care of the trailing edge: `trim()` does not treat
|
|
27
|
+
* `\0` as whitespace, so it never eats the sentinel a caller's split relies
|
|
28
|
+
* on.
|
|
29
|
+
*/
|
|
30
|
+
async function gitRaw(cwd, args) {
|
|
31
|
+
const r = await run('git', args, { cwd, timeoutMs: TIMEOUT_MS });
|
|
32
|
+
if (!ok(r)) {
|
|
33
|
+
throw new Error(`git ${args.join(' ')} failed in ${cwd} (exit ${r.exitCode}): ${r.stderr.trim()}`);
|
|
34
|
+
}
|
|
35
|
+
return r.stdout;
|
|
36
|
+
}
|
|
37
|
+
export async function repoRoot(dir) {
|
|
38
|
+
return git(dir, ['rev-parse', '--show-toplevel']);
|
|
39
|
+
}
|
|
40
|
+
export async function headCommit(root) {
|
|
41
|
+
return git(root, ['rev-parse', 'HEAD']);
|
|
42
|
+
}
|
|
43
|
+
export function shortSha(sha) {
|
|
44
|
+
return sha.slice(0, 7);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A tree is clean only if it has no modifications AND no untracked files.
|
|
48
|
+
* `--porcelain` lists untracked entries too (respecting .gitignore, so an
|
|
49
|
+
* untracked file inside an ignored directory does not count): a baseline
|
|
50
|
+
* pinned against what is on disk rather than what is in git is not
|
|
51
|
+
* reproducible, so a stray untracked file must make the tree dirty.
|
|
52
|
+
*/
|
|
53
|
+
export async function isClean(root) {
|
|
54
|
+
return (await git(root, ['status', '--porcelain'])) === '';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Splits a NUL-separated `-z` git listing into repo-relative POSIX paths.
|
|
58
|
+
* `out` must come from `gitRaw`, not `git` — see `gitRaw`'s doc comment for
|
|
59
|
+
* why trimming first would silently corrupt a path with a leading space.
|
|
60
|
+
*/
|
|
61
|
+
function parseNulList(out) {
|
|
62
|
+
return out
|
|
63
|
+
.split('\0')
|
|
64
|
+
.filter((s) => s !== '')
|
|
65
|
+
.map((s) => s.split(path.sep).join('/'));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Repo-relative POSIX paths of every tracked file whose git-index "assume
|
|
69
|
+
* unchanged" or "skip-worktree" bit is set.
|
|
70
|
+
*
|
|
71
|
+
* Either bit tells git to stop comparing that path against the working
|
|
72
|
+
* tree at all -- `git diff <ref>` (which `changedFiles` otherwise relies on
|
|
73
|
+
* to see committed-vs-disk differences) reports NO difference for such a
|
|
74
|
+
* file even after its on-disk content is completely rewritten, because git
|
|
75
|
+
* trusts the index entry without ever re-reading the file. That is a
|
|
76
|
+
* complete, one-command bypass of both the scope gate and gate 8's
|
|
77
|
+
* clean-tree check (`git update-index --assume-unchanged <path>`, or
|
|
78
|
+
* `--skip-worktree`) -- strictly easier than the `.gitignore`-hiding attack
|
|
79
|
+
* this function otherwise closes -- so it is detected directly rather than
|
|
80
|
+
* trusted through a diff mechanism that cannot see it.
|
|
81
|
+
*
|
|
82
|
+
* `git ls-files -v` tags every tracked path with one status letter; the
|
|
83
|
+
* letter is lowercased when the assume-unchanged bit is set, and a
|
|
84
|
+
* skip-worktree path is tagged `S` regardless. Either is reported here.
|
|
85
|
+
*/
|
|
86
|
+
async function tamperedIndexEntries(root) {
|
|
87
|
+
const out = await gitRaw(root, ['ls-files', '-v', '-z']);
|
|
88
|
+
const flagged = [];
|
|
89
|
+
for (const entry of out.split('\0')) {
|
|
90
|
+
if (entry === '')
|
|
91
|
+
continue;
|
|
92
|
+
const tag = entry.charAt(0);
|
|
93
|
+
const rel = entry.slice(2); // "<tag><SP><path>"
|
|
94
|
+
if (tag === 'S' || (tag >= 'a' && tag <= 'z')) {
|
|
95
|
+
flagged.push(rel.split(path.sep).join('/'));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return flagged;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Repo-relative POSIX paths of every `.gitignore` (a plain file -- a
|
|
102
|
+
* SYMLINKED `.gitignore` is caught separately, as an untracked symlink)
|
|
103
|
+
* that is either untracked or differs from `sinceRef`: one whose rules
|
|
104
|
+
* cannot be trusted for this comparison.
|
|
105
|
+
*
|
|
106
|
+
* `--exclude-standard` (used below to list ordinary untracked files) is
|
|
107
|
+
* only safe to rely on once this comes back empty. An agent-authored
|
|
108
|
+
* `.gitignore` an agent just wrote to hide a directory of untracked source
|
|
109
|
+
* (`printf '*\n' > lib/.gitignore`) is exactly what this catches: rather
|
|
110
|
+
* than distrust `--exclude-standard`'s output in general (which would also
|
|
111
|
+
* make it blind to the REPOSITORY's own, entirely legitimate ignore rules
|
|
112
|
+
* -- `dist/`, `.env`, `.DS_Store`, `*.log`, ...), an untracked or modified
|
|
113
|
+
* `.gitignore` is treated as a violation in its own right and refused
|
|
114
|
+
* before `--exclude-standard`'s output is ever trusted.
|
|
115
|
+
*/
|
|
116
|
+
function untrustedGitignores(allFiles, tracked, diffed) {
|
|
117
|
+
return allFiles.filter((f) => path.posix.basename(f) === '.gitignore' && (!tracked.has(f) || diffed.has(f)));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Repo-relative POSIX paths touched since `sinceRef`: everything the scope
|
|
121
|
+
* gate (and gate 8's clean-tree check) must treat as "changed," whether or
|
|
122
|
+
* not it was ever `git add`-ed, committed, or hidden from git's own normal
|
|
123
|
+
* views.
|
|
124
|
+
*
|
|
125
|
+
* This is the union of several views, because no one of them alone answers
|
|
126
|
+
* the question:
|
|
127
|
+
*
|
|
128
|
+
* - `diff --name-only <ref>` (ref vs. the *working tree*, not `HEAD`) --
|
|
129
|
+
* catches committed changes, uncommitted edits to tracked files, and
|
|
130
|
+
* files the agent deleted. Blind to a brand-new file never `git add`-ed,
|
|
131
|
+
* and to a tracked file flagged assume-unchanged/skip-worktree (below).
|
|
132
|
+
* - `ls-files --others --exclude-standard` -- untracked files, respecting
|
|
133
|
+
* `.gitignore`. Safe to trust here ONLY because `untrustedGitignores`
|
|
134
|
+
* (above) is checked first and separately: this function does NOT
|
|
135
|
+
* re-derive an ignore-immune untracked-file list of its own (an earlier
|
|
136
|
+
* version did, and it made the tool refuse on a repository's own
|
|
137
|
+
* ordinary `dist/`, `.env` or `*.log` entries -- the opposite failure).
|
|
138
|
+
* - `untrustedGitignores` -- an untracked or modified `.gitignore` is
|
|
139
|
+
* itself reported as a change, so `--exclude-standard`'s output for
|
|
140
|
+
* THIS invocation is never trusted while the rules it depends on are in
|
|
141
|
+
* an unverified state.
|
|
142
|
+
* - `listSymlinks` minus git's tracked set -- an untracked symlink is
|
|
143
|
+
* invisible to the ordinary file walk `walkRepo` uses (by design; see
|
|
144
|
+
* its own doc comment) and to `--exclude-standard` only if it happens to
|
|
145
|
+
* be gitignored, but it is exactly what Node and `tsc` resolve at
|
|
146
|
+
* measure time. Reported unconditionally, gitignored or not: a symlink
|
|
147
|
+
* is content indirection, and hiding a NEW one behind an ignore rule is
|
|
148
|
+
* not a legitimate use this gate needs to accommodate the way `dist/`
|
|
149
|
+
* or `.env` are.
|
|
150
|
+
* - `tamperedIndexEntries` -- see its own doc comment: a complete bypass
|
|
151
|
+
* of `diff` for a tracked file, detected directly.
|
|
152
|
+
*
|
|
153
|
+
* `diff` and every `ls-files` call use `-z`: a path with a space or
|
|
154
|
+
* embedded newline would otherwise be able to split into extra entries
|
|
155
|
+
* under the default newline-separated, C-quoted output, and a scope gate
|
|
156
|
+
* that mis-parses a filename is one an agent can bypass by naming a file
|
|
157
|
+
* carefully. This is a security property, not formatting.
|
|
158
|
+
*/
|
|
159
|
+
export async function changedFiles(root, sinceRef) {
|
|
160
|
+
const [diffOut, trackedOut, untrackedOut, allFiles, symlinks, tamperedTags] = await Promise.all([
|
|
161
|
+
gitRaw(root, ['diff', '--name-only', '-z', sinceRef]),
|
|
162
|
+
gitRaw(root, ['ls-files', '-z']),
|
|
163
|
+
gitRaw(root, ['ls-files', '--others', '--exclude-standard', '-z']),
|
|
164
|
+
walkRepo(root),
|
|
165
|
+
listSymlinks(root),
|
|
166
|
+
tamperedIndexEntries(root),
|
|
167
|
+
]);
|
|
168
|
+
const tracked = new Set(parseNulList(trackedOut));
|
|
169
|
+
const diffed = new Set(parseNulList(diffOut));
|
|
170
|
+
const gitignoreViolations = untrustedGitignores(allFiles, tracked, diffed);
|
|
171
|
+
const untrackedSymlinks = symlinks.filter((f) => !tracked.has(f));
|
|
172
|
+
return [
|
|
173
|
+
...new Set([
|
|
174
|
+
...diffed,
|
|
175
|
+
...parseNulList(untrackedOut),
|
|
176
|
+
...gitignoreViolations,
|
|
177
|
+
...untrackedSymlinks,
|
|
178
|
+
...tamperedTags,
|
|
179
|
+
]),
|
|
180
|
+
].sort();
|
|
181
|
+
}
|
|
182
|
+
export async function currentBranch(root) {
|
|
183
|
+
return git(root, ['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
184
|
+
}
|
|
185
|
+
export async function branchExists(root, name) {
|
|
186
|
+
const r = await run('git', ['show-ref', '--verify', '--quiet', `refs/heads/${name}`], {
|
|
187
|
+
cwd: root,
|
|
188
|
+
timeoutMs: TIMEOUT_MS,
|
|
189
|
+
});
|
|
190
|
+
return r.exitCode === 0;
|
|
191
|
+
}
|
|
192
|
+
export async function createBranch(root, name) {
|
|
193
|
+
await git(root, ['checkout', '-q', '-b', name]);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Deletes a local branch, force (`-D`) rather than `-d`: this exists for the
|
|
197
|
+
* `baseline` unwind path, where a run that fails partway must delete the run
|
|
198
|
+
* branch it just created so a retry does not die on "branch already
|
|
199
|
+
* exists." A branch created moments ago for a fresh run is never something
|
|
200
|
+
* the merge-safety check behind `-d` needs to protect. Fails (does not
|
|
201
|
+
* silently succeed) if the branch does not exist, since a caller unwinding
|
|
202
|
+
* a partial failure needs to know its assumption about what it created was
|
|
203
|
+
* wrong.
|
|
204
|
+
*/
|
|
205
|
+
export async function deleteBranch(root, name) {
|
|
206
|
+
await git(root, ['branch', '-D', name]);
|
|
207
|
+
}
|
|
208
|
+
export async function addWorktree(root, dir, commit) {
|
|
209
|
+
await git(root, ['worktree', 'add', '--detach', '-q', dir, commit]);
|
|
210
|
+
}
|
|
211
|
+
export async function removeWorktree(root, dir) {
|
|
212
|
+
await git(root, ['worktree', 'remove', '--force', dir]);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Moves an existing detached worktree to another commit.
|
|
216
|
+
*
|
|
217
|
+
* This is how the MEASUREMENT commit advances after a KEEP. It must never be
|
|
218
|
+
* used on the frozen-test snapshot: moving the measurement point must not move
|
|
219
|
+
* the success criteria.
|
|
220
|
+
*
|
|
221
|
+
* `--force` (in addition to `-q --detach`): this is also how `eval` gate 8
|
|
222
|
+
* self-heals a worktree merely left at the wrong commit (e.g. by a crash
|
|
223
|
+
* between recording an advanced `measureCommit` and repointing the
|
|
224
|
+
* worktree to match it -- see `pipeline/eval.ts`). That worktree's own
|
|
225
|
+
* frozen files were restored on a previous run and may still differ from
|
|
226
|
+
* the target commit's tree; a plain `checkout --detach` would refuse to
|
|
227
|
+
* discard those local changes, which the self-heal must not depend on a
|
|
228
|
+
* human clearing first. Safe to discard unconditionally: the worktree
|
|
229
|
+
* holds nothing this tool did not itself put there, and `restore` runs
|
|
230
|
+
* again immediately after this to reassert the frozen bytes regardless.
|
|
231
|
+
*/
|
|
232
|
+
export async function repointWorktree(worktreeDir, commit) {
|
|
233
|
+
await git(worktreeDir, ['checkout', '-q', '--detach', '--force', commit]);
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/gitx/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Benchmark } from '../discover/benchmarks.js';
|
|
2
|
+
export type Observations = Map<string, number[]>;
|
|
3
|
+
export interface InterleaveOptions {
|
|
4
|
+
rounds: number;
|
|
5
|
+
benchmarks: Benchmark[];
|
|
6
|
+
baseDir: string;
|
|
7
|
+
candDir: string;
|
|
8
|
+
measureOne: (dir: string, b: Benchmark) => Promise<number>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Alternates the two sides while measuring, and accumulates one observation
|
|
12
|
+
* per benchmark per round per side.
|
|
13
|
+
*
|
|
14
|
+
* Two orderings matter, for two different reasons.
|
|
15
|
+
*
|
|
16
|
+
* Across rounds: comparing a candidate measured now against a baseline
|
|
17
|
+
* measured minutes ago attributes thermal drift, frequency scaling and
|
|
18
|
+
* background load to the code change. Alternating cancels it.
|
|
19
|
+
*
|
|
20
|
+
* Within a pair: measuring base immediately before cand, every time, leaves a
|
|
21
|
+
* small consistent bias on a machine that is steadily warming. Swapping the
|
|
22
|
+
* order on alternate rounds cancels that too -- an asymmetry the Go
|
|
23
|
+
* implementation documents as known and residual.
|
|
24
|
+
*
|
|
25
|
+
* Within one round, both sides of a given benchmark are measured adjacently
|
|
26
|
+
* before moving on to the next benchmark, keeping the pair as close in time
|
|
27
|
+
* as possible -- which is the whole point of interleaving at all.
|
|
28
|
+
*/
|
|
29
|
+
export declare function interleave(o: InterleaveOptions): Promise<{
|
|
30
|
+
base: Observations;
|
|
31
|
+
cand: Observations;
|
|
32
|
+
}>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alternates the two sides while measuring, and accumulates one observation
|
|
3
|
+
* per benchmark per round per side.
|
|
4
|
+
*
|
|
5
|
+
* Two orderings matter, for two different reasons.
|
|
6
|
+
*
|
|
7
|
+
* Across rounds: comparing a candidate measured now against a baseline
|
|
8
|
+
* measured minutes ago attributes thermal drift, frequency scaling and
|
|
9
|
+
* background load to the code change. Alternating cancels it.
|
|
10
|
+
*
|
|
11
|
+
* Within a pair: measuring base immediately before cand, every time, leaves a
|
|
12
|
+
* small consistent bias on a machine that is steadily warming. Swapping the
|
|
13
|
+
* order on alternate rounds cancels that too -- an asymmetry the Go
|
|
14
|
+
* implementation documents as known and residual.
|
|
15
|
+
*
|
|
16
|
+
* Within one round, both sides of a given benchmark are measured adjacently
|
|
17
|
+
* before moving on to the next benchmark, keeping the pair as close in time
|
|
18
|
+
* as possible -- which is the whole point of interleaving at all.
|
|
19
|
+
*/
|
|
20
|
+
export async function interleave(o) {
|
|
21
|
+
const base = new Map();
|
|
22
|
+
const cand = new Map();
|
|
23
|
+
for (const b of o.benchmarks) {
|
|
24
|
+
base.set(b.id, []);
|
|
25
|
+
cand.set(b.id, []);
|
|
26
|
+
}
|
|
27
|
+
for (let round = 0; round < o.rounds; round++) {
|
|
28
|
+
const baseFirst = round % 2 === 0;
|
|
29
|
+
for (const b of o.benchmarks) {
|
|
30
|
+
if (baseFirst) {
|
|
31
|
+
base.get(b.id).push(await o.measureOne(o.baseDir, b));
|
|
32
|
+
cand.get(b.id).push(await o.measureOne(o.candDir, b));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
cand.get(b.id).push(await o.measureOne(o.candDir, b));
|
|
36
|
+
base.get(b.id).push(await o.measureOne(o.baseDir, b));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { base, cand };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=interleave.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interleave.js","sourceRoot":"","sources":["../../src/measure/interleave.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAoB;IAInD,MAAM,IAAI,GAAiB,IAAI,GAAG,EAAE,CAAA;IACpC,MAAM,IAAI,GAAiB,IAAI,GAAG,EAAE,CAAA;IACpC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QAClB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;IACpB,CAAC;IAED,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,CAAA;QACjC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;gBACtD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;YACxD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;gBACtD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;YACxD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Benchmark } from '../discover/benchmarks.js';
|
|
2
|
+
import { type Delta } from '../stats/delta.js';
|
|
3
|
+
import { type Verdict } from '../verdict/verdict.js';
|
|
4
|
+
export type GateName =
|
|
5
|
+
/** No baseline for this tag, or the config file itself could not be loaded at all. */
|
|
6
|
+
'setup' | 'scope' | 'config-integrity' | 'restore' | 'unmanifested' | 'typecheck' | 'build' | 'test' | 'worktree-integrity' | 'measure'
|
|
7
|
+
/** Advancing measureCommit after a KEEP was already decided. */
|
|
8
|
+
| 'advance';
|
|
9
|
+
/**
|
|
10
|
+
* The subset of `RunCtx` (see `cli/runctx.ts`) this pipeline needs. Declared
|
|
11
|
+
* independently rather than importing `RunCtx` itself so the pipeline layer
|
|
12
|
+
* does not depend on the CLI layer -- `cli/cmd-eval.ts` passes its `RunCtx`
|
|
13
|
+
* straight through, which satisfies this structurally.
|
|
14
|
+
*/
|
|
15
|
+
export interface EvalRepoCtx {
|
|
16
|
+
repoRoot: string;
|
|
17
|
+
configPath: string;
|
|
18
|
+
resultsPath: string;
|
|
19
|
+
}
|
|
20
|
+
export interface EvalOptions {
|
|
21
|
+
ctx: EvalRepoCtx;
|
|
22
|
+
tag: string;
|
|
23
|
+
/** Free-text experiment description, recorded on the results.tsv row. */
|
|
24
|
+
description: string;
|
|
25
|
+
/** Subprocess transcripts (typecheck/build/test/measurement children). */
|
|
26
|
+
log?: (chunk: string) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Testing hook: overrides how one benchmark is measured in one directory.
|
|
29
|
+
* Defaults to a real `runChild` spawn. Exists so gate-order tests can prove
|
|
30
|
+
* a rejected gate never measures anything, by asserting this was never
|
|
31
|
+
* called, without needing to spawn (and then discard) a real subprocess.
|
|
32
|
+
*/
|
|
33
|
+
measureOne?: (dir: string, b: Benchmark) => Promise<number>;
|
|
34
|
+
}
|
|
35
|
+
export interface EvalOutcome {
|
|
36
|
+
verdict: Verdict;
|
|
37
|
+
deltas: Delta[];
|
|
38
|
+
stopRequested: boolean;
|
|
39
|
+
failedGate?: GateName;
|
|
40
|
+
message: string;
|
|
41
|
+
/**
|
|
42
|
+
* Every non-verdict warning gathered along the way (e.g. "gate 3 restored
|
|
43
|
+
* N frozen file(s)"), followed by the verdict's own warnings when a score
|
|
44
|
+
* was actually computed. Not in the brief's minimal interface, but
|
|
45
|
+
* `cmd-eval`'s `--json` output and its human "WARNING:" lines both need a
|
|
46
|
+
* single combined list, and building it here (once, where the gates run)
|
|
47
|
+
* beats recomputing it at the CLI layer from partial information.
|
|
48
|
+
*/
|
|
49
|
+
warnings: string[];
|
|
50
|
+
/** Repo-relative frozen files whose content differed from baseline and were restored. */
|
|
51
|
+
restoredFiles: string[];
|
|
52
|
+
/** HEAD of the repository being evaluated -- the commit this verdict is about. */
|
|
53
|
+
candidateCommit: string;
|
|
54
|
+
frozenCommit: string;
|
|
55
|
+
measureCommit: string;
|
|
56
|
+
/** 1-based count of experiments recorded in results.tsv, this one included. */
|
|
57
|
+
experiment: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Runs one experiment end to end: the full gate chain, and -- for whatever
|
|
61
|
+
* outcome it ends in -- one `results.tsv` row.
|
|
62
|
+
*
|
|
63
|
+
* The eval lock is held for the whole chain and released in a `finally`, so
|
|
64
|
+
* a crash mid-chain (this function throwing something genuinely
|
|
65
|
+
* unanticipated) never leaves a future eval permanently blocked.
|
|
66
|
+
*/
|
|
67
|
+
export declare function runEval(opts: EvalOptions): Promise<EvalOutcome>;
|