from __future__ import annotations

from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]


def _collapsed(text: str) -> str:
    return " ".join(text.split())


def test_heuristic_system_documents_error_inbox_and_operation_records() -> None:
    text = (ROOT / "HEURISTIC_SYSTEM.md").read_text(encoding="utf-8")
    collapsed = _collapsed(text)

    assert "Important unresolved workflow gap" in text
    assert "heuristic-system/error-inbox/" in text
    assert "heuristic-system/error-inbox/archive/YYYY/" in text
    assert "heuristic-system/operation-records/" in text
    assert "heuristic-error-inbox" in text
    assert "raw runtime records in their evidence location" in text
    assert "Operation records are not required for every promoted inbox entry." in text
    assert "## Case Layout" in text
    assert "heuristic-system/error-inbox/<slug>/ENTRY.md" in text
    assert "heuristic-system/operation-records/<slug>/RECORD.md" in text
    assert "raw `skill-usage.record.json`" in collapsed
    assert "<workspace>" in text


def test_heuristic_system_documents_body_level_redaction_boundary() -> None:
    framework = (ROOT / "HEURISTIC_SYSTEM.md").read_text(encoding="utf-8")
    inbox_readme = (ROOT / "heuristic-system/error-inbox/README.md").read_text(encoding="utf-8")
    inbox_collapsed = _collapsed(inbox_readme)

    assert "The ingest redaction guardrail applies to files under `<slug>/evidence/`" in framework
    assert "Starting with `heuristic-inbox 0.10.2`" in framework
    assert "Non-strict verify reports body warnings" in framework
    assert "`verify --strict` escalates body findings into violations" in framework
    assert "heuristic-inbox verify --strict" in _collapsed(framework)

    assert "The primitive's ingest redaction guardrail covers files under `<slug>/evidence/`" in inbox_collapsed
    assert "Starting with `heuristic-inbox 0.10.2`" in inbox_readme
    assert "Non-strict verify reports body warnings" in inbox_readme
    assert "`verify --strict` escalates those findings into violations" in inbox_readme
    assert "entries should pass strict verify" in inbox_collapsed


def test_heuristic_system_retained_cases_use_workspace_placeholders() -> None:
    retained_paths = [
        ROOT
        / "heuristic-system/error-inbox/archive/2026/deliver-gitlab-mr-skipped-pipeline-and-cleanup/ENTRY.md",
        ROOT / "heuristic-system/operation-records/github-pr-required-check-gating/RECORD.md",
    ]

    for path in retained_paths:
        text = path.read_text(encoding="utf-8")
        assert "<workspace>/out/" in text
        assert "/Users/" not in text
        assert "/home/" not in text


def test_heuristic_system_documents_unified_activation_and_canonical_checklist() -> None:
    text = (ROOT / "HEURISTIC_SYSTEM.md").read_text(encoding="utf-8")
    collapsed = _collapsed(text)

    assert "Heuristic triage activates from one signal" in text
    assert "`skill-usage.record.v1` is the strict envelope for named-skill workflows" in text
    assert "Outside a named skill, no usage record is owed" in text
    assert "`exit_code != 0`, stderr output, a single retry, or a corrected typo starts judgment" in collapsed
    assert "This is the canonical triage checklist" in collapsed
    assert "Did the same command, validation, or workaround require repeated retries?" in text
    assert "Did documented behavior and actual behavior disagree?" in text
    assert "Was the error output unclear for the action the agent needed to take?" in text
    assert "Did the fix require a semantic workaround" in text
    assert "Did the friction happen inside a named skill workflow or contradict a skill" in text
    assert "Would a future agent benefit from a test, runbook, issue, inbox entry" in text
    assert "record the command/script/dependency failure in" in text
    assert "Do not commit raw stderr or turn ordinary authoring mistakes into retained artifacts." in collapsed
    assert "active lifecycle is `open | promoted | wontfix`" in text


