AgentProjectMinenraeumer / ProjectIntakeTower /verifier /generate_doc_reality_sync.py
smlflg's picture
Initial public upload from Projekte/AgentProjectMinenraeumer (part 9)
b67a1e9 verified
Raw History Blame Contribute Delete
6.68 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/'doc_reality_sync'
PLANS=OUT/'plans'
REPORTS=OUT/'reports'
PATCHES=OUT/'patches'
JOBS=ROOT/'jobs/pending'
for d in [OUT,PLANS,REPORTS,PATCHES,JOBS]: d.mkdir(parents=True,exist_ok=True)
MAX_PROJECTS=25
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 doc_status(row):
has_readme=bool(row.get('readme_present'))
dirty=row.get('dirty_count',0)
plans=row.get('plan_hit_count',0)
todos=row.get('todo_fixme_count',0)
cats=row.get('categories',[])
issues=[]
if not has_readme: issues.append('README missing/unknown')
if dirty: issues.append(f'{dirty} uncommitted changes may make docs stale')
if plans>=3: issues.append(f'{plans} old plans/handoffs may conflict with current state')
if todos>=20: issues.append(f'{todos} TODO/FIXME signals need doc triage')
if 'MERGE' in cats: issues.append('duplicate/merge candidate docs may describe wrong source of truth')
if 'ARCHIVE' in cats: issues.append('archive candidate docs should mark stale status')
return issues or ['docs appear low-risk but need reality smoke check']
def plan(row):
issues=doc_status(row)
return f"""# DOC_REALITY_SYNC 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_DOC_REALITY_SYNC.
Do not edit project docs directly. Produce a reality report and optional README patch artifact under ProjectIntakeTower.
## Suspected doc/reality gaps
""" + ''.join(f'- {x}\n' for x in issues) + f"""
## Required checks
1. Read README / AGENTS / CLAUDE / docs index if present.
2. Compare claimed status/features/run commands against actual files/manifests/tests.
3. Identify stale claims, missing setup steps, broken commands, unclear source-of-truth.
4. Produce `reports/{slug(row['path'])}_doc_reality_report.md`.
5. If useful, produce `patches/{slug(row['path'])}_README.patch.md` as a patch artifact only.
## Forbidden
- No source edits.
- No dependency installs.
- No commit/push/merge.
- No GitHub issue creation.
- No secrets.
## Output standard
Each report must answer:
- What docs claim.
- What repo reality shows.
- What is stale/missing/wrong.
- Minimal doc patch proposal.
- Verifier command for checking the claim.
"""
def report_template(row):
return f"""# DOC_REALITY_SYNC Report — {row['name']}
Project: `{row['path']}`
Status: draft_report_needs_worker
## Docs claim
TODO(worker): summarize README/docs claims with file references.
## Repo reality
TODO(worker): compare against actual files, manifests, tests, git state.
## Mismatches
TODO(worker): list stale/missing/wrong doc claims.
## Minimal patch proposal
TODO(worker): write exact README/docs patch suggestion here, not applied.
## Verifier
TODO(worker): command or file-exists/schema check proving docs match reality.
## Safety
No source docs were edited by this intake artifact.
"""
def patch_template(row):
return f"""# README Patch Artifact — {row['name']}
Project: `{row['path']}`
Status: placeholder_patch_not_applied
```diff
# Worker writes proposed README/docs diff here.
```
Human gate required before applying.
"""
def main():
pri=load(TRIAGE/'PROJECT_PRIORITIZATION.json')
selected=[]; seen=set()
for cat in ['KEEP','URGENT','MERGE','TOKEN_BURN_CANDIDATE','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=['# DOC_REALITY_SYNC','',f'Generated: {datetime.now(timezone.utc).isoformat()}','',f'Projects selected: {len(selected)}','', 'Mode: READ_ONLY_DOC_REALITY_SYNC — reports/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}_doc_reality_report.md'
patch_path=PATCHES/f'{i:02d}_{s}_README.patch.md'
plan_path.write_text(plan(row),encoding='utf-8')
report_path.write_text(report_template(row),encoding='utf-8')
patch_path.write_text(patch_template(row),encoding='utf-8')
job={
'job_id':f'docsync-2026-05-04-{i:02d}-{s.lower()}',
'project_name':row['name'], 'project_path':row['path'], 'mode':'review_only',
'allowed_actions':['read docs/source manifests','compare doc claims to repo reality','write ProjectIntakeTower doc reality report only','write ProjectIntakeTower patch artifact only'],
'forbidden_actions':['modify source project files','commit','push','merge','delete files','install dependencies','create GitHub issues','print secrets'],
'allowed_files':[f'{row["path"]} read-only','ProjectIntakeTower/doc_reality_sync write scope'],
'expected_artifacts':[str(plan_path),str(report_path),str(patch_path)],
'verifier_commands':['python3 ProjectIntakeTower/verifier/verify_doc_reality_sync.py'],
'stop_conditions':['source edit required','dependency install required','credentials required','unclear source-of-truth requires Samuel'],
'objective':f'Compare documentation claims to repository reality for {row["name"]}; produce report and patch artifact only.',
'source_plan':str(plan_path)
}
jp=JOBS/f'docsync_{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'Plan: `{plan_path}`',f'Report: `{report_path}`',f'Patch artifact: `{patch_path}`','']
result={'status':'succeeded','mode':'READ_ONLY_DOC_REALITY_SYNC','projects':len(selected),'plans':len(list(PLANS.glob('*.md'))),'reports':len(list(REPORTS.glob('*_doc_reality_report.md'))),'patch_artifacts':len(list(PATCHES.glob('*_README.patch.md'))),'jobs_created':len(jobs),'jobs':jobs}
(OUT/'DOC_REALITY_SYNC.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()