Skip to content

Formatters

formatters

Output formatters for audit results โ€” human-readable and JSON.

format_agent(result)

Agent-optimized output: passed=summary, failed=full detail.

Minimizes tokens for passing checks while giving full context on failures. For failed checks, text and details are both included when present (None values are omitted). Passed checks that carry actionable detail (e.g. missing docstrings) are promoted to dicts. Rule-specific metadata (e.g. tautology verdicts, duplicate clusters, pyramid mismatches) is propagated verbatim under the metadata key on both passed and failed entries when non-empty.

Score/grade derive from the single serialization source (:func:axm_audit.score.score_grade_or_none); this lax surface tolerates an incalculable score as None rather than failing loud.

Source code in packages/axm-audit/src/axm_audit/formatters.py
Python
def format_agent(result: AuditResult) -> dict[str, object]:
    """Agent-optimized output: passed=summary, failed=full detail.

    Minimizes tokens for passing checks while giving full context on
    failures.  For failed checks, ``text`` and ``details`` are both included
    when present (``None`` values are omitted).  Passed checks that
    carry actionable detail (e.g. missing docstrings) are promoted to dicts.
    Rule-specific ``metadata`` (e.g. tautology verdicts, duplicate clusters,
    pyramid mismatches) is propagated verbatim under the ``metadata`` key
    on both passed and failed entries when non-empty.

    Score/grade derive from the single serialization source
    (:func:`axm_audit.score.score_grade_or_none`); this lax surface tolerates
    an incalculable score as ``None`` rather than failing loud.
    """
    score, grade = score_grade_or_none(result)
    return {
        "score": score,
        "grade": grade,
        "passed": [_render_passed_entry(c) for c in result.checks if c.passed],
        "failed": [_render_failed_entry(c) for c in result.checks if not c.passed],
    }

format_agent_text(data, category=None)

Render agent-format audit data as compact text for LLM consumption.

Consumes the dict produced by format_agent and returns a minimal text representation optimised for token count.

Source code in packages/axm-audit/src/axm_audit/formatters.py
Python
def format_agent_text(
    data: dict[str, object],
    category: str | None = None,
) -> str:
    """Render agent-format audit data as compact text for LLM consumption.

    Consumes the dict produced by ``format_agent`` and returns a minimal
    text representation optimised for token count.
    """
    score = data.get("score")
    grade = data.get("grade")
    raw_passed = data.get("passed", [])
    raw_failed = data.get("failed", [])
    passed: list[str | dict[str, object]] = (
        list(raw_passed) if isinstance(raw_passed, list) else []
    )
    failed: list[dict[str, object]] = (
        [f for f in raw_failed if isinstance(f, dict)]
        if isinstance(raw_failed, list)
        else []
    )

    cat_label = f" {category}" if category else ""
    score_part = f" {grade} {score}" if score is not None and grade is not None else ""
    header = f"audit{cat_label} |{score_part} | {len(passed)} pass ยท {len(failed)} fail"
    lines: list[str] = [header]

    lines.extend(_render_passed(passed))
    for f in failed:
        lines.extend(_render_failed_check(f))

    return "\n".join(lines)

format_json(result)

Format audit result as JSON-serializable dict.

The score/grade pair is resolved through the single serialization source (:func:axm_audit.score.resolve_score_grade): the payload always carries a numeric score, and when a score cannot be computed at all it raises :class:axm_audit.score.ScoreIncalculableError rather than emit a success payload without a score key.

Source code in packages/axm-audit/src/axm_audit/formatters.py
Python
def format_json(result: AuditResult) -> dict[str, object]:
    """Format audit result as JSON-serializable dict.

    The ``score``/``grade`` pair is resolved through the single serialization
    source (:func:`axm_audit.score.resolve_score_grade`): the payload always
    carries a numeric ``score``, and when a score cannot be computed at all it
    raises :class:`axm_audit.score.ScoreIncalculableError` rather than emit a
    success payload without a ``score`` key.
    """
    score, grade = resolve_score_grade(result)
    return {
        "score": score,
        "grade": grade,
        "total": result.total,
        "failed": result.failed,
        "success": result.success,
        "checks": [
            {
                "rule_id": c.rule_id,
                "passed": c.passed,
                "message": c.message,
                "details": c.details,
                "metadata": c.metadata or None,
            }
            for c in result.checks
        ],
    }

