Skip to content

Commit f233619

Browse files
committed
per-language base channel configs (closes #2)
- Dfg.base_cfg_for ext: .py adds string_values+field_names on top of the global base (N8 sweep: ALL MRR 0.955->0.969, evolved 0.862->0.929, samefile FPR halved; those channels cost recall on Rust) - Signature.extract ?ext selects the per-language cfg; threaded through every extraction site (units/bench/corpus/lsp/mcp/cli); diff_functions and graph build per-side/per-file cfgs - sigdb: format_version 2; cache tag carries rust+python channel bits - --with still composes on the global base for ablations - acceptance: python benchmark reproduces combo numbers with no flags; 16 sanity + 4 regression + protocol smokes green
1 parent 9f038a5 commit f233619

9 files changed

Lines changed: 48 additions & 22 deletions

File tree

nonna/cli/bench.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ let rank (pairs_file : string) (corpus_paths : string list) =
376376
let sig_of : (int, Signature.t) Hashtbl.t = Hashtbl.create 8192 in
377377
Units.units_of_paths corpus_paths
378378
|> List.iter (fun (u : Units.unit_info) ->
379-
let sg = Signature.extract u.Units.ucfg in
379+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
380380
if Signature.size sg >= Units.min_features then (
381381
let fid =
382382
Engine.add eng
@@ -486,7 +486,7 @@ let eval ?(scores_out : string option) (pairs_file : string) =
486486
Units.units_of_file file
487487
|> List.iter (fun (u : Units.unit_info) ->
488488
Hashtbl.replace t u.Units.uline_start
489-
(Signature.extract u.Units.ucfg))
489+
(Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg))
490490
with _ -> ());
491491
Hashtbl.replace cache file t;
492492
t

nonna/cli/corpus.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ let cache_dir () : string =
101101
let index_dir (dir : string) : Sigdb.entry list =
102102
Units.units_of_paths [ dir ]
103103
|> List.filter_map (fun (u : Units.unit_info) ->
104-
let sg = Signature.extract u.Units.ucfg in
104+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
105105
if Signature.size sg < Units.min_features then None
106106
else
107107
Some

nonna/cli/lsp_server.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ let index_workspace_async (root : string) : unit =
103103
let eng = Engine.create () in
104104
Units.units_of_paths [ root ]
105105
|> List.iter (fun (u : Units.unit_info) ->
106-
let sg = Signature.extract u.Units.ucfg in
106+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
107107
if Signature.size sg >= Units.min_features then
108108
ignore
109109
(Engine.add eng
@@ -131,7 +131,7 @@ let line_range (line0 : int) : J.t =
131131
let diagnostics_for (path : string) : J.t list =
132132
Units.units_of_file path
133133
|> List.filter_map (fun (u : Units.unit_info) ->
134-
let sg = Signature.extract u.Units.ucfg in
134+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
135135
if Signature.size sg < Units.min_features then None
136136
else
137137
Engine.query !engine sg ~threshold:report_threshold ~max_results:5
@@ -218,7 +218,7 @@ let find_similar (uri : string) (line0 : int) : J.t =
218218
match Units.unit_at path (line0 + 1) with
219219
| None -> `Assoc [ ("query", `Null); ("hits", `List []) ]
220220
| Some u ->
221-
let sg = Signature.extract u.Units.ucfg in
221+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
222222
let hits =
223223
Engine.query !engine sg ~threshold:0.2 ~max_results:15
224224
|> List.filter (fun (h : Engine.hit) ->

nonna/cli/main.ml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ let cmd_features (file : string) =
2020
Units.units_of_file file
2121
|> List.iter (fun (u : Units.unit_info) ->
2222
let feats = Dfg.extract u.Units.ucfg in
23-
let sg = Signature.extract u.Units.ucfg in
23+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
2424
Printf.printf "=== %s (%s) — %d dfg features, %d total\n"
2525
u.Units.uname (Units.loc_str u) (List.length feats)
2626
(Signature.size sg);
@@ -50,7 +50,7 @@ let cmd_query (corpus : string list) (draft : string) (threshold : float)
5050
Printf.printf "corpus: %d units indexed\n" (List.length kept);
5151
Units.units_of_file draft
5252
|> List.iter (fun (u : Units.unit_info) ->
53-
let sg = Signature.extract u.Units.ucfg in
53+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
5454
Printf.printf "\n── %s (%s) — %d features\n" u.Units.uname
5555
(Units.loc_str u) (Signature.size sg);
5656
if Signature.size sg < Units.min_features then
@@ -103,7 +103,10 @@ let cmd_graph (file : string) (fn_filter : string option) (outdir : string) =
103103
in
104104
selected
105105
|> List.iter (fun (u : Units.unit_info) ->
106-
let g = Dfg.graph_of u.Units.ucfg in
106+
let g =
107+
Dfg.graph_of ~fc:(Dfg.base_cfg_for (Filename.extension file))
108+
u.Units.ucfg
109+
in
107110
let source =
108111
if u.Units.uline_start > 0 && file_lines <> [] then
109112
Some

nonna/cli/mcp_server.ml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ let index_async (root : string) : unit =
7272
let eng = Engine.create () in
7373
Units.units_of_paths [ root ]
7474
|> List.iter (fun (u : Units.unit_info) ->
75-
let sg = Signature.extract u.Units.ucfg in
75+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
7676
if Signature.size sg >= Units.min_features then
7777
ignore
7878
(Engine.add eng
@@ -188,7 +188,7 @@ let hit_block (h : Engine.hit) : string =
188188

189189
let query_unit (u : Units.unit_info) ~(threshold : float) ~(top_k : int) :
190190
Engine.hit list =
191-
let sg = Signature.extract u.Units.ucfg in
191+
let sg = Signature.extract ~ext:(Filename.extension u.Units.ufile) u.Units.ucfg in
192192
if Signature.size sg < Units.min_features then []
193193
else
194194
Engine.query !engine sg ~threshold ~max_results:(top_k + 1)
@@ -262,10 +262,18 @@ let diff_functions (args : J.t) : J.t =
262262
match (resolve_side args "a", resolve_side args "b") with
263263
| Error e, _ | _, Error e -> tool_text ~is_error:true e
264264
| Ok (la, ua), Ok (lb, ub) ->
265-
let sa = Signature.extract ua.Units.ucfg in
266-
let sb = Signature.extract ub.Units.ucfg in
267-
let ga = Dfg.graph_of ua.Units.ucfg in
268-
let gb = Dfg.graph_of ub.Units.ucfg in
265+
let sa = Signature.extract ~ext:(Filename.extension ua.Units.ufile) ua.Units.ucfg in
266+
let sb = Signature.extract ~ext:(Filename.extension ub.Units.ufile) ub.Units.ucfg in
267+
let ga =
268+
Dfg.graph_of
269+
~fc:(Dfg.base_cfg_for (Filename.extension ua.Units.ufile))
270+
ua.Units.ucfg
271+
in
272+
let gb =
273+
Dfg.graph_of
274+
~fc:(Dfg.base_cfg_for (Filename.extension ub.Units.ufile))
275+
ub.Units.ucfg
276+
in
269277
let text =
270278
String.concat "\n\n"
271279
[

nonna/cli/sigdb.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ module Engine = Nonna_index.Engine
88
module Signature = Nonna_features.Signature
99

1010
(* bump on any change to hashing/features/weights *)
11-
let format_version = 1
11+
let format_version = 2
1212

1313
type entry = { meta : Engine.meta; sg : Signature.t }
1414

1515
let profile_tag () : string =
1616
let module Dfg = Nonna_features.Dfg in
17-
Printf.sprintf "%s-i%d-b%x"
17+
Printf.sprintf "%s-i%d-b%x-p%x"
1818
(if !Signature.default_profile = Signature.full_profile then "full"
1919
else "structural")
2020
!Dfg.iterations
21-
(Dfg.cfg_bits !Dfg.base_cfg)
21+
(Dfg.cfg_bits (Dfg.base_cfg_for ".rs"))
22+
(Dfg.cfg_bits (Dfg.base_cfg_for ".py"))
2223

2324
let save (path : string) (entries : entry list) : unit =
2425
let tmp = path ^ ".tmp" in

nonna/cli/units.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ let index_units (units : unit_info list) :
171171
let kept =
172172
units
173173
|> List.filter_map (fun u ->
174-
let sg = Signature.extract u.ucfg in
174+
let sg = Signature.extract ~ext:(Filename.extension u.ufile) u.ucfg in
175175
if Signature.size sg < min_features then None
176176
else (
177177
ignore

nonna/features/dfg.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ let keep_value (fc : cfg) (kind : string) : bool =
141141
let base_cfg : cfg ref =
142142
ref { structural_cfg with call_names = true; int_values = true }
143143

144+
(* Per-language base (N8 sweeps, issue #2): channel optima differ by
145+
language. Python additionally wants string_values + field_names
146+
(stringly-typed: literals and attribute names are API identity there;
147+
ALL MRR 0.955→0.969, evolved 0.862→0.929, samefile FPR halved) — the
148+
same channels COST recall on Rust. Composed on top of the global
149+
base_cfg so --with ablations still apply everywhere. *)
150+
let base_cfg_for (ext : string) : cfg =
151+
let b = !base_cfg in
152+
match ext with
153+
| ".py" -> { b with string_values = true; field_names = true }
154+
| _ -> b
155+
144156
(* compact tag for cache keys / reports *)
145157
let cfg_bits (c : cfg) : int =
146158
(if c.call_names then 1 else 0)

nonna/features/signature.ml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,16 @@ let full_profile =
4343
(* Set once at CLI startup (--profile). *)
4444
let default_profile : profile ref = ref structural_profile
4545

46-
let extract ?(profile : profile option) (fcfg : IL.fun_cfg) : t =
46+
(* [ext] selects the per-language base channels (Dfg.base_cfg_for). *)
47+
let extract ?(profile : profile option) ?(ext = "") (fcfg : IL.fun_cfg) : t =
4748
let p = match profile with Some p -> p | None -> !default_profile in
49+
let fc = Dfg.base_cfg_for ext in
4850
let sem = Semantic.extract_parts fcfg in
4951
let all : (Fhash.t * float) list =
50-
(Dfg.extract fcfg
52+
(Dfg.extract ~fc fcfg
5153
|> List.map (fun (f : Dfg.feature) -> (f.Dfg.hash, dfg_weight f.Dfg.tag)))
5254
@ (if p.w_delta_sem > 0. then
53-
Dfg.extract_delta ~rich:Dfg.semantic_cfg fcfg
55+
Dfg.extract_delta ~base:fc ~rich:Dfg.semantic_cfg fcfg
5456
|> List.map (fun (f : Dfg.feature) ->
5557
(f.Dfg.hash, p.w_delta_sem *. dfg_weight f.Dfg.tag))
5658
else [])

0 commit comments

Comments
 (0)