[Self-Heal] Add self-scheduling auto-repair workflow#60
Conversation
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
There was a problem hiding this comment.
Code Review
This pull request introduces a self-adapting, self-healing automated repair pipeline, adding setup documentation, ESLint configuration, and scripts to compute schedules, run healthchecks, and execute repair steps. Key feedback includes resolving a fatal ESLint error caused by the invalid preserve-caught-error rule, and ensuring self_heal.mjs exits with code 0 instead of 1 when the initial healthcheck passes to prevent workflow failures. Additionally, it is recommended to split the chained lint and format commands, add defensive checks for empty or invalid YAML configurations, verify successful cron schedule updates, and remove a redundant TypeScript compilation step to optimize execution speed.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| 'prefer-const': 'warn', | ||
| 'preserve-caught-error': 'warn' |
| if (checkHealth()) { | ||
| console.log('✅ Initial healthcheck passed. No repairs needed.'); | ||
| process.exit(1); // Exit 1 to prevent PR creation if no repairs are needed. | ||
| } |
There was a problem hiding this comment.
Exiting with code 1 when the initial healthcheck passes will cause the GitHub Actions workflow run to be marked as failed. Since a healthy repository is a successful state, the script should exit with 0. The subsequent PR creation step in the workflow will naturally skip creating a PR if there are no git changes.
| if (checkHealth()) { | |
| console.log('✅ Initial healthcheck passed. No repairs needed.'); | |
| process.exit(1); // Exit 1 to prevent PR creation if no repairs are needed. | |
| } | |
| if (checkHealth()) { | |
| console.log('✅ Initial healthcheck passed. No repairs needed.'); | |
| process.exit(0); | |
| } |
| if (existsSync(SCHEDULE_FILE)) { | ||
| try { | ||
| currentConfig = yaml.load(readFileSync(SCHEDULE_FILE, 'utf8')); | ||
| } catch (e) { | ||
| console.warn('Could not parse existing schedule file, using defaults.'); | ||
| } | ||
| } |
There was a problem hiding this comment.
If the .github/self-heal-schedule.yml file is empty or invalid, yaml.load can return null or undefined. Accessing properties on it later (e.g., currentConfig.last_updated) will throw a TypeError and crash the script. It is safer to defensively verify that the parsed result is an object before merging it.
if (existsSync(SCHEDULE_FILE)) {
try {
const parsed = yaml.load(readFileSync(SCHEDULE_FILE, 'utf8'));
if (parsed && typeof parsed === 'object') {
currentConfig = Object.assign({}, currentConfig, parsed);
}
} catch (e) {
console.warn('Could not parse existing schedule file, using defaults.');
}
}| let content = readFileSync(WORKFLOW_FILE, 'utf8'); | ||
| // Regex matches the cron line with the inline marker | ||
| content = content.replace( | ||
| /cron:\s*['"][^'"]+['"]\s*#\s*AUTO-UPDATED/, | ||
| `cron: "${newSchedule}" # AUTO-UPDATED` | ||
| ); | ||
| writeFileSync(WORKFLOW_FILE, content, 'utf8'); | ||
| console.log('Successfully updated self-heal.yml workflow.'); |
There was a problem hiding this comment.
If the regex replacement does not find a match (for example, if the # AUTO-UPDATED marker is missing or formatted differently), content.replace will silently do nothing, and the script will write the unmodified content back while still logging a success message. Adding a check to verify if the content actually changed provides better visibility and prevents silent failures.
let content = readFileSync(WORKFLOW_FILE, 'utf8');
const updatedContent = content.replace(
/cron:\s*['"][^'"]+['"]\s*#\s*AUTO-UPDATED/,
'cron: "' + newSchedule + '" # AUTO-UPDATED'
);
if (content === updatedContent) {
console.warn('Warning: Could not find a matching cron schedule with the "# AUTO-UPDATED" marker in self-heal.yml.');
} else {
writeFileSync(WORKFLOW_FILE, updatedContent, 'utf8');
console.log('Successfully updated self-heal.yml workflow.');
}| const steps = [ | ||
| { name: '1. Rebuild/reinstall', cmd: 'npm install' }, | ||
| { name: '2. Lint/format auto-fix', cmd: 'npx eslint --fix . && npx prettier --write .' }, | ||
| { name: '3. Snapshot/generated updates', cmd: 'npx vitest run -u --passWithNoTests' }, | ||
| { name: '4. Type stubs/analyzer config', cmd: 'npx typesync || true' }, | ||
| { name: '5. Dependency re-resolve', cmd: 'npm update' }, | ||
| { name: '6. Static asset regeneration', cmd: 'npm run build' } | ||
| ]; |
There was a problem hiding this comment.
Chaining the lint and format commands with && means that if ESLint exits with a non-zero code (which happens when there are remaining un-fixable lint errors), the Prettier formatting step will be skipped entirely. Splitting them into separate steps ensures both run independently and are committed/healthchecked properly.
| const steps = [ | |
| { name: '1. Rebuild/reinstall', cmd: 'npm install' }, | |
| { name: '2. Lint/format auto-fix', cmd: 'npx eslint --fix . && npx prettier --write .' }, | |
| { name: '3. Snapshot/generated updates', cmd: 'npx vitest run -u --passWithNoTests' }, | |
| { name: '4. Type stubs/analyzer config', cmd: 'npx typesync || true' }, | |
| { name: '5. Dependency re-resolve', cmd: 'npm update' }, | |
| { name: '6. Static asset regeneration', cmd: 'npm run build' } | |
| ]; | |
| const steps = [ | |
| { name: '1. Rebuild/reinstall', cmd: 'npm install' }, | |
| { name: '2. Lint auto-fix', cmd: 'npx eslint --fix .' }, | |
| { name: '3. Format auto-fix', cmd: 'npx prettier --write .' }, | |
| { name: '4. Snapshot/generated updates', cmd: 'npx vitest run -u --passWithNoTests' }, | |
| { name: '5. Type stubs/analyzer config', cmd: 'npx typesync || true' }, | |
| { name: '6. Dependency re-resolve', cmd: 'npm update' }, | |
| { name: '7. Static asset regeneration', cmd: 'npm run build' } | |
| ]; |
| const main = () => { | ||
| const steps = [ | ||
| { name: 'TypeScript Compilation', cmd: 'npx tsc --build' }, | ||
| { name: 'Lint', cmd: 'npx eslint .' }, | ||
| { name: 'Build', cmd: 'npm run build' } | ||
| ]; |
There was a problem hiding this comment.
The TypeScript Compilation step is redundant because the subsequent Build step (npm run build) already runs tsc -build as part of its script. Removing this redundant step will significantly speed up the healthcheck, which is run multiple times during the self-heal pipeline.
const main = () => {
const steps = [
{ name: 'Lint', cmd: 'npx eslint .' },
{ name: 'Build', cmd: 'npm run build' }
];
[Self-Heal] Add self-scheduling auto-repair workflow
This PR introduces an automated, self-adapting repair pipeline to continuously detect and resolve code drift (e.g., formatting, outdated snapshots, or missing type stubs).
Triggers
ciworkflow fails.Self-Scheduling & Initial Telemetry
The pipeline adjusts its scheduled frequency based on project velocity (analyzed via commit frequency).
0 0 * * 0To manually override this schedule, modify
.github/self-heal-schedule.yml.Reviewer Checklist
When reviewing future self-healing PRs, always check:
For more details on the setup, view the
SELF_HEAL_SETUP.mddocumentation included in this commit.PR created automatically by Jules for task 11919046782672604664 started by @badMade