def test_heuristic_system_error_inbox_readme_defines_curated_queue_contract() -> None:
    text = (ROOT / "heuristic-system/error-inbox/README.md").read_text(encoding="utf-8")
    collapsed = _collapsed(text)

    assert "versioned summaries of important workflow gaps" in text
    assert "This is not a raw log archive" in text
    assert "Observed CLI, hook, validation, dependency, or workflow friction is important" in text
    assert "Do not retain a case only because `exit_code != 0`" in collapsed
    assert "docs/behavior mismatch" in collapsed
    assert "- `open`: gap is known and not yet resolved." in text
    assert "The primitive rejects new writes for legacy lifecycle values (`triaged`," in collapsed
    assert "Do not add `archived` as a lifecycle status." in collapsed
    assert "status is `promoted` or `wontfix`" in text
    assert "`Next Action` starts with `None.`" in text
    assert "Each top-level folder is an active inbox case." in text
    assert "## Case Folder Layout" in text
    assert "`<slug>/ENTRY.md`" in text
    assert "`<slug>/evidence/`" in text
    assert "## Entry Template" in text
    assert "## Archive" in text
    assert "## Cleanup Rules" in text
    assert "heuristic-error-inbox" in text


def test_skill_usage_runbook_routes_unresolved_gaps_to_error_inbox() -> None:
    text = (ROOT / "docs/runbooks/skills/SKILL_USAGE_RECORDING_V1.md").read_text(encoding="utf-8")

    assert "If a failure remains unresolved" in text
    assert "heuristic-system/error-inbox/" in text
    assert "heuristic-error-inbox" in text
    assert "Do not commit the raw `skill-usage.record.json` as the tracker." in text
    assert "Do not run multiple `skill-usage` write commands against the same `--out`" in text


def test_skill_usage_runbook_keeps_non_skill_friction_out_of_usage_envelope() -> None:
    text = (ROOT / "docs/runbooks/skills/SKILL_USAGE_RECORDING_V1.md").read_text(encoding="utf-8")
    tool_text = (ROOT / "skills/tools/workflow-evidence/skill-usage/SKILL.md").read_text(encoding="utf-8")
    collapsed = _collapsed(text)

    assert "Skill-bound friction belongs in `failures`" in text
    assert "Non-skill observed friction should be triaged through `HEURISTIC_SYSTEM.md`" in text
    assert "Do not force ordinary CLI pain, authoring mistakes, or unrelated non-zero exits" in collapsed
    assert "direct skill-contract mismatch has a lower retention threshold" in text
    assert "validator repeatedly emits unclear contract errors" in collapsed
    assert "The primitive is not an automatic command-failure detector or policy engine." in text
    assert "does not decide that every `exit_code != 0` deserves retention" in text
    assert "this CLI does not detect or classify every command failure" in tool_text
    assert "Keep observed-friction promotion policy in `HEURISTIC_SYSTEM.md`" in tool_text


def test_heuristic_system_workflow_docs_keep_archive_and_compression_narrow() -> None:
    text = (ROOT / "skills/workflows/heuristic-system/heuristic-error-inbox/SKILL.md").read_text(encoding="utf-8")
    index_text = (ROOT / "skills/workflows/heuristic-system/README.md").read_text(encoding="utf-8")
    collapsed_index = _collapsed(index_text)

    assert "heuristic-inbox archive <case-folder|ENTRY.md>" in text
    assert "Closed cases keep status `promoted` or `wontfix`" in text
    assert "`archived` lifecycle status" in text
    assert "several related" in text
    assert "archived inbox or operation records" in text
    assert "observed-friction signal that has already passed judgment-first" in text
    assert "single non-zero exits, or raw stderr dumps" in text
    assert "HEURISTIC_SYSTEM.md#activation-and-triage" in text
    assert "ingest-evidence" in text
    assert "redaction guardrail" in text
    assert "Archive completed inbox entries so the active backlog stays small." in index_text
    assert "Create an operation record only for repeated, cross-skill, audit-worthy" in index_text
    assert "including observed-friction entries that passed HEURISTIC_SYSTEM triage" in collapsed_index
    assert "does not own implementation fixes for the underlying bug or tool gap" in collapsed_index
