feat: Karpathy-inspired upgrades — contradiction, lint, synthesis
Three additive upgrades borrowed from Karpathy's LLM Wiki pattern: 1. CONTRADICTION DETECTION: auto-triage now has a fourth verdict — "contradicts". When a candidate conflicts with an existing memory (not duplicates, genuine disagreement like "Option A selected" vs "Option B selected"), the triage model flags it and leaves it in the queue for human review instead of silently rejecting or double-storing. Preserves source tension rather than suppressing it. 2. WEEKLY LINT PASS: scripts/lint_knowledge_base.py checks for: - Orphan memories (active but zero references after 14 days) - Stale candidates (>7 days unreviewed) - Unused entities (no relationships) - Empty-state projects - Unregistered projects auto-detected in memories Runs Sundays via the cron. Outputs a report. 3. WEEKLY SYNTHESIS: scripts/synthesize_projects.py uses sonnet to generate a 3-5 sentence "current state" paragraph per project from state + memories + entities. Cached in project_state under status/synthesis_cache. Wiki project pages now show this at the top under "Current State (auto-synthesis)". Falls back to a deterministic summary if no cache exists. deploy/dalidou/batch-extract.sh: added Step C (synthesis) and Step D (lint) gated to Sundays via date check. All additive — nothing existing changes behavior. The database remains the source of truth; these operations just produce better synthesized views and catch rot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ def generate_project_overview(project: str) -> str:
|
||||
"""Generate a full project overview page in markdown."""
|
||||
sections = [
|
||||
_header(project),
|
||||
_synthesis_section(project),
|
||||
_state_section(project),
|
||||
_system_architecture(project),
|
||||
_decisions_section(project),
|
||||
@@ -40,6 +41,52 @@ def generate_project_overview(project: str) -> str:
|
||||
return "\n\n".join(s for s in sections if s)
|
||||
|
||||
|
||||
def _synthesis_section(project: str) -> str:
|
||||
"""Generate a short LLM synthesis of the current project state.
|
||||
|
||||
Reads the cached synthesis from project_state if available
|
||||
(category=status, key=synthesis_cache). If not cached, returns
|
||||
a deterministic summary from the existing structured data.
|
||||
The actual LLM-generated synthesis is produced by the weekly
|
||||
lint/synthesis pass on Dalidou (where claude CLI is available).
|
||||
"""
|
||||
entries = get_state(project)
|
||||
cached = ""
|
||||
for e in entries:
|
||||
if e.category == "status" and e.key == "synthesis_cache":
|
||||
cached = e.value
|
||||
break
|
||||
|
||||
if cached:
|
||||
return f"## Current State (auto-synthesis)\n\n> {cached}"
|
||||
|
||||
# Fallback: deterministic summary from structured data
|
||||
stage = ""
|
||||
summary = ""
|
||||
next_focus = ""
|
||||
for e in entries:
|
||||
if e.category == "status":
|
||||
if e.key == "stage":
|
||||
stage = e.value
|
||||
elif e.key == "summary":
|
||||
summary = e.value
|
||||
elif e.key == "next_focus":
|
||||
next_focus = e.value
|
||||
|
||||
if not (stage or summary or next_focus):
|
||||
return ""
|
||||
|
||||
bits = []
|
||||
if summary:
|
||||
bits.append(summary)
|
||||
if stage:
|
||||
bits.append(f"**Stage**: {stage}")
|
||||
if next_focus:
|
||||
bits.append(f"**Next**: {next_focus}")
|
||||
|
||||
return "## Current State\n\n" + "\n\n".join(bits)
|
||||
|
||||
|
||||
def _header(project: str) -> str:
|
||||
return (
|
||||
f"# {project} — Project Overview\n\n"
|
||||
|
||||
Reference in New Issue
Block a user