Metadata-Version: 2.4
Name: ifuri-doctor
Version: 0.3.0
Summary: Central diagnostic, validation and repair runner for if-uri repositories.
Author: if-uri
License: Apache-2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: tzdata>=2026.1
Requires-Dist: ifuri-todo-agent>=0.9.0
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Dynamic: license-file

# ifuri-doctor

`ifuri-doctor` is the central MVP diagnostic, validation and repair runner for GitHub repositories in the `if-uri` organization.

The first version intentionally focuses on a safe, testable workflow:

1. discover repositories from a local workspace or `gh repo list`;
2. exclude configurable name patterns such as `*-agent` and `*-agents`;
3. clone or create isolated working copies;
4. prepare `.env` from `.env.example`, `.env.doctor` and safe CI-prefixed variables;
5. execute only declared Makefile targets;
6. classify failures and generate stable fingerprints;
7. apply one controlled automatic repair: add a missing `doctor-health` target;
8. re-run validation;
9. validate explicitly configured repository pairs;
10. create dry-run draft PR or issue records with deduplication;
11. write `reports/latest.md` and `reports/latest.json`.

The system never merges Pull Requests.

## Responsibilities

`ifuri-doctor` is responsible for:

- discovering repositories in the `if-uri` organization;
- detecting build, test, runtime, dependency, configuration, documentation and CI problems;
- confirming that a problem is still reproducible before opening work for repair;
- creating or updating deduplicated GitHub Issues with `doctor:detected` and `repair:pending`;
- writing the agent YAML contract, acceptance criteria, logs and reproduction command;
- preserving a shared `correlation_id` for downstream agents;
- reporting scan results and dry-run operations.

`ifuri-doctor` is not responsible for:

- applying broad code changes across target repositories;
- approving or merging Pull Requests;
- replacing `repair-agent` or `validator-agent`.

## Repository Layout

```text
src/ifuri_doctor/
  cli.py          command line entrypoint
  config.py       profiles, timeouts and integration config
  discovery.py    local and GitHub repository discovery
  sync.py         isolated checkout/worktree preparation
  envfile.py      .env preparation and secret masking
  makefile.py     declared Makefile target validation and execution
  classifier.py   failure categories
  fingerprint.py  error normalization and fingerprints
  repair.py       controlled safe repairs
  integration.py  explicit pair validation
  github.py       dry-run PR/issue creation with dedupe store
  report.py       Markdown and JSON reports
tests/
  test_doctor_mvp.py
```

## Local Example

```bash
python -m pip install -e ".[test]"
python -m pytest -q
python -m ifuri_doctor --config doctor.example.json --workspace ../fixtures --profile development
```

Reports are written to:

```text
reports/latest.md
reports/latest.json
```

## Development Profile

```json
{
  "profile": "development",
  "profiles": {
    "development": {
      "schedule": { "light_scan_minutes": 12, "full_scan_minutes": 36 },
      "timing_multiplier": 0.2
    }
  },
  "timeouts": {
    "test": { "production_seconds": 600, "development_seconds": 120, "minimum_seconds": 60 }
  }
}
```

## Production Profile

```json
{
  "profile": "production",
  "profiles": {
    "production": {
      "schedule": { "light_scan_minutes": 60, "full_scan_minutes": 180 },
      "timing_multiplier": 1.0
    }
  }
}
```

## Pair Validation Example

```json
{
  "integrations": [
    {
      "id": "examples-with-urirun",
      "provider": {
        "repository": "if-uri/urirun",
        "start": "make doctor-start",
        "health": "make doctor-health"
      },
      "consumer": {
        "repository": "if-uri/examples",
        "test": "make doctor-integration-test"
      },
      "environment": { "URIRUN_URL": "http://urirun:8080" },
      "timeout_seconds": 600
    }
  ]
}
```

## Example Failure, Repair and Deduplication

If a repository has a `Makefile` but lacks `doctor-health`, Doctor records a `SKIPPED_UNDECLARED` step with a fingerprint such as `doctor:0123abcd...`.

The MVP repair appends:

```makefile
.PHONY: doctor-health
doctor-health:
	@echo "doctor-health: default MVP healthcheck OK"
```

Doctor then re-runs all declared MVP targets. If they pass, it creates one dry-run draft PR record in `.doctor-state/items.json`. A second run finds the same fingerprint, updates `last_seen`, and reuses the existing item instead of creating a duplicate.

If a failure is not safely repairable, Doctor creates one issue record using the same dedupe path.

## GitHub Mode

Set `"source": "github"` to discover repositories through GitHub CLI:

```bash
gh repo list if-uri --limit 1000 --json nameWithOwner,sshUrl,url,isArchived,defaultBranchRef
```

The MVP keeps PR and issue creation in dry-run state records by default. This makes local validation safe and avoids writing secrets or noisy duplicate issues while the repair policy is still being expanded.

## Issue, Project, Actions

- GitHub Issue is one ticket describing one detected Doctor problem.
- GitHub Project is the organization board that organizes tickets. It is not the `if-uri/ifuri-doctor` repository.
- GitHub Actions runs Doctor on a schedule or on demand and updates Issues and Project fields.
- `if-uri/ifuri-doctor` is only the application repository.

The target organization Project is:

```text
Owner: if-uri
Title: Tickets
```

## GitHub Auth

GitHub Projects require a token with project access. Refresh local `gh` auth with:

```bash
gh auth refresh -s project
gh auth refresh -s project -s read:project -s repo -s read:org
gh auth status
```

Doctor detects missing project scope and prints the refresh command. It keeps local diagnostics running when Project writes are unavailable.

