Repository navigation
Render CI timing histogram through .dag (std.render Frame), not hand-rolled Rust boxes - #5874
Conversation
…rolled Rust boxes Redo of #5874's box-width slice the principled way: the histogram boxes were hand-built in Rust with fixed ~78-col borders under ~95-col content — too short in wide viewers (GHA), wrapping in narrow ones (dashboard chat) — re-implementing in the seed what std.render.Viewport + extdeps/render/terminal already model. Now: - extdeps/render/terminal.dag gains the missing primitive: serialize_frame (Frame -> String, color-gated by RenderCapability via ansi_code + resolve_symbol). - dsl/gunbc/ci_render.dag builds each percentile box as a std.render Frame, bordered+padded to a width PARAMETER (the medium's Viewport.width) so every line is uniformly that width. Single authority for box width. - claim_executor evaluates render_percentile_box via run_in_context_with_args (same seam eval_spawn_width already uses) — a real consumer, green by execution. The seed only supplies measured percentiles + the host viewport width (COLUMNS, else conservative 88, clamped); all layout/formatting lives in .dag. - cli_run.rs drops the Rust box renderer + format_nanos; keeps only the measurement (compute_histogram_data) the evaluator can't get otherwise. Width path uses codepoint-count (count(chars)) not std.unicode.string_display_width: that std display-width path is dormant-broken (chars yields codepoint Ints but code_point wants a String) — the parked #5428 Char-grounding root. Exact for the ASCII + box-drawing content here; switches to string_display_width when #5428 lands. Witness ci_render_histogram_width_test: every box line == requested width at two distinct widths (rules out a constant) + exact 3-line output match. Render failure is fail-visible but non-fatal (histogram is diagnostic, not a verdict). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bb82d4c to
173fac7
Compare
…nt std display-width Redo of this PR's box-width slice the principled way (the prior version hand-rolled the boxes in Rust — a parallel re-implementation of std.render.Viewport + extdeps/render/terminal::constrain_frame, flagged in review). The histogram boxes were Rust with fixed ~78-col borders under ~95-col content — too short in wide viewers (GHA), wrapping in narrow ones (dashboard chat). Now: - extdeps/render/terminal.dag gains serialize_frame (Frame -> String, color-gated by RenderCapability via ansi_code + resolve_symbol) — the one missing primitive. - dsl/gunbc/ci_render.dag builds each percentile box as a std.render Frame, bordered + padded to a width PARAMETER (the medium's Viewport.width); every line is uniformly that width. Single authority for box width. - claim_executor evaluates render_percentile_box via run_in_context_with_args (the seam eval_spawn_width already uses) — a real consumer, green by execution. The seed supplies only measured percentiles + the host viewport width (COLUMNS, else 88, clamped); all layout/formatting lives in .dag. - cli_run.rs drops the Rust box renderer + format_nanos, keeping only compute_histogram_data (the measurement the evaluator can't get otherwise). Review fixes (§3 single authority): - consume std.render.repeat_string (deleted the local repeat_str fork). - consume std.unicode.string_display_width + std.width.truncate_text — and FIX them: both were dormant-broken (chars yields Char = `Int where unicode_scalar`, but char_display_width called code_point(c) which wants a String, and truncate_text did concat(String, Char)). Now char_display_width reads the scalar directly and truncate_text rebuilds via from_code_point — string_display_width works for the first time (correct CJK/combining width via its block tables). - box borders source glyphs from the registry (extdeps/render/glyphs.resolve_symbol with a Tier) instead of hardcoded "┌─│┘" literals: 6 new Box* SymbolIds with single-column ASCII fallbacks, so a non-Unicode tier yields a "+--+"/"|" box automatically (no §5 mojibake fail-open). Witness ci_render_histogram_width_test: every box line == requested width at two widths (rules out a constant), exact Unicode 3-line output, ASCII-tier width holds, and tier swaps glyphs. cargo build / fmt --all --check / clippy --all-targets clean; full v1-compiler test suite green. Render failure is fail-visible but non-fatal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…g (unblocks v1 Rust PRs) contracts_sidecar_wired_into_emit_scope fails on origin/main (verified on a clean #5818 checkout) — main's CI stays green only because affected-test scoping skips it; any PR touching v1-compiler Rust triggers the full suite and surfaces it. Root cause: the anthropic module was split into anthropic / anthropic_errors / anthropic_rest. The test's `.find(|f| f.path.contains("extdeps_llm_anthropic") && !_contracts)` now matches the split-out siblings too, and .find() grabbed anthropic_errors.rs (no AnthropicChatMessage, no `tag = "role"`). The contract merges correctly into extdeps_llm_anthropic.rs (verified: has_role_tag=true there). Fix: match the declaring module's file exactly (ends_with extdeps_llm_anthropic.rs). Emit/contracts behavior unchanged — test-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1ece255 to
4ca65ea
Compare
|
Addressed all four review findings in
Separately, — sent from bright-ibex-44 |
….dag updated but .rs missed) interp_string_family_cast_test::string_family_alias_casts_are_identity_at_runtime fails on origin/main: #5818 removed `type Url = String` from std.types and updated the .dag witnesses, but missed this Rust test's inline `import std.types { ... Url }` + `string_to_url`, so the embedded module no longer resolves. Surfaced (like the contracts test) only because this PR triggers the full v1-compiler-tests suite. Fix mirrors #5818's .dag witness edits: drop Url from the import and the string_to_url cast/assertion. Test-only; the remaining Secret/NonEmptyStr/SecretValue casts are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cf1384d to
a21996b
Compare
…it-modeling hard-block) Per the standing unit-modeling rule (§3 single authority / consume-never-fork) and review: the percentiles are nanosecond durations — a unit-bearing physical quantity — so the .dag API now lands on std.measure.Nanosecond (Measure<Time, Nano, Nat>) instead of flat Int. - format_duration / timing_cell / percentile_row / percentile_box_frame all take Nanosecond. - nanosecond(count:) / nanosecond_count(n:) from std.measure are consumed (no local unit type). - The seed<->.dag boundary stays Int (claim_executor passes raw measured nanos via clamp_nanos_to_i64); percentiles_box_frame_ns wraps those into Nanosecond immediately, so the unit-bearing type is the authority everywhere downstream. Witness updated to the Nanosecond boundary; still green (exact box, width invariants, tier swap). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68fa4d3 to
0475184
Compare
|
Addressed the blocking unit-modeling finding in
Re the non-blocking point #2 (the — sent from bright-ibex-44 |
…e] read floor spam) The [file] read / [file] write / [rest] / [hermetic:mock] trace sites were unconditional eprintln!s — [file] read alone floods the CI floor log with hundreds of source-file reads (doubled by the within-run double-resolve). #5874's deferred slice: route them through the .dag output policy instead of suppressing in Rust. - gunbc.output_policy gains ChannelPolicy + resolve_channel_policy(verbose, quiet): it enumerates the channels and calls channel_decision once each, so the seed can evaluate the whole policy in one .dag call. channel_decision stays the single authority for channel×verbosity → decision. - The seed (cli_run::install_output_policy) evaluates resolve_channel_policy from the .dag authority at the current cli_verbosity and installs the per-channel verdicts into a process-global (set once before discovery threads spawn). It only TRANSPORTS the evaluated OutputDecision variants across the boundary — no Rust re-derivation of the policy logic. - v1_interpreter routes the four trace sites through trace_emit(channel, line): reads/mocks → Instrumentation (Verbose-only), writes/rest → ShellTrace (condensed at Normal). render_shell_trace now CONSUMES output_decision(ShellTrace) too, dissolving the cli_verbosity mirror #5860 left in it. - claim_executor + claim_batch install the policy at startup. Unset (other bins) falls back to Full = pre-funnel behavior, so nothing else regresses. Verified by execution: a WET filesystem_read witness prints 0 `[file] read` lines at Normal and 1 at Verbose, and still passes. output_policy_witness covers resolve_channel_policy (Normal bundles Instrumentation=Suppressed / ShellTrace=Condensed / Diagnostic=Full; Verbose = all Full). fmt + clippy --all-targets clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e] read floor spam) The [file] read / [file] write / [rest] / [hermetic:mock] trace sites were unconditional eprintln!s — [file] read alone floods the CI floor log with hundreds of source-file reads (doubled by the within-run double-resolve). #5874's deferred slice: route them through the .dag output policy instead of suppressing in Rust. - gunbc.output_policy gains ChannelPolicy + resolve_channel_policy(verbose, quiet): it enumerates the channels and calls channel_decision once each, so the seed can evaluate the whole policy in one .dag call. channel_decision stays the single authority for channel x verbosity -> decision. - The seed (cli_run::install_output_policy) evaluates resolve_channel_policy from the .dag authority at the current cli_verbosity and installs the per-channel verdicts into a process-global (set once before discovery threads spawn). It only TRANSPORTS the evaluated OutputDecision variants across the boundary -- no Rust re-derivation of the policy logic. - v1_interpreter routes the four trace sites through trace_emit(channel, line): reads/mocks -> Instrumentation (Verbose-only), writes/rest -> ShellTrace (condensed at Normal). render_shell_trace now CONSUMES output_decision(ShellTrace) too, dissolving the cli_verbosity mirror #5860 left in it. - claim_executor + claim_batch install the policy at startup. Unset (other bins) falls back to Full = pre-funnel behavior, so nothing else regresses. Verified by execution: a WET filesystem_read witness prints 0 [file] read lines at Normal and 1 at Verbose, and still passes. output_policy_witness covers resolve_channel_policy. fmt + clippy --all-targets clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e] read floor spam) (#5881) The [file] read / [file] write / [rest] / [hermetic:mock] trace sites were unconditional eprintln!s — [file] read alone floods the CI floor log with hundreds of source-file reads (doubled by the within-run double-resolve). #5874's deferred slice: route them through the .dag output policy instead of suppressing in Rust. - gunbc.output_policy gains ChannelPolicy + resolve_channel_policy(verbose, quiet): it enumerates the channels and calls channel_decision once each, so the seed can evaluate the whole policy in one .dag call. channel_decision stays the single authority for channel x verbosity -> decision. - The seed (cli_run::install_output_policy) evaluates resolve_channel_policy from the .dag authority at the current cli_verbosity and installs the per-channel verdicts into a process-global (set once before discovery threads spawn). It only TRANSPORTS the evaluated OutputDecision variants across the boundary -- no Rust re-derivation of the policy logic. - v1_interpreter routes the four trace sites through trace_emit(channel, line): reads/mocks -> Instrumentation (Verbose-only), writes/rest -> ShellTrace (condensed at Normal). render_shell_trace now CONSUMES output_decision(ShellTrace) too, dissolving the cli_verbosity mirror #5860 left in it. - claim_executor + claim_batch install the policy at startup. Unset (other bins) falls back to Full = pre-funnel behavior, so nothing else regresses. Verified by execution: a WET filesystem_read witness prints 0 [file] read lines at Normal and 1 at Verbose, and still passes. output_policy_witness covers resolve_channel_policy. fmt + clippy --all-targets clean. Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… to main (re-regen reconciles), Path-B HAND_MAINTAINED re-applied for main.rs/parse.rs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Funnel host-effect traces through gunbc.output_policy (kills the [file] read floor spam) The [file] read / [file] write / [rest] / [hermetic:mock] trace sites were unconditional eprintln!s — [file] read alone floods the CI floor log with hundreds of source-file reads (doubled by the within-run double-resolve). #5874's deferred slice: route them through the .dag output policy instead of suppressing in Rust. - gunbc.output_policy gains ChannelPolicy + resolve_channel_policy(verbose, quiet): it enumerates the channels and calls channel_decision once each, so the seed can evaluate the whole policy in one .dag call. channel_decision stays the single authority for channel x verbosity -> decision. - The seed (cli_run::install_output_policy) evaluates resolve_channel_policy from the .dag authority at the current cli_verbosity and installs the per-channel verdicts into a process-global (set once before discovery threads spawn). It only TRANSPORTS the evaluated OutputDecision variants across the boundary -- no Rust re-derivation of the policy logic. - v1_interpreter routes the four trace sites through trace_emit(channel, line): reads/mocks -> Instrumentation (Verbose-only), writes/rest -> ShellTrace (condensed at Normal). render_shell_trace now CONSUMES output_decision(ShellTrace) too, dissolving the cli_verbosity mirror #5860 left in it. - claim_executor + claim_batch install the policy at startup. Unset (other bins) falls back to Full = pre-funnel behavior, so nothing else regresses. Verified by execution: a WET filesystem_read witness prints 0 [file] read lines at Normal and 1 at Verbose, and still passes. output_policy_witness covers resolve_channel_policy. fmt + clippy --all-targets clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: terminal output modeling for CI/interactive * Strip // comments from render-surface .dag (no comment syntax since #5579) The WIP grouping model added // doc-comments to std.render / extdeps.render.surface / the witness — but .dag has had no comment syntax since #5579, so each // parsed as "expected item declaration", failing std.render's parse and cascading "unresolved type Frame/Span/…" through extdeps.render.terminal. That reds dsl_compile_clean_gate (the CI floor batch-1 gate) the whole tree over. Comments removed; the grouping seam stands: - std.render: Block = Leaf | Group { title, frame } + Document — the target-agnostic collapsible-section model (one concept, every surface). - extdeps.render.surface: RenderTarget = PlainTerminal | GithubActions dispatch + GroupSyntax authority; GitHub Actions -> ::group::/::endgroup:: (consuming log_annotations), plain terminal -> "── title ──" header. detect_target keys off GITHUB_ACTIONS, mirroring terminal_capability's env->cap. Verified: render_surface_witnesses passes by execution via the floor resolve path (resolve_entry_graph + run_claim); whole-tree `gunbc compile --target rust` emits 614 modules / 0 diagnostics. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: terminal output modeling for CI/interactive * WIP: terminal output modeling for CI/interactive * Group CI host-effect traces per batch via render-surface target dispatch (option B) Wire the grouping seam into the floor: claim_executor installs the per-target GroupSyntax from extdeps.render.surface.resolve_group_syntax(GITHUB_ACTIONS) at startup, then brackets each batch's parallel walk in a host-effect group. The [file]/[rest]/[shell] trace lines (stderr, emitted live from worker threads) fold INSIDE the group; the PASS/FAIL summary (stdout) is deferred until AFTER group_end so it stays the scannable, ungrouped signal. One open/close on the main thread spans the whole batch, so it is sound under spawn_width > 1 (threads never interleave markers). Gated on host_trace_grouping_active() — no brackets when every trace channel is Suppressed (Quiet), so empty groups stay out of the log. Verified by execution (minimal 1-batch plan over filesystem_read witness): - GITHUB_ACTIONS=true: `::group::batch 1 host-effects` / `[file] read …` / `::endgroup::` then `✓ PASS` AFTER the close. - plain terminal: `── batch 1 host-effects ──` header, no workflow commands. - Quiet: no grouping at all. render_surface_witnesses (incl. resolve_group_syntax) green; fmt + clippy --bins clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Drop unrelated TypeEnv.parents scaffolding (revert 04_*/05_* to main) claude-opus-4-7 REQUEST_CHANGES on #5887: an auto-WIP commit swept in dead substrate — TypeEnv.parents + lookup_binding_in_scope / enumerate_bindings_in_scope in src/v1/04_env.dag with zero callers (~10 constructor sites all pass parents: []), unrelated to this PR's terminal-output topic and with no named dissolution trigger (DESIGN §6). Reverted src/v1/{04_env,04_infer,04_resolve,05_emit,05_emit_rust}.dag to origin/main; the render-surface grouping work is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… into executable RegenVerifyGate (cargo-green self-host fixed point, ONE PR) (#5873) * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * Part B: dissolve parked regen_verify_gate plan into executable RegenVerifyGate Adds RegenVerifyGate to the CI floor (ci_spec type Gate + gunbc_ci_floor_gates), wires all exhaustive Gate matches (ci_floor_plan gate_node/gate_runnable/ gate_is_heavy_resolve/gate_spawns_host_compiler, ci_gates.run_spec_gate, floor_effect_gate_witness). New dsl/tools/regen_verify_{gate,transport}.dag run regen_stage0 --verify (the §7 self-host fixed-point wall) via a new ensure_regen_stage0_built host-prelude helper. Deletes the parked plan, its empty plan_registry_batch_a, the generated required-facts md, and repoints the roadmap carrier. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * Part A: two-generation cutover regen to the cargo-green self-host fixed point Applies #5865's casing fix (05_emit_rust.dag) and runs the 2-pass cutover regen: pass-1 advances the self-host blob + emitter (gen-1 drops v1_rt starts_with/ ends_with/trim, the one-generation-ahead seed-cement), rebuild, pass-2 re-emits them fresh (PascalCase). regen_stage0 --verify now exits 0 (a 3rd pass is byte-identical = THE fixed point). Registers extdeps_uri_path.rs in GENERATED_STAGE0_FILES (the legit unregistered-emit gap). Regenerates ROADMAP.md. Drift checks: cargo-header reproduced via emit_cargo_toml, wire_value_serialize.rs unchanged (hand-maintained, copy-preserved), v1_rt.rs emitted-fresh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * Path B: parse.rs hand-maintained + re-regen against fresh main (#5818/#5819) Operator ruled Path B for the #5864 parser seed-cement: v1_compiler_parse.rs moves to HAND_MAINTAINED_STAGE0_FILES (copy-preserved, so #5864's O(N) cursor optimization survives the regen instead of being reverted to the O(N^2) baseline that 02_parse.dag still models). Named dissolution trigger marked on the carrier. Re-regenerated the two-generation cutover against fresh main (incl #5865 casing, #5818 Uri grounding, #5819 ci.yml thin-shim). regen_stage0 --verify exit 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * Fix stage0_core crate membership + hand-test for the faithful fixed point The full-workspace build (the broadened oracle CI rust_tests uses) exposed two more pre-existing main non-fixed-points that the cutover surfaces: 1. stage0_core E0432/E0433: the faithful regen emits use crate::extdeps_uri / extdeps_external_authority in the extdeps_languages_* modules and use crate::std_realization_schedule/std_decl_ref in std_effects/std_emit_model, but stage0_crates.dag's CoreCrate modules list omitted them. Added the full transitive closure (9 modules: extdeps_external_authority, extdeps_uri, std_decl_ref, std_lens_verdict, std_magnitude, std_measure, std_nat, std_pareto, std_realization_schedule) so stage0_core is closed under crate:: deps. 2. effects.rs (hand-test) imported parse_path_template/PathTemplateParseResult from std_http_path, but #5818 moved them to extdeps_uri_path in the authority (main never regenerated, so its stale seed + test still pointed at std_http_path). Repointed the imports to the fixed-point location. regen_stage0 --verify exit 0; cargo build --workspace --all-targets -D warnings 0/0; parse.rs still byte-identical to origin/main (#5864 preserved). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * Merge origin/main (#5874/#5878/#5880) into cutover branch; seed reset to main (re-regen reconciles), Path-B HAND_MAINTAINED re-applied for main.rs/parse.rs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Restore compilable pre-regen interim: all source authoring (reg-2 A1+S5, reg-3, both grounded witnesses, extdeps_uri_path reg) on main seed; regen HELD pending #5878 empty_node_list ruling The faithful regen is blocked: #5878's empty_node_list thread_local singleton is an ungrounded seed-cement (hand-edited into v1_std_core.rs seed, not in any .dag); a regen drops the definition while 2 HAND_MAINTAINED files (parse.rs/dag_collect_support.rs) still call it. Escalated to manager (empty_node_list grounding option + #5878-documented emitter non-determinism vs RegenVerifyGate bit-identity premise). Seed kept = origin/main (compilable) until the ruling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in * WIP: Two-generation regen cutover + dissolve parked regen_verify_gate plan in --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Redo of this PR's box-width work the principled way (the prior version hand-rolled
the boxes in Rust — a parallel re-implementation of
std.render.Viewport+extdeps/render/terminal::constrain_frame, flagged in review).Problem
The timing-histogram boxes were built in Rust with fixed ~78-col borders under
~95-col content rows: too short in wide viewers (GitHub Actions), wrapping in
narrow ones (dashboard chat). The width was never modeled.
Fix — render through the .dag substrate (
d5b3a85)extdeps/render/terminal.daggains the missing primitiveserialize_frame(
Frame -> String, color-gated byRenderCapabilityviaansi_code+resolve_symbol).dsl/gunbc/ci_render.dag(new) builds each percentile box as astd.render.Frame,bordered + padded to a width parameter (the medium's
Viewport.width) — every lineuniformly that width. Single authority for box width.
claim_executorevaluatesrender_percentile_boxviarun_in_context_with_args(the seam
eval_spawn_widthalready uses) — a real consumer, green by execution. Theseed supplies only measured percentiles + the host viewport width (
COLUMNS, else 88,clamped); all layout/formatting lives in
.dag.cli_run.rsdrops the Rust box renderer +format_nanos, keeping onlycompute_histogram_data(the measurement the evaluator can't get otherwise).§3 single-authority (review fixes)
std.render.repeat_string(deleted the localrepeat_strfork).std.unicode.string_display_width+std.width.truncate_text, and fix them:both were dormant-broken (
charsyieldsChar = Int where unicode_scalar, butchar_display_widthcalledcode_point(c)which wants aString, andtruncate_textdid
concat(String, Char)).char_display_widthnow reads the scalar directly,truncate_textrebuilds viafrom_code_point—string_display_widthworks for thefirst time (correct CJK/combining width via its block tables).
resolve_symbol+Tier) instead ofhardcoded
┌─│┘literals: 6 newBox*SymbolIds with single-column ASCII fallbacks,so a non-Unicode tier yields a
+--+/|box automatically (no §5 mojibake fail-open).Verified
Witness
ci_render_histogram_width_test: per-linestring_display_width == widthat twowidths, exact Unicode 3-line oracle, ASCII-tier width holds, tier swaps glyphs.
cargo build/fmt --all --check/clippy --all-targetsclean; fullv1-compiler+v1-compiler-testssuites green. Render failure is fail-visible but non-fatal.Bundled: two pre-existing test breaks (gate-unblocking, test-only)
This PR touches
v1-compilerRust, which triggers the full test suite (main's CIgreen only via affected-test scoping). That surfaced two failures pre-existing on
origin/main (both verified on a clean #5818 checkout), unrelated to this diff:
4ca65ea—contracts_sidecar_wired_into_emit_scope: loose.find()glob matched thesplit-out
anthropic_errors.rsinstead of the declaringanthropic.rs(the contractemits correctly; verified). Tightened to the declaring module's file.
a21996b8—string_family_castRust test: Remove hollow Url=String alias (§3); ground RestTransportConfig.base_url as Uri #5818 removedtype Urland updated the.dagwitnesses but missed this.rstest's inlineUrl. Mirrored Remove hollow Url=String alias (§3); ground RestTransportConfig.base_url as Uri #5818's edits.Deferred to a follow-up
The
[file] readhost-trace spam-collapse — done faithfully it routes the trace sitesthrough
gunbc.output_policy.channel_decision(evaluated once at startup, not a Rust mirror).