From 6c780c59096d98d0417df7bd7d630e0aafae9700 Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sat, 12 Sep 2026 12:32:15 -0400 Subject: [PATCH 1/7] fix(legend): compact --impact, --callers, --safe-delete, --communities, --community and the map header printed attributes with no definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under --legend=compact (the MCP default) these answers carried attributes the compact legend never defined, because the prose that defined them (if any did) is stripped and kCompactCompletenessTerms had no row: - the map header: unresolved=, and the always-on files=/symbols=/edges=/shown=/ambiguous=/order= plus the conditional roots=, changed=, skipped_oversize=, unindexed=/unindexed_exts=, escaped_root=, precise= (the full map legend defines only shown=; serialize.h records why it cannot hold the rest); - --impact: defs=, reaches=, radius_tested=, radius_untested=, importers=, shown_importers=, and importer rows; its columnar form's format=, and lens= (lens= also on --order=stable's ); - --callers, --callees, --impact and the MCP impact twin: tested="1" on rows. No probe saw it, because test/fixture holds no test; --impact=svector::push_back on this repo prints four; - --safe-delete: radius_tested=, radius_untested=, t=, p=, defs=, ambiguous_callers=, dead_code_candidate=; - --communities: drill=, shown_modules=, bridges=, isolated= and its isolated_doc/_decl/_header/_source split, modules=, shown_bridges=, connected_singletons=, symbols=; --community=ID: dir=, label=, bridges=, partition=, modules=, shown_bridges=; the rows of both (a= b= from_label= to_label= edges=, to= to_label= edges=). Definitions, each checked against its emitter (verbs_report.h, verbs_navigate.h runSafeDelete, serialize.h buildStats and emitImportRowsXml, graph.h scanImporterEdges and isTestedByReach, columnar.h, quality.h). Root vocabulary every answer carries reads in the purpose lines; everything that rides only some answers is a present-only term (element-qualified on , , , and , header-only for the map header's fields). Owner decision: per-verb pins that fit honest definitions (docs/METHODOLOGY.md §9). A design review read every new reading against its emitter before this commit and corrected three: - --safe-delete t= p= read "its lowest-id def's kind and file:line". On a header-qualified file:name selector the decl->def widening keeps the declarations (graph.h declToDefFollowThrough), so the lowest id can be one. Now "its lowest-id match's", the unit defs= counts. - the map header's changed= read "K git-changed files seed the PageRank teleport (0: uniform)". main.cpp counts INDEXED files only, and a tree git cannot read counts 0. Now "K indexed git-changed files ... (0: uniform, incl. no git)". - --communities' bridges= read "module pairs joined by a call edge" beside modules= "modules of 2+ symbols", but it counts pairs that include one-symbol communities. Now "community pairs joined by a call edge". It found the tested= reading missing ((D31), red first) and fourteen shortenings that keep each reading exact, all applied: edges=, roots=, skipped_oversize=, unindexed=, escaped_root=, lens=, dead_code_candidate=, --communities' shown_modules=/ shown_bridges= (merged), symbols= and connected_singletons=, --community's bridges=, , , and unresolved= folded into the always-on files= clause. buildStats writes both fields into every header, and compactlegendcheck (S) now accepts an unmarked always-on field spelled inside that clause; with unresolved= deleted from it, (S) FAILs on unresolved= and on nothing else. Pins (test/compactlegendcheck.sh). M held every verb under one 400 B (U) ceiling, (L) 4,100 B and a 400 B (M) ceiling. Rule: the largest measured probe on the gate fixture, rounded up to the next 10 B, plus 10 B. pinFor is now a data table (schema, pin, measured) with the rule stated once. schema old->measured->pin: map 400->799->810; map-diff 400->789->800; pack-signatures 400->663->680; metrics 400->702->720; deps 400->245->260; hotspots 400->264->280; clones 400->280->290; readability 400->224->240; nonlocal-state 400->344->360; ensemble 400->261->280; context-ratio 400->240->250; quality-panel 400->271->290; naming-calibration 400->206->220; naming-consistency 400->261->280; comment-coherence 400->241->260; cochange 400->271->290; communities 400->807->820; zoom 400->394->410; tree 400->238->250; seams 400->365->380; handoff 400->325->340; test-gate 400->400->410; field-affinity 400->304->320; skipped 400->195->210; lint 400->240->250; lint-catalog 400->124->140; external-surface 400->171->190; scan-skills 400->147->160; owners 400->207->220; dead-code 400->297->310; quality-delta 400->212->230; dmm 400->189->200; pr-context 400->399->410; stray-content 400->179->190; flags 400->159->170; doc-drift 400->205->220; notes 400->135->150; path 400->263->280; connect 400->392->410; impact 400->770->780; mentions 400->168->180; affected 400->339->350; verify 400->316->330; help-task 400->153->170; query 400->611->630; grep 400->345->360; match 400->260->270; lego 400->275->290; exemplar 400->232->250; around 400->707->720; callers 400->317->330; callees 400->369->380; uses 400->271->290; batch 400->142->160; safe-delete 400->708->720; at 400->161->180; from-trace 400->290->300; plan-lint 400->156->170; merge-scout 400->208->220; whereis 400->223->240; community 400->719->730; layout 400->149->160; pack-task 400->327->340; pack-top-n 400->649->660; expand 400->265->280 (L) ten-verb loop: 4,100 -> 4,849 -> 4,900 (--impact 390 -> 770 B, --safe-delete 328 -> 708 B; nothing else moved). (M) impact 400 -> 770 -> 780; uses 400 -> 271 -> 290; path_between 400 -> 263 -> 280; lego 400 -> 249 -> 260; exemplar 400 -> 243 -> 260. The compact saving, restated from measurement. --help promised "at least 50% of a small --callers/--uses/--impact/--affected answer"; test/legendcostcheck.sh measures lookupLang and src/wrap.h in root-normalised bytes: callers 65.91% (M: 68.17%), uses 63.79%, impact 46.17% (M: 52.78%), affected 64.73%. The minimum rounded down to a multiple of 5 is 45, so --help now says "at least 45%" and the gate re-derives it from that sentence. callers and impact fell because lookupLang's rows carry tested="1" and now pay its reading. Published text: src/cli.h's --legend entry no longer promises "ONE <=400 B legend" and states the measured per-call drop, 2.8-5.8 KB (--callers/--callees/--uses/--impact/--edit-check=lookupLang, root-normalised: 2,769 B on --callers to 5,792 B on --edit-check; it read 2.9-5.2 KB), with --edit-check 6.3 KB -> 0.5 KB (it read 5.2 KB -> <0.4 KB, already stale); src/main.cpp's two comments and src/compactlegend.h's size comments stop quoting a 400 B ceiling; test/showcase_capture.py's demo note says one compact comment. docs/COMMANDS.md regenerated (the one --legend line). test/printf_parity.manifest re-pinned: help_all moved, 41 labels unchanged. Left as written: docs/EVALS.md's and bench/tokenaudit/README.md's quotes of "at least 50%" (dated 2026-09-09 round records), docs/EVALS.md's other dated lines, compactlegend.h's dated A6 hub_floor note, test/mcpmanifestcheck.sh's comment quoting 2.9-5.2 KB. Red -> green. The (D24)..(D29) rows FAILed 36 specs on the build before the sweep's last pass; (D30), the present-only mirror, is green on both by construction and its controls assert each lack first. (D31)'s three rows FAILed on the last-pass build, plain and ASan alike, and nothing else did; (D32), its mirror, is green by construction and fires with the reading spliced into a legend whose document has no tested row. compactlegendcheck now: plain 125 PASS 0 FAIL, ASan 125 PASS 0 FAIL. legendcostcheck, docs/limits_build.py --check and docs/gatecount_build.py --check pass. Byte identity against M's binary: 39 non-compact answers (the map, --impact and its columnar form, --safe-delete including a header-qualified selector, --communities, --community, --zoom, --map-diff, --max-tokens, --order=stable, --callers/ --callees/--uses/--edit-check/--affected/--test-gate/--from-trace, test/chafix, --scip, a tree with a test, two roots, refusals, MCP legend:"full", --help, --help=--uses) match in stdout, stderr and exit code; only --help=all differs. 26 compact answers keep rows and data comments identical (est_tokens aside, which prices the emitted bytes); only legend text moves, on 20 of them. quality-delta (against M) gates on two findings, both expected. One is short-horizon churn of kCompactLegendSpecs: four sweeps and this review edited that table in one day, each adding or correcting readings. The other is the verbosity of kCompactCompletenessTerms (47 -> 64 lines, bar 60): it holds one row per present-only reading, and splitting it would reorder the clauses every existing compact legend prints. Minor: churn on kCompactCompletenessTerms, kCompactProsePrefixes (a comment) and condArm. Co-Authored-By: Claude Opus 5 --- docs/COMMANDS.md | 2 +- src/cli.h | 6 +- src/compactlegend.h | 130 +++++++++-- src/main.cpp | 4 +- test/compactlegendcheck.sh | 417 +++++++++++++++++++++++++++++++++--- test/printf_parity.manifest | 2 +- test/showcase_capture.py | 2 +- 7 files changed, 501 insertions(+), 62 deletions(-) diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index a9e07897..0e149607 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -4304,7 +4304,7 @@ $ ./build/ripwire . --callers=rankGraphTeleport --format=bogus **Answers:** choose the legend posture for every XML verb — use compact when calling repeatedly output legend posture for EVERY XML verb. -MAKING REPEATED CALLS (an agent, a script, a benchmark harness)? USE compact. The legend is a FIXED ~3 KB per call, so its share is a function of ANSWER SIZE, not of the verb: at least 50% of a small --callers/--uses/--impact/--affected answer (and more on --callees and --edit-check), a little of a large --for bundle. Every ROW is byte-identical; the only payload change is a schema="ripwire./v1" attribute the root GAINS. The CLI default is full because a human reading ONE map needs the prose; the MCP server already defaults to compact, so the CLI is the path that pays. full is byte-identical to the default. compact keeps every row byte and every data/completeness attribute (counts_floor= capped= shown= total= has_more= next_offset= est_tokens= at= root= graph_ambiguous= …), adds a versioned schema id on the root (schema="ripwire./v1") and replaces the explanatory prose with ONE <=400 B legend naming those attributes — the meanings live here and in the full legend. DATA comments stay (the map header, pack-task's body-omitted rows, +more). Per call this drops 2.9-5.2 KB on the navigation verbs (--edit-check 5.2 KB -> <0.4 KB); the MCP twin is the argument legend: on every XML-answering verb, where compact is the DEFAULT and legend:"full" restores this prose (M1, 2026-09-05: the ten-verb MCP edit loop pays 2,866 B of legend instead of 30,839 B). The CLI default stays full. Runs with nothing to compact refuse it, naming the verb: prose/markdown/JSON answers (--situ --recall --report --mermaid --html --plan-lanes --sarif --eval*) and the writers (edit verbs, --note-add, --quality-baseline/--quality-ack, --index-out, --export). +MAKING REPEATED CALLS (an agent, a script, a benchmark harness)? USE compact. The legend is a FIXED ~3 KB per call, so its share is a function of ANSWER SIZE, not of the verb: at least 45% of a small --callers/--uses/--impact/--affected answer (and more on --callees and --edit-check), a little of a large --for bundle. Every ROW is byte-identical; the only payload change is a schema="ripwire./v1" attribute the root GAINS. The CLI default is full because a human reading ONE map needs the prose; the MCP server already defaults to compact, so the CLI is the path that pays. full is byte-identical to the default. compact keeps every row byte and every data/completeness attribute (counts_floor= capped= shown= total= has_more= next_offset= est_tokens= at= root= graph_ambiguous= …), adds a versioned schema id on the root (schema="ripwire./v1") and replaces the explanatory prose with ONE legend naming those attributes — the meanings live here and in the full legend. DATA comments stay (the map header, pack-task's body-omitted rows, +more). Per call this drops 2.8-5.8 KB on the navigation verbs (--edit-check 6.3 KB -> 0.5 KB); the MCP twin is the argument legend: on every XML-answering verb, where compact is the DEFAULT and legend:"full" restores this prose (M1, 2026-09-05: the ten-verb MCP edit loop pays 2,866 B of legend instead of 30,839 B). The CLI default stays full. Runs with nothing to compact refuse it, naming the verb: prose/markdown/JSON answers (--situ --recall --report --mermaid --html --plan-lanes --sarif --eval*) and the writers (edit verbs, --note-add, --quality-baseline/--quality-ack, --index-out, --export). **Try it** diff --git a/src/cli.h b/src/cli.h index fcacacf2..b9a16b13 100644 --- a/src/cli.h +++ b/src/cli.h @@ -2341,7 +2341,7 @@ inline constexpr char kHelpTail[] = " --legend=full|compact choose the legend posture for every XML verb — use compact when calling repeatedly\n" " output legend posture for EVERY XML verb. MAKING REPEATED CALLS (an agent, a\n" " script, a benchmark harness)? USE compact. The legend is a FIXED ~3 KB per call,\n" - " so its share is a function of ANSWER SIZE, not of the verb: at least 50% of a\n" + " so its share is a function of ANSWER SIZE, not of the verb: at least 45% of a\n" " small --callers/--uses/--impact/--affected answer (and more on --callees and\n" " --edit-check), a little of a large --for bundle. Every ROW is byte-identical; the\n" " only payload change is a schema=\"ripwire./v1\" attribute the root GAINS.\n" @@ -2351,9 +2351,9 @@ inline constexpr char kHelpTail[] = " keeps every row byte and every data/completeness attribute (counts_floor= capped= shown=\n" " total= has_more= next_offset= est_tokens= at= root= graph_ambiguous= …), adds a versioned\n" " schema id on the root (schema=\"ripwire./v1\") and replaces the explanatory prose\n" - " with ONE <=400 B legend naming those attributes — the meanings live here and in the full\n" + " with ONE legend naming those attributes — the meanings live here and in the full\n" " legend. DATA comments stay (the map header, pack-task's body-omitted rows, +more). Per\n" - " call this drops 2.9-5.2 KB on the navigation verbs (--edit-check 5.2 KB -> <0.4 KB);\n" + " call this drops 2.8-5.8 KB on the navigation verbs (--edit-check 6.3 KB -> 0.5 KB);\n" " the MCP twin is the argument legend: on every XML-answering verb, where compact is\n" " the DEFAULT and legend:\"full\" restores this prose (M1, 2026-09-05: the ten-verb MCP\n" " edit loop pays 2,866 B of legend instead of 30,839 B). The CLI default stays full.\n" diff --git a/src/compactlegend.h b/src/compactlegend.h index a4aeb74d..1d9f111d 100644 --- a/src/compactlegend.h +++ b/src/compactlegend.h @@ -5,12 +5,13 @@ // legend, the canonical ten-verb edit loop pays 29,824 B of legend per session for ~9 KB of rows, and the // MCP server re-pays it on every call. --for/--grep/--slice grew a compact dialect by hand (each emitter // branching on the posture); the other ~60 XML roots are printed by as many emitters. Compact is therefore -// applied HERE, once, to the finished document: the explanatory comments are replaced by ONE ≤400 B legend -// (schema id + the verb's purpose + a reading for every completeness attribute the document actually -// carries), the root gains schema="ripwire./v1", and every payload byte is untouched — rows, root -// attributes, CDATA bodies, and the comments that CARRY DATA (the map header's , pack-task's -// , the marker, --notes' counted header). The full dialect (the default, -// and --legend=full) never passes through this file. +// applied HERE, once, to the finished document: the explanatory comments are replaced by ONE legend (schema id + +// the verb's purpose + a reading for every completeness attribute the document actually carries), held to that +// verb's measured byte pin (test/compactlegendcheck.sh pinFor: the pins fit the definitions, docs/METHODOLOGY.md §9), +// the root gains schema="ripwire./v1", and every payload byte is untouched — rows, root attributes, CDATA +// bodies, and the comments that CARRY DATA (the map header's , pack-task's , +// the marker, --notes' counted header). The full dialect (the default, and --legend=full) never passes +// through this file. // // WHAT IS PROSE. A comment is explanatory prose iff it starts with one of kCompactProsePrefixes and none of // kCompactDataPrefixes — the prefixes are the legend openers the emitters use (` comment outside CDATA) is -# ≤ 400 B and names every completeness attribute the document carries (counts_floor / capped / shown / +# • the root carries schema="ripwire./v1"; the legend (= every comment outside CDATA) fits +# its verb's byte pin and names every completeness attribute the document carries (counts_floor / capped / shown / # total / has_more / next_offset / offset / limit / *_capped / est_tokens / at / root / graph_ambiguous # / graph_unresolved …) — the prose moved to --help and --legend=full; # • the ROWS are byte-identical to the full dialect and the root's attribute-name set is the full set plus @@ -23,13 +23,20 @@ # UNIVERSE arm (U): the verb set is DERIVED from src/cli.h (test/flaguniverse.py) — the same derivation # jsoncheck #8b and shapingflagcheck (F) use — so a verb added tomorrow is probed tomorrow. Each flag runs at # defaults on a tmp git fixture; whatever answers with an XML root is an XML verb and must honor compact, -# everything else must refuse it. LOOP arm (L): the ten-verb loop's compact legend bill ≤ 4,100 B (was 29,824 -# on the ripwire tree). MCP arm (M): edit_check with legend:"compact" answers in ≤ 900 B on a clean tree. +# everything else must refuse it, and each verb's prose legend fits its per-verb pin (pinFor). LOOP arm (L): the ten-verb +# loop's compact legend bill ≤ 4,900 B (was 29,824 on the ripwire tree). MCP arm (M): edit_check with legend:"compact" answers +# in ≤ 900 B on a clean tree, and five more MCP verbs' legends fit their per-verb pins. # CONDITIONAL arm (D): an absent-at-zero or form-conditional attribute (declined_calls=, unproven_defs=, bodyless_defs=, # the member form, the multi-root rows, --lego's caveat=; on the map family and --impact: pr_iters=, # pr_converged=, the map header's gauges, --around's defs=, --rank-by's rank_by=/window=; in the third sweep: --tree's -# files=, --zoom's root counts and , churn-decay's , the map rows' lpin=/overloads=/prov=) is -# DEFINED by the compact legend of a document that carries it, and by none that does not. STRUCTURAL arm (S): every +# files=, --zoom's root counts and , churn-decay's , the map rows' lpin=/overloads=/prov=; in the +# fourth sweep: the map header's unresolved=, --impact's defs=/reaches=/importers=/shown_importers=/radius_tested=/ +# radius_untested=, --communities' drill=/isolated=/isolated_*=/shown_modules=/bridges=, --community's dir=/label=/bridges=/ +# partition=/modules=, --safe-delete's radius_tested=/radius_untested=; in that sweep's last pass: --communities' modules=/ +# shown_bridges=/connected_singletons=/symbols=, --community's shown_bridges=, the rows, --safe-delete's t=/defs=/ +# ambiguous_callers=/dead_code_candidate=, --impact's , every map-header field, the columnar format=/ and +# lens=; from that sweep's design review: the rows of --callers/--impact) is DEFINED by the compact legend of a +# document that carries it, and by none that does not. STRUCTURAL arm (S): every # conditional attribute the graphlegend.h helper family emits, the PageRank disclosure, every conditional hdr: field of # the map header, and every absence-marked row field of the map legend, read from source, has a compact reading — so the # next one cannot land undefined. @@ -309,6 +316,88 @@ probeFor() *) printf '%s' "$1" ;; esac } +# PER-VERB PINS (owner decision 2026-09-12: per-verb pins that fit honest definitions, docs/METHODOLOGY.md §9: honesty lives in +# attributes, the ceiling is a constraint). One 400 B ceiling held every verb until the fourth sweep, and three sweeps stopped on it +# with attributes still undefined. Each schema's pin is its LARGEST measured (U) probe on this gate's fixture, rounded up to the +# next multiple of 10 B, plus 10 B, so a verb whose legend grows is re-pinned in the commit that adds the bytes, with the bytes +# attributed there. A schema with no row FAILS: a new XML verb is measured and pinned, never waved through under a default. +# --for keeps its native dialect and is exempt (below). +# ONE ROW PER SCHEMA: the pin, then the largest (U) probe it was measured from. Measured 2026-09-12 in the fourth sweep's last +# pass, once every attribute the --impact, --safe-delete, --communities, --community and map-header answers print had a reading; +# re-measured the same day after that sweep's design review corrected three readings, added the present-only reading +# (no probe on this fixture prints one) and shortened fourteen readings without losing accuracy. Ten pins moved down. +# schema pin measured +PIN_TABLE=' +ripwire.map/v1 810 799 +ripwire.map-diff/v1 800 789 +ripwire.pack-signatures/v1 680 663 +ripwire.metrics/v1 720 702 +ripwire.deps/v1 260 245 +ripwire.hotspots/v1 280 264 +ripwire.clones/v1 290 280 +ripwire.readability/v1 240 224 +ripwire.nonlocal-state/v1 360 344 +ripwire.ensemble/v1 280 261 +ripwire.context-ratio/v1 250 240 +ripwire.quality-panel/v1 290 271 +ripwire.naming-calibration/v1 220 206 +ripwire.naming-consistency/v1 280 261 +ripwire.comment-coherence/v1 260 241 +ripwire.cochange/v1 290 271 +ripwire.communities/v1 820 807 +ripwire.zoom/v1 410 394 +ripwire.tree/v1 250 238 +ripwire.seams/v1 380 365 +ripwire.handoff/v1 340 325 +ripwire.test-gate/v1 410 400 +ripwire.field-affinity/v1 320 304 +ripwire.skipped/v1 210 195 +ripwire.lint/v1 250 240 +ripwire.lint-catalog/v1 140 124 +ripwire.external-surface/v1 190 171 +ripwire.scan-skills/v1 160 147 +ripwire.owners/v1 220 207 +ripwire.dead-code/v1 310 297 +ripwire.quality-delta/v1 230 212 +ripwire.dmm/v1 200 189 +ripwire.pr-context/v1 410 399 +ripwire.stray-content/v1 190 179 +ripwire.flags/v1 170 159 +ripwire.doc-drift/v1 220 205 +ripwire.notes/v1 150 135 +ripwire.path/v1 280 263 +ripwire.connect/v1 410 392 +ripwire.impact/v1 780 770 +ripwire.mentions/v1 180 168 +ripwire.affected/v1 350 339 +ripwire.verify/v1 330 316 +ripwire.help-task/v1 170 153 +ripwire.query/v1 630 611 +ripwire.grep/v1 360 345 +ripwire.match/v1 270 260 +ripwire.lego/v1 290 275 +ripwire.exemplar/v1 250 232 +ripwire.around/v1 720 707 +ripwire.callers/v1 330 317 +ripwire.callees/v1 380 369 +ripwire.uses/v1 290 271 +ripwire.batch/v1 160 142 +ripwire.safe-delete/v1 720 708 +ripwire.at/v1 180 161 +ripwire.from-trace/v1 300 290 +ripwire.plan-lint/v1 170 156 +ripwire.merge-scout/v1 220 208 +ripwire.whereis/v1 240 223 +ripwire.community/v1 730 719 +ripwire.layout/v1 160 149 +ripwire.pack-task/v1 340 327 +ripwire.pack-top-n/v1 660 649 +ripwire.expand/v1 280 265 +' +pinFor() +{ + printf '%s\n' "$PIN_TABLE" | awk -v schema="$1" '$1 == schema { printf "%s", $2; exit }' +} nXml=0; nXmlBad=0; nRefuse=0; nSkip=0; loopBytes=0; xmlVerbs="" while IFS="$( printf '\t' )" read -r flag kind example policy; do [ -n "$flag" ] || continue @@ -338,7 +427,12 @@ while IFS="$( printf '\t' )" read -r flag kind example policy; do case "$schema" in ripwire.*/v1) ;; *) no "(U) $probe compact root has no schema=\"ripwire./v1\" (got '$schema')" ;; esac case "$flag" in --for=) [ "$lb" -lt "$lbfull" ] || no "(U) --for compact legend ($lb B) did not shrink vs full ($lbfull B)" ;; # native dialect, data in its comments (A10) — registered follow-up - *) [ "$lb" -le 400 ] || no "(U) $probe compact PROSE legend is $lb B (> 400 B; all comments $lball B, full $lbfull B): $( leg legend "$TMP/u.c" | head -c 200 )" ;; + *) pin="$( pinFor "$schema" )" + if [ -z "$pin" ]; then + no "(U) $probe answers $schema, which has no per-verb pin: measure its compact PROSE legend ($lb B here) and pin it in pinFor" + elif [ "$lb" -gt "$pin" ]; then + no "(U) $probe compact PROSE legend is $lb B (> its $pin B pin for $schema; all comments $lball B, full $lbfull B): $( leg legend "$TMP/u.c" | head -c 200 )" + fi ;; esac [ "$lball" -lt "$lbfull" ] || [ "$lbfull" -eq 0 ] || no "(U) $probe compact comments ($lball B) are not smaller than the full dialect's ($lbfull B)" fa="$( leg rootattrs "$TMP/u.full" )"; ca="$( leg rootattrs "$TMP/u.c" )" @@ -380,7 +474,7 @@ while IFS="$( printf '\t' )" read -r flag kind example policy; do xmllint --noout "$TMP/u.c" >/dev/null 2>&1 || no "(U) $probe compact document is malformed XML" fi done < "$UNIV" -[ "$nXml" -ge 60 ] && [ "$nXmlBad" -eq 0 ] && ok "(U) $nXml XML flags answer under --legend=compact (schema id, ≤400 B legend, rows byte-identical, root attrs kept):$xmlVerbs" \ +[ "$nXml" -ge 60 ] && [ "$nXmlBad" -eq 0 ] && ok "(U) $nXml XML flags answer under --legend=compact (schema id, legend within its per-verb pin, rows byte-identical, root attrs kept):$xmlVerbs" \ || no "(U) $nXml XML flags probed, $nXmlBad refused compact (want ≥ 60 probed, 0 refused — rows above name them):$xmlVerbs" [ "$nRefuse" -ge 60 ] && ok "(U) $nRefuse non-XML flags refuse --legend=compact (empty stdout, non-zero exit); $nSkip write/serve/exec flags not probed" \ || no "(U) only $nRefuse non-XML flags refused compact (want ≥ 60)" @@ -401,7 +495,18 @@ echo # else in the loop moved. Same rule the SIZE ceilings in test/mcpmanifestcheck.sh follow — a ceiling moves up # only for a DECLARED attribute the contract obliges to define, in the commit that lands it, with its bytes # attributed here, never for prose. -echo "=== (L) the canonical ten-verb edit loop: compact legend bill ≤ 4,100 B (29,824 B in full on the ripwire tree) ===" +# RE-ANCHORED 2026-09-12 (the fourth sweep): 4,100 → 4,400 B, measured 4,392 (from 4,089). Owner decision 2026-09-12: per-verb +# pins that fit honest definitions (METHODOLOGY §9); the loop's pin is the next multiple of 100 B above its measured total. +# Attributed against a build of the parent merge: --impact 390 → 597 B (defs=/reaches=/radius_tested=/radius_untested=/ +# importers= in its purpose line, shown_importers= as a term) and --safe-delete 328 → 424 B (its radius pair); nothing else +# in the loop moved. +# RE-ANCHORED 2026-09-12 (the fourth sweep's last pass): 4,400 → 4,900 B, measured 4,860 (from 4,392), by the same rule. Attributed +# against the previous lane build: --impact 597 → 777 B (its importer-row reading) and --safe-delete 424 → 712 B (t=/p=, +# defs=, ambiguous_callers=, dead_code_candidate=); nothing else in the loop moved. +# RE-MEASURED 2026-09-12 (that sweep's design review): 4,849 B, the pin unchanged at 4,900. Attributed against the last-pass build: +# --impact 777 → 770 B (the shorter reading) and --safe-delete 712 → 708 B (t= reads a match, dead_code_candidate= says +# outside); nothing else in the loop moved. +echo "=== (L) the canonical ten-verb edit loop: compact legend bill ≤ 4,900 B (29,824 B in full on the ripwire tree) ===" loopBytes=0; fullBytes=0 for v in "--for=geometry distance" "--callers=distance" "--impact=distance" "--uses=distance" "--edit-check=total_area" \ "--quality-delta" "--test-gate=geometry.cpp" "--affected=geometry.cpp" "--safe-delete=total_area" "--slice=total_area"; do @@ -410,11 +515,11 @@ for v in "--for=geometry distance" "--callers=distance" "--impact=distance" "--u b="$( leg bytes "$TMP/l.c" )"; f="$( leg bytes "$TMP/l.f" )" loopBytes=$(( loopBytes + b )); fullBytes=$(( fullBytes + f )) done -[ "$loopBytes" -le 4100 ] && ok "(L) ten-verb loop: $loopBytes B of compact legend (full: $fullBytes B)" \ - || no "(L) ten-verb loop pays $loopBytes B of compact legend (> 4,100 B; full: $fullBytes B)" +[ "$loopBytes" -le 4900 ] && ok "(L) ten-verb loop: $loopBytes B of compact legend (full: $fullBytes B)" \ + || no "(L) ten-verb loop pays $loopBytes B of compact legend (> 4,900 B; full: $fullBytes B)" echo -echo "=== (M) MCP: legend:\"compact\" on edit_check answers in ≤ 900 B on a clean tree; every XML verb takes the argument ===" +echo "=== (M) MCP: legend:\"compact\" on edit_check answers in ≤ 900 B on a clean tree; every XML verb takes the argument, within its per-verb legend pin ===" mcp_call() { printf '%s\n' "$@" | ( cd "$REPO" && "$BIN" --mcp 2>/dev/null ); } mcp_text() { # mcp_text VERB '' → the text payload, or __ERROR__:code:message mcp_call '{"jsonrpc":"2.0","id":1,"method":"initialize"}' \ @@ -445,19 +550,25 @@ cmp -s "$TMP/m.p1" "$TMP/m.p2" && ok "(M) MCP edit_check rows are byte-identical mcp_text edit_check '{"path":".","symbol":"total_area","legend":"terse"}' >"$TMP/m.bad" grep -q '^__ERROR__' "$TMP/m.bad" && ok "(M) MCP edit_check legend:\"terse\" is refused (closed set full|compact)" \ || no "(M) MCP edit_check accepted legend:\"terse\" — an unknown value read as a default" -for pair in "impact:{\"path\":\".\",\"symbol\":\"distance\",\"legend\":\"compact\"}" \ - "uses:{\"path\":\".\",\"symbol\":\"distance\",\"legend\":\"compact\"}" \ - "path_between:{\"path\":\".\",\"from\":\"total_area\",\"to\":\"distance\",\"legend\":\"compact\"}" \ - "lego:{\"path\":\".\",\"type\":\"Point\",\"legend\":\"compact\"}" \ - "exemplar:{\"path\":\".\",\"kind\":\"fn\",\"task\":\"distance\",\"legend\":\"compact\"}"; do - verb="${pair%%:*}"; args="${pair#*:}" +# Per-verb legend pins, the (U) rule on the MCP surface (the legend, never the whole answer, which edit_check's 900 B above bounds): +# impact 780 measured 770 B; owner decision 2026-09-12: per-verb pins that fit honest definitions (METHODOLOGY §9) +# uses 290 measured 271 B; owner decision 2026-09-12: per-verb pins that fit honest definitions (METHODOLOGY §9) +# path_between 280 measured 263 B; owner decision 2026-09-12: per-verb pins that fit honest definitions (METHODOLOGY §9) +# lego 260 measured 249 B; owner decision 2026-09-12: per-verb pins that fit honest definitions (METHODOLOGY §9) +# exemplar 260 measured 243 B; owner decision 2026-09-12: per-verb pins that fit honest definitions (METHODOLOGY §9) +for pair in "impact:780:{\"path\":\".\",\"symbol\":\"distance\",\"legend\":\"compact\"}" \ + "uses:290:{\"path\":\".\",\"symbol\":\"distance\",\"legend\":\"compact\"}" \ + "path_between:280:{\"path\":\".\",\"from\":\"total_area\",\"to\":\"distance\",\"legend\":\"compact\"}" \ + "lego:260:{\"path\":\".\",\"type\":\"Point\",\"legend\":\"compact\"}" \ + "exemplar:260:{\"path\":\".\",\"kind\":\"fn\",\"task\":\"distance\",\"legend\":\"compact\"}"; do + verb="${pair%%:*}"; rest="${pair#*:}"; mpin="${rest%%:*}"; args="${rest#*:}" mcp_text "$verb" "$args" >"$TMP/m.v" if grep -q '^__ERROR__' "$TMP/m.v"; then no "(M) MCP $verb legend:compact refused: $( head -c 160 "$TMP/m.v" )" - elif [ "$( leg bytes "$TMP/m.v" )" -le 400 ] && [ -n "$( leg schema "$TMP/m.v" )" ]; then - ok "(M) MCP $verb legend:compact: $( leg bytes "$TMP/m.v" ) B legend, schema $( leg schema "$TMP/m.v" )" + elif [ "$( leg bytes "$TMP/m.v" )" -le "$mpin" ] && [ -n "$( leg schema "$TMP/m.v" )" ]; then + ok "(M) MCP $verb legend:compact: $( leg bytes "$TMP/m.v" ) B legend (pin $mpin B), schema $( leg schema "$TMP/m.v" )" else - no "(M) MCP $verb legend:compact: legend $( leg bytes "$TMP/m.v" ) B, schema '$( leg schema "$TMP/m.v" )'" + no "(M) MCP $verb legend:compact: legend $( leg bytes "$TMP/m.v" ) B (pin $mpin B), schema '$( leg schema "$TMP/m.v" )'" fi done @@ -595,8 +706,8 @@ isHdr = spec.startswith( "#" ) # `#name`: an UNQUOTED field of the map header, tag, _, attr = ( "", "", spec[ 1: ] ) if isHdr else spec.rpartition( ":" ) def on( t ): # a tag-qualified spec reads only that element: is not return not tag or re.match( r"<" + re.escape( tag ) + r"[\s/>]", t ) is not None -if isHdr: - vals = [ m.group( 1 ) for h in header for m in [ re.search( r"\s" + re.escape( attr ) + r"=([^\s\"]+)", h ) ] if m ] +if isHdr: # a header field's value is bare (files=6) or QUOTED (unindexed="f90:1,zzqa:1"): both spellings are read + vals = [ m.group( 1 ) for h in header for m in [ re.search( r"\s" + re.escape( attr ) + r"=(\"[^\"]*\"|[^\s\"]+)", h ) ] if m ] else: vals = [ m.group( 1 ) for t in tags if on( t ) for m in [ re.search( r"\s" + re.escape( attr ) + r"=\"([^\"]*)\"", t ) ] if m ] leg = " ".join( legend ) @@ -606,18 +717,24 @@ elif op == "defines": print( 1 if re.search( r"(? file rows): of="6" is carried but the compact legend never defines it # FAIL (D16) the map over test/declinefix (merged overloads, split edges): prov="split" is carried but the compact legend never defines it -# NOT FIXED, stopped on the (U) 400 B pin: --communities' drill= and isolated=. Its compact prose is 385 B on this gate's -# repo; the shortest honest pair ("drill= takes an id=; isolated= edgeless symbols") costs 49 B (434 B), and even -# "drill=/isolated=: id= verb/edgeless" costs 37 B (422 B). No ceiling is raised for it. +# Stopped here on the (U) 400 B pin, and defined in the fourth sweep (D20) below once the owner raised the pins to fit honest +# definitions: --communities' drill= and isolated=. condPair D13 "--tree (files= on its root)" "$FIX" "--tree" tree:files condPair D13 "--zoom (its root's counts)" "$FIX" "--zoom" zoom:symbols zoom:isolated zoom:top_modules zoom:levels_shown [ -d "$ROOT/test/chafix" ] || no "(D14) fixture missing: test/chafix — its children= row would be vacuous" @@ -820,6 +939,213 @@ for v in "--around=distance" "--rank-by=churn" "--zoom" "" "--communities"; do done [ "$d17bad" -eq 0 ] && [ "$d17n" -eq 5 ] && ok "(D17) mirror: no third-sweep reading prints on $d17n answers that lack its field (--around's , churn, a one-level zoom, the plain map, --communities' isolated=/symbols=)" +# ── THE FOURTH SWEEP (2026-09-12): the vocabulary the earlier sweeps stopped on at the byte pins ───────────────────────── +# Owner decision 2026-09-12: per-verb pins that fit honest definitions (docs/METHODOLOGY.md §9 — honesty lives in attributes, +# the ceiling is a constraint). Each attribute below rides EVERY answer of its document, and was defined by prose if at all: +# (D18) the map header's unresolved= (serialize.h buildStats writes it unconditionally; the always-on legend's +# hdr:unresolved= clause defines it), read from the header ALONE: --from-trace's is a frame count; +# (D19) --impact's defs=, reaches=, importers=, shown_importers=, radius_tested=, radius_untested= on the XML form, the +# columnar form (which omits shown_importers= and names the omission in lens=) and the MCP default; +# (D20) --communities' drill=, isolated= and its isolated_decl=/isolated_header=/isolated_source=/isolated_doc= split, +# shown_modules=, bridges= ( and count other things); +# (D21) --community=ID's dir=, label=, bridges=, partition=, modules= (, are +# other roots' attributes); +# (D22) --safe-delete's radius_tested=/radius_untested=, which partition impact_reaches= where --impact's partition reaches=. +# A `!` spec is one the FULL legend does not define either (condArm's comment): --impact's defs=, the isolated_* split, +# shown_modules=, --communities' bridges= (its full legend spells bridge=), --community's dir=/label=/bridges=. +condPair D18 "the flagless map (unresolved= on its header)" "$FIX" "" "#unresolved" +condPair D18 "--max-tokens=50 (the header beside a fit-cut root)" "$FIX" "--max-tokens=50" "#unresolved" +condPair D19 "--impact=distance" "$FIX" "--impact=distance" '!impact:defs' impact:reaches impact:importers impact:shown_importers impact:radius_tested impact:radius_untested +condPair D19 "--impact=distance --format=columnar" "$FIX" "--impact=distance --format=columnar" '!impact:defs' impact:reaches impact:importers impact:radius_tested impact:radius_untested +mcp_text impact "{\"path\":\"$FIX\",\"symbol\":\"distance\",\"legend\":\"full\"}" >"$TMP/d.full" +mcp_text impact "{\"path\":\"$FIX\",\"symbol\":\"distance\"}" >"$TMP/d.comp" +condArm D19 "MCP impact at its DEFAULT posture (compact) vs legend:\"full\"" "$TMP/d.full" "$TMP/d.comp" '!impact:defs' impact:reaches impact:importers impact:shown_importers impact:radius_tested impact:radius_untested +condPair D20 "--communities (its root's counts)" "$FIX" "--communities" communities:drill communities:isolated '!communities:isolated_decl' '!communities:isolated_header' \ + '!communities:isolated_source' '!communities:isolated_doc' '!communities:shown_modules' '!communities:bridges' +condPair D21 "--community=0 (its root's counts and names)" "$FIX" "--community=0" community:partition community:modules '!community:dir' '!community:label' '!community:bridges' +condPair D22 "--safe-delete=total_area (its root's radius partition)" "$FIX" "--safe-delete=total_area" safe-delete:radius_tested safe-delete:radius_untested + +# (D23) THE MIRROR, on answers chosen for what they LACK, each lack asserted before it is relied on. The needles are the +# readings' own openers, so a reading printed on the wrong document is caught however its NAME is spelled there: --from-trace +# carries and no map header; the columnar --impact carries no shown_importers= (the one present-only term +# here); --safe-delete carries radius_tested= over impact_reaches= and no ; --zoom carries an isolated= of its own; +# --seams carries modules=/bridges= of its own; --community=0 carries its own bridges= and no drill=; --communities carries its +# own bridges= and no partition=; the plain map carries none of these roots. +rrun --from-trace="$TMP/trace.txt" --legend=compact >"$TMP/d23.trace" +[ "$( ca carries "$TMP/d23.trace" trace:unresolved )" = 1 ] && [ "$( ca carries "$TMP/d23.trace" "#unresolved" )" != 1 ] \ + || no "(D23) control: --from-trace no longer carries without a map header, so it proves nothing about the header-only read" +rrun --impact=distance --format=columnar --legend=compact >"$TMP/d23.col" +[ "$( ca carries "$TMP/d23.col" impact:reaches )" = 1 ] && [ "$( ca carries "$TMP/d23.col" impact:shown_importers )" != 1 ] \ + || no "(D23) control: the columnar --impact no longer carries reaches= without shown_importers=, so it proves nothing about that term being present-only" +rrun --safe-delete=total_area --legend=compact >"$TMP/d23.sd" +[ "$( ca carries "$TMP/d23.sd" safe-delete:radius_tested )" = 1 ] && [ "$( ca carries "$TMP/d23.sd" impact:reaches )" != 1 ] \ + || no "(D23) control: --safe-delete carries no radius_tested= (or now an ), so it no longer proves the two partitions read apart" +rrun --zoom --legend=compact >"$TMP/d23.zoom" +[ "$( ca carries "$TMP/d23.zoom" zoom:isolated )" = 1 ] \ + || no "(D23) control: --zoom carries no isolated= any more, so it no longer proves the communities reading is element-qualified" +rrun --seams --legend=compact >"$TMP/d23.seams" +[ "$( ca carries "$TMP/d23.seams" seams:modules )" = 1 ] && [ "$( ca carries "$TMP/d23.seams" seams:bridges )" = 1 ] \ + || no "(D23) control: --seams carries no modules=/bridges= any more, so it no longer proves the module readings are element-qualified" +rrun --community=0 --legend=compact >"$TMP/d23.one" +[ "$( ca carries "$TMP/d23.one" community:bridges )" = 1 ] && [ "$( ca carries "$TMP/d23.one" communities:drill )" != 1 ] \ + || no "(D23) control: --community=0 no longer carries its bridges= without a drill=, so it proves nothing about the two roots reading apart" +d23bad=0; d23n=0 +for v in "--from-trace=$TMP/trace.txt" "--impact=distance --format=columnar" "--safe-delete=total_area" "--impact=distance" "--zoom" "--seams" \ + "--communities" "--community=0" ""; do + rrun $v --legend=compact >"$TMP/d23.c" + if [ ! -s "$TMP/d23.c" ]; then + no "(D23) ${v:-the flagless map} --legend=compact answered nothing — its mirror row would be vacuous"; d23bad=1; continue + fi + d23n=$(( d23n + 1 )) + for pair in "unresolved= calls with in-tree evidence@#unresolved" "reaches= their transitive callers@impact:reaches" "shown_importers=:@impact:shown_importers" \ + "non-tests of impact_reaches=@safe-delete:radius_tested" "drill= the verb taking@communities:drill" \ + "isolated= symbols with no call edge@communities:isolated" "bridges= community pairs@communities:bridges" \ + "partition= module count@community:partition" "bridges= modules a call edge joins@community:bridges" "label= dir::name@community:label"; do + needle="${pair%%@*}"; spec="${pair#*@}" + if [ "$( ca mentions "$TMP/d23.c" "$needle" )" = 1 ] && [ "$( ca carries "$TMP/d23.c" "$spec" )" != 1 ]; then + no "(D23) ${v:-the flagless map}: the compact legend spells '$needle' but the document carries no $spec — a reading of a field that is not there" + d23bad=1 + fi + done +done +[ "$d23bad" -eq 0 ] && [ "$d23n" -eq 9 ] && ok "(D23) mirror: no fourth-sweep reading prints on $d23n answers that lack its field (--from-trace, the columnar --impact, --safe-delete, --impact, --zoom, --seams, --communities, --community=0, the plain map)" + +# ── THE FOURTH SWEEP, LAST PASS (2026-09-12): every attribute the four answers and the map header print ───────────────────── +# (D18)..(D23) closed what the earlier sweeps had named. This pass LISTED every attribute the compact --impact, --safe-delete, +# --communities, --community=ID and map-header documents emit, on test/fixture and on corpora that reach their conditional +# rows, and found these still undefined (each RUN before any reading landed): +# (D24) --communities' modules=, shown_bridges=, connected_singletons=, symbols= and --community's shown_bridges=: EVERY answer +# of the root carries them, so they read in the purpose lines; +# (D25) the rows: --communities' a=/b=/from_label=/to_label=/edges= and --community's to=/to_label=/edges=. Only an +# answer with a cross-module call edge prints one (test/chafix does; test/fixture does not), so each is a present-only +# term read on alone; +# (D26) --safe-delete's t=, defs=, ambiguous_callers=, dead_code_candidate= (its root p= reads in t='s clause; it is not a red +# spec because already spells the name); +# (D27) --impact's importer rows, present-only on : the columnar form prints no row; +# (D28) the map header: the always-on files=/symbols=/edges=/shown=/ambiguous=/order=, and the conditional roots=, changed=, +# skipped_oversize=, unindexed=/unindexed_exts=, escaped_root=, precise=. The full map legend defines none but shown= +# (serialize.h buildUnindexedAttr records why it cannot: tokenbudgetcheck arm #3 leaves that floor seven bytes); a +# compact legend replaces MORE prose than it adds, which (U) asserts on every probe, so here the readings fit; +# (D29) the columnar form's format=/ ( reads in the same term, and is not a red spec because the +# purpose line's already spells the name) and lens=, which --order=stable's carries too. +# A `#name` header value may be QUOTED (unindexed="zzqa:1,…"), so condattr.py reads both spellings. +OVR="$TMP/oversize"; mkdir -p "$OVR"; cp -R "$FIX"/. "$OVR"/; head -c 5000 /dev/zero | tr '\0' 'a' >"$OVR/huge.py" +UNX="$TMP/unindexed"; mkdir -p "$UNX"; printf 'x = 1\n' >"$UNX/a.py" +for e in zzqa zzqb zzqc zzqd zzqe zzqf zzqg; do printf 'text\n' >"$UNX/a.$e"; done +ESC="$TMP/escape"; mkdir -p "$ESC/inner" "$ESC/outside"; cp -R "$FIX"/. "$ESC/inner"/ +printf 'def far():\n return 2\n' >"$ESC/outside/far.py"; ln -s ../outside/far.py "$ESC/inner/far.py" +CHA="$ROOT/test/chafix"; SCIPF="$ROOT/test/scipfix" +for d in "$CHA" "$SCIPF"; do [ -d "$d" ] || no "(D25/D28) fixture missing: $d — every row reading it would be vacuous"; done + +condPair D24 "--communities (the rest of its root's counts)" "$FIX" "--communities" \ + '!communities:modules' '!communities:shown_bridges' '!communities:connected_singletons' '!communities:symbols' +condPair D24 "--community=0 (its bridge listing's width)" "$FIX" "--community=0" '!community:shown_bridges' +cdRun "$TMP/d25.cm" "$CHA" --communities +chaModule="$( grep -o ' row any more, so both rows below are vacuous" +condPair D25 "--communities over test/chafix (a cross-module row)" "$CHA" "--communities" \ + '!bridge:a' '!bridge:b' '!bridge:from_label' '!bridge:to_label' '!bridge:edges' +condPair D25 "--community=${chaModule:-0} over test/chafix (its peer row)" "$CHA" "--community=${chaModule:-0}" '!bridge:to' '!bridge:to_label' '!bridge:edges' +condPair D26 "--safe-delete=total_area (the rest of its root)" "$FIX" "--safe-delete=total_area" \ + safe-delete:t safe-delete:defs safe-delete:ambiguous_callers safe-delete:dead_code_candidate +condPair D27 "--impact=distance ( importer rows)" "$FIX" "--impact=distance" f:lazy +mcp_text impact "{\"path\":\"$FIX\",\"symbol\":\"distance\",\"legend\":\"full\"}" >"$TMP/d.full" +mcp_text impact "{\"path\":\"$FIX\",\"symbol\":\"distance\"}" >"$TMP/d.comp" +condArm D27 "MCP impact at its DEFAULT posture (compact) vs legend:\"full\"" "$TMP/d.full" "$TMP/d.comp" f:lazy +condPair D28 "the flagless map (its always-on header)" "$FIX" "" '!#files' '!#symbols' '!#edges' '#shown' '!#ambiguous' '!#order' +"$BIN" "$FIX" "$H1" >"$TMP/d.full" 2>/dev/null "$TMP/d.comp" 2>/dev/null of its own (the trace's dialect) and no ; --communities and --community=0 over test/fixture print no +# row; the columnar --impact prints no row; --impact=distance carries no map header and no lens=; the flagless +# map carries none of the conditional header fields. The needles are the readings' own openers, as in (D23). +rrun --from-trace="$TMP/trace.txt" --legend=compact >"$TMP/d30.trace" +[ "$( ca carries "$TMP/d30.trace" trace:format )" = 1 ] && [ "$( ca carries "$TMP/d30.trace" cols:fields )" != 1 ] \ + || no "(D30) control: --from-trace no longer carries without , so it proves nothing about the columnar reading's element" +rrun --communities --legend=compact >"$TMP/d30.cm" +[ "$( ca carries "$TMP/d30.cm" communities:bridges )" = 1 ] && [ "$( ca carries "$TMP/d30.cm" bridge:edges )" != 1 ] \ + || no "(D30) control: --communities over the fixture now prints a row, so it no longer proves the bridge readings are present-only" +rrun --impact=distance --format=columnar --legend=compact >"$TMP/d30.col" +[ "$( ca carries "$TMP/d30.col" impact:importers )" = 1 ] && [ "$( ca carries "$TMP/d30.col" f:lazy )" != 1 ] \ + || no "(D30) control: the columnar --impact now prints an row, so it no longer proves that reading is present-only" +rrun --impact=distance --legend=compact >"$TMP/d30.imp" +[ "$( ca carries "$TMP/d30.imp" f:lazy )" = 1 ] && [ "$( ca carries "$TMP/d30.imp" "#files" )" != 1 ] && [ "$( ca carries "$TMP/d30.imp" lens )" != 1 ] \ + || no "(D30) control: --impact=distance no longer carries without a map header or lens=, so it proves nothing about the header-only and head readings" +d30bad=0; d30n=0 +for v in "--from-trace=$TMP/trace.txt" "--communities" "--community=0" "--impact=distance --format=columnar" "--impact=distance" ""; do + rrun $v --legend=compact >"$TMP/d30.c" + if [ ! -s "$TMP/d30.c" ]; then + no "(D30) ${v:-the flagless map} --legend=compact answered nothing — its mirror row would be vacuous"; d30bad=1; continue + fi + d30n=$(( d30n + 1 )) + for pair in ":@f:lazy" ":@bridge:a" "from_label=/to_label=:@bridge:from_label" ":@bridge:to" \ + ":@bridge:edges" "files=/symbols=:@#files" "roots=N:@#roots" "changed=K:@#changed" "skipped_oversize=K:@#skipped_oversize" \ + "unindexed=ext:N:@#unindexed" "unindexed_exts=E:@#unindexed_exts" "escaped_root=K:@#escaped_root" "precise=K:@#precise" \ + "format=columnar:@cols:fields" "lens=:@lens"; do + needle="${pair%%@*}"; spec="${pair#*@}" + if [ "$( ca mentions "$TMP/d30.c" "$needle" )" = 1 ] && [ "$( ca carries "$TMP/d30.c" "$spec" )" != 1 ]; then + no "(D30) ${v:-the flagless map}: the compact legend spells '$needle' but the document carries no $spec — a reading of a field that is not there" + d30bad=1 + fi + done +done +[ "$d30bad" -eq 0 ] && [ "$d30n" -eq 6 ] && ok "(D30) mirror: no last-pass reading prints on $d30n answers that lack its field (--from-trace, --communities, --community=0, the columnar --impact, --impact, the plain map)" + +# ── THE TESTED ROW LENS (2026-09-12, the design review of the fourth sweep) ────────────────────────────────────────────────── +# (D31) rows. --callers/--callees and --impact (verbs_navigate.h), the MCP impact twin (mcpverbs.h) and the map's +# own rows (serialize.h, over computeQMetrics' tested[] column) print tested="1" on a row graph.h isTestedByReach accepts: an +# indexed test transitively reaches it and it is not itself a test symbol; never a literal 0. The full legend defines it +# (graphlegend.h kTestedRowLegend) and the compact layer stripped that clause with nothing to put back. No row above could see +# it: test/fixture holds no test, so every probe here printed radius_tested="0" and no tested row, while --impact= +# svector::push_back on this repo printed four. The corpus below is the smallest that prints one: test_lib.py's test_run calls +# run, which calls helper. The reading is ELEMENT-qualified on : flipimpact.h's prints 0 as well as 1, and +# is another root's attribute. +# RED on the fourth sweep's last-pass build (the uncommitted lane over b7c55908, plain and ASan alike): all three rows FAILed and +# nothing else did, for example +# FAIL (D31) --callers=helper over a tree with a test (its caller run is tested): tested="1" is carried but the compact legend never defines it +# FAIL (D31) MCP impact over a tree with a test, at its DEFAULT posture (compact) vs legend:"full": tested="1" is carried but the compact legend never defines it +TESTED="$TMP/testedrows"; mkdir -p "$TESTED/src" +printf 'def helper():\n return 1\n\n\ndef run():\n return helper()\n' >"$TESTED/src/lib.py" +printf 'from src.lib import run\n\n\ndef test_run():\n assert run() == 1\n' >"$TESTED/test_lib.py" +condPair D31 "--callers=helper over a tree with a test (its caller run is tested)" "$TESTED" "--callers=helper" s:tested +condPair D31 "--impact=helper over a tree with a test (run, in its reach set, is tested)" "$TESTED" "--impact=helper" s:tested +mcp_text impact "{\"path\":\"$TESTED\",\"symbol\":\"helper\",\"legend\":\"full\"}" >"$TMP/d.full" +mcp_text impact "{\"path\":\"$TESTED\",\"symbol\":\"helper\"}" >"$TMP/d.comp" +condArm D31 "MCP impact over a tree with a test, at its DEFAULT posture (compact) vs legend:\"full\"" "$TMP/d.full" "$TMP/d.comp" s:tested + +# (D32) THE MIRROR, on answers chosen for what they LACK, each lack asserted before it is relied on: --callers=run over the same +# corpus lists one caller, test_run, which is a test symbol, so it carries hop_tested= and no tested row; --safe-delete=helper +# carries radius_tested= and lists rows; test/fixture's --callers, --impact and flagless map carry no tested row at all. The +# needle is the reading's own opener, as in (D23)/(D30). Green on the red build by construction, like (D7). Shown able to fail: +# with the reading spliced into the legend of --callers=run over this corpus, the row's check read the needle as spelled and no +# row as carried, which is its FAIL. +cdRun "$TMP/d32.run" "$TESTED" --callers=run --legend=compact +[ "$( ca carries "$TMP/d32.run" callers:hop_tested )" = 1 ] && [ "$( ca carries "$TMP/d32.run" s:tested )" != 1 ] \ + || no "(D32) control: --callers=run over the tested corpus no longer carries hop_tested= without a tested row, so it proves nothing about the row reading being present-only" +d32bad=0; d32n=0 +for v in "$TESTED@--callers=run" "$TESTED@--safe-delete=helper" "$REPO@--callers=distance" "$REPO@--impact=distance" "$REPO@"; do + dir="${v%%@*}"; args="${v#*@}" + cdRun "$TMP/d32.c" "$dir" $args --legend=compact + if [ ! -s "$TMP/d32.c" ]; then + no "(D32) ${args:-the flagless map} --legend=compact answered nothing — its mirror row would be vacuous"; d32bad=1; continue + fi + d32n=$(( d32n + 1 )) + if [ "$( ca mentions "$TMP/d32.c" ":" )" = 1 ] && [ "$( ca carries "$TMP/d32.c" s:tested )" != 1 ]; then + no "(D32) ${args:-the flagless map}: the compact legend spells ':' but the document carries no row — a reading of a field that is not there" + d32bad=1 + fi +done +[ "$d32bad" -eq 0 ] && [ "$d32n" -eq 5 ] && ok "(D32) mirror: the tested row reading prints on none of $d32n answers that lack an row (a test-only caller list, --safe-delete's radius, the fixture's --callers/--impact, the plain map)" + echo echo "=== (S) STRUCTURAL: every conditional attribute the graphlegend.h family, the PageRank disclosure, the map header and the map's rows emit has a compact reading ===" # The (D) rows prove today's members; this row keeps the NEXT one from landing undefined. The population is READ FROM @@ -845,10 +1171,13 @@ echo "=== (S) STRUCTURAL: every conditional attribute the graphlegend.h family, # conditional at its CALL SITE rather than inside graphlegend.h (fielduses.h's member form, serialize.h's multi-root # table, --lego's caveat=) — rows (D4)/(D5)/(D6) are what guard those; nor a map-family clause not spelled `hdr:` # (kMaxTokensFitLegend's max_tokens=/fit_bytes=/over_ceiling=, est_tokens= under order=stable, --around's defs=, -# --rank-by's rank_by=/window=) — (D10)/(D11) guard those. And BY CONSTRUCTION not the always-on header field unresolved= -# (no absent-if-0 marker), which the reader prints as INFO on every run because it is STILL undefined under compact: its -# shortest reading, "unresolved=: resolver gauge", costs 29 B on every map and puts two (U) probes over the 400 B ceiling -# (--max-tokens=3 379 -> 408, --rank-by=churn 376 -> 405 over their measured legends). No ceiling is raised for it. +# --rank-by's rank_by=/window=) — (D10)/(D11) guard those. The always-on header field unresolved= (no absent-if-0 marker) +# was printed here as INFO, still undefined under compact, until the fourth sweep (2026-09-12, owner decision: raise the pins +# to fit honest definitions): population 3 now requires a header reading for EVERY hdr: field of that legend, marked or +# not, and (D18) shows the reading live. Shown able to fail: this reader run over 27fc151d's src/compactlegend.h (no row) +# FAILed on unresolved= and on nothing else. The sweep's design review folded unresolved= into the always-on files= clause, so an +# UNMARKED field may read inside that one row; a marked field still needs a row of its own. Shown able to fail on the fold: with +# unresolved= deleted from that clause, this reader FAILed on unresolved= and on nothing else. # RED on origin/main 28ee1df3: bodyless_defs=, declined_calls= and unproven_defs= FAILed. Shown able to fail on the fix # too: with the declined_calls row deleted from kCompactCompletenessTerms this arm went red on that name (landing commit). # RED on 34a97f66 for population 3: pr_iters=, pr_converged= and all seven hdr: fields FAILed. Shown able to fail on the @@ -1014,7 +1343,25 @@ else: print( "FAIL|%s= (%s) has no kCompactCompletenessTerms row that reads the payload (wholeDoc or onTag) — a compact map carrying it leaves it undefined" % ( attr, rowPop[ attr ] ) ) if len( rowCovered ) == len( rowPop ): print( "PASS|map rows: %d of %d absence-marked row fields of the always-on legend have a payload-reading compact term: %s" % ( len( rowCovered ), len( rowPop ), " ".join( rowCovered ) ) ) -print( "INFO|outside that population by construction (unconditional on every map, no absent-if-0 marker): %s — still undefined under compact, see the arm's comment" % " ".join( a + "=" for a in sorted( always ) ) ) +# The always-on header fields (no absent-if-0 marker) ride EVERY map header, so each needs a header reading as much as a +# conditional one does (the fourth sweep, 2026-09-12: unresolved=). Since that sweep's design review the reading may sit inside +# the always-on header clause, the `files` row (MapHeaderRead::Only): buildStats writes files= into every header, so a field +# spelled there is read exactly when the header is. A CONDITIONAL field never qualifies that way (the population above wants a +# row of its own), so a field that gains an absence marker leaves this set and fails there until it is split back out. +hdrClause = None +for m in re.finditer( r"\{\s*\"S(\d+)\"\s*,\s*\"S(\d+)\"(?:[^{}]|\{\})*?MapHeaderRead::Only", rows ): + if clits[ int( m.group( 1 ) ) ] == "files": + hdrClause = clits[ int( m.group( 2 ) ) ] +if hdrClause is None: + print( "FAIL|no always-on map-header row (attr files, MapHeaderRead::Only) was read from src/compactlegend.h — the reader broke, so the always-on row below means nothing" ) + hdrClause = "" +inClause = lambda a: re.search( r"(?"$TMP/s.rows" 2>"$TMP/s.err" || no "(S) the source reader crashed: $( head -c 300 "$TMP/s.err" )" [ -s "$TMP/s.rows" ] || no "(S) the source reader printed no rows — the structural arm would be vacuous" diff --git a/test/printf_parity.manifest b/test/printf_parity.manifest index 5ba246ff..7b4e406b 100644 --- a/test/printf_parity.manifest +++ b/test/printf_parity.manifest @@ -38,5 +38,5 @@ safe_delete 0 b06980d52e4991e57563059d8be986bb4614779e20ccfd3790aac1ee076d2512 e verify_layer 1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 5288c345d7d6e335f88b9c1daa8935db22e1dcf89c0c8bc1f6140d4cb5af0b48 graph_query 1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 bfa4319feb9dee09cfbd3991cf6fbd752297e99d14de9e75768820d2a9c8832f callers_limit 0 ab9dee52240f70055fa4d82d6b928ef52f4f5781c6a80ee39edb49805b892719 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -help_all 0 48f9b4c3fe1f9b27b3ce87c7a9d0d87f1522b56eaa953bbe3ae328f6645172ad e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +help_all 0 8f10d3ac1a86bcce9df83c7a3e226bdaf710640049a3926069beb52f7ee7fdf4 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 help_one 0 d958f81abe53aa21051deaf47dded37bf80d707a049148a6356c96e331a28da1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/test/showcase_capture.py b/test/showcase_capture.py index 5ad49e6b..c02edb17 100644 --- a/test/showcase_capture.py +++ b/test/showcase_capture.py @@ -307,7 +307,7 @@ def add(section, cmd, what, **opts): add(S2, f"{BIN} . --around=rankGraphTeleport --around-depth=2", "The restoring knob: --around-depth=2 brings back the whole 2-hop neighbourhood (depth=\"2\" on the root) — pay for it only when the 1-hop view was not enough.") add(S2, f"{BIN} . --around=rankGraphTeleport --around-fanout=4", "The other knob: --around-fanout=4 keeps only the 4 strongest edges per node (default 32) — the same 1-hop depth, a quarter of the rows.") add(S2, f"{BIN} . --callers=rankGraphTeleport", "Who calls SYM (1-hop in-edges).") -add(S2, f"{BIN} . --callers=rankGraphTeleport --legend=compact", "The same rows under --legend=compact: the prose legend becomes one <=400 B comment plus schema=\"ripwire.callers/v1\" on the root — every row byte and every completeness attribute (counts_floor=, graph_ambiguous=, next=) identical, ~3 KB of legend gone. Works on EVERY XML verb now, not four.") +add(S2, f"{BIN} . --callers=rankGraphTeleport --legend=compact", "The same rows under --legend=compact: the prose legend becomes one compact comment plus schema=\"ripwire.callers/v1\" on the root — every row byte and every completeness attribute (counts_floor=, graph_ambiguous=, next=) identical, ~3 KB of legend gone. Works on EVERY XML verb now, not four.") add(S2, f"{BIN} . --callers=DoesNotExist", "Unknown-symbol REFUSAL shape (exit 1) with a did-you-mean from real edit distance.") add(S2, f"{BIN} . --callees=rankGraphTeleport", "What SYM calls (1-hop out-edges).") add(S2, f"{BIN} . --uses=rankGraphTeleport", "The resolvable use-sites (call/read/write/import/extends) with file:line; count= is a floor.") From f773d4eaded093a39f12678b66d12f74b3bbf568 Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sat, 12 Sep 2026 14:08:39 -0400 Subject: [PATCH 2/7] fix(legend): compact rows and the columnar tested column printed with no definition Under --legend=compact two forms of the tested lens reached the reader undefined. signature rows (--pack-task --metrics; serialize.h, from computeQMetrics' tested[] column) matched no term, because the reading is element-qualified on . The columnar form of --callers/--callees/--impact names tested in and writes a dense array of 1 and 0 (columnar.h emitColumnarTestedColumn), which no term read either; over a tree with no test that array is all zeros. Readings added to kCompactCompletenessTerms, each present-only: - : a non-test row an indexed test transitively reaches (absent otherwise, never 0) - column: 1 = a non-test row an indexed test transitively reaches; 0 = none found, or a test row The column term keys on a that lists tested rather than on a 1, so CompactCompletenessTerm gains valueItem and payloadHasAnyAttr reads one comma-separated item of the attribute's value (a defaulted parameter; its two callers are unchanged). test/compactlegendcheck.sh: (D33) the reading on --pack-task=helper --metrics over a tree with a test; (D34) the column reading on columnar --callers/--callees/--impact, including an all-zero column over test/fixture; (D35) the mirror on five answers that lack each field. Red on e45bd3ab, plain and ASan alike: the six (D33)/(D34) checks failed and nothing else did. Green on both after. No pin moved: every (U) probe's prose legend, the (M) legends and the (L) loop (4,849 B) measure the same before and after, because no pinned probe carries either field. Full-dialect answers are byte-identical against e45bd3ab; compact payloads are identical and legends only gain the two readings (+105 B on a columnar callers/callees/impact answer, +95 B on --pack-task --metrics over a tree with a test). Co-Authored-By: Claude Opus 5 --- src/compactlegend.h | 52 +++++++++++++++++++-- test/compactlegendcheck.sh | 96 +++++++++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 7 deletions(-) diff --git a/src/compactlegend.h b/src/compactlegend.h index 1d9f111d..4b0367ad 100644 --- a/src/compactlegend.h +++ b/src/compactlegend.h @@ -250,6 +250,8 @@ struct CompactCompletenessTerm std::string_view onTag = {}; // read ONLY on this element and never on the head: label= on the multi-root // rows is not the label= --communities carries on its first child MapHeaderRead mapHeader = MapHeaderRead::No; + std::string_view valueItem = {}; // with onTag: read only where that attribute's quoted value LISTS this comma-separated + // item: naming tested carries the tested column, not every columnar answer }; inline constexpr CompactCompletenessTerm kCompactCompletenessTerms[] = @@ -377,15 +379,27 @@ inline constexpr CompactCompletenessTerm kCompactCompletenessTerms[] = { "escaped_root", "escaped_root=K: K files refused: a symlink led out of the root", false, {}, MapHeaderRead::Only }, { "precise", "precise=K: K call edges a SCIP index pinned", false, {}, MapHeaderRead::Only }, { "fields", "format=columnar: parallel arrays, not row attributes: maps I=path, each array holds n= comma-separated values in one row order, fields= naming them (the path column indexes ; , is a comma)", true, "cols" }, + // THE TESTED COLUMN (2026-09-12, the follow-up to the row below). --callers/--callees/--impact --format=columnar + // always pass the test-reach lens (verbs_navigate.h), so fields= names tested and columnar.h emitColumnarTestedColumn writes one + // DENSE value per row: 1 where graph.h isTestedByReach holds, 0 on every other row, a test symbol's row included. A parallel + // array cannot omit a false entry, so unlike the attribute this prints 0, and an answer over a tree with no test carries a + // column of zeros: the term reads the COLUMN (a that lists tested), never a 1. compactlegendcheck (D34)/(D35). + { "fields", " column: 1 = a non-test row an indexed test transitively reaches; 0 = none found, or a test row", true, "cols", MapHeaderRead::No, "tested" }, { "lens", "lens=: attributes another form of this answer serves, withheld here" }, // THE SWEEP'S DESIGN REVIEW (2026-09-12) checked every reading above against its emitter and found one row reading still // missing: tested="1" on . --callers/--callees and --impact (verbs_navigate.h), the MCP impact twin (mcpverbs.h) and the // map's own rows (serialize.h, whose tested[] column computeQMetrics fills by the same predicate) print it where graph.h // isTestedByReach holds: an indexed test transitively reaches that row's symbol and the symbol is not itself a test. Never // a literal 0. ELEMENT-qualified on : flipimpact.h's prints 0 as well as 1 and is another - // root's attribute; a body row's tested= is not read by this row. No earlier sweep saw it because the gate fixture holds + // root's attribute; a signature row's tested= is the next row's. No earlier sweep saw it because the gate fixture holds // no test (compactlegendcheck (D31) builds the smallest tree that prints one). { "tested", ": a non-test row an indexed test transitively reaches (absent otherwise, never 0)", true, "s" }, + // The same lens on the signature rows (2026-09-12, the follow-up): serialize.h's two row writers print tested="1" from + // computeQMetrics' tested[] column, which the same isTestedByReach fills, and never a literal 0. main.cpp computes that column + // only under --metrics, --for or --exemplar, so the reading rides the answers that computed it (--pack-task --metrics; --for + // keeps its native legend). ELEMENT-qualified on , like the row above: flipimpact.h's and the dead-code + // rows carry no tested=. compactlegendcheck (D33)/(D35). + { "tested", ": a non-test row an indexed test transitively reaches (absent otherwise, never 0)", true, "d" }, { "parse_degraded", "parse_degraded=1: ERROR nodes in that parse", true }, { "tier_partial", "tier_partial=1: tier elected under a partial classification" }, { "dangling", "dangling=1: matches nothing indexed", true }, @@ -580,8 +594,35 @@ inline bool isElementNamed( std::string_view tag, std::string_view name ) noexce return next == ' ' || next == '/' || next == '>'; } -// Row-level terms: does ANY tag outside comments/CDATA carry ` ="`? With `onTag`, only a `` element counts. -inline bool payloadHasAnyAttr( std::string_view doc, std::string_view attr, std::string_view onTag = {} ) +// Does the quoted value that opens `value` (up to its closing quote) list `item` as one whole comma-separated entry? An empty +// item accepts any value: only a valueItem term asks what the attribute holds rather than whether it is there. +inline bool quotedValueListsItem( std::string_view value, std::string_view item ) noexcept +{ + if( item.empty() ) + { + return true; + } + const std::string_view list = value.substr( 0, value.find( '"' ) ); + std::size_t begin = 0; + while( begin <= list.size() ) + { + std::size_t end = list.find( ',', begin ); + if( end == std::string_view::npos ) + { + end = list.size(); + } + if( list.substr( begin, end - begin ) == item ) + { + return true; + } + begin = end + 1; + } + return false; +} + +// Row-level terms: does ANY tag outside comments/CDATA carry ` ="`? With `onTag`, only a `` element counts; with +// `valueItem`, only a value that lists that item. +inline bool payloadHasAnyAttr( std::string_view doc, std::string_view attr, std::string_view onTag = {}, std::string_view valueItem = {} ) { std::string needle; needle.reserve( attr.size() + 3 ); @@ -605,7 +646,8 @@ inline bool payloadHasAnyAttr( std::string_view doc, std::string_view attr, std: { const std::size_t j = doc.find( '>', i ); const std::string_view tag = doc.substr( i, j == std::string_view::npos ? doc.size() - i : j + 1 - i ); - if( tag.find( needle ) != std::string_view::npos && isElementNamed( tag, onTag ) ) { return true; } + const std::size_t at = tag.find( needle ); + if( at != std::string_view::npos && isElementNamed( tag, onTag ) && quotedValueListsItem( tag.substr( at + needle.size() ), valueItem ) ) { return true; } i = j == std::string_view::npos ? doc.size() : j + 1; } else @@ -652,7 +694,7 @@ inline bool isCompletenessTermPresent( const CompactCompletenessTerm& t, std::st } if( !t.onTag.empty() ) { - return payloadHasAnyAttr( doc, t.attr, t.onTag ); + return payloadHasAnyAttr( doc, t.attr, t.onTag, t.valueItem ); } return headHasAttr( head, t.attr ) || ( t.wholeDoc && payloadHasAnyAttr( doc, t.attr ) ); } diff --git a/test/compactlegendcheck.sh b/test/compactlegendcheck.sh index a994377d..041cdd85 100755 --- a/test/compactlegendcheck.sh +++ b/test/compactlegendcheck.sh @@ -35,8 +35,9 @@ # partition=/modules=, --safe-delete's radius_tested=/radius_untested=; in that sweep's last pass: --communities' modules=/ # shown_bridges=/connected_singletons=/symbols=, --community's shown_bridges=, the rows, --safe-delete's t=/defs=/ # ambiguous_callers=/dead_code_candidate=, --impact's , every map-header field, the columnar format=/ and -# lens=; from that sweep's design review: the rows of --callers/--impact) is DEFINED by the compact legend of a -# document that carries it, and by none that does not. STRUCTURAL arm (S): every +# lens=; from that sweep's design review: the rows of --callers/--impact; in its follow-up: the rows of +# --pack-task --metrics and the columnar tested column) is DEFINED by the compact legend of a document that carries it, and by +# none that does not. STRUCTURAL arm (S): every # conditional attribute the graphlegend.h helper family emits, the PageRank disclosure, every conditional hdr: field of # the map header, and every absence-marked row field of the map legend, read from source, has a compact reading — so the # next one cannot land undefined. @@ -1146,6 +1147,97 @@ for v in "$TESTED@--callers=run" "$TESTED@--safe-delete=helper" "$REPO@--callers done [ "$d32bad" -eq 0 ] && [ "$d32n" -eq 5 ] && ok "(D32) mirror: the tested row reading prints on none of $d32n answers that lack an row (a test-only caller list, --safe-delete's radius, the fixture's --callers/--impact, the plain map)" +# ── THE TESTED LENS ON ROWS AND IN THE COLUMNAR FORM (2026-09-12, the follow-up to (D31)/(D32)) ────────────────────────────── +# (D31)'s reading is ELEMENT-qualified on , and two more forms print the same lens with no reading. Each was run, and read +# against its emitter, before any reading landed: +# (D33) signature rows. serialize.h's two signature-row writers print it from computeQMetrics' tested[] column, +# which graph.h isTestedByReach fills: the rows' predicate, an indexed test transitively reaches that symbol and it +# is not itself a test. Never a literal 0. main.cpp computes that column only under --metrics, --for or --exemplar, so a +# plain --pack-task prints no tested= at all; --pack-task --metrics does, and main.cpp's compactLegendHint checks +# metrics before pack-task, so that answer compacts under the pack-signatures schema. Its FULL legend never names +# tested= either (a `!` spec). condArm's left-anchored tested= would also be satisfied by (D31)'s reading +# on an answer printing both forms, so the row asserts the reading's own opener too. +# (D34) the columnar form's tested column. --callers/--callees/--impact --format=columnar always pass the test-reach lens +# (verbs_navigate.h), so fields= names tested and holds one DENSE value per row (columnar.h +# emitColumnarTestedColumn): 1 where isTestedByReach holds, 0 on every other row, a test row included. Unlike the +# attribute it prints 0, so the reading rides the COLUMN rather than a 1: over test/fixture, which holds no test, +# --callers=distance carries 0,0, and a reading keyed to a 1 would leave those zeros undefined. The +# full legend's only tested sentence is kTestedRowLegend's attribute reading ("never 0"), so no full control is taken. +# RED on e45bd3ab (plain and ASan alike): all six (D33)/(D34) checks FAILed and nothing else did ((D35) is green by construction), +# for example +# FAIL (D33) --pack-task=helper --metrics over a tree with a test (its rows helper and run are tested): tested="1" is carried but the compact legend never defines it +# FAIL (D34) --callers=distance --format=columnar over test/fixture (...): fields="path,name,line,kind,tested" and 0,0 are carried but the compact legend never reads the column +condPair D33 "--pack-task=helper --metrics over a tree with a test (its rows helper and run are tested)" "$TESTED" "--pack-task=helper --metrics" '!d:tested' +if [ "$( ca carries "$TMP/d.comp" d:tested )" = 1 ] && [ "$( ca mentions "$TMP/d.comp" ":" )" = 1 ]; then + ok "(D33) --pack-task=helper --metrics: the reading is the row's own (':')" +else + no "(D33) --pack-task=helper --metrics: carried=$( ca carries "$TMP/d.comp" d:tested ), but the compact legend does not spell the row reading ':': $( leg legend "$TMP/d.comp" | head -c 260 )" +fi +COLTESTED=" column:" +namesTested(){ case ",$1," in *,tested,*) return 0 ;; esac; return 1; } +# colTestedRow ID LABEL DIR "ARGS" — one columnar answer in both postures: the control (fields= names tested in both), then the +# compact legend must spell the column's reading. +colTestedRow() +{ + local id="$1" label="$2" dir="$3" args="$4" col + cdRun "$TMP/d.full" "$dir" $args; cdRun "$TMP/d.comp" "$dir" $args --legend=compact + col="$( grep -o '[^<]*' "$TMP/d.comp" | head -1 )" + if ! namesTested "$( ca value "$TMP/d.full" cols:fields )" || ! namesTested "$( ca value "$TMP/d.comp" cols:fields )"; then + no "($id) $label: control broken — does not name tested in both postures, so its reading row would be vacuous: $( head -c 160 "$TMP/d.comp" )" + elif [ "$( ca mentions "$TMP/d.comp" "$COLTESTED" )" != 1 ]; then + no "($id) $label: fields=\"$( ca value "$TMP/d.comp" cols:fields )\" and $col are carried but the compact legend never reads the column: $( leg legend "$TMP/d.comp" | head -c 260 )" + else + ok "($id) $label: fields= names tested ($col), and the compact legend reads the column" + fi + return 0 +} +colTestedRow D34 "--callers=helper --format=columnar over a tree with a test" "$TESTED" "--callers=helper --format=columnar" +colTestedRow D34 "--callees=run --format=columnar over a tree with a test" "$TESTED" "--callees=run --format=columnar" +colTestedRow D34 "--impact=helper --format=columnar over a tree with a test (test_run, a test row, reads 0)" "$TESTED" "--impact=helper --format=columnar" +colTestedRow D34 "--callers=distance --format=columnar over test/fixture (no test: the column still rides, every value 0)" "$REPO" "--callers=distance --format=columnar" + +# (D35) THE MIRROR, on answers chosen for what they LACK, each lack asserted before it is relied on: --pack-task=helper over the +# tested corpus prints rows with no tested= (no --metrics, so no column was computed); --pack-task=geometry --metrics over +# test/fixture prints rows and no tested= (no test reaches them); --uses=helper --format=columnar has a fields= that does +# not name tested; --callers=helper carries rows and neither a row nor ; --pack-task=helper --metrics carries +# and no row, which also keeps (D31)'s reading on . The needles are the readings' own openers, as in +# (D32). Green on the red build by construction, like (D7). Shown able to fail: with each reading spliced into the compact legend +# of a real answer that lacks its field (the column reading into --uses=helper --format=columnar, the reading into +# --pack-task=helper, (D31)'s reading into --pack-task=helper --metrics), its check here fired on all three spliced answers +# and on none of the three unspliced ones. The column check is the one a dropped valueItem trips: without it the fields= term +# reads every , --uses' included. +cdRun "$TMP/d35.pt" "$TESTED" --pack-task=helper --legend=compact +[ "$( ca carries "$TMP/d35.pt" d:l )" = 1 ] && [ "$( ca carries "$TMP/d35.pt" d:tested )" != 1 ] \ + || no "(D35) control: --pack-task=helper over the tested corpus no longer prints rows without tested=, so it proves nothing about the reading being present-only" +cdRun "$TMP/d35.uses" "$TESTED" --uses=helper --format=columnar --legend=compact +{ [ "$( ca carries "$TMP/d35.uses" cols:fields )" = 1 ] && ! namesTested "$( ca value "$TMP/d35.uses" cols:fields )"; } \ + || no "(D35) control: --uses=helper --format=columnar no longer carries a fields= without tested, so it proves nothing about the column reading riding the column" +cdRun "$TMP/d35.ptm" "$TESTED" --pack-task=helper --metrics --legend=compact +[ "$( ca carries "$TMP/d35.ptm" d:tested )" = 1 ] && [ "$( ca carries "$TMP/d35.ptm" s:tested )" != 1 ] \ + || no "(D35) control: --pack-task=helper --metrics no longer carries without an row, so it proves nothing about the two row readings reading apart" +d35bad=0; d35n=0 +for v in "$TESTED@--pack-task=helper" "$REPO@--pack-task=geometry --metrics" "$TESTED@--uses=helper --format=columnar" "$TESTED@--callers=helper" \ + "$TESTED@--pack-task=helper --metrics"; do + dir="${v%%@*}"; args="${v#*@}" + cdRun "$TMP/d35.c" "$dir" $args --legend=compact + if [ ! -s "$TMP/d35.c" ]; then + no "(D35) $args --legend=compact answered nothing — its mirror row would be vacuous"; d35bad=1; continue + fi + d35n=$(( d35n + 1 )) + for pair in ":@d:tested" ":@s:tested"; do + needle="${pair%%@*}"; spec="${pair#*@}" + if [ "$( ca mentions "$TMP/d35.c" "$needle" )" = 1 ] && [ "$( ca carries "$TMP/d35.c" "$spec" )" != 1 ]; then + no "(D35) $args: the compact legend spells '$needle' but the document carries no <${spec%%:*} tested=> row — a reading of a field that is not there" + d35bad=1 + fi + done + if [ "$( ca mentions "$TMP/d35.c" "$COLTESTED" )" = 1 ] && ! namesTested "$( ca value "$TMP/d35.c" cols:fields )"; then + no "(D35) $args: the compact legend spells '$COLTESTED' but no names tested — a reading of a column that is not there" + d35bad=1 + fi +done +[ "$d35bad" -eq 0 ] && [ "$d35n" -eq 5 ] && ok "(D35) mirror: neither new tested reading, nor (D31)'s, prints on $d35n answers that lack its field ( rows with no column computed, rows over a tree with no test, a columnar fields= without tested, rows alone, rows alone)" + echo echo "=== (S) STRUCTURAL: every conditional attribute the graphlegend.h family, the PageRank disclosure, the map header and the map's rows emit has a compact reading ===" # The (D) rows prove today's members; this row keeps the NEXT one from landing undefined. The population is READ FROM From 3a5e390ef27c21b68cade8ccbddeba5ec39ce33c Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sat, 12 Sep 2026 15:09:44 -0400 Subject: [PATCH 3/7] fix(legend): --pack-task --metrics compacted under the pack-signatures schema, its vocabulary undefined main.cpp's compactLegendHint derived one key from the flags in one order: map-diff, metrics, around, query, then the bundle verbs. A key names a spec only under its own root, and a key from the other family silently took that root's FIRST spec, so --pack-task --metrics, --from-trace --metrics and --pack-task beside --around all compacted as pack-signatures. No single flag order is right, because verb precedence interleaves the families: --pack-task and --from-trace answer over --around, while --around answers over --expand and --pack-signatures. The root now picks the family (compactMapLegendHint for , compactBundleLegendHint otherwise), and the flags pick the key within it in the old order. Under the right schema the answer still printed attributes no compact reading named. The pack-task purpose line now spells the bundle's own vocabulary (task=, the //// rows, of_top=, rel=, shared=, run=), checked against packtask.h. Present-only terms read the lens facts serialize.h sigRowHead writes on a ranked bundle's rows (r=, cx=/ccx=, in=, and amp= under --metrics), and route= reads on . --from-trace's rows carry the same four facts and now read them too. Gate: compactlegendcheck (D36) reads the schema of four neighbouring combinations (the around-over-expand row is the one a flag reorder breaks), and requires every attribute name the compact --pack-task --metrics answer carries, on the CLI over two corpora and from MCP explore at its compact default, to be spelled NAME= in its legend. (D37) is the mirror. RED on 036c827d: eleven (D36) checks FAILed and nothing else did. Green: compactlegendcheck ALL PASS on the plain build and on ASan. (D37) was shown able to fail by splicing each reading into an answer that lacks its field. Pins, by the lane's rule (measured, rounded up to 10 B, plus 10 B): pack-task 340 -> 820 (804 B), from-trace 300 -> 460 (445 B). A compact diff against 036c827d over 191 probes moved only pack-task and from-trace answers. Co-Authored-By: Claude Opus 5 --- src/compactlegend.h | 25 ++++++- src/main.cpp | 21 +++++- test/compactlegendcheck.sh | 131 +++++++++++++++++++++++++++++++++++-- 3 files changed, 166 insertions(+), 11 deletions(-) diff --git a/src/compactlegend.h b/src/compactlegend.h index 4b0367ad..28d6a04f 100644 --- a/src/compactlegend.h +++ b/src/compactlegend.h @@ -40,7 +40,8 @@ namespace rw // of the verb and of the root vocabulary EVERY answer of that root carries. Its bytes count against the verb's // per-verb pin in test/compactlegendcheck.sh, and that pin is measured from the definitions, never the reverse. // Roots shared by several verbs (`r` = the ranked map family, `ctx` = the bundle family) are disambiguated by a -// HINT the caller derives from its own flags (compactLegendHintFromRoot). +// HINT the caller derives from the root's family, then from its own flags (main.cpp compactLegendHint; mcpverbs.h +// mcpCompactLegendHint keys it by verb name). struct CompactLegendSpec { std::string_view rootTag; @@ -63,7 +64,13 @@ inline constexpr CompactLegendSpec kCompactLegendSpecs[] = { "ctx", "notes", "field notes by target: holds ; counts = the rows" }, { "ctx", "lego", "ONE interface/base type: , its method contract, every implementor" }, { "ctx", "expand", "full bodies: of ; resolved callees" }, - { "ctx", "pack-task", "one-call task bundle under budget_tokens=: ranking > > callers > notes > tests_to_run" }, + // pack-task (2026-09-12, the lane's end): the bundle's own vocabulary reads here, checked against packtask.h. task= is the task + // text (a bare --pack-task refuses); is the ranked name-only tier inside (renderNameOnlyRows: t= n= p=), of_top= + // there the ranked rows it was cut from (topRanked); are a body's callee signatures; rows are the bodies' + // 1-hop neighbours in either direction, rel= which one, of_top= there the bodies that qualified (bodiesTotal), shared= how many + // of them a row neighbours (emitted above 1); run= rides a row only when a runner is derivable (testmap.h runHint). The + // lens facts and route= ride only some answers and are present-only terms below. compactlegendcheck (D36). + { "ctx", "pack-task", "one-call task bundle for task= under budget_tokens=: ranking, ranked but over 1 hop out (of_top= ranked rows) > with callees > 1-hop from the bodies (of_top= bodies; shared= bodies reached, absent at 1) > notes > (run= when derivable)" }, { "ctx", "from-trace", "trace frames mapped to indexed symbols, innermost first; the innermost in-corpus body included" }, { "ctx", "exemplar", "the best-in-class instance of kind= for the task, chosen by role: , to imitate" }, { "ctx-partitions", "pack-task", "N minimally overlapping agent bundles carved along call-graph communities plus one shared core; each wraps a " }, @@ -400,6 +407,20 @@ inline constexpr CompactCompletenessTerm kCompactCompletenessTerms[] = // keeps its native legend). ELEMENT-qualified on , like the row above: flipimpact.h's and the dead-code // rows carry no tested=. compactlegendcheck (D33)/(D35). { "tested", ": a non-test row an indexed test transitively reaches (absent otherwise, never 0)", true, "d" }, + // THE LENS FACTS ON ROWS (2026-09-12, the lane's end). serialize.h sigRowHead writes r= on a lens row (rank > 0), cx=/ccx= + // under facts.metrics and in= when a fan-in vector was supplied, and packSignatures' lens appends amp= (main.cpp computes it + // under --metrics; printed above 0). --pack-task passes metrics and supplies its own fan-in, so every one of its rows + // carries the first four, and --from-trace's do too; their full legends define them in a "Row keys" clause, which is prose and + // goes. amp= is graph.h's callerCount (direct callers, the in-edge CSR) plus the co-change degree of the symbol's file (the + // other files sharing a commit with it in git's 18-month window; 0 without git). ELEMENT-qualified on : the map's rows + // carry the same names under the metrics schema's purpose line, and is another root's. route= (serialize.h + // ctxRootOpen) rides a bundle whose task was routed to a ranker: --pack-task always, MCP explore unless no_route; it is + // ELEMENT-qualified on . compactlegendcheck (D36)/(D37). + { "r", ": rank N in this ranking, rows in r= order", true, "d" }, + { "ccx", ": cyclomatic/cognitive complexity", true, "d" }, + { "in", ": N callers in the index (absent: not measured)", true, "d" }, + { "amp", ": direct callers + files sharing a commit with its file (absent at 0)", true, "d" }, + { "route", "route=: the ranker the task was routed to, and why", true, "ctx" }, { "parse_degraded", "parse_degraded=1: ERROR nodes in that parse", true }, { "tier_partial", "tier_partial=1: tier elected under a partial classification" }, { "dangling", "dangling=1: matches nothing indexed", true }, diff --git a/src/main.cpp b/src/main.cpp index 83addb0f..3e3e514e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2728,13 +2728,23 @@ static std::string_view scipIndexUnreadableReason( const std::string& scipPath ) static int dispatchMain( const rw::Config& cfg, char** argv ); -// the key for a SHARED root (`r` = the map family, `ctx` = the bundle family), from the flags that shaped it -static std::string_view compactLegendHint( const rw::Config& c ) noexcept +// The key for a SHARED root (`r` = the map family, `ctx` = the bundle family): the ROOT picks the family, then the flags that +// shaped the answer pick the key, in the order below. One flag order across both families cannot be right, because verb +// precedence interleaves them: --pack-task and --from-trace answer over --around, while --around answers over --expand and +// --pack-signatures. A key from the other family matches no spec under the root, and findCompactSpec then takes that root's +// FIRST spec, so --pack-task --metrics compacted as pack-signatures, its bundle vocabulary read under a schema that never named +// it (test/compactlegendcheck.sh (D36)). +static std::string_view compactMapLegendHint( const rw::Config& c ) noexcept { if( c.mapDiff ) { return "map-diff"; } if( c.metrics ) { return "metrics"; } if( !c.around.empty() ) { return "around"; } if( !c.query.empty() ) { return "query"; } + return {}; +} + +static std::string_view compactBundleLegendHint( const rw::Config& c ) noexcept +{ if( c.skippedList ) { return "skipped"; } if( c.notesList ) { return "notes"; } if( !c.legoType.empty() ) { return "lego"; } @@ -2747,6 +2757,11 @@ static std::string_view compactLegendHint( const rw::Config& c ) noexcept return {}; } +static std::string_view compactLegendHint( const rw::Config& c, std::string_view rootTag ) noexcept +{ + return rootTag == "r" ? compactMapLegendHint( c ) : compactBundleLegendHint( c ); +} + // --for's compact legend is its own (verbs_for.h): it splices est_tokens=/dropped_positive=/weak= and the // adaptive/relevance-floor counts INTO its comments (estchargecheck A10 pins the form), so the layer would strip // data there. It is the one verb the layer skips. --grep/--slice compact natively too, but their compact @@ -2796,7 +2811,7 @@ static int runWithCompactLegend( const rw::Config& cfg, char** argv ) { return rc; // a refusal (or an empty answer) — nothing to rewrite, the exit code says what happened } - switch( rw::applyCompactDialect( doc, compactLegendHint( cfg ) ) ) + switch( rw::applyCompactDialect( doc, compactLegendHint( cfg, rw::findCompactRoot( doc ).tag ) ) ) { case rw::CompactOutcome::Rewritten: case rw::CompactOutcome::AlreadyCompact: diff --git a/test/compactlegendcheck.sh b/test/compactlegendcheck.sh index 041cdd85..aab8f88e 100755 --- a/test/compactlegendcheck.sh +++ b/test/compactlegendcheck.sh @@ -36,8 +36,9 @@ # shown_bridges=/connected_singletons=/symbols=, --community's shown_bridges=, the rows, --safe-delete's t=/defs=/ # ambiguous_callers=/dead_code_candidate=, --impact's , every map-header field, the columnar format=/ and # lens=; from that sweep's design review: the rows of --callers/--impact; in its follow-up: the rows of -# --pack-task --metrics and the columnar tested column) is DEFINED by the compact legend of a document that carries it, and by -# none that does not. STRUCTURAL arm (S): every +# --pack-task --metrics and the columnar tested column; at the lane's end: the schema of a bundle answered beside a map-family +# flag, every attribute of --pack-task --metrics, and the lens facts) is DEFINED by the compact legend of +# a document that carries it, and by none that does not. STRUCTURAL arm (S): every # conditional attribute the graphlegend.h helper family emits, the PageRank disclosure, every conditional hdr: field of # the map header, and every absence-marked row field of the map legend, read from source, has a compact reading — so the # next one cannot land undefined. @@ -327,6 +328,8 @@ probeFor() # pass, once every attribute the --impact, --safe-delete, --communities, --community and map-header answers print had a reading; # re-measured the same day after that sweep's design review corrected three readings, added the present-only reading # (no probe on this fixture prints one) and shortened fourteen readings without losing accuracy. Ten pins moved down. +# Re-measured at the lane's end, (D36): pack-task 327 -> 804 B (its purpose line spells the bundle's own vocabulary, and the +# and route= readings ride its rows) and from-trace 290 -> 445 B (the same four readings); no other schema moved. # schema pin measured PIN_TABLE=' ripwire.map/v1 810 799 @@ -385,13 +388,13 @@ ripwire.uses/v1 290 271 ripwire.batch/v1 160 142 ripwire.safe-delete/v1 720 708 ripwire.at/v1 180 161 -ripwire.from-trace/v1 300 290 +ripwire.from-trace/v1 460 445 ripwire.plan-lint/v1 170 156 ripwire.merge-scout/v1 220 208 ripwire.whereis/v1 240 223 ripwire.community/v1 730 719 ripwire.layout/v1 160 149 -ripwire.pack-task/v1 340 327 +ripwire.pack-task/v1 820 804 ripwire.pack-top-n/v1 660 649 ripwire.expand/v1 280 265 ' @@ -1153,8 +1156,8 @@ done # (D33) signature rows. serialize.h's two signature-row writers print it from computeQMetrics' tested[] column, # which graph.h isTestedByReach fills: the rows' predicate, an indexed test transitively reaches that symbol and it # is not itself a test. Never a literal 0. main.cpp computes that column only under --metrics, --for or --exemplar, so a -# plain --pack-task prints no tested= at all; --pack-task --metrics does, and main.cpp's compactLegendHint checks -# metrics before pack-task, so that answer compacts under the pack-signatures schema. Its FULL legend never names +# plain --pack-task prints no tested= at all; --pack-task --metrics does (it compacted under the pack-signatures +# schema until (D36) had the hint read the root's family first). Its FULL legend never names # tested= either (a `!` spec). condArm's left-anchored tested= would also be satisfied by (D31)'s reading # on an answer printing both forms, so the row asserts the reading's own opener too. # (D34) the columnar form's tested column. --callers/--callees/--impact --format=columnar always pass the test-reach lens @@ -1238,6 +1241,122 @@ for v in "$TESTED@--pack-task=helper" "$REPO@--pack-task=geometry --metrics" "$T done [ "$d35bad" -eq 0 ] && [ "$d35n" -eq 5 ] && ok "(D35) mirror: neither new tested reading, nor (D31)'s, prints on $d35n answers that lack its field ( rows with no column computed, rows over a tree with no test, a columnar fields= without tested, rows alone, rows alone)" +# ── THE HINT READS THE ROOT, AND THE BUNDLE'S OWN VOCABULARY (2026-09-12, found at the end of the lane) ────────────────────────────── +# (D36) main.cpp's compactLegendHint derived ONE key from the flags in ONE order: map-diff, metrics, around, query, then the bundle +# verbs. A key names a spec only under its own root ( for those four, for the rest), and a key from the other family took +# that root's FIRST spec, pack-signatures. --pack-task --metrics is a pack-task bundle whose rows --metrics shapes, and it compacted +# as pack-signatures; so did --from-trace --metrics and --pack-task beside --around. No single flag order is right, because verb +# precedence interleaves the families (each pair run, its stderr read): --pack-task and --from-trace answer over --around, while +# --around answers over --expand and --pack-signatures, whose bundles it never renders. So the ROOT picks the family and the flags +# pick the key within it, in the old order; the around-over-expand row is the neighbour a flag reorder would break. +# Under the right schema the bundle still carried attributes no compact reading named: task=, route=, its //// +# row vocabulary, of_top=, rel=, shared=, run=, and the lens facts serialize.h sigRowHead writes on every row of a ranked bundle, +# r= cx= ccx= in= (amp= too under --metrics). The full legend's "Row keys" clause defines most of them and is prose, so the layer +# stripped it. schemaRow reads the schema. allAttrsRow reads EVERY attribute name the compact answer carries, and each must be +# spelled NAME= in that legend; the and route= readings must also be their own openers, as in (D33). --from-trace carries the +# same four facts, and its full legend defines them. +# RED on 036c827d (plain): eleven (D36) checks FAILed and nothing else did (the around-over-expand row and (D37) are green by +# construction), for example +# FAIL (D36) --pack-task=helper --metrics (a pack-task bundle; --metrics shapes its rows) compacts under 'ripwire.pack-signatures/v1', not ripwire.pack-task/v1 +# FAIL (D36) --pack-task=helper --metrics over a tree with a test: carried, and spelled NAME= nowhere in the compact legend: amp budget_tokens ccx cx in of_top r rel route run t task +# FAIL (D36) MCP explore over a tree with a test, at its DEFAULT posture (compact): carried, and spelled NAME= nowhere in the compact legend: ccx cx in l n of_top r rel route run t task +schemaRow() +{ + local id="$1" label="$2" dir="$3" args="$4" want="$5" got + cdRun "$TMP/d36.s" "$dir" $args --legend=compact + got="$( leg schema "$TMP/d36.s" )" + if [ "$got" = "$want" ]; then + ok "($id) $label compacts under $want" + else + no "($id) $label compacts under '$got', not $want" + fi + return 0 +} +schemaRow D36 "--pack-task=helper --metrics (a pack-task bundle; --metrics shapes its rows)" "$TESTED" "--pack-task=helper --metrics" "ripwire.pack-task/v1" +schemaRow D36 "--from-trace --metrics (a from-trace bundle)" "$REPO" "--from-trace=$TMP/trace.txt --metrics" "ripwire.from-trace/v1" +schemaRow D36 "--pack-task=geometry --around=distance (--pack-task answers)" "$REPO" "--pack-task=geometry --around=distance" "ripwire.pack-task/v1" +schemaRow D36 "--around=distance --expand=distance (--around answers; the neighbour a flag reorder breaks)" "$REPO" "--around=distance --expand=distance" "ripwire.around/v1" +cat > "$TMP/allattrs.py" <<'PY' +import re, sys +buf = open( sys.argv[1], encoding = "utf-8", errors = "replace" ).read() +legend, tags = [], [] +i = 0; n = len( buf ) +while i < n: + if buf.startswith( "", i ); i = n if j < 0 else j + 3 + elif buf.startswith( "", i ); j = n if j < 0 else j + 3; legend.append( buf[ i:j ] ); i = j + elif buf[ i ] == "<": + j = buf.find( ">", i ); j = n if j < 0 else j + 1; tags.append( buf[ i:j ] ); i = j + else: + j = buf.find( "<", i ); i = n if j < 0 else j +leg = " ".join( legend ) +names = sorted( { a for t in tags for a in re.findall( r'\s([\w:.-]+)="', t ) } - { "schema" } ) +print( len( names ), " ".join( a for a in names if not re.search( r"(?:" ":" ":" ":" "route=:"; do + [ "$( ca mentions "$TMP/d36.a" "$opener" )" = 1 ] || d36miss="$d36miss '$opener'" +done +if [ -z "$d36miss" ]; then + ok "(D36) --pack-task=helper --metrics: the lens facts and route= read under their own openers" +else + no "(D36) --pack-task=helper --metrics: the compact legend does not spell the reading(s)$d36miss: $( leg legend "$TMP/d36.a" | head -c 260 )" +fi +cdRun "$TMP/d36.b" "$REPO" --pack-task=geometry --metrics --legend=compact +allAttrsRow D36 "--pack-task=geometry --metrics over the fixture" "$TMP/d36.b" +mcp_text explore "{\"path\":\"$TESTED\",\"task\":\"helper\"}" >"$TMP/d36.c" +allAttrsRow D36 "MCP explore over a tree with a test, at its DEFAULT posture (compact)" "$TMP/d36.c" +condPair D36 "--from-trace (its rows carry the lens facts)" "$REPO" "--from-trace=$TMP/trace.txt" d:r d:cx d:ccx d:in + +# (D37) THE MIRROR, on answers chosen for what they LACK, each lack asserted before it is relied on: --pack-task=helper without +# --metrics prints rows carrying r=/cx=/ccx=/in= and no amp=; --pack-signatures prints rows with none of the four (no lens +# rank, no metrics); MCP explore with no_route prints and no route=. The needles are the readings' own openers, as in +# (D35). Green on the red build by construction, like (D7). +cdRun "$TMP/d37.pt" "$TESTED" --pack-task=helper --legend=compact +cdRun "$TMP/d37.ps" "$REPO" --pack-signatures --legend=compact +mcp_text explore "{\"path\":\"$TESTED\",\"task\":\"helper\",\"no_route\":true}" >"$TMP/d37.nr" +{ [ "$( ca carries "$TMP/d37.pt" d:ccx )" = 1 ] && [ "$( ca carries "$TMP/d37.pt" d:amp )" != 1 ]; } \ + || no "(D37) control: --pack-task=helper no longer prints rows without amp=, so it proves nothing about the amp= reading being present-only" +{ [ "$( ca carries "$TMP/d37.ps" d:l )" = 1 ] && [ "$( ca carries "$TMP/d37.ps" d:r )" != 1 ] && [ "$( ca carries "$TMP/d37.ps" d:ccx )" != 1 ] \ + && [ "$( ca carries "$TMP/d37.ps" d:in )" != 1 ]; } \ + || no "(D37) control: --pack-signatures no longer prints rows without r=/ccx=/in=, so it proves nothing about those readings being present-only" +{ [ "$( ca carries "$TMP/d37.nr" ctx:task )" = 1 ] && [ "$( ca carries "$TMP/d37.nr" ctx:route )" != 1 ]; } \ + || no "(D37) control: MCP explore with no_route no longer prints without route=, so it proves nothing about the route= reading being present-only" +d37bad=0; d37n=0 +for v in "--pack-task=helper@d37.pt" "--pack-signatures@d37.ps" "MCP explore no_route@d37.nr"; do + label="${v%%@*}"; f="$TMP/${v#*@}" + if [ ! -s "$f" ] || grep -q '^__ERROR__' "$f"; then + no "(D37) $label answered nothing — its mirror row would be vacuous"; d37bad=1; continue + fi + d37n=$(( d37n + 1 )) + for pair in ":@d:r" ":@d:ccx" ":@d:in" ":@d:amp" "route=:@ctx:route"; do + needle="${pair%%@*}"; spec="${pair#*@}" + if [ "$( ca mentions "$f" "$needle" )" = 1 ] && [ "$( ca carries "$f" "$spec" )" != 1 ]; then + no "(D37) $label: the compact legend spells '$needle' but the document carries no <${spec%%:*} ${spec#*:}=> — a reading of a field that is not there" + d37bad=1 + fi + done +done +[ "$d37bad" -eq 0 ] && [ "$d37n" -eq 3 ] && ok "(D37) mirror: no lens-fact or route= reading prints on $d37n answers that lack its field ( rows without amp=, rows without the lens facts, a bundle not routed)" + echo echo "=== (S) STRUCTURAL: every conditional attribute the graphlegend.h family, the PageRank disclosure, the map header and the map's rows emit has a compact reading ===" # The (D) rows prove today's members; this row keeps the NEXT one from landing undefined. The population is READ FROM From 8eb4e5055c8ae39e74c45c7d994a79e42362020a Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sat, 12 Sep 2026 15:09:44 -0400 Subject: [PATCH 4/7] fix(legend): the columnar tested column read "never 0" beside a column of zeros --callers/--callees/--impact --format=columnar carry the tested lens as a dense column (columnar.h emitColumnarTestedColumn): 1 where isTestedByReach holds, 0 on every other row, a test row included. Their full legend printed kTestedRowLegend anyway, so test/fixture's --callers=distance --format=columnar said tested is "never 0, omitted when it does not" beside 0,0. graphlegend.h gains kTestedColumnLegend ("1 = a non-test row an indexed test transitively reaches; 0 = none found, or a test row", the words of the compact column reading) and testedLensLegend( bool ), the one form-to-sentence choice that callHierarchyLegendOpen and runImpact both call. The XML rows keep the row sentence. The MCP impact twin has no columnar form and is unchanged. Gate: impactpartitioncheck arm (5), beside arm (4), which already checks that the tested lens's legend rides where the partition is read. Each columnar form's legend must read the 0s its column prints and not carry the row sentence; each XML form must keep the row sentence, print no , and carry no column reading. RED on 036c827d: the three columnar rows FAILed and nothing else did. Green: ALL PASS. Bytes: non-compact answers are byte-identical to 036c827d's over 191 probes, except the six columnar callers/callees/impact answers, which differ in this sentence alone. Compact answers are unaffected, because the layer strips the sentence. graphlegendbudgetcheck measures the XML forms and did not move. callHierarchyLegendOpen gains a third parameter; --edit-check finds one caller, 0 incompatible. Co-Authored-By: Claude Opus 5 --- src/graphlegend.h | 23 ++++++++++++++++--- src/verbs_navigate.h | 7 +++--- test/impactpartitioncheck.sh | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/graphlegend.h b/src/graphlegend.h index e31d8ace..4fa21bb2 100644 --- a/src/graphlegend.h +++ b/src/graphlegend.h @@ -389,6 +389,14 @@ inline constexpr const char* kTestedLensBlindSpotLegend = inline constexpr const char* kTestedRowLegend = "tested=\"1\" on a row means an indexed test transitively reaches it (never 0, omitted when it does not). "; +// The same lens in the COLUMNAR form (2026-09-12). A parallel array cannot omit a false entry, so --callers/--callees/--impact +// --format=columnar carry it as a dense column (columnar.h emitColumnarTestedColumn): 1 where graph.h isTestedByReach +// holds, 0 on every other row, a test symbol's row included. Those forms printed kTestedRowLegend's "never 0" beside a column of +// zeros (test/fixture's --callers=distance read 0,0), so they read the column instead, in the words of +// compactlegend.h's compact column reading. Gate: test/impactpartitioncheck.sh arm (5). +inline constexpr const char* kTestedColumnLegend = + "tested= is a dense column in this form: fields= names tested, and holds one value per row: 1 = a non-test row an indexed test transitively reaches; 0 = none found, or a test row. "; + // --callers / --callees shipped NO legend at all (0 bytes on both, which is why every one of their root // attributes sits in test/legendcoverage_baseline.txt). ONE legend serves both forms: the two verbs are one // code path with the edge direction flipped, and giving them two descriptions is precisely the per-verb @@ -410,17 +418,26 @@ inline constexpr const char* kCallHierarchyLegendCalleesOnly = inline constexpr const char* kCallersNextSelectorLegend = "next= is the one pasteable follow-up (the uses verb on this selector: the call sites). "; inline constexpr const char* kCallersNextBareNameLegend = "next= is the one pasteable follow-up (the uses verb on the called name: all same-named definitions' call sites, including sites bound to other definitions, because a declined call names no single definition). "; +// The tested lens's reading for the form a document takes: an XML row omits a false tested=, the columnar array prints 0. +// ONE choice for --callers/--callees (callHierarchyLegendOpen below) and --impact (verbs_navigate.h runImpact), so the verbs +// cannot disagree about which form reads which sentence. +inline constexpr const char* testedLensLegend( bool isColumnar ) noexcept +{ + return isColumnar ? kTestedColumnLegend : kTestedRowLegend; +} + // The composed opener, one call for the caller — keeps the wantCallers/callees branch out of // runCallHierarchy (already this file's largest dispatcher) rather than adding a ternary at the call site. -inline std::string callHierarchyLegendOpen( bool wantCallers, bool nextUsesBareName = false ) +inline std::string callHierarchyLegendOpen( bool wantCallers, bool nextUsesBareName, bool isColumnar ) { const char* const callersNextClause = nextUsesBareName ? kCallersNextBareNameLegend : kCallersNextSelectorLegend; + const char* const testedClause = testedLensLegend( isColumnar ); // F-02: the blind-spot clause rides with hop_tested=/hop_untested=, which both forms always carry. // P3 (L7): next= defined where the reader meets it — callers hand over the SITES (the uses verb on the same // selector, its @FILE:LINE spelling mirrored), callees the BODY whose callees these are (expand). // nextUsesBareName is the emitter's OWN decision, never re-derived here; no double hyphen in comment text. - return wantCallers ? std::string( kCallHierarchyLegendOpen ) + kTestedRowLegend + kTestedLensBlindSpotLegend + callersNextClause - : std::string( kCallHierarchyLegendOpen ) + kTestedRowLegend + kTestedLensBlindSpotLegend + kCallHierarchyLegendCalleesOnly + "next= is the one pasteable follow-up (expand on this selector: the body). "; + return wantCallers ? std::string( kCallHierarchyLegendOpen ) + testedClause + kTestedLensBlindSpotLegend + callersNextClause + : std::string( kCallHierarchyLegendOpen ) + testedClause + kTestedLensBlindSpotLegend + kCallHierarchyLegendCalleesOnly + "next= is the one pasteable follow-up (expand on this selector: the body). "; } // ── LB-G (r10 GitNexus round) — the DISPLAY-CAP clause the neighbour verbs share ───────────────────────── diff --git a/src/verbs_navigate.h b/src/verbs_navigate.h index d80ab8c8..a85196ad 100644 --- a/src/verbs_navigate.h +++ b/src/verbs_navigate.h @@ -138,7 +138,8 @@ std::optional runCallHierarchy( const MainDispatch& d ) // §H4 §3.4: the FIRST legend these two verbs have ever shipped (0 bytes before — which is why every // one of their root attributes sits in test/legendcoverage_baseline.txt), and the floor marker that // is the round's honest half. ONE opener for both forms, printed BEFORE the format branches so the - // columnar and default shapes carry the identical disclosure. JSON has no comment-node analogue, so + // columnar and default shapes carry the same disclosure, all but the tested lens's reading, which names + // its form's shape (kTestedColumnLegend: the columnar array prints 0). JSON has no comment-node analogue, so // there the marker travels as the counts_floor key on the root object instead. // V1 fix (verifier finding 3): bodyless_defs= is callees-only (main.cpp gates the attribute itself // behind !wantCallers a few lines up), so its defining sentence rides along only on the callees @@ -149,7 +150,7 @@ std::optional runCallHierarchy( const MainDispatch& d ) { // M12: under multi-root this verb carries no root= at all (correctly — no single root exists) // and, before this, disclosed nothing about the `