perf(gateguard): profile a change only when used and check its window first

This commit is contained in:
Jeffrey Montoya
2026-09-30 12:13:18 -04:00
parent d39fcd8ac3
commit 2ec52af6d0
5 changed files with 35 additions and 5 deletions
+11 -2
View File
@@ -1674,6 +1674,11 @@ function countTrivialAllow() {
return saveState({ ...state, trivial_allows: getTrivialAllowCount(state) + 1 });
}
// see docs/gateguard/change-profile.md#when-a-change-is-profiled
function needsProfile(toolName, cls) {
return targetClass().questionsUseProfile(cls) || ((toolName === 'Edit' || toolName === 'MultiEdit') && TRIVIAL_CLASSES.has(cls)) || isMetricsEnabled();
}
function isTrivialChange(cls, restricted, profile) {
return !restricted && TRIVIAL_CLASSES.has(cls) && Boolean(profile) && profile.known === true && profile.trivial === true;
}
@@ -2332,7 +2337,9 @@ function gate(rawInput) {
recordDecision('credit', 'prior-search', { target: filePath, cls, sensitive });
return { additionalContext: creditNote(credit, filePath), exitCode: 0 };
}
const profile = restricted || toolName === 'NotebookEdit' ? null : changeProfileFor(toolName, filePath, [toolInput], toolInput.content, data);
const profile = restricted || toolName === 'NotebookEdit' || !needsProfile(toolName, cls)
? null
: changeProfileFor(toolName, filePath, [toolInput], toolInput.content, data);
if (toolName === 'Edit' && isTrivialChange(cls, restricted, profile)) {
if (!countTrivialAllow()) {
return allowWithStateWarning();
@@ -2406,7 +2413,9 @@ function gate(rawInput) {
notes.push(creditNote(credit, filePath));
continue;
}
const profile = restricted ? null : changeProfileFor('Edit', filePath, entriesFor(edits, fileKey, data), undefined, data);
const profile = restricted || !needsProfile('MultiEdit', cls)
? null
: changeProfileFor('Edit', filePath, entriesFor(edits, fileKey, data), undefined, data);
if (isTrivialChange(cls, restricted, profile)) {
if (!countTrivialAllow()) {
return allowWithStateWarning();
+3 -2
View File
@@ -708,12 +708,13 @@ function trivialInFile(pairs, fileText, spec) {
const start = windowStart(text, found.first);
const end = windowEnd(text, found.last + oldString.length);
work += start + 2 * (end - start);
if (end - start > MAX_WINDOW_CHARS || work > MAX_CONTEXT_WORK || !spec.startsFresh(text.slice(0, start), spec)) return false;
if (end - start > MAX_WINDOW_CHARS || work > MAX_CONTEXT_WORK) return false;
const before = text.slice(start, end);
const after = replaceAll
? before.split(oldString).join(newString)
: `${text.slice(start, found.first)}${newString}${text.slice(found.first + oldString.length, end)}`;
if (!isTrivialEdit(before, after, spec)) return false;
// see docs/gateguard/change-profile.md#file-context
if (!isTrivialEdit(before, after, spec) || !spec.startsFresh(text.slice(0, start), spec)) return false;
text = `${text.slice(0, start)}${after}${text.slice(end)}`;
if (text.length > MAX_FILE_CHARS) return false;
}
+6
View File
@@ -193,6 +193,11 @@ function codeQuestionIds(isWrite, profile) {
}
/** Stable ids of the first-touch questions for a class, action and change profile. */
/** True when a class's questions depend on the change profile. */
function questionsUseProfile(cls) {
return !Object.hasOwn(CLASS_QUESTION_IDS, cls);
}
function questionIdsFor(cls, isWrite, profile) {
const ids = Object.hasOwn(CLASS_QUESTION_IDS, cls) ? CLASS_QUESTION_IDS[cls](Boolean(isWrite)) : codeQuestionIds(Boolean(isWrite), profile);
return [...ids, 'quote-instruction'];
@@ -407,6 +412,7 @@ function collapseGateDir(filePath, data, cls) {
}
module.exports = {
questionsUseProfile,
WINDOWS_PATH_PATTERN,
COLLAPSIBLE_CLASSES,
CLASS_QUESTIONS,