format_report(result)

Format audit result as human-readable category-grouped report.

Source code in packages/axm-audit/src/axm_audit/formatters.py
Python
def format_report(result: AuditResult) -> str:
    """Format audit result as human-readable category-grouped report."""
    lines: list[str] = [
        "๐Ÿ“‹ axm-audit โ€” Quality Audit",
        f"   Path: {result.project_path or 'unknown'}",
        "",
    ]
    lines.extend(_format_categories(result))
    lines.extend(_format_score(result))
    lines.extend(_format_improvements(result))
    lines.extend(_format_failures(result))
    return "\n".join(lines)

format_test_quality_json(result)

JSON superset: clusters + verdicts + pyramid + private violations.

Source code in packages/axm-audit/src/axm_audit/formatters.py
Python
def format_test_quality_json(result: AuditResult) -> dict[str, object]:
    """JSON superset: clusters + verdicts + pyramid + private violations."""
    private, pyramid, clusters, verdicts, no_pkg, file_naming = _extract_test_quality(
        result
    )
    rule_ids = sorted(
        {
            c.rule_id
            for c in result.checks
            if (c.rule_id or "").startswith("TEST_QUALITY_")
        }
    )
    score, grade = score_grade_or_none(result)
    payload: dict[str, object] = {
        "score": score,
        "grade": grade,
        "rules": rule_ids,
        "clusters": clusters,
        "verdicts": verdicts,
        "pyramid_mismatches": pyramid,
        "private_import_violations": private,
        "no_package_symbol": [
            {**entry, "rule_id": "TEST_QUALITY_NO_PACKAGE_SYMBOL"} for entry in no_pkg
        ],
        "file_naming": [
            {**entry, "rule_id": "TEST_QUALITY_FILE_NAMING"} for entry in file_naming
        ],
    }
    return payload

format_test_quality_text(result, mismatches_only=False)

Render test-quality findings grouped by rule.

Order: private imports โ†’ pyramid โ†’ duplicates โ†’ tautologies. With mismatches_only=True only the pyramid section is emitted, filtered to entries whose folder differs from the classified level.

Source code in packages/axm-audit/src/axm_audit/formatters.py
Python
def format_test_quality_text(
    result: AuditResult,
    mismatches_only: bool = False,
) -> str:
    """Render test-quality findings grouped by rule.

    Order: private imports โ†’ pyramid โ†’ duplicates โ†’ tautologies.
    With ``mismatches_only=True`` only the pyramid section is emitted,
    filtered to entries whose folder differs from the classified level.
    """
    private, pyramid, clusters, verdicts, no_pkg, file_naming = _extract_test_quality(
        result
    )

    if mismatches_only:
        return _format_pyramid_only(pyramid)

    lines: list[str] = []
    lines.extend(_format_private_section(private))
    lines.append("")
    lines.extend(_format_pyramid_section(pyramid))
    lines.append("")
    lines.extend(_format_duplicates_section(clusters))
    lines.append("")
    lines.extend(_format_tautologies_section(verdicts))
    if no_pkg:
        lines.append("")
        lines.append("TEST_QUALITY_NO_PACKAGE_SYMBOL:")
        for entry in no_pkg:
            lines.append(
                f"  [{entry.get('verdict', '?')}] {entry.get('test_file', '?')}"
            )
    if file_naming:
        lines.append("")
        lines.append("TEST_QUALITY_FILE_NAMING:")
        for entry in file_naming:
            lines.append(
                f"  [{entry.get('verdict', '?')}] "
                f"{entry.get('current_name') or entry.get('canonical_name', '?')} "
                f"โ†’ {entry.get('proposed_name', '?')}"
            )

    return "\n".join(lines)