Skip to content

[Self-Heal] Add self-scheduling auto-repair workflow#61

Draft
badMade wants to merge 1 commit into
mainfrom
feat/self-heal-automation-11992912434856171913
Draft

[Self-Heal] Add self-scheduling auto-repair workflow#61
badMade wants to merge 1 commit into
mainfrom
feat/self-heal-automation-11992912434856171913

Conversation

@badMade

@badMade badMade commented Jun 8, 2026

Copy link
Copy Markdown
Owner

This PR introduces an automated, self-adapting "self-healing" CI pipeline for maintaining code health, resolving drift, and handling routine fixes like dependency resolution and linting.

Key Components:

  1. Triggers: Scheduled runs (proactive), CI failures (reactive), and manual dispatches.
  2. Idempotent Repair Pipeline (scripts/self_heal.mjs): Reinstalls deps, formats/lints, regenerates snapshots, fetches types, updates deps, and rebuilds assets.
  3. Adaptive Scheduling (scripts/compute_schedule.mjs): A weekly workflow recalculates the frequency of the self-heal schedule based on repository PR velocity, saving CI time during dormant periods.
  4. Safety Gates: Built-in protections against infinite loops, concurrent duplicate PRs, drift outside allowed directories, and potential secret leaks.

See SELF_HEAL_SETUP.md for detailed reviewer checklists and manual override instructions.

Generated by Jules via Claude Code


PR created automatically by Jules for task 11992912434856171913 started by @badMade

Implements an adaptive self-healing CI pipeline that:
- Proactively checks for codebase drift on a schedule
- Reactively triggers on CI failures
- Includes an idempotent 6-step repair process (deps, lint, snapshots, etc.)
- Dynamically recalculates its own schedule based on PR telemetry
- Strictly gates repairs to ensure no logic is changed and secrets are protected

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an adaptive, automated self-healing pipeline to maintain codebase health, including scripts for computing schedules, running health checks, and executing repair steps, alongside ESLint and Prettier configurations. The review feedback highlights several critical issues: hasDiff() in the self-heal script incorrectly detects its own log file as a change, ESLint contains a non-existent rule (preserve-caught-error) that will cause it to crash, and the schedule computation script needs better error handling for telemetry failures and should avoid writing to the configuration file when the schedule remains unchanged to prevent unnecessary dirty git states.

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.

