smlflg's picture
Initial public upload from Projekte/AgentProjectMinenraeumer (part 9)
b67a1e9 verified
Raw History Blame Contribute Delete
6.16 kB
#!/usr/bin/env python3
import json, re
from pathlib import Path
from datetime import datetime, timezone
ROOT=Path(__file__).resolve().parents[1]
TRIAGE=ROOT/'triage'
OUT=ROOT/'small_fix'
PLANS=OUT/'plans'; PATCHES=OUT/'patches'; REPORTS=OUT/'reports'; JOBS=ROOT/'jobs/pending'
for d in [OUT,PLANS,PATCHES,REPORTS,JOBS]: d.mkdir(parents=True,exist_ok=True)
MAX_PROJECTS=20
def load(p): return json.loads(Path(p).read_text(encoding='utf-8'))
def slug(s): return re.sub(r'[^A-Za-z0-9_.-]+','_',s.replace('/home/smlflg/',''))[:100]
def classify_fix(row):
cats=row.get('categories',[]); tech=(row.get('tech') or '').lower()
if 'MERGE' in cats: return 'write merge note / source-of-truth marker patch'
if not row.get('readme_present'): return 'add minimal README status section patch'
if row.get('dirty_count',0): return 'stabilize docs/tests around uncommitted change, no source edit'
if 'python' in tech: return 'add smoke test patch artifact'
return 'add verifier/docs status patch artifact'
def verifier(row):
tech=(row.get('tech') or '').lower()
if 'python' in tech: return 'python -m compileall -q . && pytest -q'
if 'node' in tech: return 'npm test'
return 'git status --short && test -e README.md || test -e README'
def plan(row):
fix=classify_fix(row); cmd=verifier(row)
return f"""# SMALL_FIX Plan — {row['name']}
Project: `{row['path']}`
Categories: {', '.join(row['categories'])}
Score: {row['score']}
Dirty: {row['dirty_count']}
TODO/FIXME: {row['todo_fixme_count']}
Plans: {row['plan_hit_count']}
## Mode
READ_ONLY_SMALL_FIX.
No direct source edits. Produce one minimal patch artifact under ProjectIntakeTower.
## Fix class
{fix}
## Constraints
- One small fix only.
- Must have root-cause note before patch proposal.
- Must include verifier command.
- No refactor.
- No dependency install.
- No commit/push/merge.
- If unclear, mark needs_human.
## Suggested verifier
```bash
cd {row['path']}
{cmd}
```
## Required output
- Report: `small_fix/reports/{slug(row['path'])}_small_fix_report.md`
- Patch artifact: `small_fix/patches/{slug(row['path'])}_small_fix.patch.md`
"""
def report(row):
return f"""# SMALL_FIX Report — {row['name']}
Project: `{row['path']}`
Status: draft_needs_worker
## Root-cause note
TODO(worker): explain why this small fix is needed from observed repo/doc/test evidence.
## Proposed minimal fix
TODO(worker): one small, bounded fix only.
## Patch artifact
See matching file in `small_fix/patches/`.
## Verifier
```bash
cd {row['path']}
{verifier(row)}
```
## Safety
No source files were changed by this intake artifact.
"""
def patch(row):
return f"""# SMALL_FIX Patch Artifact — {row['name']}
Project: `{row['path']}`
Fix class: {classify_fix(row)}
Status: placeholder_patch_not_applied
```diff
# Worker writes minimal proposed diff here.
# Do not apply without Samuel approval.
```
Verifier:
```bash
cd {row['path']}
{verifier(row)}
```
"""
def main():
pri=load(TRIAGE/'PROJECT_PRIORITIZATION.json')
selected=[]; seen=set()
# Prefer valuable + human-decision projects where small artifacts reduce ambiguity.
for cat in ['URGENT','KEEP','MERGE','HUMAN_DECISION_REQUIRED']:
for r in pri['categories'].get(cat,[]):
if r['path'] in seen: continue
if 'ARCHIVE' in r['categories'] and 'KEEP' not in r['categories']: continue
selected.append(r); seen.add(r['path'])
if len(selected)>=MAX_PROJECTS: break
if len(selected)>=MAX_PROJECTS: break
index=['# SMALL_FIX','',f'Generated: {datetime.now(timezone.utc).isoformat()}','',f'Projects selected: {len(selected)}','', 'Mode: READ_ONLY_SMALL_FIX — patch artifacts only; no source edits.', '']
jobs=[]
for i,row in enumerate(selected,1):
s=slug(row['path'])
plan_path=PLANS/f'{i:02d}_{s}.md'; report_path=REPORTS/f'{i:02d}_{s}_small_fix_report.md'; patch_path=PATCHES/f'{i:02d}_{s}_small_fix.patch.md'
plan_path.write_text(plan(row),encoding='utf-8'); report_path.write_text(report(row),encoding='utf-8'); patch_path.write_text(patch(row),encoding='utf-8')
job={
'job_id':f'smallfix-2026-05-04-{i:02d}-{s.lower()}',
'project_name':row['name'],'project_path':row['path'],'mode':'review_only',
'allowed_actions':['read files','inspect root cause evidence','write ProjectIntakeTower small_fix report only','write ProjectIntakeTower patch artifact only','run non-destructive verifier discovery'],
'forbidden_actions':['modify source project files','commit','push','merge','delete files','install dependencies','create GitHub issues','print secrets','refactor unrelated code'],
'allowed_files':[f'{row["path"]} read-only','ProjectIntakeTower/small_fix write scope'],
'expected_artifacts':[str(plan_path),str(report_path),str(patch_path)],
'verifier_commands':['python3 ProjectIntakeTower/verifier/verify_small_fix.py'],
'stop_conditions':['root cause unclear','source edit required','dependency install required','human product decision required'],
'objective':f'Produce one minimal small-fix patch artifact for {row["name"]}; do not apply it.',
'fix_class':classify_fix(row),'suggested_verifier':verifier(row)
}
jp=JOBS/f'smallfix_{i:02d}_{s}.json'; jp.write_text(json.dumps(job,indent=2,ensure_ascii=False),encoding='utf-8'); jobs.append(str(jp))
index += [f'## {i}. {row["name"]}',f'Path: `{row["path"]}`',f'Fix class: {classify_fix(row)}',f'Plan: `{plan_path}`',f'Report: `{report_path}`',f'Patch: `{patch_path}`','']
result={'status':'succeeded','mode':'READ_ONLY_SMALL_FIX','projects':len(selected),'plans':len(list(PLANS.glob('*.md'))),'reports':len(list(REPORTS.glob('*_small_fix_report.md'))),'patch_artifacts':len(list(PATCHES.glob('*_small_fix.patch.md'))),'jobs_created':len(jobs),'jobs':jobs}
(OUT/'SMALL_FIX.md').write_text('\n'.join(index),encoding='utf-8'); (OUT/'result.json').write_text(json.dumps(result,indent=2,ensure_ascii=False),encoding='utf-8')
print(json.dumps(result,indent=2))
if __name__=='__main__': main()