Repository navigation
feat: bind cross-project comparisons to source and intent evidence - #33
Conversation
There was a problem hiding this comment.
Validator approval after policy checks for exact head 3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab.
Ticket: ticket-025
Correlation ID: redup-025-comparison-evidence
Model: openai/cursor-auto
Reviewed diff chunks: 3
Advisory LLM verdict: REQUEST_CHANGES
Advisory summary: Reviewed all 3 diff chunk(s). The visible chunk adds source-bound comparison evidence, explicit analysis diagnostics, project-qualified scanner paths, and separate optional intent matching without exposing a blocking correctness or security defect. Both protected required checks passed. | The required protected checks pass, and the evidence model appropriately separates advisory similarity from quality decisions. However, source observation is not robust to valid relative repository paths. | The visible chunk adds focused regression coverage for stable evidence identities, source freshness and mutation safety, Git revision binding, explicit origin declarations, optional semantic and intent integrations, advisory recommendations, report limits, and cross-project identity. Required Python 3.10 and 3.13 checks passed. No unresolved code or security defects are evident in this chunk.
Advisory findings: source_observation() assumes root is absolute without enforcing or normalizing it. With a relative root such as Path('.'), path.resolve().relative_to(root) rejects every scanned file because it compares an absolute path to a relative one, and root.as_uri() then raises ValueError. Normalize root once with root.resolve() (and consistently use that normalized root in _fresh_source), or explicitly validate and reject relative roots at the API boundary.
The LLM output above is advisory and was not used as the approval trust root.
Semantic review prerequisite: not_required; policy 676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7.
Actual PR impact radar
Exact range: e3fec7f8b196fc506bd3ffa8cd91e8a84ab2fb98...3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab
Change digest: 8170de11f0e85642e436b778bc6372c6a9f59ecf34fdb299cad450f163a880c5
Score: 60/100 (L), estimated 75 min, split recommended: true
Affected services/components: repository-wide/unclassified
Machine-readable radar JSONL and SVG
{"actual_change":{"additions":680,"base_sha":"e3fec7f8b196fc506bd3ffa8cd91e8a84ab2fb98","binary_files":0,"categories":{"code":3,"configuration":1,"docs":1,"tests":1},"change_digest":"8170de11f0e85642e436b778bc6372c6a9f59ecf34fdb299cad450f163a880c5","comparison":"e3fec7f8b196fc506bd3ffa8cd91e8a84ab2fb98...3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab","deletions":8,"file_count":6,"files":["project/ticket-025/README.md","project/ticket-025/intent.json","src/redup/core/comparator.py","src/redup/core/comparison_evidence.py","src/redup/reporters/comparison_reporter.py","tests/test_comparison_reporter.py"],"head_sha":"3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab","service_count":0,"services":[]},"assessment_mode":"observed-pr","axes":{"coupling":5,"delivery":2,"scope":4,"uncertainty":3,"validation":1},"complexity":"L","confidence":0.9,"diagnostics":["RADAR-ACCEPTANCE-MISSING","RADAR-BUDGET-EXCEEDED"],"estimate":{"budget_minutes":30,"minutes":75,"within_budget":false},"impact":{"components":["3.10","block","project","src/redup","tests"],"files":["3.10/3.13","block/file","project/ticket-025/README.md","project/ticket-025/intent.json","src/redup/core/comparator.py","src/redup/core/comparison_evidence.py","src/redup/reporters/comparison_reporter.py","tests/test_comparison_reporter.py"],"public_interfaces":[],"runtime_dependencies":0},"schema":"subactor.ticket-radar/v1","score":60,"split":{"parts":[{"estimated_minutes":13,"name":"Implement 3.10","scope":["3.10"]},{"estimated_minutes":13,"name":"Implement block","scope":["block"]},{"estimated_minutes":13,"name":"Implement project","scope":["project"]},{"estimated_minutes":13,"name":"Implement src/redup","scope":["src/redup"]},{"estimated_minutes":13,"name":"Implement tests","scope":["tests"]},{"estimated_minutes":15,"name":"Validate and project to trackers","scope":["tests","planfile","github/gitlab/jira projections"]}],"reason":"estimated_minutes_exceed_budget","recommended":true},"standards":[{"id":"wellmanifest/dsl","revision":"6c60fc4e0dd1f1bb74f46a7745e28019908d1203","version":"0.1.0-dev"},{"id":"wellmanifest/ticket-lifecycle","revision":"5bf581907a87b46a13a73e6c033d3abe4d9a306f","version":"0.1.0-dev"},{"id":"wellmanifest/git-lifecycle","revision":"7d77d4b7af57e69bc75c3a0290b3a4805c5c4438","version":"0.2.0-dev"},{"id":"wellmanifest/logs","revision":"48c284ef7a069055c0bcb6b900147ce5e65f8b43","version":"0.3.0"}],"ticket_ref":"ticket-025"}<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img"><title>ticket-025: feat: bind cross-project comparisons to source and intent evidence</title><rect width="128" height="128" rx="12" fill="#f8fafc"/><g stroke-width="1"><polygon points="64,55 72,61 69,71 59,71 56,61" fill="none" stroke="#d7dde5"/><polygon points="64,47 80,59 74,78 54,78 48,59" fill="none" stroke="#d7dde5"/><polygon points="64,38 89,56 79,85 49,85 39,56" fill="none" stroke="#d7dde5"/><polygon points="64,30 97,53 84,92 44,92 31,53" fill="none" stroke="#d7dde5"/><polygon points="64,21 105,51 89,99 39,99 23,51" fill="none" stroke="#d7dde5"/><line x1="64" y1="64" x2="64" y2="21" stroke="#aab4c0"/><line x1="64" y1="64" x2="105" y2="51" stroke="#aab4c0"/><line x1="64" y1="64" x2="89" y2="99" stroke="#aab4c0"/><line x1="64" y1="64" x2="39" y2="99" stroke="#aab4c0"/><line x1="64" y1="64" x2="23" y2="51" stroke="#aab4c0"/></g><polygon points="64,30 105,51 79,85 59,71 48,59" fill="#fb923c" fill-opacity="0.45" stroke="#c2410c" stroke-width="2"/><circle cx="64" cy="64" r="3" fill="#c2410c"/><g font-family="sans-serif" font-size="7" fill="#334155"><text x="64" y="11" text-anchor="middle">SCO</text><text x="114" y="48" text-anchor="middle">COU</text><text x="95" y="107" text-anchor="middle">UNC</text><text x="33" y="107" text-anchor="middle">VAL</text><text x="14" y="48" text-anchor="middle">DEL</text></g><text x="64" y="124" text-anchor="middle" font-family="sans-serif" font-size="8" fill="#0f172a">L · 75m</text></svg>DECISION D-025-5395
TICKET ticket-025
HEAD_SHA 3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab
CORRELATION_ID redup-025-comparison-evidence
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["test (3.10)=PASS","test (3.13)=PASS","governance / enforce=PASS","governance / remote lifecycle=PASS"]
INPUT required_checks = ["test (3.10)","test (3.13)"]
INPUT required_checks_source = "protected registry (env/request)"
INPUT reviewer_login = "ifuri-validator-agent[bot]"
INPUT semantic_review_assessment = {"schema":"subactor.validator/semantic-review-assessment/v1","subject":{"repository":"semcod/redup","pull_request":33,"head_sha":"3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab","base_sha":"e3fec7f8b196fc506bd3ffa8cd91e8a84ab2fb98","diff_sha256":"6d066e5ce1ce59673b7b512b2e895f22ed7e5a385a324a0b0a330ea2d48fda34"},"policy":{"policy_schema":"subactor.validator/semantic-review-policy/v1","policy_version":1,"policy_sha256":"676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7","required":false,"critical_paths":[],"observed_paths":["project/ticket-025/README.md","project/ticket-025/intent.json","src/redup/core/comparator.py","src/redup/core/comparison_evidence.py","src/redup/reporters/comparison_reporter.py","tests/test_comparison_reporter.py"]},"grounding":"full-diff-not-per-finding-proof","execution_authority":false,"status":"not_required","reason":null,"review_sha256":null,"unresolved":[]}
INPUT superseded_checks = []
INPUT ticket_radar_receipt = {"schema":"subactor.ticket-radar/v1","base_sha":"e3fec7f8b196fc506bd3ffa8cd91e8a84ab2fb98","head_sha":"3e71d7fd297d837f7a3c66a5bbb1bb18eb9d6eab","change_digest":"8170de11f0e85642e436b778bc6372c6a9f59ecf34fdb299cad450f163a880c5","score":60,"complexity":"L","estimated_minutes":75,"split_recommended":true,"services":[],"authority":"ADVISORY","promotion":"FORBIDDEN"}
VERDICT APPROVE AUTHORITY DETERMINISTIC
REJECTED REQUEST_CHANGES BECAUSE NO_UNSAFE_CHANGE_REASON_FOUND
ADVISORY llm_verdict = "REQUEST_CHANGES" MODEL "openai/cursor-auto"
ASSERT VERDICT_AUTHORITY != "ADVISORY"
Cross-project reports now include versioned source evidence: scanned block/file hashes, observed Git HEAD, freshness, explicit provenance and stable candidate identities. Optional inline intent matching delegates to Intract and remains separate from LOC overlap; similarity and recommendations cannot select a quality winner. Relative scanner paths are qualified per project so equal filenames in separate roots remain distinct.
Validation: 45 affected comparator, reporter, real Intract, MCP and CLI tests passed on Python 3.11.15; Ruff, diff checks and managed governance passed. Hosted Python 3.10/3.13 checks and independent publication remain required. The deployed OneDev verifier currently has no redup profile; this PR does not change that policy.
Ticket: ticket-025; Planfile: PLF-20326 (parent PLF-20321). Refs #32. The exact Heyasa campaign is paused with no jobs while this native writer owns the branch. Local checkout identity and observed HEAD are deliberately distinguished from canonical remote identity and committed source; manifest artifact comparison remains with Intract.