Comment thread scripts/self_heal.mjs
Comment on lines +33 to +36
function hasDiff() {
const status = execSync('git status --porcelain').toString().trim();
return status !== '';
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Since the script writes logs to repair.log in the workspace, git status --porcelain will always detect repair.log as an untracked/modified file. This causes hasDiff() to always return true, making the script exit early with a 'success' status after the very first step (npm ci), even if no actual repairs or changes were made to the codebase. We should filter out .log files when checking for git diffs.

Suggested change
function hasDiff() {
const status = execSync('git status --porcelain').toString().trim();
return status !== '';
}
function hasDiff() {
const status = execSync('git status --porcelain').toString().trim();
if (!status) return false;
const lines = status.split('\n').filter(line => {
const file = line.slice(3).trim();
return !file.endsWith('.log');
});
return lines.length > 0;
}

Comment thread eslint.config.mjs
Comment on lines +24 to +25
"prefer-const": "off",
"preserve-caught-error": "off"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The rule preserve-caught-error is not a standard ESLint or TypeScript ESLint rule. Including a non-existent rule in the configuration will cause ESLint to throw an error and crash, which in turn will fail the healthcheck script. You should remove this line.

      "prefer-const": "off"

Comment on lines +36 to +42
let prs = [];
try {
const output = execSync('gh pr list --state merged --json mergedAt --limit 100').toString();
prs = JSON.parse(output);
} catch (e) {
console.warn('Failed to fetch PR telemetry:', e.message);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the gh pr list command fails (e.g., due to rate limits, network issues, or missing authentication in CI), the prs array will remain empty. This will silently set recentPrs to 0 and downgrade the schedule to the 'Dormant tier (Weekly)' even if the repository is highly active. We should guard against this by skipping the schedule update if the telemetry fetch fails.

Suggested change
let prs = [];
try {
const output = execSync('gh pr list --state merged --json mergedAt --limit 100').toString();
prs = JSON.parse(output);
} catch (e) {
console.warn('Failed to fetch PR telemetry:', e.message);
}
let prs = [];
let telemetrySuccess = false;
try {
const output = execSync('gh pr list --state merged --json mergedAt --limit 100').toString();
prs = JSON.parse(output);
telemetrySuccess = true;
} catch (e) {
console.warn('Failed to fetch PR telemetry:', e.message);
}
if (!telemetrySuccess) {
console.log('Skipping schedule update due to telemetry fetch failure.');
process.exit(0);
}

Comment thread scripts/self_heal.mjs
Comment on lines +48 to +55
const steps = [
{ name: 'Rebuild/Reinstall', cmd: 'npm ci' },
{ name: 'Lint/Format Auto-fix', cmd: 'npx eslint . --fix && npx prettier -w .' },
{ name: 'Snapshot Regeneration', cmd: 'npx vitest run -u --passWithNoTests' },
{ name: 'Type Stubs', cmd: 'npx typesync || true' },
{ name: 'Dependency Re-resolve', cmd: 'npm update' },
{ name: 'Static Assets', cmd: 'npm run build' }
];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two main issues with the current repair steps:

  1. npx eslint . --fix && npx prettier -w . uses &&. If ESLint fails (e.g., due to unfixable syntax/lint errors), Prettier formatting will be skipped entirely. Splitting them into separate steps ensures both run independently.
  2. npx typesync only modifies package.json but does not install the newly added types. Running npm install immediately after is necessary so that the types are installed and package-lock.json is updated before the healthcheck runs.
Suggested change
const steps = [
{ name: 'Rebuild/Reinstall', cmd: 'npm ci' },
{ name: 'Lint/Format Auto-fix', cmd: 'npx eslint . --fix && npx prettier -w .' },
{ name: 'Snapshot Regeneration', cmd: 'npx vitest run -u --passWithNoTests' },
{ name: 'Type Stubs', cmd: 'npx typesync || true' },
{ name: 'Dependency Re-resolve', cmd: 'npm update' },
{ name: 'Static Assets', cmd: 'npm run build' }
];
const steps = [
{ name: 'Rebuild/Reinstall', cmd: 'npm ci' },
{ name: 'Lint Auto-fix', cmd: 'npx eslint . --fix || true' },
{ name: 'Format Auto-fix', cmd: 'npx prettier -w .' },
{ name: 'Snapshot Regeneration', cmd: 'npx vitest run -u --passWithNoTests' },
{ name: 'Type Stubs', cmd: 'npx typesync && npm install || npm install' },
{ name: 'Dependency Re-resolve', cmd: 'npm update' },
{ name: 'Static Assets', cmd: 'npm run build' }
];

Comment on lines +62 to +72
if (newSchedule === currentConfig.schedule) {
console.log('Schedule unchanged based on telemetry. No update needed.');
// We still update the lastUpdated timestamp so we don't keep checking
const newConfig = {
...currentConfig,
lastUpdated: now
};
const yamlOutput = yaml.dump(newConfig, { forceQuotes: true });
fs.writeFileSync(SCHEDULE_FILE, yamlOutput);
process.exit(0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When the computed schedule is unchanged, updating the lastUpdated timestamp and writing it back to .github/self-heal-schedule.yml will create a dirty git state. This will cause the CI workflow to commit the change and open a new PR every few days just to update a timestamp, creating unnecessary noise for maintainers. If the schedule is unchanged, we should simply exit without writing the file.

if (newSchedule === currentConfig.schedule) {
  console.log('Schedule unchanged based on telemetry. No update needed.');
  process.exit(0);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant