Skip to content

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

Draft
badMade wants to merge 1 commit into
mainfrom
selfheal-setup-913983608745794504
Draft

[Self-Heal] Add self-scheduling auto-repair workflow#52
badMade wants to merge 1 commit into
mainfrom
selfheal-setup-913983608745794504

Conversation

@badMade

@badMade badMade commented May 29, 2026

Copy link
Copy Markdown
Owner

Overview

This PR implements a robust, self-adapting, self-healing CI pipeline designed to automatically detect code drift, repair formatting/linting issues, update snapshots, sync types, and resolve dependency updates.

Created by Jules/Claude Code. See original chat context for full implementation details.

Triggers

This automation runs based on three distinct triggers:

  1. Scheduled: Runs on an adaptive computed cadence based on telemetry.
  2. Reactive: Triggers automatically when the ci workflow fails.
  3. Manual: Can be triggered manually via the GitHub Actions workflow_dispatch UI.

Initial Schedule & Rationale

Initial Schedule: 0 0 * * *
Rationale: Standard fallback schedule (daily at midnight). The system will compute real telemetry based on active PRs within a 7-day rolling window, starting on its first automated Sunday computation or manually triggered workflow execution.

Periodic Recompute

A separate workflow (compute-schedule.yml) evaluates PR merge velocity to intelligently step the daily/weekly cadence up or down based on repository activity, using safe YAML updates to avoid corruption.

Manual Overrides

To manually override the schedule:

  1. Modify .github/self-heal-schedule.yml with your desired SCHEDULE and RATIONALE.
  2. Update the timestamp in LAST_UPDATED (in ms since epoch).
  3. The automation will respect your change until it computes a significant velocity shift or the oscillation guard expires.

Reviewer Checklist

When reviewing a future selfheal-* PR, please verify:

  • No secrets or keys have been inadvertently committed.
  • The pre-check.log, repair.log, and post-check.log artifacts provide clear explanations for the automated changes.
  • Logic files (source code, tests aside from snapshots) have not been negatively impacted by the formatting/linting changes.
  • Dependency updates appear intentional and safe.

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

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 automated self-healing CI pipeline to address code drift, keep dependencies updated, format code, and sync types. It adds documentation, a telemetry-based scheduling script, a healthcheck script, and a main self-healing pipeline script, along with ESLint and Prettier configurations. The code review identified several key areas for improvement: the ESLint configuration currently enables no rules, rendering linting ineffective; the healthcheck evaluation in self_heal.mjs should ignore untracked files to prevent false positives; the schedule updater should verify regex matches before writing to prevent silent failures; and redundant || true command suffixes should be removed to preserve error logging.

Comment thread eslint.config.mjs
Comment on lines +1 to +29
export default [
{
ignores: [
"build/**",
"dist/**",
"coverage/**",
"bin/**",
"node_modules/**"
]
},
{
languageOptions: {
globals: {
console: "readonly",
process: "readonly",
setTimeout: "readonly",
clearTimeout: "readonly",
setInterval: "readonly",
clearInterval: "readonly",
__dirname: "readonly",
__filename: "readonly",
module: "readonly",
require: "readonly",
exports: "readonly",
Buffer: "readonly"
}
}
}
];

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 current ESLint configuration does not enable any rules or extend any recommended configurations. As a result, ESLint will run with zero rules enabled, making npx eslint --fix a no-op and rendering the linting step in the self-healing pipeline ineffective.

To fix this, import @eslint/js and extend js.configs.recommended (or your preferred base configuration). Note that you may also want to add @eslint/js to your devDependencies in package.json to ensure it is explicitly tracked.

import js from "@eslint/js";

export default [
  {
    ignores: [
      "build/**",
      "dist/**",
      "coverage/**",
      "bin/**",
      "node_modules/**"
    ]
  },
  js.configs.recommended,
  {
    languageOptions: {
      globals: {
        console: "readonly",
        process: "readonly",
        setTimeout: "readonly",
        clearTimeout: "readonly",
        setInterval: "readonly",
        clearInterval: "readonly",
        __dirname: "readonly",
        __filename: "readonly",
        module: "readonly",
        require: "readonly",
        exports: "readonly",
        Buffer: "readonly"
      }
    }
  }
];

Comment thread scripts/self_heal.mjs
Comment on lines +33 to +36
function hasDiff() {
const diff = execSync('git status --porcelain').toString().trim();
return diff.length > 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.

high

Using git status --porcelain to detect changes will include any untracked files (such as log files like pre-check.log, repair.log, post-check.log mentioned in the PR description, or temporary build artifacts) that are not explicitly ignored in .gitignore. This can lead to false positives where hasDiff() returns true even if no actual code repairs or modifications were made, causing the script to exit prematurely with 0.

To make this more robust, ensure that all log files and build artifacts are added to .gitignore, or refine hasDiff() to only check for changes in tracked files (e.g., using git status --porcelain -uno).

Suggested change
function hasDiff() {
const diff = execSync('git status --porcelain').toString().trim();
return diff.length > 0;
}
function hasDiff() {
const diff = execSync('git status --porcelain -uno').toString().trim();
return diff.length > 0;
}

Comment on lines +88 to +99
if (fs.existsSync(WORKFLOW_FILE)) {
let workflowContent = fs.readFileSync(WORKFLOW_FILE, 'utf8');
// Regex matches `- cron: "..." # AUTO-UPDATED`
const updatedWorkflow = workflowContent.replace(
/- cron: "[^"]+" # AUTO-UPDATED/,
`- cron: "${newSchedule.cron}" # AUTO-UPDATED`
);
fs.writeFileSync(WORKFLOW_FILE, updatedWorkflow, 'utf8');
console.log('Updated workflow file.');
} else {
console.warn('Workflow file not found to update!');
}

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

If the workflow file does not contain the exact pattern - cron: "[^"]+" # AUTO-UPDATED, the replace operation will silently fail (returning the original string) and the script will still print "Updated workflow file." and write the unmodified content back to disk.

To prevent this silent failure, verify that the regex pattern matches the workflow content before attempting to replace and write the file.

  if (fs.existsSync(WORKFLOW_FILE)) {
    const workflowContent = fs.readFileSync(WORKFLOW_FILE, 'utf8');
    const cronRegex = /- cron: "[^"]+" # AUTO-UPDATED/;
    if (cronRegex.test(workflowContent)) {
      const updatedWorkflow = workflowContent.replace(
        cronRegex,
        `- cron: "${newSchedule.cron}" # AUTO-UPDATED`
      );
      fs.writeFileSync(WORKFLOW_FILE, updatedWorkflow, 'utf8');
      console.log('Updated workflow file.');
    } else {
      console.warn("Pattern - cron: '...' # AUTO-UPDATED not found in workflow file. Skipping workflow update.");
    }
  } else {
    console.warn('Workflow file not found to update!');
  }

Comment thread scripts/self_heal.mjs
Comment on lines +61 to +81
// Step 2: Lint/format auto-fix
console.log('\n--- Step 2: Format & Lint ---');
runCmd('npx eslint --fix . || true');
runCmd('npx prettier -w . || true');
evaluateState('Format & Lint');

// Step 3: Snapshot/generated updates
console.log('\n--- Step 3: Update Test Snapshots ---');
runCmd('npx vitest run -u || true');
evaluateState('Update Test Snapshots');

// Step 4: Type stubs/analyzer config
console.log('\n--- Step 4: Sync Types ---');
runCmd('npx typesync || true');
runCmd('npm install || true'); // Install new types if added
evaluateState('Sync Types');

// Step 5: Dependency re-resolve
console.log('\n--- Step 5: Update Dependencies ---');
runCmd('npm update || true');
evaluateState('Update Dependencies');

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

Appending || true to the shell commands prevents execSync from throwing an error when a command fails. Since runCmd already wraps execSync in a try-catch block to gracefully handle and log failures, using || true is redundant and actively suppresses the error logging (Command failed: ...), making debugging much harder.

Removing || true allows runCmd to correctly log which step failed while still allowing the pipeline to proceed to the next step.

// Step 2: Lint/format auto-fix
console.log('\n--- Step 2: Format & Lint ---');
runCmd('npx eslint --fix .');
runCmd('npx prettier -w .');
evaluateState('Format & Lint');

// Step 3: Snapshot/generated updates
console.log('\n--- Step 3: Update Test Snapshots ---');
runCmd('npx vitest run -u');
evaluateState('Update Test Snapshots');

// Step 4: Type stubs/analyzer config
console.log('\n--- Step 4: Sync Types ---');
runCmd('npx typesync');
runCmd('npm install'); // Install new types if added
evaluateState('Sync Types');

// Step 5: Dependency re-resolve
console.log('\n--- Step 5: Update Dependencies ---');
runCmd('npm update');
evaluateState('Update Dependencies');

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