learn: in-function def-use slice from the tree-sitter layer + leak audit (\$0)

slice.py renders source -> step -> sink lines with fixed wording for flow,
no-flow and not-analysable; the prompt option is default-off (byte-identical
default prompt). semantic IR: JS/C declarations count as assignments, augmented
assignment keeps its target (gate, map_gate, pair_gate outputs unchanged).
Audit over exp-004's 501 units: 59 flow, 161 no-flow, 281 not analysable;
has-flow within-pair accuracy 0.52, pooled AUC 0.55 -- no leak. Fixes a
numbering bug that rejected every excerpt with a blank line. With Codex.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Marius Ciepluch
2026-10-03 14:56:52 +02:00
co-authored by Claude Opus 5.5
parent 2836b78819
commit 1b2c7993a7
7 changed files with 6789 additions and 4 deletions
+10
View File
@@ -15,6 +15,7 @@ class Bind:
is_constant: bool
names: tuple[str, ...]
call_name: str | None
order: int = 0 # evaluation end position; calls precede their containing assignment
@dataclass(frozen=True)
@@ -25,6 +26,7 @@ class CallSite:
arg_is_constant: tuple[bool, ...]
arg_names: tuple[tuple[str, ...], ...]
extra_arg_is_sequence: bool
order: int = 0
@dataclass(frozen=True)
@@ -119,6 +121,7 @@ def _collect_stmt(stmt: ast.stmt, binds: list[Bind], calls: list[CallSite]) -> N
is_constant=value_bind[1],
names=value_bind[2],
call_name=value_bind[3],
order=_end_position(stmt.value),
)
)
_collect_expr_calls(stmt.value, calls)
@@ -133,6 +136,7 @@ def _collect_stmt(stmt: ast.stmt, binds: list[Bind], calls: list[CallSite]) -> N
is_constant=value_bind[1],
names=value_bind[2],
call_name=value_bind[3],
order=_end_position(stmt.value),
)
)
_collect_expr_calls(stmt.value, calls)
@@ -147,6 +151,7 @@ def _collect_stmt(stmt: ast.stmt, binds: list[Bind], calls: list[CallSite]) -> N
is_constant=False,
names=tuple(sorted(set(value_bind[2]) | {stmt.target.id})),
call_name=value_bind[3],
order=_end_position(stmt.value),
)
)
_collect_expr_calls(stmt.value, calls)
@@ -190,6 +195,7 @@ def _call_site(node: ast.Call) -> CallSite:
if len(node.args) >= 2:
extra_sequence = isinstance(node.args[1], ast.Tuple | ast.List | ast.Set)
return CallSite(
order=_end_position(node),
name=_call_name(node),
line=node.lineno,
arg_texts=tuple(arg_texts),
@@ -199,6 +205,10 @@ def _call_site(node: ast.Call) -> CallSite:
)
def _end_position(node: ast.AST) -> int:
return int(getattr(node, "end_lineno", 0) or 0) * 1_000_000 + int(getattr(node, "end_col_offset", 0) or 0)
def _call_name(node: ast.AST) -> str:
func = node.func if isinstance(node, ast.Call) else node
return _unparse(func)