Skip to content

[Bug]: report digest (= MCP run_id) includes cache execution state, checkout dirname, and evaluator thresholds #56

Description

@orenlab

Metadata

Field Value
CodeClone version 2.1.0a1 (reproduced on release/2.1.0a2, commit 932d4b73)
Affected area Canonical report / JSON

What happened?

The canonical report digest (integrity.digest.value) — which is the MCP run_id — includes volatile execution provenance and presentation data. Two runs over byte-identical facts produce different run identities, and that churn cascades through the whole change-control and memory plane.

Volatile inputs proven to be inside the digest (codeclone/report/document/integrity.py:15-48 strips only meta.runtime, display_facts, and volatile file counters):

  1. meta.cache.used / meta.cache.status — a cache-off run vs a warm cache-reuse run over identical facts hash differently ({"used": false, "status": "missing"} vs {"used": true, "status": "ok"}).
  2. meta.project_name — literally scan_root.name (codeclone/report/meta.py:67). The same repo checked out at codeclone/ vs codeclone-copy/ gets different digests, even though scan_root itself is hardcoded to "." and all file paths are relative.
  3. meta.analysis_thresholds — evaluator policy (complexity/coupling/cohesion thresholds) changes semantic identity without any fact changing.

Cascade (all bindings verified):

  • MCP run_id = this digest (surfaces/mcp/session.py:472);
  • active change intents expire when the digest changes (_session_intent_mixin.py:777-791) — so re-running analysis with a warm cache can invalidate an intent mid-edit;
  • review receipts (_session_review_receipt_mixin.py:284), patch trail, audit rows (audit/schema.py:33), and Engineering Memory ingestion keys (memory/project.py:99-116) all record the volatile digest.

What did you expect instead?

A digest hierarchy separating semantic identity from execution/presentation:

  • facts_digest — canonical facts only; excludes cache usage, project display name, timestamps, absolute paths, evaluator thresholds;
  • evaluation_digest — gate policy applied at run time;
  • envelope_digest — full-document artifact identity (current semantics, kept for exact-artifact binding).

MCP run_id and intent freshness bind to facts_digest; receipts/audit/memory record both tiers. Cache execution path and checkout dirname must not change run identity; real content/config changes must.

Minimal reproduction

# Run 1 (cold): codeclone . --json out1.json      (cache missing)
# Run 2 (warm): codeclone . --json out2.json      (cache reused, zero file changes)
# Compare integrity.digest.value: DIFFERENT, though findings/metrics/inventory
# are byte-identical. Renaming the checkout directory reproduces it too.

Additional context

  • REPORT_SCHEMA_VERSION is stamped at write time but never enforced on read anywhere — a report from a different build is silently accepted (same digest-trust family of gaps).
  • Fix contract: Phase 39 spec specs/phase-39-baseline-container-lanes.md §10.8 + invariant I-18 (volatile-free run identity), §6.3 (read-side schema enforcement).
  • Note for triage: get_report_section does not re-hash per call (in-memory document); this issue is about digest composition, not hashing cost.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions