Skip to content

feat(fingerprint, ticket-013): export read-only CFG and DFG fingerprints for semantic retrieval (#9) - #19

Merged
ifuri-validator-agent[bot] merged 1 commit into
mainfrom
ticket/013-cfg-dfg-fingerprints-9
Oct 27, 2026
Merged

ifuri-validator-agent[bot] merged 1 commit into
mainfrom
ticket/013-cfg-dfg-fingerprints-9

Conversation

@tom-sapletta-com

Copy link
Copy Markdown
Contributor

Implement read-only structural IR export (code2logic.structural_fingerprint/v1, code2logic.structural_export/v1, code2logic.structural_similarity/v1) for semantic retrieval candidates (PLF-006).

Summary

  • Extract symbol-local normalized Control-Flow Graphs (CFG), Data-Flow Graphs (DFG), I/O profiles, and side-effect profiles with SHA-256 raw source and normalized structural hashes in code2logic/fingerprint.py (re-exported via code2logic.core).
  • Ensure alpha-renaming equivalence across parameters, local variables, recursive self-calls, and docstrings/comments while diverging on behavior-changing edits (branch predicate changes, data-flow dependency rewiring, side-effect mutations/exceptions).
  • Keep structural similarity comparison and retrieval candidate ranking strictly read-only and advisory (read_only=True, authority="advisory_only", grants_authority=False).

Closes #9
Ticket: ticket-013

@ifuri-validator-agent ifuri-validator-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validator approval after policy checks for exact head 4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2.

Ticket: ticket-013
Correlation ID: local-semcod-code2logic-pr-19-ticket-013
Model: openai/cursor-auto
Reviewed diff chunks: 7
Advisory LLM verdict: REQUEST_CHANGES
Advisory summary: Reviewed all 7 diff chunk(s). Required checks passed, but the visible alpha-normalization implementation does not consistently normalize equivalent method receiver parameters. | Required checks pass, and the visible implementation provides immutable, advisory-only structural records. However, the f-string normalization omits behaviorally significant formatting details. | Required checks pass, but the visible CFG construction for try/finally does not preserve Python's mandatory-finally execution semantics. | Required checks pass, but the visible implementation has unresolved structural-fingerprint correctness defects in control-flow and I/O-profile extraction. | Required checks pass, but the visible effects extraction has a semantic correctness defect: it attributes effects from nested function/class bodies to the enclosing symbol. | The visible chunk implements deterministic advisory-only structural similarity ranking, exports the intended public API, records ticket scope, and adds focused tests for alpha-renaming, recursive self-calls, and behavior-changing divergence. All protected required checks passed. | The visible test chunk verifies export metadata, serialization, candidate counts, exact structural-equivalence ranking, advisory-only authority, and lower ranking for an unrelated recursive function. No unresolved code or security defects are evident. All protected required checks passed.
Advisory findings: _SymbolAlphaNormalizer._bind_parameters maps a method's first parameter to "$self" only when its source name is literally "self" or "cls". An otherwise equivalent method using a different receiver name is mapped to "$arg0", producing a different normalized representation and structural digest solely because of alpha-renaming. This contradicts the stated symbol-local parameter alpha-renaming guarantee. Normalize the first method receiver by position or otherwise ensure receiver renames remain structurally equivalent, and add a regression test.; ast.JoinedStr normalization records only the formatted value expression and ignores each ast.FormattedValue node's conversion and format_spec. Consequently, behavior-changing expressions such as f"{value}", f"{value!r}", and f"{value:.2f}" can receive identical normalized AST and downstream structural fingerprints, contradicting the stated requirement that behavior-changing edits diverge. Include normalized conversion and format-spec information and cover these cases with tests.; In _CFGBuilder._process_block, the finally_block is connected only from try_tails + handler_tails. Abrupt control transfers inside the try or handlers—such as return, raise, break, and continue—are not tails and therefore bypass the finally node in the generated CFG, even though Python always executes the finally suite before completing those transfers. This can produce structurally incorrect fingerprints and similarity results for functions using try/finally.; CFG construction drops break control flow: a break node is created, but no edge connects it to the enclosing loop exit, and current_incoming is cleared. This produces an incomplete/incorrect CFG for loops containing break.; _build_io_profile uses ast.walk over each top-level statement without pruning nested function, async-function, class, or lambda scopes. Consequently, returns and yields inside nested definitions are attributed to the enclosing function, corrupting its return/yield shapes and potentially misclassifying it as a generator.; _build_effects_profile uses ast.walk(stmt) without stopping at nested FunctionDef, AsyncFunctionDef, Lambda, or ClassDef scopes. Consequently, calls, raises, awaits, and mutations inside a nested definition are recorded as effects of the enclosing function even though those bodies are not executed when the enclosing function runs. Scope-aware traversal is required.
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: 2906d908b70411513553a7337f17a0b4f34a8849...4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2
Change digest: cb665c6ac3b952d7437497dae94a6cf6d06d6319b82a913b7c4c499b1ab8e698
Score: 68/100 (L), estimated 127 min, split recommended: true
Affected services/components: repository-wide/unclassified

Machine-readable radar JSONL and SVG
{"actual_change":{"additions":1881,"base_sha":"2906d908b70411513553a7337f17a0b4f34a8849","binary_files":0,"categories":{"code":2,"configuration":1,"docs":2,"tests":1},"change_digest":"cb665c6ac3b952d7437497dae94a6cf6d06d6319b82a913b7c4c499b1ab8e698","comparison":"2906d908b70411513553a7337f17a0b4f34a8849...4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2","deletions":0,"file_count":6,"files":["code2logic/core/__init__.py","code2logic/fingerprint.py","project/TICKETS.md","project/ticket-013/README.md","project/ticket-013/intent.json","tests/test_structural_fingerprint.py"],"head_sha":"4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2","service_count":0,"services":[]},"assessment_mode":"observed-pr","axes":{"coupling":5,"delivery":3,"scope":5,"uncertainty":3,"validation":1},"complexity":"L","confidence":0.9,"diagnostics":["RADAR-ACCEPTANCE-MISSING","RADAR-BUDGET-EXCEEDED"],"estimate":{"budget_minutes":30,"minutes":127,"within_budget":false},"impact":{"components":["I","code2logic","code2logic.structural_export","code2logic.structural_fingerprint","code2logic.structural_similarity","docstrings","mutations","project","tests"],"files":["I/O","code2logic.structural_export/v1","code2logic.structural_fingerprint/v1","code2logic.structural_similarity/v1","code2logic/core/__init__.py","code2logic/fingerprint.py","docstrings/comments","mutations/exceptions","project/TICKETS.md","project/ticket-013/README.md","project/ticket-013/intent.json","tests/test_structural_fingerprint.py"],"public_interfaces":[],"runtime_dependencies":1},"schema":"subactor.ticket-radar/v1","score":68,"split":{"parts":[{"estimated_minutes":13,"name":"Implement I","scope":["I"]},{"estimated_minutes":13,"name":"Implement code2logic","scope":["code2logic"]},{"estimated_minutes":13,"name":"Implement code2logic.structural_export","scope":["code2logic.structural_export"]},{"estimated_minutes":13,"name":"Implement code2logic.structural_fingerprint","scope":["code2logic.structural_fingerprint"]},{"estimated_minutes":13,"name":"Implement code2logic.structural_similarity","scope":["code2logic.structural_similarity"]},{"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-013"}
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img"><title>ticket-013: feat(fingerprint, ticket-013): export read-only CFG and DFG fingerprints for semantic retrieval (#9)</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,21 105,51 79,85 59,71 39,56" 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 · 127m</text></svg>
Merge will be attempted after this approval when explicitly authorized. ## Decision record (recomputable)
DECISION D-013-8016
TICKET ticket-013
HEAD_SHA 4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2
CORRELATION_ID local-semcod-code2logic-pr-19-ticket-013
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["test (3.11)=PASS","test (3.13)=PASS","governance / enforce=PASS","test (3.12)=PASS","governance / remote lifecycle=PASS","test (3.11)=PASS","test (3.13)=PASS","test (3.12)=PASS"]
INPUT required_checks = ["test (3.11)","test (3.12)","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/code2logic","pull_request":19,"head_sha":"4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2","base_sha":"2906d908b70411513553a7337f17a0b4f34a8849","diff_sha256":"f75ac053f59d15e6e9ca8abcb44c3790676e8bcdc7786701c7d05e6a1fc64313"},"policy":{"policy_schema":"subactor.validator/semantic-review-policy/v1","policy_version":1,"policy_sha256":"676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7","required":false,"critical_paths":[],"observed_paths":["code2logic/core/__init__.py","code2logic/fingerprint.py","project/TICKETS.md","project/ticket-013/README.md","project/ticket-013/intent.json","tests/test_structural_fingerprint.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":"2906d908b70411513553a7337f17a0b4f34a8849","head_sha":"4d417117c0bd3ee1c00bd5b48f9cab7cdc349fa2","change_digest":"cb665c6ac3b952d7437497dae94a6cf6d06d6319b82a913b7c4c499b1ab8e698","score":68,"complexity":"L","estimated_minutes":127,"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"

@ifuri-validator-agent
ifuri-validator-agent Bot merged commit 34d6a5f into main Oct 27, 2026
8 checks passed
@ifuri-validator-agent
ifuri-validator-agent Bot deleted the ticket/013-cfg-dfg-fingerprints-9 branch October 27, 2026 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export CFG and DFG fingerprints for semantic retrieval candidates

1 participant