git-slop 0.16.4

A deterministic repository token-defragmenter for humans and AI agents.
Documentation
fn run_html(repo_root: &Path, args: HtmlArgs) -> Result<i32> {
    let (loaded, report_path) = report_or_missing_with_currentness(
        repo_root,
        args.report.as_deref(),
        args.require_current,
    )?;
    let output = args
        .output
        .map(|path| resolve_repo_path(repo_root, &path))
        .unwrap_or_else(|| {
        report_path
            .parent()
            .map_or_else(|| config::latest_dir(repo_root), Path::to_path_buf)
            .join("report.html")
        });
    if let Some(parent) = output.parent() {
        fs::create_dir_all(parent)?;
    }

    let array_records = |pointer: &str| {
        loaded
            .pointer(pointer)
            .and_then(Value::as_array)
            .cloned()
            .unwrap_or_default()
    };
    let section_records = |pointer: &str| {
        loaded
            .pointer(pointer)
            .and_then(Value::as_object)
            .into_iter()
            .flat_map(|sections| sections.values())
            .filter_map(Value::as_array)
            .flatten()
            .cloned()
            .collect::<Vec<_>>()
    };
    let embedded_limit = 5_000usize;
    let bounded = |records: &[Value]| records.iter().take(embedded_limit).cloned().collect::<Vec<_>>();
    let files = array_records("/files");
    let folders = array_records("/folders");
    let action_queue = array_records("/action_queue");
    let observation_feed = array_records("/observation_feed");
    let health = array_records("/health/findings");
    let policy_failures = failing_records_in(
        &loaded,
        loaded
            .pointer("/policy_evaluation/thresholds/context_band")
            .and_then(Value::as_str),
        loaded
            .pointer("/policy_evaluation/thresholds/slop_band")
            .and_then(Value::as_str),
        false,
    );
    let relationships = section_records("/overlays/organization_health/relationships");
    let clusters = deduplicate_clusters(section_records(
        "/overlays/organization_health/clusters",
    ));
    let view_metadata = |records: &[Value]| {
        json!({
            "total": records.len(),
            "embedded": records.len().min(embedded_limit),
            "truncated": records.len() > embedded_limit
        })
    };
    let source_report = args
        .include_local_paths
        .then(|| relative_display(&report_path, repo_root));
    let freshness = (!repo_root.as_os_str().is_empty())
        .then(|| crate::freshness::evaluate(repo_root, &loaded).ok())
        .flatten();
    let payload = serde_json::to_string(&json!({
        "schema_version": loaded.get("schema_version"),
        "generated_at": loaded.get("generated_at"),
        "analyzed_revision_at": loaded.get("analyzed_revision_at"),
        "analyzer": loaded.get("analyzer"),
        "repo": loaded.get("repo"),
        "scope": loaded.get("scope"),
        "config_digests": {
            "config": loaded.pointer("/analyzer/config_digest"),
            "analysis": loaded.pointer("/analyzer/analysis_config_digest"),
            "evidence": loaded.pointer("/analyzer/evidence_config_digest"),
            "policy": loaded.pointer("/analyzer/policy_config_digest"),
            "presentation": loaded.pointer("/analyzer/presentation_config_digest")
        },
        "collection_metadata": loaded.get("collection_metadata"),
        "evidence_completeness": loaded.get("evidence_completeness"),
        "overview": {
            "policy_failures": policy_failures.len(),
            "interventions": action_queue.len(),
            "observations": observation_feed.len(),
            "advisory_health_findings": health.len(),
            "tracked_paths": loaded.pointer("/stats/tracked_file_count"),
            "analyzed_paths": loaded.pointer("/stats/analyzed_file_count")
        },
        "files": bounded(&files),
        "folders": bounded(&folders),
        "policy_failures": bounded(&policy_failures),
        "action_queue": bounded(&action_queue),
        "observation_feed": bounded(&observation_feed),
        "health": {
            "summary": loaded.pointer("/health/summary"),
            "findings": bounded(&health)
        },
        "organization": {
            "relationships": bounded(&relationships),
            "clusters": bounded(&clusters)
        },
        "embedded_evidence": {
            "record_limit_per_view": embedded_limit,
            "view_metadata": {
                "files": view_metadata(&files),
                "folders": view_metadata(&folders),
                "policy_failures": view_metadata(&policy_failures),
                "action_queue": view_metadata(&action_queue),
                "observation_feed": view_metadata(&observation_feed),
                "health": view_metadata(&health),
                "relationships": view_metadata(&relationships),
                "clusters": view_metadata(&clusters)
            }
        },
        "source_report": source_report
        ,"freshness": freshness
    }))?
    .replace("</", "<\\/");
    let csp_nonce = &hex::encode(sha2::Sha256::digest(payload.as_bytes()))[..24];
    let html = format!(
        r##"<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data:; style-src 'nonce-{nonce}'; script-src 'nonce-{nonce}'; base-uri 'none'; form-action 'none'">
  <title>Git Slop local report</title>
  <style nonce="{nonce}">{style}</style>
</head>
<body>
  <a class="skip-link" href="#report-main">Skip to report</a>
  <header class="hero shell">
    <div>
      <p class="eyebrow">Local repository evidence</p>
      <h1>Git Slop report</h1>
      <p id="descriptor" class="descriptor"></p>
    </div>
    <span id="schema-badge" class="hero-badge"></span>
  </header>
  <main id="report-main" class="shell">
    <section class="report-card" aria-labelledby="report-heading">
      <h2 id="report-heading" class="sr">Report explorer</h2>
      <p id="freshness" class="notice" role="status"></p>
      <p id="truncation" class="notice" role="status"></p>
      <p id="selection-status" class="sr" role="status" aria-live="polite"></p>
      <section class="overview" aria-labelledby="overview-heading">
        <div>
          <p class="eyebrow">Decision overview</p>
          <h2 id="overview-heading">Start with the surface that matches your decision</h2>
          <p class="muted">Policy failures enforce configured thresholds. Interventions warrant review. Observations and health findings are advisory.</p>
        </div>
        <div id="overview-grid" class="overview-grid"></div>
      </section>
      <nav class="views" aria-label="Report view">
        <button type="button" data-view="policy" aria-pressed="false">Policy failures</button>
        <button type="button" data-view="queue" aria-pressed="false">Interventions</button>
        <button type="button" data-view="observations" aria-pressed="false">Observations</button>
        <button type="button" data-view="health" aria-pressed="false">Advisory health</button>
        <button type="button" data-view="files" aria-pressed="false">Files</button>
        <button type="button" data-view="folders" aria-pressed="false">Folders</button>
        <button type="button" data-view="relationships" aria-pressed="false">Relationships</button>
        <button type="button" data-view="clusters" aria-pressed="false">Clusters</button>
      </nav>
      <div class="controls">
        <div class="control">
          <label for="query">Search records</label>
          <input id="query" type="search" placeholder="Search paths" autocomplete="off">
        </div>
        <div class="control">
          <label for="profile">Profile</label>
          <select id="profile"><option value="">All profiles</option></select>
        </div>
        <div class="control">
          <label for="classification">Classification</label>
          <select id="classification"><option value="">All classifications</option></select>
        </div>
        <div class="control">
          <label for="language">Language</label>
          <select id="language"><option value="">All languages</option></select>
        </div>
        <div class="control">
          <label for="context-band">Context/load band</label>
          <select id="context-band"><option value="">All context bands</option></select>
        </div>
        <div class="control">
          <label for="slop-band">Maintenance band</label>
          <select id="slop-band"><option value="">All maintenance bands</option></select>
        </div>
        <div class="control">
          <label for="severity">Review severity</label>
          <select id="severity"><option value="">All severities</option></select>
        </div>
        <div class="control control-action">
          <button id="reset-filters" type="button">Reset filters</button>
        </div>
      </div>
      <div class="results-toolbar">
        <div>
          <p id="count" aria-live="polite"></p>
          <p id="sort-state" class="muted" aria-live="polite"></p>
        </div>
        <div class="pagination" aria-label="Result pages">
          <button id="first" type="button">First</button>
          <button id="previous" type="button">Previous</button>
          <label class="page-jump" for="page-number">Page <input id="page-number" type="number" min="1" value="1"></label>
          <label class="page-jump" for="page-size">Rows <select id="page-size"><option>25</option><option selected>100</option><option>250</option></select></label>
          <button id="next" type="button">Next</button>
          <button id="last" type="button">Last</button>
        </div>
      </div>
      <div class="explorer-layout">
        <div class="table-shell" tabindex="0" role="region" aria-label="Scrollable report table">
          <table>
            <caption class="sr">Git Slop report records</caption>
            <thead><tr id="headers"></tr></thead>
            <tbody id="rows"></tbody>
          </table>
        </div>
        <aside id="detail-panel" class="detail-panel" aria-labelledby="detail-title" hidden>
        <div class="detail-heading">
          <div>
            <p class="eyebrow">Selected evidence</p>
            <h2 id="detail-title" tabindex="-1"></h2>
          </div>
          <button id="close-detail" type="button" aria-label="Close selected record">Close</button>
        </div>
        <p id="detail-summary" class="detail-summary"></p>
        <dl id="detail-metrics" class="metric-grid"></dl>
        <div id="detail-evidence"></div>
        <div class="detail-section">
          <h3>Next commands</h3>
          <div id="detail-commands" class="command-list"></div>
        </div>
        <details>
          <summary>Raw record JSON</summary>
          <pre id="detail-raw"></pre>
        </details>
        </aside>
      </div>
      <details>
        <summary>Evidence and portability summary</summary>
        <pre id="evidence-summary"></pre>
      </details>
    </section>
  </main>
  <script id="report" type="application/json">{payload}</script>
  <script nonce="{nonce}">{model}</script>
  <script nonce="{nonce}">{script}</script>
</body>
</html>"##,
        nonce = csp_nonce,
        style = include_str!("html/report-app.css"),
        payload = payload,
        model = include_str!("html/report-model.js"),
        script = include_str!("html/report-app.js")
    );
    config::write_text_atomically(&output, html, false)?;
    println!("Wrote local HTML report to {}.", output.display());
    if args.serve {
        let html = fs::read_to_string(&output)?;
        serve_report(&html, args.serve_seconds, args.open)?;
    }
    Ok(0)
}