Repository navigation
ta.txt #13594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ta.txt #13594
Changes from all commits
ec099f3
71a9a1c
bd2cd6d
2ab5f7c
78cd059
bb7cbf8
ebf385f
65dc5b1
74eec69
dc666b6
f342997
a78f65c
546b230
529775c
d5c217e
bcfae75
6d01965
8e28d6f
c2108c0
ee21d9c
56affb0
4f0c70a
e2dd286
e230ee0
87466b6
2723f94
a795eea
0d17c59
4ef7e8f
aae91ac
1d33e40
81b75aa
1afb9ae
4607706
fbdfd1d
b986e1b
5bbf8db
66dac70
916752e
ecb3bce
395effc
5175c6f
7255cbb
804bfb9
04ff6fe
90f5480
cf2aefb
613317b
097bc4b
ec44083
b04ba3d
e046ab6
559477e
6bc0f82
1533497
01e7956
30fe104
eb7b1dd
201e9dd
c70ff56
84bae18
fe01fad
defd9ec
fc30f75
a9ee3f3
bbd0ddb
0ee63e1
99636d2
9e9142a
0c040c8
8baf3a8
431aae7
e3016fd
ef0ede9
f729c0f
6f8dd68
020ed88
1f2a9c2
c41c3b4
c03581a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| module gunbc.instruments.argv_word_construction_census | ||
|
|
||
| // THE TYPED-ARGV CONSTRUCTION CENSUS ROSTER (debt paydown trial, witty-tern-54, 2026-10-03). | ||
| // | ||
| // The instrument is v2.lens.argv_word_construction; this module commits WHAT IT COUNTS: the | ||
| // population of argv-string construction sites over dag/extdeps and dag/gunbc, at identity grain, | ||
| // as a typed roster that may only shrink. DESIGN 5: a count over the current tree is not an | ||
| // oracle — every row below joins to a live census member at (module_file, decl, decl_kind), a | ||
| // row that stops resolving refuses the recount, and the population never grows past the committed | ||
| // baseline: new string-built argv is refused, not enrolled. | ||
| // | ||
| // Recount (the named, re-runnable instrument run): discover the two roots' module files by the | ||
| // declaration index, walk each with the lens, and hold the gates over (live, roster, baseline). | ||
| // The gates live in the lens; this module owns the committed state: the roster, the baseline | ||
| // cardinality, and the sites classified as NOT argv debt with a stated reason. | ||
|
|
||
| import v2.lens.argv_word_construction { | ||
| ArgvWordsDeclKind, | ||
| ArgvWordsFact, | ||
| ArgvWordsRosterRow, | ||
| ArgvWordsSite, | ||
| ArgvWordsSiteClass, | ||
| ExtdepsInterfaceBuilder, | ||
| FnDecl, | ||
| DataDecl, | ||
| WorkflowCallSite, | ||
| ArgvWordsModuleEstablished, | ||
| ArgvWordsModuleRefused, | ||
| RawTreeEstablished, | ||
| RawTreeNotEstablished, | ||
| facts_of, | ||
| raw_tree_of_text, | ||
| argv_word_construction_gates, | ||
| argv_word_construction_module_sites, | ||
| argv_word_construction_for_paths | ||
| } | ||
| import v2.std.algebra { fold_list, list_reverse } | ||
| import v2.std.collection { List } | ||
| import std.algebra { Cons, Empty, FreeMonoid } | ||
| import std.process { ExitSuccess, ProcessExit, exit_failure } | ||
| import extdeps.filesystem.filesystem_io { Filesystem } | ||
| import v2.std.node { Node } | ||
| import v2.std.integer { integer_int_to_decimal_string } | ||
| import v2.lens.module_graph { ModuleDeclarationFact, module_declaration_facts_live } | ||
|
|
||
| // The modeled roots. Anything else is refused by the lens, never silently zero. | ||
| data argv_word_construction_census_roots: List<String> = ["dag/extdeps", "dag/gunbc"] | ||
|
|
||
| // THE COMMITTED BASELINE: the population the instrument counted over the two roots at the start | ||
| // of the trial (origin/main, 2026-10-03). The roster may only shrink past this number. | ||
| data argv_word_construction_census_baseline_population: Int = 0 | ||
|
|
||
| // THE ROSTER: one row per live census member. `note` names what the site is and what pays it. | ||
| // Kept at zero rows until the first committed recount fills it from the instrument (never by | ||
| // hand from a text search). | ||
| data argv_word_construction_census_roster: List<ArgvWordsRosterRow> = [] | ||
|
|
||
| // Sites whose evidence is read and REFUSED AS DEBT with a stated reason: the census classifies, | ||
| // it does not silently count. Each entry names its reason; a reason that stops being true must | ||
| // delete the entry (the same shrink discipline as the roster). | ||
| data argv_word_construction_census_excluded: List<ArgvWordsExclusion> = [] | ||
|
|
||
| type ArgvWordsExclusion { | ||
| module_file: String | ||
| decl: String | ||
| reason: String | ||
| } | ||
|
|
||
| fn excluded_identity_matches(e: ArgvWordsExclusion, s: ArgvWordsSite) -> Bool { | ||
| (e.module_file == s.module_file) && (e.decl == s.decl) | ||
| } | ||
|
|
||
| fn site_is_excluded(s: ArgvWordsSite) -> Bool { | ||
| fold_list(xs: argv_word_construction_census_excluded, empty: false, cons: fn(acc, e) { acc || excluded_identity_matches(e: e, s: s) }) | ||
| } | ||
|
|
||
| // The live census members after classification: exclusions are visible subtractions with reasons. | ||
| fn argv_word_construction_census_live(sites: List<ArgvWordsSite>) -> List<ArgvWordsSite> { | ||
| fold_list(xs: sites, empty: Empty, cons: fn(acc, s) { if site_is_excluded(s: s) { acc } else { Cons { head: s, tail: acc } } }) | ||
| } | ||
|
|
||
| // The contract over one recount's live sites. | ||
| fn argv_word_construction_census_check_sites(sites: List<ArgvWordsSite>) -> ProcessExit { | ||
| argv_word_construction_gates(live: argv_word_construction_census_live(sites: sites), roster: argv_word_construction_census_roster, baseline_population: argv_word_construction_census_baseline_population) | ||
| } | ||
|
|
||
| // The recount entry: discover the roots' module files by the declaration index (never a text | ||
| // search), walk each with the lens, and hold the contract. | ||
| fn argv_word_construction_census_recount() -> ProcessExit { | ||
| argv_word_construction_census_check_paths(paths: argv_word_construction_census_root_paths()) | ||
| } | ||
|
|
||
| // The discovered modeled roots' module files, in declaration-index order. Shared by the gated | ||
| // recount above and the roster emitters below so all see the same population. Parameterized by | ||
| // roots: the corpus walk is run ONE ROOT PER PROCESS (a wet lane kills a whole-corpus walk with | ||
| // OOM -- the per-process journal of read+parse dispatches is what grows, so the split is by the | ||
| // roots boundary, the population's own partition). | ||
| fn argv_word_construction_census_root_paths_for_roots(roots: List<String>) -> List<String> { | ||
| let decls = module_declaration_facts_live(pool_roots: roots) | ||
| let paths_reversed = fold_list(xs: decls, empty: Empty, cons: fn(acc, d) { | ||
| let p = declared_module_path(d: d) | ||
| if p == "" { acc } else { Cons { head: p, tail: acc } } | ||
| }) | ||
| list_reverse(xs: paths_reversed) | ||
| } | ||
|
|
||
| fn argv_word_construction_census_root_paths() -> List<String> { | ||
| argv_word_construction_census_root_paths_for_roots(roots: argv_word_construction_census_roots) | ||
| } | ||
|
|
||
| // The roster emitter for a wet-lane run (claim_batch --wet): the same discovered population, each | ||
| // module walked by the lens, rows written as TSV to the scratch path. The committed roster data | ||
| // decl above is filled FROM this output, never by hand from a text search. Hermetic lanes refuse | ||
| // the write by design -- the emitter exists for the recount, not for CI. | ||
| fn argv_word_construction_census_recount_emit() -> ProcessExit { | ||
| argv_word_construction_for_paths(paths: argv_word_construction_census_root_paths(), out: "target/argv_word_construction_census_recount.tsv") | ||
| } | ||
|
|
||
| fn argv_word_construction_census_recount_emit_extdeps() -> ProcessExit { | ||
| argv_word_construction_for_paths(paths: argv_word_construction_census_root_paths_for_roots(roots: ["dag/extdeps"]), out: "target/argv_word_construction_census_recount_extdeps.tsv") | ||
| } | ||
|
|
||
| fn argv_word_construction_census_recount_emit_gunbc() -> ProcessExit { | ||
| argv_word_construction_for_paths(paths: argv_word_construction_census_root_paths_for_roots(roots: ["dag/gunbc"]), out: "target/argv_word_construction_census_recount_gunbc.tsv") | ||
| } | ||
|
|
||
| // The fixture root is OUTSIDE the modeled roots by design (the boundary-refusal claim pins that), | ||
| // so the walk above never sees it and for_paths refuses any module outside the roots. The | ||
| // fixture's facts are therefore read at the FACT level -- the same read/parse/facts_of route the | ||
| // fixture claims use -- and rendered where a human reads them: one TSV row per fact with every | ||
| // field the fixture claims pin. This is the observation those claims' expectations are aligned | ||
| // against, not a hand-maintained parallel list of what the lens is supposed to say. | ||
| fn argv_word_construction_census_fixture_facts_dump() -> ProcessExit { | ||
| let read = Filesystem.Read(path: "src/v2/test/fixture_roots/argv_word_construction/host_words.dag") | ||
| match read.success { | ||
| false => exit_failure(reason: "fixture facts absent: fixture unreadable") | ||
| true => | ||
| match raw_tree_of_text(text: read.content) { | ||
| RawTreeNotEstablished { cause: cause } => exit_failure(reason: concat("fixture unparseable: ", cause)) | ||
| RawTreeEstablished { root: root } => fixture_facts_write(root: root) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn fixture_facts_write(root: Node) -> ProcessExit { | ||
| let rows = fold_list(xs: facts_of(root: root), empty: "decl\tkind\tcounted\tcandidates_n\tcandidates\tflag_words_n\treturns_argv_words\tlist_string_params\tlist_string_data", cons: fn(acc, f) { | ||
| concat(acc, concat("\n", fixture_fact_row(f: f))) | ||
| }) | ||
| let written = Filesystem.Write(path: "target/argv_word_construction_fixture_facts.tsv", content: rows) | ||
| if written.success { ExitSuccess } else { exit_failure(reason: concat("fixture facts write refused: ", written.error)) } | ||
| } | ||
|
|
||
| fn fixture_fact_row(f: ArgvWordsFact) -> String { | ||
| let kind = fact_kind_word(k: f.decl_kind) | ||
| let counted = bool_word(b: f.counted) | ||
| let n_cand = integer_int_to_decimal_string(value: length(xs: f.candidates)) | ||
| let cands = join(f.candidates, ";") | ||
| let n_flags = integer_int_to_decimal_string(value: length(xs: f.flag_words)) | ||
| let returns = bool_word(b: f.returns_argv_words) | ||
| let n_params = integer_int_to_decimal_string(value: f.list_string_params) | ||
| let data = bool_word(b: f.list_string_data) | ||
| join([f.decl, kind, counted, n_cand, cands, n_flags, returns, n_params, data], "\t") | ||
| } | ||
|
|
||
| fn fact_kind_word(k: ArgvWordsDeclKind) -> String { | ||
| match k { | ||
| FnDecl => "FnDecl" | ||
| DataDecl => "DataDecl" | ||
| } | ||
| } | ||
|
|
||
| fn bool_word(b: Bool) -> String { | ||
| match b { | ||
| true => "true" | ||
| false => "false" | ||
| } | ||
| } | ||
|
|
||
| fn declared_module_path(d: ModuleDeclarationFact) -> String { | ||
| d.path | ||
| } | ||
|
|
||
| // The distinct module files named by the committed roster, in first-appearance order: exactly the | ||
| // population the bounded-contract claim re-walks, so CI executes the gates at roster size without | ||
| // ever walking the whole corpus. | ||
| fn argv_word_construction_census_roster_modules() -> List<String> { | ||
| let reversed = fold_list(xs: argv_word_construction_census_roster, empty: Empty, cons: fn(acc, r) { | ||
| if contains_string(xs: acc, x: r.module_file) { acc } else { Cons { head: r.module_file, tail: acc } } | ||
| }) | ||
| list_reverse(xs: reversed) | ||
| } | ||
|
|
||
| fn contains_string(xs: List<String>, x: String) -> Bool { | ||
| fold_list(xs: xs, empty: false, cons: fn(acc, y) { acc || (y == x) }) | ||
| } | ||
|
|
||
| type ArgvWordsCollected { | ||
| sites: FreeMonoid<ArgvWordsSite> | ||
| refusals: FreeMonoid<String> | ||
| } | ||
|
|
||
| fn collect_path(c: ArgvWordsCollected, p: String) -> ArgvWordsCollected { | ||
| match argv_word_construction_module_sites(path: p) { | ||
| ArgvWordsModuleRefused { path: rp, reason: r } => | ||
| ArgvWordsCollected { sites: c.sites, refusals: Cons { head: concat(concat(concat("REFUSED\t", rp), "\t"), r), tail: c.refusals } } | ||
| ArgvWordsModuleEstablished { path: _, sites: sites } => | ||
| ArgvWordsCollected { sites: fold_list(xs: sites, empty: c.sites, cons: fn(acc, s) { Cons { head: s, tail: acc } }), refusals: c.refusals } | ||
| } | ||
| } | ||
|
|
||
| // The contract over an explicit path list: the per-module walk is the lens's; the gates run on the | ||
| // collected live sites, and every per-module refusal is named, never dropped. Kept separate from | ||
| // the discovery so a bounded recount (one module, one directory) is runnable in a claim test | ||
| // without the whole corpus. | ||
| fn argv_word_construction_census_check_paths(paths: List<String>) -> ProcessExit { | ||
| let collected = fold_list(xs: paths, empty: ArgvWordsCollected { sites: Empty, refusals: Empty }, cons: collect_path) | ||
| match list_reverse(xs: collected.refusals) { | ||
| Empty => argv_word_construction_census_check_sites(sites: list_reverse(xs: collected.sites)) | ||
| nonempty => exit_failure(reason: join_lines(rs: nonempty)) | ||
| } | ||
| } | ||
|
|
||
| fn join_lines(rs: FreeMonoid<String>) -> String { | ||
| fold_list(xs: list_reverse(xs: rs), empty: "", cons: fn(acc, l) { if acc == "" { l } else { concat(concat(acc, "\n"), l) } }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| #![allow(clippy::disallowed_macros)] | ||
|
|
||
| //! THROWAWAY parse probe for the typed-argv census lens (deleted before commit). | ||
| //! Prints the exact v1 parse error for each argv-word-construction file. | ||
|
|
||
| use im::HashMap; | ||
| use std::rc::Rc; | ||
| use v1_compiler::cli_run::workspace_root; | ||
| use v1_compiler::v1_compiler_parse::ParseResult; | ||
| use v1_compiler::v1_std_core::{diagnostic_to_message, diagnostic_to_span}; | ||
|
|
||
| fn parse_path(relative_path: &str) -> Result<(), String> { | ||
| let path = workspace_root().join(relative_path); | ||
| let source = std::fs::read_to_string(&path) | ||
| .unwrap_or_else(|e| panic!("failed to read {}: {}", path.display(), e)); | ||
| let tokens = v1_compiler::v1_compiler_tokenize::tokenize( | ||
| source.clone(), | ||
| relative_path.to_string(), | ||
| v1_compiler::extdeps_languages_dag_syntax::dag_parse_environment(), | ||
| ); | ||
| let source_index = | ||
| v1_compiler::v1_std_core::build_newline_index(relative_path.to_string(), source.clone()); | ||
| let mut source_indices = HashMap::new(); | ||
| source_indices.insert(relative_path.to_string(), source_index); | ||
| let result: Rc<ParseResult> = | ||
| v1_compiler::v1_compiler_parse::parse(tokens, Rc::new(source_indices)); | ||
| match result.error.clone() { | ||
| Some(err) => { | ||
| let s = diagnostic_to_span(err.diagnostic.clone()); | ||
| let line = source[..(s.start.max(0) as usize).min(source.len())] | ||
| .chars() | ||
| .filter(|c| *c == '\n') | ||
| .count() | ||
| + 1; | ||
| Err(format!( | ||
| "{}:{} parse error: {}", | ||
| relative_path, | ||
| line, | ||
| diagnostic_to_message(err.diagnostic.clone()) | ||
| )) | ||
| } | ||
| None => Ok(()), | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn probe_parses_argv_word_construction_files() { | ||
| let files = [ | ||
| "src/v2/lens/argv_word_construction.dag", | ||
| "dag/gunbc/instruments/argv_word_construction_census.dag", | ||
| "src/v2/test/claim/argv_word_construction/census_test.dag", | ||
| "test/fixture_roots/argv_word_construction/host_words.dag", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Every run of this Rust test panics in Useful? React with 👍 / 👎. |
||
| ]; | ||
| let mut failures = Vec::new(); | ||
| for f in files { | ||
| match parse_path(f) { | ||
| Ok(()) => println!("PARSE-OK {}", f), | ||
| Err(e) => { | ||
| println!("PARSE-FAIL {}", e); | ||
| failures.push(e); | ||
| } | ||
| } | ||
| } | ||
| assert!( | ||
| failures.is_empty(), | ||
| "{} of {} files failed", | ||
| failures.len(), | ||
| files.len() | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this roster empty and the baseline set to zero,
argv_word_construction_census_roster_modules()returns no paths, socommitted_census_holds_its_own_contractcallscheck_paths([])and succeeds without inspecting either modeled root. The corpus already contains many matchingList<String>builders (for example the argv functions indag/extdeps/tools/id.dag), so new or existing string-built argv cannot be rejected until the initial recount is committed here.Useful? React with 👍 / 👎.