feat(example): migrate to infospace config with tooling integration (S3.1)
Add infospace.yaml declaring topic, disciplines, schemas, viability thresholds. Integrate infospace tooling into process_chapters.py with --infospace-status, --infospace-check, and --infospace-viability flags. Initial check: 85 entities, 4/5 viable (coverage 0.36 < 0.50 — only 7/35 chapters processed so far). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
51
examples/infospace-with-history/infospace.yaml
Normal file
51
examples/infospace-with-history/infospace.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
# Infospace: The Wealth of Nations through the Viable System Model
|
||||
#
|
||||
# This configuration declares the infospace built by processing
|
||||
# Adam Smith's "The Wealth of Nations" (1776) through the lens of
|
||||
# Stafford Beer's Viable System Model (VSM).
|
||||
|
||||
topic:
|
||||
name: "The Wealth of Nations"
|
||||
domain: "Classical Economics"
|
||||
sources: artifacts/sources/
|
||||
|
||||
disciplines:
|
||||
- name: "Viable System Model"
|
||||
path: artifacts/vsm-reference/
|
||||
|
||||
schemas:
|
||||
entity: schemas/economic-entity-schema-v1.0.md
|
||||
mapping: schemas/vsm-mapping-schema-v1.0.md
|
||||
analysis: schemas/chapter-analysis-schema-v1.0.md
|
||||
|
||||
competency_questions: |
|
||||
1. How does Smith's division of labour map to VSM System 1 operations?
|
||||
2. What mechanisms in WoN correspond to VSM coordination (System 2)?
|
||||
3. Where does Smith describe self-organising regulation (System 3)?
|
||||
4. What role does the "invisible hand" play as a System 4 mechanism?
|
||||
5. How do Smith's views on government map to System 5 policy?
|
||||
6. Is the WoN entity set viable as an explanatory framework?
|
||||
|
||||
viability:
|
||||
redundancy_ratio:
|
||||
max: 0.10
|
||||
coverage_ratio:
|
||||
min: 0.50
|
||||
coherence_components:
|
||||
max: 3
|
||||
consistency_cycles:
|
||||
max: 0
|
||||
granularity_entropy:
|
||||
min: 1.0
|
||||
|
||||
pipeline:
|
||||
stages:
|
||||
- name: extract-entities
|
||||
template: templates/extract-entities.md
|
||||
- name: map-to-vsm
|
||||
template: templates/map-to-vsm.md
|
||||
- name: synthesize-analysis
|
||||
template: templates/synthesize-analysis.md
|
||||
post_batch:
|
||||
- name: assess-metrics
|
||||
template: templates/assess-metrics.md
|
||||
@@ -856,6 +856,125 @@ class ChapterProcessor:
|
||||
print(f" (No data yet: {e})")
|
||||
|
||||
|
||||
# ── Infospace tooling integration ─────────────────────────────────
|
||||
|
||||
|
||||
def _load_infospace(example_dir: Path):
|
||||
"""Load infospace config and entities from the example directory."""
|
||||
from markitect.infospace.config import load_infospace_config
|
||||
from markitect.infospace.entity_parser import parse_entity_directory
|
||||
|
||||
config_path = example_dir / "infospace.yaml"
|
||||
if not config_path.is_file():
|
||||
print("Error: No infospace.yaml found. Create one first.")
|
||||
sys.exit(1)
|
||||
|
||||
config = load_infospace_config(config_path)
|
||||
entities_dir = example_dir / config.entities_dir
|
||||
entities = parse_entity_directory(entities_dir) if entities_dir.is_dir() else []
|
||||
return config, config_path, entities
|
||||
|
||||
|
||||
def _run_infospace_status(example_dir: Path):
|
||||
"""Show infospace status using the tooling layer."""
|
||||
from markitect.infospace.state import build_state
|
||||
|
||||
config, config_path, entities = _load_infospace(example_dir)
|
||||
state = build_state(config, entities=entities)
|
||||
|
||||
print(f"Infospace: {state.topic_name}")
|
||||
print(f"Domain: {config.topic.domain}")
|
||||
print(f"Entities: {state.entity_count}")
|
||||
if state.domains:
|
||||
print(f"Domains: {', '.join(state.domains)}")
|
||||
if config.disciplines:
|
||||
names = [d.name for d in config.disciplines]
|
||||
print(f"Disciplines: {', '.join(names)}")
|
||||
|
||||
# Show processing progress
|
||||
sources_dir = example_dir / "artifacts" / "sources"
|
||||
total_chapters = len(list(sources_dir.glob("*.md")))
|
||||
processed = len(list((example_dir / "output" / "analyses").glob("*-analysis.md")))
|
||||
print(f"Chapters: {processed}/{total_chapters} processed")
|
||||
|
||||
|
||||
def _run_infospace_check(example_dir: Path):
|
||||
"""Run collection-level quality checks."""
|
||||
from markitect.infospace.checks import run_all_checks
|
||||
from markitect.infospace.history import record_check_results
|
||||
|
||||
config, config_path, entities = _load_infospace(example_dir)
|
||||
|
||||
if not entities:
|
||||
print("No entities to check.")
|
||||
return
|
||||
|
||||
print(f"Running collection checks on {len(entities)} entities...\n")
|
||||
report = run_all_checks(entities=entities)
|
||||
|
||||
d = report.to_dict()
|
||||
for concern_name, concern_data in d.items():
|
||||
label = concern_data.get("concern", concern_name.upper())
|
||||
print(f" {label} — {concern_name}")
|
||||
for k, v in concern_data.items():
|
||||
if k == "concern":
|
||||
continue
|
||||
print(f" {k}: {v}")
|
||||
print()
|
||||
|
||||
m = report.metrics()
|
||||
if m:
|
||||
print("Metrics summary:")
|
||||
for k, v in sorted(m.items()):
|
||||
print(f" {k}: {v:.4f}")
|
||||
snap = record_check_results(report, config, example_dir, entity_count=len(entities))
|
||||
print(f"\nRecorded snapshot {snap.snapshot_id}")
|
||||
|
||||
|
||||
def _run_infospace_viability(example_dir: Path):
|
||||
"""Show viability dashboard."""
|
||||
from markitect.infospace.history import read_metrics_file
|
||||
from markitect.infospace.state import build_state
|
||||
|
||||
config, config_path, entities = _load_infospace(example_dir)
|
||||
|
||||
if not config.viability:
|
||||
print("No viability thresholds configured.")
|
||||
return
|
||||
|
||||
metrics = read_metrics_file(example_dir / config.metrics_dir / "metrics.yaml")
|
||||
if not metrics:
|
||||
print("No metrics available. Run --infospace-check first.")
|
||||
print("\nConfigured thresholds:")
|
||||
for name, t in config.viability.items():
|
||||
bounds = []
|
||||
if t.min is not None:
|
||||
bounds.append(f"min={t.min}")
|
||||
if t.max is not None:
|
||||
bounds.append(f"max={t.max}")
|
||||
print(f" {name}: {', '.join(bounds)}")
|
||||
return
|
||||
|
||||
state = build_state(config, entities=entities, metrics=metrics)
|
||||
|
||||
print(f"{'Metric':<30} {'Value':>8} {'Threshold':>15} {'Status':>8}")
|
||||
print("-" * 63)
|
||||
for r in state.viability_results:
|
||||
bounds = []
|
||||
if r.threshold.min is not None:
|
||||
bounds.append(f"min={r.threshold.min}")
|
||||
if r.threshold.max is not None:
|
||||
bounds.append(f"max={r.threshold.max}")
|
||||
status_str = "PASS" if r.passed else "FAIL"
|
||||
print(f"{r.metric:<30} {r.value:>8.4f} {', '.join(bounds):>15} {status_str:>8}")
|
||||
|
||||
print()
|
||||
if state.is_viable:
|
||||
print(f"Viable: YES ({state.viability_pass_count}/{state.viability_total_count} thresholds met)")
|
||||
else:
|
||||
print(f"Viable: NO ({state.viability_pass_count}/{state.viability_total_count} thresholds met)")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Process Wealth of Nations chapters through VSM analysis pipeline"
|
||||
@@ -869,6 +988,12 @@ def main():
|
||||
group.add_argument("--stats", action="store_true", help="Show dependency statistics")
|
||||
group.add_argument("--archive-entity", type=str, metavar="SLUG",
|
||||
help="Archive an entity (move to archive/ with reason)")
|
||||
group.add_argument("--infospace-status", action="store_true",
|
||||
help="Show infospace status via infospace tooling")
|
||||
group.add_argument("--infospace-check", action="store_true",
|
||||
help="Run collection-level quality checks (C1-C5)")
|
||||
group.add_argument("--infospace-viability", action="store_true",
|
||||
help="Show viability dashboard")
|
||||
|
||||
parser.add_argument("--reason", type=str, default=None,
|
||||
help="Reason for archiving (used with --archive-entity)")
|
||||
@@ -930,6 +1055,15 @@ def main():
|
||||
for ch in chapters:
|
||||
processor.process_chapter(ch, auto_commit=not args.no_commit)
|
||||
print()
|
||||
elif args.infospace_status:
|
||||
_run_infospace_status(example_dir)
|
||||
return
|
||||
elif args.infospace_check:
|
||||
_run_infospace_check(example_dir)
|
||||
return
|
||||
elif args.infospace_viability:
|
||||
_run_infospace_viability(example_dir)
|
||||
return
|
||||
|
||||
processor.show_stats()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user