feat(infospace): add collection-level quality checks C1–C5 (S2.4)
Five concern checks: Redundancy (embedding/word overlap), Coverage (FCA gap analysis), Coherence (graph connectivity), Consistency (cycle detection), Granularity (Shannon entropy). Orchestrator runs all or selected checks, CLI `markitect infospace check` command added. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -273,3 +273,61 @@ def viability(config_path: Optional[str]):
|
||||
click.echo(f"Viable: YES ({state.viability_pass_count}/{state.viability_total_count} thresholds met)")
|
||||
else:
|
||||
click.echo(f"Viable: NO ({state.viability_pass_count}/{state.viability_total_count} thresholds met)")
|
||||
|
||||
|
||||
# ── check ───────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@infospace_commands.command()
|
||||
@click.option("--config", "config_path", default=None, help="Path to infospace.yaml.")
|
||||
@click.option(
|
||||
"--concern", "concerns", multiple=True,
|
||||
type=click.Choice(["redundancy", "coverage", "coherence", "consistency", "granularity"]),
|
||||
help="Run specific concern(s). Omit to run all five.",
|
||||
)
|
||||
@click.option("--json", "as_json", is_flag=True, help="Output results as JSON.")
|
||||
def check(config_path: Optional[str], concerns: tuple, as_json: bool):
|
||||
"""Run collection-level quality checks (C1–C5)."""
|
||||
cfg, cfg_path = _load_config_or_exit(config_path)
|
||||
root = cfg_path.parent
|
||||
|
||||
entities_dir = root / cfg.entities_dir
|
||||
if not entities_dir.is_dir():
|
||||
click.echo("Error: No entities directory found.", err=True)
|
||||
raise SystemExit(1)
|
||||
|
||||
entity_list = parse_entity_directory(entities_dir)
|
||||
if not entity_list:
|
||||
click.echo("No entities to check.")
|
||||
return
|
||||
|
||||
from markitect.infospace.checks import run_all_checks
|
||||
|
||||
checks_list = list(concerns) if concerns else None
|
||||
|
||||
report = run_all_checks(
|
||||
entities=entity_list,
|
||||
checks=checks_list,
|
||||
)
|
||||
|
||||
if as_json:
|
||||
import json
|
||||
click.echo(json.dumps(report.to_dict(), indent=2))
|
||||
else:
|
||||
click.echo(f"Collection checks — {len(entity_list)} entities\n")
|
||||
d = report.to_dict()
|
||||
for concern_name, concern_data in d.items():
|
||||
label = concern_data.get("concern", concern_name.upper())
|
||||
click.echo(f" {label} — {concern_name}")
|
||||
for k, v in concern_data.items():
|
||||
if k == "concern":
|
||||
continue
|
||||
click.echo(f" {k}: {v}")
|
||||
click.echo()
|
||||
|
||||
# Show summary metrics
|
||||
m = report.metrics()
|
||||
if m and not as_json:
|
||||
click.echo("Metrics summary:")
|
||||
for k, v in sorted(m.items()):
|
||||
click.echo(f" {k}: {v:.4f}")
|
||||
|
||||
Reference in New Issue
Block a user