## Project Commands

```bash
gh project list --owner if-uri
gh project create --owner if-uri --title "Tickets"
gh project link PROJECT_NUMBER --owner if-uri --repo if-uri/ifuri-doctor

ifuri-doctor project init
ifuri-doctor project inspect
ifuri-doctor project sync
ifuri-doctor project link
```

`project init` finds or creates the `Tickets` Project, checks or plans required fields, links it to `if-uri/ifuri-doctor`, and stores a local cache. In dry-run it prints planned operations such as:

```text
DRY RUN: would create project if-uri/Tickets
DRY RUN: would link project to if-uri/ifuri-doctor
DRY RUN: would create project field Agent Status
```

Required Project fields include `Agent Status`, `Repository`, `Failure Type`, `Severity`, `Fingerprint`, `Last Seen`, `Doctor Result`, `Pull Request`, and `Merge Readiness`.

## Issues and Deduplication

Doctor stores fingerprints in Issue bodies as hidden comments:

```html
<!-- ifuri-doctor:fingerprint=doctor:... -->
```

Before creating an Issue it checks GitHub and the local cache. Existing Issues are reused, closed recurring Issues are reopened, and Project fields such as `Last Seen` and `Doctor Result` are updated idempotently.

## Agent Handoff Contract

`ifuri-doctor` is the only diagnostic repository. It hands work to `if-uri/repair-agent` by creating Issues in `if-uri/ifuri-doctor` with the initial labels:

```text
doctor:detected
repair:pending
```

Every Issue contains a machine-readable YAML block:

```yaml
source_agent: ifuri-doctor
target_repository: owner/repository
problem_type: ci | tests | build | dependency | configuration | documentation | runtime | other
severity: critical | high | medium | low
detected_at: ISO-8601
deduplication_key: stable-problem-key
correlation_id: ifuri-doctor-YYYYMMDD-repository-key
failing_command: command
workflow_run_url: link
commit_sha: SHA
```

The `deduplication_key` is also stored in hidden comments so repeated scans update or reuse the existing Issue instead of opening duplicates. The same `correlation_id` must appear in repair-agent logs, repair branches, Pull Requests, validator-agent reports and merge comments.

Required shared configuration names:

```text
GITHUB_ORG=if-uri
DOCTOR_REPOSITORY=ifuri-doctor
REPAIR_REPOSITORY=repair-agent
VALIDATOR_REPOSITORY=validator-agent
ACTIVE_TIMEZONE=Europe/Warsaw
```

Optional secrets and variables used by the agent system are `OPENROUTER_API_KEY`, `OPENROUTER_MODEL`, `GH_APP_ID`, `GH_APP_PRIVATE_KEY`, `GH_APP_INSTALLATION_ID`, `NOTIFICATION_EMAIL`, `ACTIVE_HOURS_START` and `ACTIVE_HOURS_END`.

## Codex

Codex execution is configurable:

```json
{
  "codex": {
    "enabled": true,
    "command": "codex",
    "timeout_seconds": 1800,
    "dry_run": true
  }
}
```

Doctor passes repository, ticket, fingerprint, failure type, logs, reproduce command, test results, integration pairs, constraints, and expected output. Codex must work in an isolated branch/worktree. Diff validation rejects unsafe changes such as removed tests, `skip`/`xfail`, disabled linting, removed healthchecks, secrets, branch protection changes, unrelated files, and ignored failures.

## Pull Requests

Successful repairs create draft PRs only after revalidation:

```bash
gh pr create --repo OWNER/REPO --draft --title "..." --body-file PR_BODY.md
```

Doctor never merges PRs. It deduplicates by fingerprint, branch, PR body, and local cache.

Inspect merge readiness with:

```bash
ifuri-doctor inspect-pr --repo if-uri/example --pr 123
```

Possible results are `READY_TO_MERGE`, `BLOCKED_BY_CHECKS`, `BLOCKED_BY_CONFLICTS`, `BLOCKED_BY_REVIEW`, `DRAFT`, and `UNKNOWN`.

## Scan and Schedule

```bash
ifuri-doctor scan --mode light --profile development
ifuri-doctor scan --mode full --profile development
ifuri-doctor schedule --profile development
ifuri-doctor schedule --profile production
```

Production uses a light scan every 60 minutes and a full scan every 180 minutes. Development uses exactly one fifth of those times: 12 and 36 minutes, with timing multiplier `0.2` and safe minimum timeouts.

Light scan covers repository list, PRs, workflows, Issues, Project and ticket statuses. Full scan performs clone/fetch, `.env`, Makefile validation, build, lint, test, start, healthcheck, pair integrations, Codex planning, revalidation, and PR or ticket creation.

## GitHub Actions

The default `${{ secrets.GITHUB_TOKEN }}` is not enough for organization Projects. Create a PAT or GitHub App token and store it as:

```bash
gh secret set PROJECT_TOKEN --repo if-uri/ifuri-doctor
```

The workflow maps it to:

```yaml
env:
  GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
```

Minimal workflow permissions are:

```yaml
permissions:
  contents: write
  issues: write
  pull-requests: write
  checks: read
  actions: read
```

Project access still comes from the separate PAT or GitHub App token.

## Dry Run

Dry-run never creates Projects, Issues, Project items, Codex runs, pushes, PRs, or status updates. It reports exact planned operations:

```text
DRY RUN: would create issue
DRY RUN: would add issue to project
DRY RUN: would set Agent Status=Ready for repair
DRY RUN: would run Codex
DRY RUN: would create draft PR
```
