@cat-factory/orchestration 0.301.3 → 0.302.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/dist/modules/execution/BugFishingController.d.ts +35 -9
- package/dist/modules/execution/BugFishingController.d.ts.map +1 -1
- package/dist/modules/execution/BugFishingController.js +49 -14
- package/dist/modules/execution/BugFishingController.js.map +1 -1
- package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
- package/dist/modules/execution/RunDispatcher.js +7 -0
- package/dist/modules/execution/RunDispatcher.js.map +1 -1
- package/dist/modules/execution/bugFishing.logic.d.ts +37 -3
- package/dist/modules/execution/bugFishing.logic.d.ts.map +1 -1
- package/dist/modules/execution/bugFishing.logic.js +124 -23
- package/dist/modules/execution/bugFishing.logic.js.map +1 -1
- package/dist/modules/execution/bugFishingPass.d.ts +35 -0
- package/dist/modules/execution/bugFishingPass.d.ts.map +1 -0
- package/dist/modules/execution/bugFishingPass.js +45 -0
- package/dist/modules/execution/bugFishingPass.js.map +1 -0
- package/dist/modules/execution/bugFishingSurvey.d.ts +87 -0
- package/dist/modules/execution/bugFishingSurvey.d.ts.map +1 -0
- package/dist/modules/execution/bugFishingSurvey.js +130 -0
- package/dist/modules/execution/bugFishingSurvey.js.map +1 -0
- package/dist/modules/execution/bugFishingTerritories.logic.d.ts +89 -0
- package/dist/modules/execution/bugFishingTerritories.logic.d.ts.map +1 -0
- package/dist/modules/execution/bugFishingTerritories.logic.js +519 -0
- package/dist/modules/execution/bugFishingTerritories.logic.js.map +1 -0
- package/dist/modules/execution/dispatcher-registries.d.ts +8 -0
- package/dist/modules/execution/dispatcher-registries.d.ts.map +1 -1
- package/dist/modules/execution/dispatcher-registries.js +52 -8
- package/dist/modules/execution/dispatcher-registries.js.map +1 -1
- package/package.json +11 -11
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { BlueprintService, BugFishingPhase, BugFishingTerritory, BugFishingUnfishedCell, RepoTreeListing } from '@cat-factory/kernel';
|
|
2
|
+
/** Whether a repo-relative path is source the expedition should fish. */
|
|
3
|
+
export declare function isFishablePath(path: string): boolean;
|
|
4
|
+
/** One file of the survey's manifest: the path (survey-root-relative), and what it weighs. */
|
|
5
|
+
export interface SurveyedFile {
|
|
6
|
+
path: string;
|
|
7
|
+
bytes: number;
|
|
8
|
+
}
|
|
9
|
+
/** What a survey of the repository tree produced. */
|
|
10
|
+
export interface CodebaseSurvey {
|
|
11
|
+
/** The partition, in the order the expedition fishes it. Always at least one entry. */
|
|
12
|
+
territories: BugFishingTerritory[];
|
|
13
|
+
/**
|
|
14
|
+
* Every fishable file under the survey root, indexed by territory id, with paths in the survey
|
|
15
|
+
* root's frame (see this module's header).
|
|
16
|
+
*/
|
|
17
|
+
filesByTerritory: Map<string, SurveyedFile[]>;
|
|
18
|
+
/** True when the provider cut the tree short: the manifest is a prefix of the codebase. */
|
|
19
|
+
treeTruncated: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Options a survey takes beyond the tree itself. */
|
|
22
|
+
export interface SurveyOptions {
|
|
23
|
+
/**
|
|
24
|
+
* The monorepo subdirectory the service lives in, when it has one. The survey walks from here
|
|
25
|
+
* rather than from the repository root: a sibling service's code is out of scope for an
|
|
26
|
+
* expedition exactly as it is for every other run. It is also the frame every path this module
|
|
27
|
+
* emits is relative to, because it is the directory the agent's checkout is rooted at.
|
|
28
|
+
*/
|
|
29
|
+
serviceDirectory?: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* The service's committed blueprint, when the repository has one. Its modules are the
|
|
32
|
+
* platform's own decomposition and win over the directory heuristic; a module whose references
|
|
33
|
+
* the tree no longer has falls through to the directory rule rather than being guessed onto a
|
|
34
|
+
* new home.
|
|
35
|
+
*/
|
|
36
|
+
blueprint?: BlueprintService | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The single territory a codebase small enough to fish whole gets.
|
|
40
|
+
*
|
|
41
|
+
* The PASS-THROUGH: its phases carry no territory id, so the expedition is byte-for-byte the one
|
|
42
|
+
* that shipped before territories existed. Large-codebase mode is a size threshold crossed, never
|
|
43
|
+
* a mode a task opts into.
|
|
44
|
+
*/
|
|
45
|
+
export declare function wholeCodebaseTerritory(files: readonly SurveyedFile[]): BugFishingTerritory;
|
|
46
|
+
/**
|
|
47
|
+
* Partition a repository tree into the territories an expedition fishes.
|
|
48
|
+
*
|
|
49
|
+
* Blueprint modules first when the repository has a blueprint, then package and directory
|
|
50
|
+
* boundaries under the survey root, sized by the tree's blob bytes. A codebase that fits one
|
|
51
|
+
* territory yields exactly one, and the expedition it plans is today's.
|
|
52
|
+
*/
|
|
53
|
+
export declare function partitionCodebase(tree: RepoTreeListing, options?: SurveyOptions): CodebaseSurvey;
|
|
54
|
+
/** One planned cell: an angle fished over a territory. */
|
|
55
|
+
export interface PlannedCell {
|
|
56
|
+
territory: BugFishingTerritory;
|
|
57
|
+
phase: BugFishingPhase;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build the pass list from the territories and the angles, TERRITORY-MAJOR, trimmed to the pass
|
|
61
|
+
* budget.
|
|
62
|
+
*
|
|
63
|
+
* Territory-major so a human gets a complete answer for one territory early and can start its
|
|
64
|
+
* fixes while the rest is still being fished, which is what the separate-dispatch design is for.
|
|
65
|
+
* The budget trims from the BOTTOM of the order rather than the middle, and what it cuts is
|
|
66
|
+
* returned as unfished: a cap silent about its tail teaches the reader that the tail was clean.
|
|
67
|
+
*
|
|
68
|
+
* A single whole-codebase territory yields the angles unchanged, with no territory stamped on
|
|
69
|
+
* them, so a small codebase's plan is field-for-field the one that shipped before territories.
|
|
70
|
+
*/
|
|
71
|
+
export declare function planTerritoryPasses(input: {
|
|
72
|
+
territories: readonly BugFishingTerritory[];
|
|
73
|
+
angles: readonly BugFishingPhase[];
|
|
74
|
+
passBudget: number;
|
|
75
|
+
}): {
|
|
76
|
+
phases: BugFishingPhase[];
|
|
77
|
+
unfished: BugFishingUnfishedCell[];
|
|
78
|
+
plannedCells: number;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Order the territories a large expedition fishes, most worth fishing first.
|
|
82
|
+
*
|
|
83
|
+
* The creator's `fishingFocus` comes first, because naming a subsystem is the deliberate act and
|
|
84
|
+
* a budget that cut it would be cutting the one thing they asked for. Size decides the rest: with
|
|
85
|
+
* no scout rating relevance yet, the biggest territory is the one most likely to hide something,
|
|
86
|
+
* and it is a fact the platform can compute rather than a judgement it would be inventing.
|
|
87
|
+
*/
|
|
88
|
+
export declare function prioritiseTerritories(territories: readonly BugFishingTerritory[], focus: string | null | undefined): BugFishingTerritory[];
|
|
89
|
+
//# sourceMappingURL=bugFishingTerritories.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bugFishingTerritories.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/bugFishingTerritories.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAEhB,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EAEtB,eAAe,EAChB,MAAM,qBAAqB,CAAA;AA0I5B,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED,8FAA8F;AAC9F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,WAAW,EAAE,mBAAmB,EAAE,CAAA;IAClC;;;OAGG;IACH,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAA;IAC7C,2FAA2F;IAC3F,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACpC;AA+ED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,mBAAmB,CAU1F;AAsND;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,OAAO,GAAE,aAAkB,GAC1B,cAAc,CAuChB;AAID,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,mBAAmB,CAAA;IAC9B,KAAK,EAAE,eAAe,CAAA;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAA;IAC3C,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAgC1F;AAWD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,SAAS,mBAAmB,EAAE,EAC3C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,mBAAmB,EAAE,CAiBvB"}
|
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import { WHOLE_CODEBASE_TERRITORY_ID } from '@cat-factory/kernel';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Partitioning a codebase into TERRITORIES, and planning the (territory x angle) matrix an
|
|
4
|
+
// expedition fishes over them.
|
|
5
|
+
//
|
|
6
|
+
// Everything here is a pure function of (tree, options) -> plan, so the rule that decides what a
|
|
7
|
+
// large expedition covers is unit-testable without a repository, a run, or a model. The design
|
|
8
|
+
// record is docs/initiatives/bug-fishing-expedition.md ("Large codebases"); the one sentence that
|
|
9
|
+
// governs the whole module is its rule: the platform COMPUTES the partition, the model JUDGES the
|
|
10
|
+
// code. Nothing below asks an LLM where the modules are.
|
|
11
|
+
//
|
|
12
|
+
// THE FRAME, and it binds every path this module emits: a territory's roots and its manifest are
|
|
13
|
+
// relative to the SURVEY ROOT, which is the service's own directory in a monorepo and the
|
|
14
|
+
// repository root otherwise. That is the frame the agent works in — the harness roots its checkout
|
|
15
|
+
// at `<clone>/<serviceDirectory>` — so it is the frame the manifest has to be written in, the
|
|
16
|
+
// frame the pass reports its reads and its findings in, and therefore the frame the scope check
|
|
17
|
+
// and the coverage intersection have to judge in. A repo-relative manifest handed to a service
|
|
18
|
+
// agent lists paths it cannot open, and every finding it reports back lands outside every root.
|
|
19
|
+
// The tree read is repo-relative, so the prefix is stripped ONCE, here, in `fishableFiles`.
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
/**
|
|
22
|
+
* Target source tokens per territory: roughly what one pass can read a meaningful share of with
|
|
23
|
+
* ranged reads. Bytes / 4 over the tree's blob sizes, so it is an estimate by construction, which
|
|
24
|
+
* is why the persisted field is named `approxTokens`.
|
|
25
|
+
*/
|
|
26
|
+
const TARGET_TERRITORY_TOKENS = 150_000;
|
|
27
|
+
/** No territory may exceed twice the target; one that would is split along its sub-directories. */
|
|
28
|
+
const MAX_TERRITORY_TOKENS = TARGET_TERRITORY_TOKENS * 2;
|
|
29
|
+
/** Bytes per token, the estimator every sizing decision here uses. */
|
|
30
|
+
const BYTES_PER_TOKEN = 4;
|
|
31
|
+
/**
|
|
32
|
+
* What a file with no reported size is assumed to weigh.
|
|
33
|
+
*
|
|
34
|
+
* GitHub's tree read carries a blob size per file; GitLab's does not. Rather than sizing a GitLab
|
|
35
|
+
* repository as weightless (which would pack the whole codebase into one territory and silently
|
|
36
|
+
* undo the partition), a size-less entry counts as a middling source file. The estimate is stated
|
|
37
|
+
* here in one place so the failure mode is "territories are sized coarsely" rather than "sizing
|
|
38
|
+
* silently stopped applying on one provider".
|
|
39
|
+
*/
|
|
40
|
+
const ASSUMED_FILE_BYTES = 4_000;
|
|
41
|
+
/**
|
|
42
|
+
* Paths never worth fishing: generated output, vendored trees, dependency directories, lockfiles
|
|
43
|
+
* and fixtures. The finding bar cannot be applied to code nobody in this repository wrote, and a
|
|
44
|
+
* territory packed with `dist/` is budget spent on nothing.
|
|
45
|
+
*
|
|
46
|
+
* The vocabulary the file-size ratchet skips (`scripts/check-file-size.mjs`'s `SKIP_DIRS`) plus
|
|
47
|
+
* the generated/vendored shapes that ratchet never has to see, because it scans a checkout and
|
|
48
|
+
* this reads a provider's whole tree.
|
|
49
|
+
*/
|
|
50
|
+
const IGNORED_DIR_SEGMENTS = new Set([
|
|
51
|
+
'node_modules',
|
|
52
|
+
'dist',
|
|
53
|
+
'build',
|
|
54
|
+
'out',
|
|
55
|
+
'vendor',
|
|
56
|
+
'vendored',
|
|
57
|
+
'third_party',
|
|
58
|
+
'coverage',
|
|
59
|
+
'.git',
|
|
60
|
+
'.turbo',
|
|
61
|
+
'.nuxt',
|
|
62
|
+
'.output',
|
|
63
|
+
'.next',
|
|
64
|
+
'.venv',
|
|
65
|
+
'.stryker-tmp',
|
|
66
|
+
'__snapshots__',
|
|
67
|
+
'__pycache__',
|
|
68
|
+
]);
|
|
69
|
+
/** File names that are generated or otherwise not source anybody reads for defects. */
|
|
70
|
+
const IGNORED_FILE_NAMES = new Set([
|
|
71
|
+
'pnpm-lock.yaml',
|
|
72
|
+
'package-lock.json',
|
|
73
|
+
'yarn.lock',
|
|
74
|
+
'bun.lockb',
|
|
75
|
+
'poetry.lock',
|
|
76
|
+
'Cargo.lock',
|
|
77
|
+
'go.sum',
|
|
78
|
+
'composer.lock',
|
|
79
|
+
'Gemfile.lock',
|
|
80
|
+
]);
|
|
81
|
+
/** A file name suffix that marks generated output regardless of where it sits. */
|
|
82
|
+
const IGNORED_FILE_SUFFIXES = ['.generated.ts', '.generated.js', '.min.js', '.snap', '.map'];
|
|
83
|
+
/**
|
|
84
|
+
* A file that marks the directory it sits in as a PACKAGE boundary. A territory stops here rather
|
|
85
|
+
* than packing across it, because a package is a unit somebody already decided was cohesive, and
|
|
86
|
+
* "has something else already handled it?" is answered inside one far more often than across two.
|
|
87
|
+
*/
|
|
88
|
+
const PACKAGE_MARKERS = new Set([
|
|
89
|
+
'package.json',
|
|
90
|
+
'pyproject.toml',
|
|
91
|
+
'setup.py',
|
|
92
|
+
'go.mod',
|
|
93
|
+
'Cargo.toml',
|
|
94
|
+
'pom.xml',
|
|
95
|
+
'build.gradle',
|
|
96
|
+
'build.gradle.kts',
|
|
97
|
+
'composer.json',
|
|
98
|
+
'Gemfile',
|
|
99
|
+
]);
|
|
100
|
+
/**
|
|
101
|
+
* The id and label stem for the files sitting DIRECTLY in a root, beside its sub-directories.
|
|
102
|
+
*
|
|
103
|
+
* They are a group in their own right rather than a claim on the root itself: see
|
|
104
|
+
* {@link groupByChildDirectory} for why owning the root would be either an over-claim or, at the
|
|
105
|
+
* survey root, nothing at all.
|
|
106
|
+
*/
|
|
107
|
+
const LOOSE_FILES_SEGMENT = 'root-files';
|
|
108
|
+
/** The label those loose files get, under a root and at the survey root. */
|
|
109
|
+
function looseFilesLabel(root) {
|
|
110
|
+
return root ? `${root} (files)` : 'Top-level files';
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Whether any of a candidate's roots is a directory carrying a package marker.
|
|
114
|
+
*
|
|
115
|
+
* Asked of every root rather than only of a lone one: a candidate that already packed two
|
|
116
|
+
* directories together is exactly the one that must stop packing when the next is a package, and
|
|
117
|
+
* the earlier "only when there is a single root" reading meant the first pack disabled the
|
|
118
|
+
* boundary check for everything after it.
|
|
119
|
+
*/
|
|
120
|
+
function isPackageRoot(candidate) {
|
|
121
|
+
return candidate.roots.some((root) => {
|
|
122
|
+
const prefix = root ? `${root}/` : '';
|
|
123
|
+
return candidate.files.some((file) => file.path.startsWith(prefix) && PACKAGE_MARKERS.has(file.path.slice(prefix.length)));
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/** Whether a repo-relative path is source the expedition should fish. */
|
|
127
|
+
export function isFishablePath(path) {
|
|
128
|
+
if (!path)
|
|
129
|
+
return false;
|
|
130
|
+
const segments = path.split('/');
|
|
131
|
+
const name = segments[segments.length - 1] ?? '';
|
|
132
|
+
if (segments.some((segment) => IGNORED_DIR_SEGMENTS.has(segment)))
|
|
133
|
+
return false;
|
|
134
|
+
if (IGNORED_FILE_NAMES.has(name))
|
|
135
|
+
return false;
|
|
136
|
+
return !IGNORED_FILE_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
137
|
+
}
|
|
138
|
+
/** Normalise a repo-relative path: no leading or trailing slash, no `./`. */
|
|
139
|
+
function normalizePath(path) {
|
|
140
|
+
return path.replace(/^\.\//, '').replace(/^\/+/, '').replace(/\/+$/, '');
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The fishable FILES of a tree, scoped to the survey root, sized, and REBASED onto that root.
|
|
144
|
+
*
|
|
145
|
+
* Directories are dropped here rather than filtered at each later step: a territory is a set of
|
|
146
|
+
* files, and a `dir` entry carries no bytes to size it with. The ignore rules are applied to the
|
|
147
|
+
* FULL repo path, before the rebase, so `packages/api/dist` is still recognised as generated
|
|
148
|
+
* output once the prefix is gone.
|
|
149
|
+
*/
|
|
150
|
+
function fishableFiles(entries, root) {
|
|
151
|
+
const prefix = root ? `${root}/` : '';
|
|
152
|
+
const files = [];
|
|
153
|
+
for (const entry of entries) {
|
|
154
|
+
if (entry.type !== 'file')
|
|
155
|
+
continue;
|
|
156
|
+
const path = normalizePath(entry.path);
|
|
157
|
+
if (prefix && !path.startsWith(prefix))
|
|
158
|
+
continue;
|
|
159
|
+
if (!isFishablePath(path))
|
|
160
|
+
continue;
|
|
161
|
+
files.push({
|
|
162
|
+
path: path.slice(prefix.length),
|
|
163
|
+
bytes: typeof entry.size === 'number' ? entry.size : ASSUMED_FILE_BYTES,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Shas of the tree's entries, keyed by normalised REPO-relative path.
|
|
170
|
+
*
|
|
171
|
+
* Directories and files both: a territory root is usually a directory, whose subtree sha answers
|
|
172
|
+
* "has this changed since it was fished" with a string compare, but the loose-files group's roots
|
|
173
|
+
* are individual files, and a blob sha answers exactly the same question about one of those.
|
|
174
|
+
*/
|
|
175
|
+
function entryShas(entries) {
|
|
176
|
+
const shas = new Map();
|
|
177
|
+
for (const entry of entries) {
|
|
178
|
+
if (entry.sha)
|
|
179
|
+
shas.set(normalizePath(entry.path), entry.sha);
|
|
180
|
+
}
|
|
181
|
+
return shas;
|
|
182
|
+
}
|
|
183
|
+
function tokensOf(files) {
|
|
184
|
+
return Math.round(files.reduce((sum, file) => sum + file.bytes, 0) / BYTES_PER_TOKEN);
|
|
185
|
+
}
|
|
186
|
+
/** The slug a territory id is built from: path-shaped, safe to read and to put in a log field. */
|
|
187
|
+
function territorySlug(idBase) {
|
|
188
|
+
const slug = idBase.replace(/[^a-zA-Z0-9._/-]/g, '-').replace(/\//g, '.');
|
|
189
|
+
return slug || WHOLE_CODEBASE_TERRITORY_ID;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Stamp a territory id that no other territory of this survey carries.
|
|
193
|
+
*
|
|
194
|
+
* Ids are DERIVED from paths, and derived ids collide: two blueprint modules whose first reference
|
|
195
|
+
* is the same directory produce the same stem, and so does a directory whose name happens to match
|
|
196
|
+
* the loose-files stem. A collision is not cosmetic — `filesByTerritory` is keyed by id, so the
|
|
197
|
+
* second territory would overwrite the first's manifest and every lookup by id would resolve both
|
|
198
|
+
* to one set of roots. Suffixing is enough because an id only has to be stable and distinct WITHIN
|
|
199
|
+
* one expedition: nothing looks a territory up across surveys (see the schema's note on why the
|
|
200
|
+
* label and roots are recorded rather than re-derived).
|
|
201
|
+
*/
|
|
202
|
+
function uniqueTerritoryId(stem, used) {
|
|
203
|
+
let id = stem;
|
|
204
|
+
for (let n = 2; used.has(id); n++)
|
|
205
|
+
id = `${stem}~${n}`;
|
|
206
|
+
used.add(id);
|
|
207
|
+
return id;
|
|
208
|
+
}
|
|
209
|
+
/** The label a human reads for a territory rooted at `root` (already in the survey frame). */
|
|
210
|
+
function labelForRoot(root) {
|
|
211
|
+
return root || 'Whole codebase';
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The single territory a codebase small enough to fish whole gets.
|
|
215
|
+
*
|
|
216
|
+
* The PASS-THROUGH: its phases carry no territory id, so the expedition is byte-for-byte the one
|
|
217
|
+
* that shipped before territories existed. Large-codebase mode is a size threshold crossed, never
|
|
218
|
+
* a mode a task opts into.
|
|
219
|
+
*/
|
|
220
|
+
export function wholeCodebaseTerritory(files) {
|
|
221
|
+
return {
|
|
222
|
+
id: WHOLE_CODEBASE_TERRITORY_ID,
|
|
223
|
+
label: 'Whole codebase',
|
|
224
|
+
roots: [],
|
|
225
|
+
fileCount: files.length,
|
|
226
|
+
approxTokens: tokensOf(files),
|
|
227
|
+
source: 'whole-codebase',
|
|
228
|
+
subtreeShas: [],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Group a set of files by their first path segment BELOW `root`, so a directory stays whole
|
|
233
|
+
* whenever it fits.
|
|
234
|
+
*
|
|
235
|
+
* Files sitting DIRECTLY in `root` form their own group, and that group owns its FILES rather than
|
|
236
|
+
* `root`. Owning `root` would be an over-claim wherever `root` is a real directory — it is a prefix
|
|
237
|
+
* over every sibling group here too, so a finding in one of them would be attributed to this one —
|
|
238
|
+
* and at the SURVEY root, where `root` is the empty string, it is worse than that: read as a
|
|
239
|
+
* prefix, the empty root matches no path at all, so every finding a pass raised on a top-level file
|
|
240
|
+
* was dropped as out of scope, and the empty id it derived was falsy enough that the pass was
|
|
241
|
+
* dispatched with no manifest and no scope in the first place.
|
|
242
|
+
*/
|
|
243
|
+
function groupByChildDirectory(files, root) {
|
|
244
|
+
const directories = new Map();
|
|
245
|
+
const loose = [];
|
|
246
|
+
const prefixLength = root ? root.length + 1 : 0;
|
|
247
|
+
for (const file of files) {
|
|
248
|
+
const rest = file.path.slice(prefixLength);
|
|
249
|
+
const slash = rest.indexOf('/');
|
|
250
|
+
if (slash === -1) {
|
|
251
|
+
loose.push(file);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const child = rest.slice(0, slash);
|
|
255
|
+
const key = root ? `${root}/${child}` : child;
|
|
256
|
+
const bucket = directories.get(key);
|
|
257
|
+
if (bucket)
|
|
258
|
+
bucket.push(file);
|
|
259
|
+
else
|
|
260
|
+
directories.set(key, [file]);
|
|
261
|
+
}
|
|
262
|
+
const groups = [...directories.entries()].map(([key, groupFiles]) => ({
|
|
263
|
+
key,
|
|
264
|
+
idBase: key,
|
|
265
|
+
roots: [key],
|
|
266
|
+
label: labelForRoot(key),
|
|
267
|
+
files: groupFiles,
|
|
268
|
+
}));
|
|
269
|
+
if (loose.length > 0) {
|
|
270
|
+
groups.push({
|
|
271
|
+
// A trailing slash sorts the loose group immediately before the child directories of the
|
|
272
|
+
// same root, and the survey root's loose group first of all.
|
|
273
|
+
key: root ? `${root}/` : '',
|
|
274
|
+
idBase: root ? `${root}/${LOOSE_FILES_SEGMENT}` : LOOSE_FILES_SEGMENT,
|
|
275
|
+
roots: loose.map((file) => file.path),
|
|
276
|
+
label: looseFilesLabel(root),
|
|
277
|
+
files: loose,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return groups.sort((a, b) => a.key.localeCompare(b.key));
|
|
281
|
+
}
|
|
282
|
+
/** A file group as a directory-sourced candidate. */
|
|
283
|
+
function directoryCandidate(group) {
|
|
284
|
+
return {
|
|
285
|
+
idBase: group.idBase,
|
|
286
|
+
roots: group.roots,
|
|
287
|
+
labels: [group.label],
|
|
288
|
+
files: group.files,
|
|
289
|
+
source: 'directory',
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Split a candidate that is over the hard ceiling along its own sub-directories, recursively.
|
|
294
|
+
*
|
|
295
|
+
* A group that cannot be split further (one directory whose own files exceed the ceiling) is
|
|
296
|
+
* KEPT oversized rather than chopped at an arbitrary file boundary: a territory is meant to be a
|
|
297
|
+
* unit somebody could reason about, and half of one is worse for the finding bar than a big one.
|
|
298
|
+
*/
|
|
299
|
+
function splitOversized(candidate) {
|
|
300
|
+
if (tokensOf(candidate.files) <= MAX_TERRITORY_TOKENS)
|
|
301
|
+
return [candidate];
|
|
302
|
+
const root = candidate.roots[0];
|
|
303
|
+
if (candidate.roots.length !== 1 || root === undefined) {
|
|
304
|
+
// A multi-root candidate over the ceiling is a blueprint module spanning several references
|
|
305
|
+
// (packing runs after this), so give each reference its own territory rather than chopping the
|
|
306
|
+
// module at a file boundary.
|
|
307
|
+
return candidate.roots
|
|
308
|
+
.map((r) => ({
|
|
309
|
+
idBase: r,
|
|
310
|
+
roots: [r],
|
|
311
|
+
labels: [labelForRoot(r)],
|
|
312
|
+
files: candidate.files.filter((f) => f.path === r || f.path.startsWith(`${r}/`)),
|
|
313
|
+
source: candidate.source,
|
|
314
|
+
}))
|
|
315
|
+
.filter((unpacked) => unpacked.files.length > 0)
|
|
316
|
+
.flatMap(splitOversized);
|
|
317
|
+
}
|
|
318
|
+
const groups = groupByChildDirectory(candidate.files, root);
|
|
319
|
+
if (groups.length <= 1)
|
|
320
|
+
return [candidate];
|
|
321
|
+
return groups.flatMap((group) => splitOversized({ ...directoryCandidate(group), source: candidate.source }));
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Pack small candidates together up to the target size, keeping catalog order.
|
|
325
|
+
*
|
|
326
|
+
* Sibling directories of a few hundred lines each are not worth their own dispatch: eight angles
|
|
327
|
+
* over a five-file territory spends the pass budget on orientation. Packing is ordered rather
|
|
328
|
+
* than best-fit so two surveys of the same tree produce the same partition.
|
|
329
|
+
*/
|
|
330
|
+
function packSmall(candidates) {
|
|
331
|
+
const packed = [];
|
|
332
|
+
for (const candidate of candidates) {
|
|
333
|
+
const previous = packed[packed.length - 1];
|
|
334
|
+
if (previous &&
|
|
335
|
+
previous.source === candidate.source &&
|
|
336
|
+
!isPackageRoot(candidate) &&
|
|
337
|
+
!isPackageRoot(previous) &&
|
|
338
|
+
tokensOf(previous.files) + tokensOf(candidate.files) <= TARGET_TERRITORY_TOKENS) {
|
|
339
|
+
previous.roots.push(...candidate.roots);
|
|
340
|
+
previous.labels.push(...candidate.labels);
|
|
341
|
+
previous.files.push(...candidate.files);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
packed.push({
|
|
345
|
+
idBase: candidate.idBase,
|
|
346
|
+
roots: [...candidate.roots],
|
|
347
|
+
labels: [...candidate.labels],
|
|
348
|
+
files: [...candidate.files],
|
|
349
|
+
source: candidate.source,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
return packed;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* A blueprint module's references, in the SURVEY root's frame.
|
|
356
|
+
*
|
|
357
|
+
* A reference is written by whoever ran the Blueprinter, and the two authorings differ by exactly
|
|
358
|
+
* the service prefix: an agent rooted at the service directory writes `src/billing`, while one
|
|
359
|
+
* that saw the repository root writes `packages/api/src/billing`. Both name the same code, so the
|
|
360
|
+
* prefix is stripped where it is present rather than assumed either way. A reference that matches
|
|
361
|
+
* nothing is dropped downstream, which is what makes normalising safe: nothing here can move a
|
|
362
|
+
* module onto code it does not name.
|
|
363
|
+
*/
|
|
364
|
+
function blueprintReferenceRoots(module, serviceRoot) {
|
|
365
|
+
return (module.references ?? [])
|
|
366
|
+
.map((reference) => normalizePath(reference))
|
|
367
|
+
.map((reference) => serviceRoot && (reference === serviceRoot || reference.startsWith(`${serviceRoot}/`))
|
|
368
|
+
? reference.slice(serviceRoot.length).replace(/^\/+/, '')
|
|
369
|
+
: reference)
|
|
370
|
+
.filter((reference) => reference.length > 0);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* The blueprint's own decomposition as candidates, plus whatever it does not cover.
|
|
374
|
+
*
|
|
375
|
+
* A blueprint's `references` were written by a model against an older tree, so a reference the
|
|
376
|
+
* tree no longer has is DROPPED and its module falls through to the directory rule for its part
|
|
377
|
+
* of the tree, never guessed onto a new home. Anything no module claims is partitioned by the
|
|
378
|
+
* directory rule too, so a partial blueprint narrows the heuristic rather than replacing it.
|
|
379
|
+
*/
|
|
380
|
+
function blueprintCandidates(files, blueprint, serviceRoot) {
|
|
381
|
+
const claimed = new Set();
|
|
382
|
+
const candidates = [];
|
|
383
|
+
for (const module of blueprint.modules ?? []) {
|
|
384
|
+
const roots = blueprintReferenceRoots(module, serviceRoot);
|
|
385
|
+
const moduleFiles = files.filter((file) => !claimed.has(file.path) &&
|
|
386
|
+
roots.some((root) => file.path === root || file.path.startsWith(`${root}/`)));
|
|
387
|
+
if (moduleFiles.length === 0)
|
|
388
|
+
continue;
|
|
389
|
+
for (const file of moduleFiles)
|
|
390
|
+
claimed.add(file.path);
|
|
391
|
+
// The module NAME is both the better label and the better id stem: it is what the person who
|
|
392
|
+
// decomposed the service called this, and unlike the first reference it distinguishes two
|
|
393
|
+
// modules that happen to share one.
|
|
394
|
+
const name = module.name?.trim() ?? '';
|
|
395
|
+
candidates.push({
|
|
396
|
+
idBase: name || (roots[0] ?? ''),
|
|
397
|
+
roots,
|
|
398
|
+
labels: [name || roots.map(labelForRoot).join(', ')],
|
|
399
|
+
files: moduleFiles,
|
|
400
|
+
source: 'blueprint',
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return { candidates, unclaimed: files.filter((file) => !claimed.has(file.path)) };
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Partition a repository tree into the territories an expedition fishes.
|
|
407
|
+
*
|
|
408
|
+
* Blueprint modules first when the repository has a blueprint, then package and directory
|
|
409
|
+
* boundaries under the survey root, sized by the tree's blob bytes. A codebase that fits one
|
|
410
|
+
* territory yields exactly one, and the expedition it plans is today's.
|
|
411
|
+
*/
|
|
412
|
+
export function partitionCodebase(tree, options = {}) {
|
|
413
|
+
const serviceRoot = normalizePath(options.serviceDirectory ?? '');
|
|
414
|
+
const files = fishableFiles(tree.entries, serviceRoot);
|
|
415
|
+
const shas = entryShas(tree.entries);
|
|
416
|
+
const filesByTerritory = new Map();
|
|
417
|
+
if (tokensOf(files) <= MAX_TERRITORY_TOKENS) {
|
|
418
|
+
const only = wholeCodebaseTerritory(files);
|
|
419
|
+
filesByTerritory.set(only.id, files);
|
|
420
|
+
return { territories: [only], filesByTerritory, treeTruncated: tree.truncated };
|
|
421
|
+
}
|
|
422
|
+
const blueprint = options.blueprint
|
|
423
|
+
? blueprintCandidates(files, options.blueprint, serviceRoot)
|
|
424
|
+
: { candidates: [], unclaimed: files };
|
|
425
|
+
const byDirectory = groupByChildDirectory(blueprint.unclaimed, '').map(directoryCandidate);
|
|
426
|
+
const candidates = packSmall([...blueprint.candidates, ...byDirectory].flatMap((candidate) => splitOversized(candidate)));
|
|
427
|
+
const usedIds = new Set();
|
|
428
|
+
const territories = candidates.map((candidate) => {
|
|
429
|
+
const id = uniqueTerritoryId(territorySlug(candidate.idBase), usedIds);
|
|
430
|
+
filesByTerritory.set(id, candidate.files);
|
|
431
|
+
return {
|
|
432
|
+
id,
|
|
433
|
+
label: candidate.labels.join(', '),
|
|
434
|
+
roots: candidate.roots,
|
|
435
|
+
fileCount: candidate.files.length,
|
|
436
|
+
approxTokens: tokensOf(candidate.files),
|
|
437
|
+
source: candidate.source,
|
|
438
|
+
// The sha map is keyed in the tree's own repo-relative frame, so the survey-framed root goes
|
|
439
|
+
// back through the service prefix to look itself up.
|
|
440
|
+
subtreeShas: candidate.roots.map((root) => shas.get(serviceRoot ? `${serviceRoot}/${root}` : root) ?? ''),
|
|
441
|
+
};
|
|
442
|
+
});
|
|
443
|
+
return { territories, filesByTerritory, treeTruncated: tree.truncated };
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Build the pass list from the territories and the angles, TERRITORY-MAJOR, trimmed to the pass
|
|
447
|
+
* budget.
|
|
448
|
+
*
|
|
449
|
+
* Territory-major so a human gets a complete answer for one territory early and can start its
|
|
450
|
+
* fixes while the rest is still being fished, which is what the separate-dispatch design is for.
|
|
451
|
+
* The budget trims from the BOTTOM of the order rather than the middle, and what it cuts is
|
|
452
|
+
* returned as unfished: a cap silent about its tail teaches the reader that the tail was clean.
|
|
453
|
+
*
|
|
454
|
+
* A single whole-codebase territory yields the angles unchanged, with no territory stamped on
|
|
455
|
+
* them, so a small codebase's plan is field-for-field the one that shipped before territories.
|
|
456
|
+
*/
|
|
457
|
+
export function planTerritoryPasses(input) {
|
|
458
|
+
const { territories, angles, passBudget } = input;
|
|
459
|
+
const only = territories[0];
|
|
460
|
+
if (territories.length === 0 || (territories.length === 1 && only?.source === 'whole-codebase')) {
|
|
461
|
+
// The whole-codebase branch names its cut cells from the ANGLES rather than from a cell list,
|
|
462
|
+
// because a survey that could not read the repository hands over no territory to build cells
|
|
463
|
+
// from — and the budget can cut angles all the same. Deriving the tail from the cells left the
|
|
464
|
+
// one case the record exists for, a cut nobody can see, as the one case it did not cover.
|
|
465
|
+
return {
|
|
466
|
+
phases: angles.slice(0, passBudget),
|
|
467
|
+
unfished: angles.slice(passBudget).map((phase) => ({
|
|
468
|
+
territoryId: only?.id ?? WHOLE_CODEBASE_TERRITORY_ID,
|
|
469
|
+
territoryLabel: only?.label ?? 'Whole codebase',
|
|
470
|
+
phaseId: phase.id,
|
|
471
|
+
phaseTitle: phase.title,
|
|
472
|
+
})),
|
|
473
|
+
plannedCells: angles.length,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const cells = territories.flatMap((territory) => angles.map((phase) => ({ territory, phase })));
|
|
477
|
+
const kept = cells.slice(0, passBudget);
|
|
478
|
+
return {
|
|
479
|
+
phases: kept.map(({ territory, phase }) => ({
|
|
480
|
+
...phase,
|
|
481
|
+
territoryId: territory.id,
|
|
482
|
+
territoryLabel: territory.label,
|
|
483
|
+
})),
|
|
484
|
+
unfished: unfishedFor(cells.slice(passBudget)),
|
|
485
|
+
plannedCells: cells.length,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
function unfishedFor(cells) {
|
|
489
|
+
return cells.map(({ territory, phase }) => ({
|
|
490
|
+
territoryId: territory.id,
|
|
491
|
+
territoryLabel: territory.label,
|
|
492
|
+
phaseId: phase.id,
|
|
493
|
+
phaseTitle: phase.title,
|
|
494
|
+
}));
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Order the territories a large expedition fishes, most worth fishing first.
|
|
498
|
+
*
|
|
499
|
+
* The creator's `fishingFocus` comes first, because naming a subsystem is the deliberate act and
|
|
500
|
+
* a budget that cut it would be cutting the one thing they asked for. Size decides the rest: with
|
|
501
|
+
* no scout rating relevance yet, the biggest territory is the one most likely to hide something,
|
|
502
|
+
* and it is a fact the platform can compute rather than a judgement it would be inventing.
|
|
503
|
+
*/
|
|
504
|
+
export function prioritiseTerritories(territories, focus) {
|
|
505
|
+
const needles = (focus ?? '')
|
|
506
|
+
.toLowerCase()
|
|
507
|
+
.split(/[\s,;]+/)
|
|
508
|
+
.map((needle) => needle.trim())
|
|
509
|
+
.filter((needle) => needle.length >= 3);
|
|
510
|
+
const focused = (territory) => needles.some((needle) => territory.label.toLowerCase().includes(needle) ||
|
|
511
|
+
(territory.roots ?? []).some((root) => root.toLowerCase().includes(needle)));
|
|
512
|
+
return [...territories].sort((a, b) => {
|
|
513
|
+
const byFocus = Number(focused(b)) - Number(focused(a));
|
|
514
|
+
if (byFocus !== 0)
|
|
515
|
+
return byFocus;
|
|
516
|
+
return (b.approxTokens ?? 0) - (a.approxTokens ?? 0);
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
//# sourceMappingURL=bugFishingTerritories.logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bugFishingTerritories.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/bugFishingTerritories.logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ import type { BinaryCandidateController } from './BinaryCandidateController.js';
|
|
|
11
11
|
import type { ForkDecisionController } from './ForkDecisionController.js';
|
|
12
12
|
import { PrReviewController } from './PrReviewController.js';
|
|
13
13
|
import { BugFishingController } from './BugFishingController.js';
|
|
14
|
+
import type { CodebaseSurveyResult } from './bugFishingSurvey.js';
|
|
14
15
|
import type { InterviewGateController } from './InterviewGateController.js';
|
|
15
16
|
import type { TesterController } from './TesterController.js';
|
|
16
17
|
import type { RalphController } from './RalphController.js';
|
|
@@ -68,6 +69,13 @@ export interface DispatcherRegistryDeps {
|
|
|
68
69
|
handleForkDecisionPhase: (ctx: StepHandlerContext) => Promise<AdvanceResult>;
|
|
69
70
|
handlePrReviewResolution: (ctx: StepHandlerContext) => Promise<AdvanceResult>;
|
|
70
71
|
handleAgentStep: (ctx: StepHandlerContext, dispatchKind?: string, augmentContext?: (context: AgentRunContext) => void) => Promise<AdvanceResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Survey the codebase a block's run targets: the repository tree partitioned into the
|
|
74
|
+
* TERRITORIES a bug-fishing expedition fishes. Bound to the dispatcher, which owns the run's
|
|
75
|
+
* repo resolution; the read is cached per ref, so the dispatch and completion paths of one
|
|
76
|
+
* expedition share it.
|
|
77
|
+
*/
|
|
78
|
+
surveyCodebase: (workspaceId: string, blockId: string) => Promise<CodebaseSurveyResult>;
|
|
71
79
|
ingestBlueprint: (workspaceId: string, blockId: string, rawService: unknown) => Promise<void>;
|
|
72
80
|
ingestSpec: (workspaceId: string, rawDoc: unknown) => Promise<void>;
|
|
73
81
|
}
|