From dcd62b957eb0b7e4d7dbc52a6e1fcdb62ac46b8b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 09:43:55 +0000 Subject: [PATCH 01/39] std.unicode.scalar: declare partial from_code_point (typed NotUnicodeScalar) + total char_text; migrate v2 callers Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/std/unicode/scalar.dag | 44 +++++++++++++++++++ ...de_scalar_from_code_point_witness_test.dag | 36 +++++++++++++++ src/v2/extdeps/languages/dag.dag | 39 ++++++++++------ src/v2/extdeps/languages/swift/rows.dag | 7 +-- .../std/compilers/semantic_decl_emission.dag | 5 ++- src/v2/test/claim/bash_command_fold_test.dag | 12 ++--- .../string_literal_value_lowering_test.dag | 10 +++++ .../effect_plan_bash_materialize_test.dag | 8 ++-- .../gha_workflow_yaml_fold_serialize_test.dag | 6 ++- .../native_refusal_detail_test.dag | 10 +++-- .../test/claim/sql_create_table_fold_test.dag | 4 +- 11 files changed, 148 insertions(+), 33 deletions(-) create mode 100644 dag/std/unicode/scalar.dag create mode 100644 dag/test/claim/unicode_scalar_from_code_point_witness_test.dag diff --git a/dag/std/unicode/scalar.dag b/dag/std/unicode/scalar.dag new file mode 100644 index 00000000000..a607c31a59b --- /dev/null +++ b/dag/std/unicode/scalar.dag @@ -0,0 +1,44 @@ +module std.unicode.scalar + +import std.algebra { Empty, list_snoc_item } +import std.coercion { unicode_scalar_fold } +import std.error_primitives { Result, Ok, Err } +import std.types { Char } +import std.unicode.types { unicode_scalar, unicode_surrogate_first_code_point, unicode_surrogate_last_code_point } + +// WHY A CODE POINT IS NOT A Char. Unicode Standard 17.0 Core Specification section 3.9, D76: the +// scalar values are U+0000..U+D7FF and U+E000..U+10FFFF, so an Int code point names a scalar only +// when std.unicode.types unicode_scalar holds. The two ways it fails are the two arms here, each +// carrying the code point it refused, so a caller reports WHICH value and WHY rather than a bare no. +type NotUnicodeScalar + = SurrogateCodePoint { code_point: Int } + | CodePointOutOfRange { code_point: Int } + +// THE ONE DECLARATION OF from_code_point, AND IT IS PARTIAL. An Int code point is spelled as host +// text only when it is a Unicode scalar; otherwise this refuses, typed. It is never a total +// Int -> String: a total reading would fabricate text for a surrogate or an out-of-range value. +// It is realized through the declared text-crossing route std.coercion unicode_scalar_fold (DESIGN +// section 4, UnicodeScalarSequenceUnfold), over a one-scalar sequence, so the kernel writer behind +// that route stays the realization. The v1 seed builtin of the same name (v1.compiler.infer_method +// BuiltinSignature "from_code_point") is total over Int; it is NOT a second authority for this +// meaning, and a caller that still binds it bare is enumerated debt +// (gunbc.recurring_failure_mode bare_from_code_point_binds_the_total_seed_builtin). +// A caller holding a Char already has a scalar by construction and spells it through +// unicode_scalar_fold directly; it never needs this function and never handles its refusal. +fn from_code_point(cp: Int) -> Result { + if unicode_scalar(code_point: cp) { + Ok { value: unicode_scalar_fold(xs: list_snoc_item(xs: Empty, item: cp)) } + } else if (cp >= unicode_surrogate_first_code_point) && (cp <= unicode_surrogate_last_code_point) { + Err { value: SurrogateCodePoint { code_point: cp } } + } else { + Err { value: CodePointOutOfRange { code_point: cp } } + } +} + +// THE TOTAL SIBLING: a Char is a Unicode scalar by construction (std.types Char = Int where +// unicode_scalar), so spelling ONE Char as host text cannot refuse. A caller that holds a Char calls +// this, never from_code_point -- handling a refusal that cannot happen would be validation standing +// where construction is available (DESIGN section 5). +fn char_text(c: Char) -> String { + unicode_scalar_fold(xs: list_snoc_item(xs: Empty, item: c)) +} diff --git a/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag b/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag new file mode 100644 index 00000000000..57921c77b62 --- /dev/null +++ b/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag @@ -0,0 +1,36 @@ +module test.claim.unicode_scalar_from_code_point_witness + +import std.error_primitives { Ok, Err } +import std.unicode.scalar { CodePointOutOfRange, SurrogateCodePoint, char_text, from_code_point } + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// std.unicode.scalar from_code_point is PARTIAL over Int and its refusal is typed by cause. The +// positive control and each refusal arm are separate claims so a red names which one moved. + +test fn from_code_point_spells_a_scalar() -> Bool { + match from_code_point(cp: 65) { + Ok { value: s } => s == "A" + Err { value: _ } => false + } +} + +test fn from_code_point_RED_a_surrogate_refuses_as_surrogate() -> Bool { + match from_code_point(cp: 55296) { + Ok { value: _ } => false + Err { value: SurrogateCodePoint { code_point: cp } } => cp == 55296 + Err { value: CodePointOutOfRange { code_point: _ } } => false + } +} + +test fn from_code_point_RED_past_the_last_scalar_refuses_as_out_of_range() -> Bool { + match from_code_point(cp: 1114112) { + Ok { value: _ } => false + Err { value: CodePointOutOfRange { code_point: cp } } => cp == 1114112 + Err { value: SurrogateCodePoint { code_point: _ } } => false + } +} + +test fn char_text_spells_one_char() -> Bool { + char_text(c: 233) == "\u{e9}" +} diff --git a/src/v2/extdeps/languages/dag.dag b/src/v2/extdeps/languages/dag.dag index 90ea36af5e5..b121477bd96 100644 --- a/src/v2/extdeps/languages/dag.dag +++ b/src/v2/extdeps/languages/dag.dag @@ -1,6 +1,6 @@ module v2.extdeps.languages.dag import std.coercion { unicode_scalar_unfold } -import std.types { List } +import std.types { Char, List } import std.occurrence_identity { NodeOccurrenceIdentity, OccurrenceId, OccurrenceMinted, OccurrenceSynthetic } import v2.std.model_core { AlgebraInhabitanceDecl, bool_model_core } import v2.std.algebra_structure_signature { boolean_algebra_node, ordered_ring_node } @@ -231,7 +231,8 @@ import v2.std.integer { } import v2.std.text { String } import extdeps.numeric.base16 { base16_digit_rows } -import std.unicode.types { unicode_scalar } +import std.unicode.scalar { char_text, from_code_point } +import std.error_primitives { Ok, Err } import v2.std.qualified_name { QualifiedName, declaration_reference_node, qualified_name_from_dotted_string, qualified_name_from_node, qualified_name_snoc } import v2.std.namespace_alias { AliasBindingRow } import v2.extdeps.languages.fidelity { @@ -4945,17 +4946,29 @@ fn dag_string_escape_value_optional(spelled: Int) -> Optional { ) } +// A code point that is not a Unicode scalar is not a hex digit: from_code_point's refusal is Absent +// here, and every caller already reads Absent as DagStringDecodeMalformed. fn dag_string_hex_digit_optional(c: Int) -> Optional { - let spelled = from_code_point(cp: c) - fold_list( - xs: base16_digit_rows, - empty: optional_absent(), - cons: fn(found, row) { if (row.lower == spelled) || (row.upper == spelled) { optional_present(value: row.value) } else { found } } - ) + match from_code_point(cp: c) { + Ok { value: spelled } => + fold_list( + xs: base16_digit_rows, + empty: optional_absent(), + cons: fn(found, row) { if (row.lower == spelled) || (row.upper == spelled) { optional_present(value: row.value) } else { found } } + ) + Err { value: _ } => optional_absent() + } } +// THE ONE PLACE A DECODED CODE POINT BECOMES TEXT, and its scalar-ness is decided by +// std.unicode.scalar from_code_point rather than by a guard at each caller: a \u{D800} or a +// \u{110000} refuses here as DagStringDecodeMalformed, which dag_string_literal_escape_refusal +// reports located. fn dag_string_decode_append(text: String, code_point: Int) -> DagStringDecode { - DagStringDecodeText { text: concat(text, from_code_point(cp: code_point)) } + match from_code_point(cp: code_point) { + Ok { value: spelled } => DagStringDecodeText { text: concat(text, spelled) } + Err { value: _ } => DagStringDecodeMalformed { spelled: code_point } + } } fn dag_string_decode_escape_step(t: String, c: Int) -> DagStringDecode { @@ -4985,7 +4998,7 @@ fn dag_string_decode_hex_step(t: String, digits: Int, value: Int, c: Int) -> Dag fn dag_string_decode_unicode_step(t: String, digits: Int, value: Int, c: Int) -> DagStringDecode { if c == 125 { - if (digits > 0) && unicode_scalar(code_point: value) { + if digits > 0 { dag_string_decode_append(text: t, code_point: value) } else { DagStringDecodeMalformed { spelled: c } @@ -5121,14 +5134,14 @@ fn dag_string_hex_text(value: Int) -> String { } } -fn dag_string_encode_scalar(c: Int) -> String { +fn dag_string_encode_scalar(c: Char) -> String { match dag_string_escape_spelled_optional(value: c) { - Present { value: spelled } => concat("\\", from_code_point(cp: spelled)) + Present { value: spelled } => concat("\\", char_text(c: spelled)) Absent => if (c < 32) || (c == 127) { concat("\\u\{", concat(dag_string_hex_text(value: c), "\}")) } else { - from_code_point(cp: c) + char_text(c: c) } } } diff --git a/src/v2/extdeps/languages/swift/rows.dag b/src/v2/extdeps/languages/swift/rows.dag index c2da8656785..82f544f5eda 100644 --- a/src/v2/extdeps/languages/swift/rows.dag +++ b/src/v2/extdeps/languages/swift/rows.dag @@ -1,6 +1,7 @@ module v2.extdeps.languages.swift.rows -import std.types { String, List, Bool, Int } +import std.types { String, List, Bool, Int, Char } +import std.unicode.scalar { char_text } import std.occurrence_identity { OccurrenceSynthetic } import v2.std.optional { Optional, Present, Absent } import v2.std.algebra { list_append, length } @@ -578,7 +579,7 @@ fn list_reverse_attrs(xs: List) -> List { } // ── String literals: a text segment's lexeme is its escaped spelling ───────────────────────── -fn swl_escape_scalar(cp: Int) -> String { +fn swl_escape_scalar(cp: Char) -> String { if cp == 92 { "\\\\" } else if cp == 34 { "\\\"" } else if cp == 10 { "\\n" } @@ -586,7 +587,7 @@ fn swl_escape_scalar(cp: Int) -> String { else if cp == 13 { "\\r" } else if cp == 0 { "\\0" } else if cp < 32 || cp >= 127 { join(["\\u\{", int_to_upper_hex(n: cp), "\}"], "") } - else { from_code_point(cp: cp) } + else { char_text(c: cp) } } fn swl_escape_text(s: String) -> String { diff --git a/src/v2/std/compilers/semantic_decl_emission.dag b/src/v2/std/compilers/semantic_decl_emission.dag index 010fec64f3f..d953808970d 100644 --- a/src/v2/std/compilers/semantic_decl_emission.dag +++ b/src/v2/std/compilers/semantic_decl_emission.dag @@ -1,6 +1,7 @@ module v2.std.compilers.semantic_decl_emission import std.types { List } +import std.unicode.scalar { char_text } import v2.std.optional { Present, Absent } import v2.std.qualified_name { declaration_reference_path_optional } import std.occurrence_identity { OccurrenceSynthetic } @@ -139,7 +140,7 @@ fn semantic_decl_emission_bundle_malformed_diagnostic(bundle: Node) -> Diagnosti // // The parameter is an ordinary string and its callers are right to pass one -- `semantic_decl_emit` // hands it a `text` and a `spelling`. What the BODY needs is the char-list view, because it folds -// each element through `from_code_point`. `chars` is the conversion between the two, and it is the +// each element through `std.unicode.scalar` `char_text`. `chars` is the conversion between the two, and it is the // same one `v2.std.compilers.lexing` already uses when it builds a `LiteralPattern`. // // WITHOUT IT THE FOLD HAS NO ELEMENT TYPE TO INFER: `String` renders as the target's native string, @@ -155,7 +156,7 @@ fn semantic_decl_string_to_bundle_node(s: String) -> Node { children: [ target_model_named_edge( name: ^free_monoid_field_head, - target: target_model_type_atom_node(identity: from_code_point(cp: c)) + target: target_model_type_atom_node(identity: char_text(c: c)) ), target_model_named_edge( name: ^free_monoid_field_tail, diff --git a/src/v2/test/claim/bash_command_fold_test.dag b/src/v2/test/claim/bash_command_fold_test.dag index 6a9bc7b0bd3..9da33641fb3 100644 --- a/src/v2/test/claim/bash_command_fold_test.dag +++ b/src/v2/test/claim/bash_command_fold_test.dag @@ -1,5 +1,7 @@ module v2.test.claim.bash_command_fold +import std.unicode.scalar { char_text } + import v2.compiler.target_serialize { target_serialize_source_from_model } import v2.extdeps.languages.bash { bash_stmt_env_prefixed_emitted, @@ -214,11 +216,11 @@ test fn bash_fold_command_single_lit_true_holds() -> Bool { } test fn bash_fold_command_multi_lit_echo_hi_holds() -> Bool { - bash_fold_stmt_kind_sentinel == from_code_point(cp: 2) - && bash_fold_word_lit_sentinel == from_code_point(cp: 0) - && bash_fold_word_var_sentinel == from_code_point(cp: 1) - && bash_fold_word_concat_sentinel == from_code_point(cp: 3) - && bash_fold_word_cmdsubst_sentinel == from_code_point(cp: 4) + bash_fold_stmt_kind_sentinel == char_text(c: 2) + && bash_fold_word_lit_sentinel == char_text(c: 0) + && bash_fold_word_var_sentinel == char_text(c: 1) + && bash_fold_word_concat_sentinel == char_text(c: 3) + && bash_fold_word_cmdsubst_sentinel == char_text(c: 4) && bash_emit_matches_golden( stmt: bash_fold_command_stmt(node: bash_fold_cmd_echo_hi_emitted), golden: bash_fold_cmd_echo_hi_golden diff --git a/src/v2/test/claim/body_lowering/string_literal_value_lowering_test.dag b/src/v2/test/claim/body_lowering/string_literal_value_lowering_test.dag index c94c082ce68..3aa25ccffce 100644 --- a/src/v2/test/claim/body_lowering/string_literal_value_lowering_test.dag +++ b/src/v2/test/claim/body_lowering/string_literal_value_lowering_test.dag @@ -170,6 +170,16 @@ test fn malformed_numeric_string_escapes_refuse() -> Bool { && (slv_decode_refusal(lexeme: "\"\\u12\"") == ^dag_string_literal_escape_malformed) } +// THE SCALAR BOUNDARY IS DECIDED BY std.unicode.scalar from_code_point, NOT BY A GUARD IN THE +// DECODER: both surrogate ends and the first value past U+10FFFF refuse, and the neighbours just +// inside each boundary decode, so a decoder that stopped consulting from_code_point reds here. +test fn a_non_scalar_unicode_escape_refuses_at_the_scalar_boundary() -> Bool { + (slv_decode_refusal(lexeme: "\"\\u\{D800\}\"") == ^dag_string_literal_escape_malformed) + && (slv_decode_refusal(lexeme: "\"\\u\{DFFF\}\"") == ^dag_string_literal_escape_malformed) + && (slv_decode_refusal(lexeme: "\"\\u\{110000\}\"") == ^dag_string_literal_escape_malformed) + && (slv_decode_value(lexeme: "\"\\u\{D7FF\}\\u\{E000\}\\u\{10FFFF\}\"") == "\u{D7FF}\u{E000}\u{10FFFF}") +} + test fn two_different_string_literals_are_two_different_nodes() -> Bool { match dag_string_literal_node_from_lexeme(lexeme: "\"a\"", occurrence_id: OccurrenceSynthetic) { Accepted { value: a, diagnostics: _ } => diff --git a/src/v2/test/claim/effect_plan_bash_materialize_test.dag b/src/v2/test/claim/effect_plan_bash_materialize_test.dag index fa8ba451528..756d1405813 100644 --- a/src/v2/test/claim/effect_plan_bash_materialize_test.dag +++ b/src/v2/test/claim/effect_plan_bash_materialize_test.dag @@ -1,5 +1,7 @@ module v2.test.claim.effect_plan_bash_materialize_test +import std.unicode.scalar { char_text } + import v2.std.effect_plan { Call, Do, @@ -266,12 +268,12 @@ test fn effect_plan_bash_metacharacters_and_newline_remain_one_quoted_word() -> // This is also the CI-enforcing receipt for the language's Unicode escape: keep the production // guard pattern authored with the Unicode escape while constructing the poison input independently -// with from_code_point(0). If the tokenizer regresses to passthrough, the pattern becomes printable +// with std.unicode.scalar char_text(c: 0). If the tokenizer regresses to passthrough, the pattern becomes printable // text, no longer matches this real NUL, and this witness reds. Rewriting the guard pattern to -// from_code_point would make both sides share a constructor and remove this discrimination. +// char_text would make both sides share a constructor and remove this discrimination. test fn effect_plan_bash_RED_nul_is_located_and_refused() -> Bool { - let nul = from_code_point(cp: 0) + let nul = char_text(c: 0) let third_argument = effect_plan_bash_materialize(plan: one_step_plan(inv: test_path_invocation( operation: "IsFile", path: concat("/tmp/a", concat(nul, "b")) diff --git a/src/v2/test/claim/gha_workflow_yaml_fold_serialize_test.dag b/src/v2/test/claim/gha_workflow_yaml_fold_serialize_test.dag index 7d2fc739a6c..32b997cd082 100644 --- a/src/v2/test/claim/gha_workflow_yaml_fold_serialize_test.dag +++ b/src/v2/test/claim/gha_workflow_yaml_fold_serialize_test.dag @@ -1,5 +1,7 @@ module v2.test.claim.gha_workflow_yaml_fold_serialize +import std.unicode.scalar { char_text } + import extdeps.languages.yaml.types { YamlValue } import extdeps.languages.yaml.emit { emit_yaml, EmittedYaml, YamlEmitRefused } import extdeps.github.actions { Job } @@ -57,8 +59,8 @@ fn gha_fold_fold_matches_oracle(job: Job) -> Bool { } test fn gha_fold_pilot_job_byte_identical_holds() -> Bool { - gha_fold_prod_kind_sentinel == from_code_point(cp: 2) - && gha_fold_scalar_kind_sentinel == from_code_point(cp: 0) + gha_fold_prod_kind_sentinel == char_text(c: 2) + && gha_fold_scalar_kind_sentinel == char_text(c: 0) && gha_fold_fold_matches_oracle(job: gha_fold_pilot_job) } diff --git a/src/v2/test/claim/native_route/native_refusal_detail_test.dag b/src/v2/test/claim/native_route/native_refusal_detail_test.dag index 51d3a6374f5..4b1800c32b3 100644 --- a/src/v2/test/claim/native_route/native_refusal_detail_test.dag +++ b/src/v2/test/claim/native_route/native_refusal_detail_test.dag @@ -1,5 +1,7 @@ module v2.test.claim.native_route.native_refusal_detail +import std.unicode.scalar { char_text } + import gunbc.witness_v2_native_route { NativeRouteMemberRow, native_route_member_row_text } import v2.compiler.compile { NativeLaneModuleContextRowsDecided, @@ -416,13 +418,13 @@ test fn an_ordinary_atom_renders_readably_holds() -> Bool { } test fn an_embedded_backtick_and_backslash_stay_unambiguous_holds() -> Bool { - atom_locus_text(lexeme: concat("left`right", concat(from_code_point(cp: 92), "x"))) - == concat(""))) + atom_locus_text(lexeme: concat("left`right", concat(char_text(c: 92), "x"))) + == concat(""))) } test fn newline_cr_and_esc_become_visible_escapes_holds() -> Bool { - let bs = from_code_point(cp: 92) - atom_locus_text(lexeme: concat("a", concat(from_code_point(cp: 10), concat("b", concat(from_code_point(cp: 13), concat("c", concat(from_code_point(cp: 27), "d"))))))) + let bs = char_text(c: 92) + atom_locus_text(lexeme: concat("a", concat(char_text(c: 10), concat("b", concat(char_text(c: 13), concat("c", concat(char_text(c: 27), "d"))))))) == concat("")))))) } diff --git a/src/v2/test/claim/sql_create_table_fold_test.dag b/src/v2/test/claim/sql_create_table_fold_test.dag index 77a488e4e7f..69aab1a4304 100644 --- a/src/v2/test/claim/sql_create_table_fold_test.dag +++ b/src/v2/test/claim/sql_create_table_fold_test.dag @@ -1,5 +1,7 @@ module v2.test.claim.sql_create_table_fold +import std.unicode.scalar { char_text } + import v2.extdeps.formats.sql { SqlColumnConstraints, SqlColumnDefaultAbsent, @@ -239,6 +241,6 @@ test fn sql_fold_single_col_uses_leaf_list_production_holds() -> Bool { } test fn sql_fold_direct_serialize_tier_holds() -> Bool { - sql_fold_stmt_kind_sentinel == from_code_point(cp: 2) + sql_fold_stmt_kind_sentinel == char_text(c: 2) && sql_fold_direct_serialize_single_col_holds() } From 4a6934b3a51206335aa96f7217eb97cbc58f4329 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 09:53:22 +0000 Subject: [PATCH 02/39] RFM: bare from_code_point binds the total seed builtin (population at identity grain, by kind) Co-Authored-By: Claude Opus 5.5 (1M context) --- ...ode_point_binds_the_total_seed_builtin.dag | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag new file mode 100644 index 00000000000..5e36acf3f38 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -0,0 +1,22 @@ +module gunbc.recurring_failure_mode.bare_from_code_point_binds_the_total_seed_builtin + +import std.types { NonEmptyStr } +import std.decl_ref { DeclarationRef, WholeDeclaration } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = RecurringFailureMode { + identity: "bare_from_code_point_binds_the_total_seed_builtin" as NonEmptyStr, + receipts: [ + "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", + "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", + "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", + "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", + "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", + "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", + ], + evidence: [ + DeclarationRef { module_path: "std.unicode.scalar", decl_name: "from_code_point", field: WholeDeclaration }, + DeclarationRef { module_path: "std.unicode.scalar", decl_name: "char_text", field: WholeDeclaration }, + DeclarationRef { module_path: "std.unicode.scalar", decl_name: "NotUnicodeScalar", field: WholeDeclaration }, + ], +} From 50c37247d05ad0b31d1b5eea5393ae41b56d19a6 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 09:56:05 +0000 Subject: [PATCH 03/39] wip --- dag/std/algebra.dag | 11 ++++++++--- dag/std/encoding.dag | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dag/std/algebra.dag b/dag/std/algebra.dag index 7c931016905..066d4e84020 100644 --- a/dag/std/algebra.dag +++ b/dag/std/algebra.dag @@ -1138,8 +1138,13 @@ fn all_algebra_template_names() -> List { // already in the compilation pool (#6985 Class B pool coincidence closed on trim by #8062). // The seam diverges before producing anything; `s` is read in the condition so the declared -// input reaches the result (wiring-liveness), mirroring the bytes.dag float-seam pattern -- -// both arms are the same unreached literal, there to give the expression its type. +// input reaches the result (wiring-liveness). The divergence is the condition's `1 / 0`, evaluated +// before either arm, so both arms are the same unreached literal there only to type the expression +// -- the shape of std.bytes pure_dag_seam_unreachable_string. That projection cannot be imported +// here (std.bytes imports std.types, which imports std.algebra), so its divergence is spelled +// in place; it was `from_code_point(1 / 0)`, which bound the total seed builtin to type a value that +// is never produced (gunbc.recurring_failure_mode bare_from_code_point_binds_the_total_seed_builtin). +// DISSOLVE-ON: the bottom type std.bytes names -- one divergent seam inhabits every result type. fn trim(s: String) -> String { - if s == s { from_code_point(1 / 0) } else { from_code_point(1 / 0) } + if s == s && 1 / 0 == 0 { "" } else { "" } } diff --git a/dag/std/encoding.dag b/dag/std/encoding.dag index b836f3b0ced..fa7056252f5 100644 --- a/dag/std/encoding.dag +++ b/dag/std/encoding.dag @@ -5,7 +5,7 @@ import std.types { Bytes } import std.integer { UInt8Result, UInt8Ready, UInt8OutOfRange, uint8_of_int, QualifiedOctets, QualifiedOctetsResult, QualifiedOctetsReady, QualifiedOctetsRefused, uint8_octets_of_ints, qualified_octet_members } import std.machine_word { Word, Width8, Width32, WordResult, WordReady, WordRefused, WordValueOutOfRange, OctetsResult, OctetsReady, OctetsRefused, word_of_int, word_from_octets, word_to_octets, word_shift_left, word_shift_right, word_and, word_or } import extdeps.toolchain.architecture_profile { BigEndian } -import std.bytes { pure_dag_seam_unreachable, pure_dag_seam_unreachable_string } +import std.bytes { pure_dag_seam_unreachable_string } import std.disposition { Disposition, Scaffold, Terminal, SingleAuthority } import std.decl_ref { DeclarationRef, WholeDeclaration } import std.unicode.types { unicode_scalar, unicode_scalar_utf8_octet_count } @@ -126,7 +126,7 @@ data encoding_bounded_lattice: BoundedLattice = { } fn utf8_decode_bytes(payload: Bytes) -> String { - from_code_point(pure_dag_seam_unreachable()) + pure_dag_seam_unreachable_string() } type Base64Variant = Standard | UrlSafe From 57d73cc42a4348f91ed1d9ac6852758f34c3a4c6 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 09:56:14 +0000 Subject: [PATCH 04/39] std seam sites: trim and utf8_decode_bytes stop binding bare from_code_point --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 5e36acf3f38..8083d59a8d4 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -12,7 +12,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", - "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", + "POPULATION, KIND STD SEAM (2 identities, BOTH REMOVED): a deliberate unreachable seam whose argument was not a code point at all, re-derived against its seam's own refusal rather than migrated: from_code_point only typed an unreached String. Dispositions: std.encoding::utf8_decode_bytes now returns std.bytes pure_dag_seam_unreachable_string (the named seam refusal); std.algebra::trim cannot import std.bytes (std.bytes -> std.types -> std.algebra would cycle), so it spells that projection's shape in place -- the condition diverges on 1 / 0 before an unreached literal arm. Neither binds the seed builtin; both dissolve with the bottom type std.bytes names.", ], evidence: [ DeclarationRef { module_path: "std.unicode.scalar", decl_name: "from_code_point", field: WholeDeclaration }, From 9b5cbe7dd83c1fb37b3453a474f79db54ef3e1d3 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 09:59:59 +0000 Subject: [PATCH 05/39] Parser decodes route NotUnicodeScalar into each parser's own typed refusal (XL-2, from_code_point follow-up) yaml.ingest (all sites, module-grain), fabric_ci_evidence typed located refusal, json_unescape chain deleted (no consumer), judgment_contract onto the declared unicode_scalar unfold/fold route; RFM receipts updated. Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/languages/json/parse.dag | 120 +----------------- dag/extdeps/languages/yaml/ingest.dag | 62 ++++++--- dag/gunbc/instruments/fabric_ci_evidence.dag | 36 ++++-- .../fabric_control_plane_live_probe.dag | 12 +- ...ode_point_binds_the_total_seed_builtin.dag | 4 +- dag/std/judgment_contract.dag | 16 +-- dag/std/materialization_provider.dag | 3 +- ...c_ci_evidence_wire_decode_witness_test.dag | 28 ++++ dag/test/claim/yaml_ingest_witness_test.dag | 10 ++ 9 files changed, 130 insertions(+), 161 deletions(-) create mode 100644 dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag diff --git a/dag/extdeps/languages/json/parse.dag b/dag/extdeps/languages/json/parse.dag index cab71e9a4d1..f4c291a1ba1 100644 --- a/dag/extdeps/languages/json/parse.dag +++ b/dag/extdeps/languages/json/parse.dag @@ -12,7 +12,6 @@ import extdeps.languages.json.grammar { JsonTextParseResult, JsonTextParseOk, JsonTextParseFail, json_text_skip_ws, json_text_parse_string, json_text_parse_number, json_number_lexeme_unchecked, is_json_digit_char, - json_hex_nibble, json_hex4_at, } // parse_json is the FORWARD reading of RFC 8259: text -> JsonValue, the inverse of @@ -25,17 +24,12 @@ import extdeps.languages.json.grammar { // the escape SET (one native split per string body, RFC 8259 section 7), so an unknown escape or // a short \u refuses the parse before a value is built and never reaches the unescaper below - // see json_escape_production_note for why that refusal lives at the scan and what it prevents -// (review 45642). The malformed-\u arm in json_unescape_decode_piece is therefore unreachable for -// any span this parser accepts; it is retained as a total fallback because json_unescape is -// exported and a caller could hand it an unvalidated span. \uXXXX IS decoded to its code point, -// which is what makes the round-trip total against escape_json_string: that emitter maps code -// points 0-31 other than the six with short escapes to \uXXXX, so a parser that passed \u through -// would silently corrupt every control character a receipt detail field can carry. Surrogate -// PAIRS are not recombined - serialize_json never emits one (it escapes only 0-31), so a lone -// \uXXXX decode is exact over this emitter's output; foreign JSON carrying an astral character as -// a surrogate pair is outside the declared fragment. A malformed \u (fewer than four hex digits, -// or a non-hex digit) refuses at the scan, so json_hex4_at's negative arm is likewise unreachable -// from parse_json and kept only for the exported-caller case. +// (review 45642). \uXXXX IS decoded to its scalar by the native json_unescape_checked kernel, +// which recombines a UTF-16 surrogate pair (RFC 8259 section 7) and refuses an unpaired surrogate, +// so a value this parser builds never carries a surrogate code point. There is no interpreted +// unescaper beside it: the former json_unescape piece decoder had no consumer and spelled each +// \u through the total seed from_code_point (gunbc.recurring_failure_mode +// bare_from_code_point_binds_the_total_seed_builtin), so it was deleted rather than migrated. data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { @@ -48,111 +42,11 @@ type JsonParse = JsonParsed { value: JsonValue, next: Int } | JsonParseFail { at: Int } -// THE UNESCAPER MOVES IN ESCAPE-SIZED STEPS, NOT PER CHARACTER (measured 2026-09-23 on -// corpus-scale shards: even with the span unescape, the per-character next-escape scan put the -// parse at roughly fourteen interpreter-minutes per megabyte, which is the 104 MB envelope's -// wall). One native split on the backslash resolves the whole escape structure — the pieces' -// boundaries ARE the parity answer, so `\\` and `\u` sequences cannot be misparsed the way -// sequential replacement passes would misparse them — and each piece decodes in one interpreted -// step. The decoded pieces stay in document order (the recursion carries the first piece -// first) and the join is one native pass; neither side copies an accumulator per escape. -// THE FIRST PIECE IS LITERAL BY CONSTRUCTION (it precedes the first backslash); the rest are -// escapes. The split is walked once, head by head, and each decoded piece is carried in -// document order. -fn json_unescape_decoded_pieces(pieces: List) -> List { - match pieces.first() { - Absent => [] - Present { value: head } => - concat( - [head], - json_unescape_decode_rest(pieces: json_unescape_drop_first(xs: pieces), literal_next: false), - ) - } -} - -// THE WALK CARRIES THE PARITY ANSWER: an empty piece is a \\ pair, and the piece after a pair -// is LITERAL — its head was never an escape letter, because the backslash that would have made -// it one is the pair's second half. (Without the flag, `\\b` decodes the b as \b and `\q` -// refuses a valid document.) The flag lasts exactly one piece. -// ONE PASS, THE PARITY AND THE DECODED PIECES IN THE ACCUMULATOR: the recursive walk -// re-dropped the tail at every level (and the drop concatenated at the end, copying per -// element), the square of a string's escape count — the read's long pole at the project -// envelope's ~3.45M escapes. The fold visits each piece once, prepends, and reverses once; -// the state machine is the recursion's, so the decoded bytes are unchanged. -type JsonUnescapeDecodeAcc { literal_next: Bool, decoded_rev: List } - -fn json_unescape_decode_rest(pieces: List, literal_next: Bool) -> List { - let acc = fold( - pieces, - init: JsonUnescapeDecodeAcc { literal_next: literal_next, decoded_rev: [] }, - f: fn(a, piece) { - if a.literal_next { - JsonUnescapeDecodeAcc { literal_next: false, decoded_rev: concat([piece], a.decoded_rev) } - } else if piece == "" { - JsonUnescapeDecodeAcc { literal_next: true, decoded_rev: concat(["\\"], a.decoded_rev) } - } else { - JsonUnescapeDecodeAcc { - literal_next: false, - decoded_rev: concat([json_unescape_decode_piece(piece: piece)], a.decoded_rev), - } - } - }, - ) - reverse(acc.decoded_rev) -} - -type JsonUnescapeDropAcc { skipped: Bool, kept: List } - -fn json_unescape_drop_first(xs: List) -> List { - let result = fold(xs, init: JsonUnescapeDropAcc { skipped: false, kept: [] }, f: fn(acc, x) { - if acc.skipped { JsonUnescapeDropAcc { skipped: true, kept: concat([x], acc.kept) } } else { JsonUnescapeDropAcc { skipped: true, kept: [] } } - }) - reverse(result.kept) -} - -// AN EMPTY PIECE IS THE ESCAPED BACKSLASH; any other piece's head is its escape letter, with \u -// carrying exactly four hex digits. The malformed-\u arm is the exported-caller fallback (the -// grammar refuses before value building, so a short or non-hex \u never reaches this builder -// from the parser): it drops the backslash and rescans the remainder as literal text, the -// total-fallback semantics, piece-local. -fn json_unescape_decode_piece(piece: String) -> String { - if piece == "" { - "\\" - } else { - let c = char_at(s: piece, pos: 0) - if c == "u" { - let cp = json_hex4_at(s: piece, i: 1) - if cp < 0 { - concat("u", json_unescape(s: substring(s: piece, start: 1, end: piece.length()))) - } else { - concat(from_code_point(cp: cp), substring(s: piece, start: 5, end: piece.length())) - } - } else { - let u = if c == "n" { from_code_point(cp: 10) } - else if c == "t" { from_code_point(cp: 9) } - else if c == "r" { from_code_point(cp: 13) } - else if c == "b" { from_code_point(cp: 8) } - else if c == "f" { from_code_point(cp: 12) } - else { c } - concat(u, substring(s: piece, start: 1, end: piece.length())) - } - } -} - -fn json_unescape(s: String) -> String { - if string_contains(s: s, pattern: "\\") { - join(json_unescape_decoded_pieces(pieces: split(s: s, delimiter: "\\")), "") - } else { - s - } -} - // THE VALUE IS THE NATIVE json_unescape_checked DECODE: the span was validated by the grammar // production one call ago, so the kernel's refusal arm is unreachable here — it is matched // anyway, because a total path outlives the argument for why it is dead. This replaces the // interpreted piece decode (one interpreted step per escape over the project envelope's ~3.45M -// escapes, the read's measured wall) with the same bytes at native speed; json_unescape below -// stays as the exported-caller authority, malformed-\u fallback included. +// escapes, the read's measured wall) with the same bytes at native speed. fn parse_json_string_at(s: String, i: Int) -> JsonParse { match json_text_parse_string(s: s, i: i) { JsonTextParseFail { end: e } => JsonParseFail { at: e } diff --git a/dag/extdeps/languages/yaml/ingest.dag b/dag/extdeps/languages/yaml/ingest.dag index 06f6f332658..22c95f02314 100644 --- a/dag/extdeps/languages/yaml/ingest.dag +++ b/dag/extdeps/languages/yaml/ingest.dag @@ -4,6 +4,9 @@ import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } import v2.std.optional { Present, Absent } import std.algebra { trim } +import std.types { Char } +import std.error_primitives { Ok, Err } +import std.unicode.scalar { SurrogateCodePoint, CodePointOutOfRange, char_text, from_code_point } import extdeps.languages.yaml.types { YamlValue, YamlKeyValue, YamlNull, YamlBool, YamlInt, YamlFloat, YamlString, YamlSequence, YamlMapping @@ -63,18 +66,26 @@ type YamlScalarResult // paragraph separators, the byte-order mark and the two noncharacters -- are refused because the // host's trim treats them as whitespace (or, for the BOM, because it is only legal at the start of // a stream), so a reader that accepted them could not tell their content from indentation. -data yaml_refused_code_points: List = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 5760, - 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232, 8233, 8239, 8287, 12288, - 65279, 65534, 65535 -] +data yaml_refused_text: String = "\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\u{B}\u{C}\u{D}\u{E}\u{F}\u{10}\u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\u{1A}\u{1B}\u{1C}\u{1D}\u{1E}\u{1F}\u{7F}\u{80}\u{81}\u{82}\u{83}\u{84}\u{85}\u{86}\u{87}\u{88}\u{89}\u{8A}\u{8B}\u{8C}\u{8D}\u{8E}\u{8F}\u{90}\u{91}\u{92}\u{93}\u{94}\u{95}\u{96}\u{97}\u{98}\u{99}\u{9A}\u{9B}\u{9C}\u{9D}\u{9E}\u{9F}\u{A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{FEFF}\u{FFFE}\u{FFFF}" -data yaml_refused_characters: List = map(yaml_refused_code_points, cp => from_code_point(cp: cp)) +// Each refused character is a Unicode scalar by construction (an element of the literal above), so +// it is spelled as text through std.unicode.scalar char_text, which cannot refuse. +data yaml_refused_code_points: List = chars(s: yaml_refused_text) + +data yaml_refused_characters: List = map(yaml_refused_code_points, c => char_text(c: c)) + +fn yaml_first_refused(text: String) -> Char? { + fold(yaml_refused_code_points, init: none, f: (acc, c) => match acc { + Present { value: found } => Present { value: found } + Absent => if string_contains(s: text, pattern: char_text(c: c)) { Present { value: c } } else { none } + }) +} fn yaml_first_refused_character(text: String) -> Int { - fold(yaml_refused_code_points, init: -1, f: (acc, cp) => if (acc == -1) && string_contains(s: text, pattern: from_code_point(cp: cp)) { cp } else { acc }) + match yaml_first_refused(text: text) { + Absent => -1 + Present { value: c } => c + } } fn yaml_contains_refused_character(text: String) -> Bool { @@ -358,7 +369,7 @@ fn yaml_double_quoted_escape(pieces: List, index: Int, p: String, acc: L if width == 0 { match map_get(yaml_double_quoted_escapes, c) { Absent => YamlScalarRefused { reason: join(["`\\", c, "` is not a YAML escape (section 5.7)"], "") } - Present { value: cp } => yaml_double_quoted_rest(pieces: pieces, index: index, rest: substring(s: p, start: 1, end: p.length()), acc: concat(acc, [from_code_point(cp: cp)])) + Present { value: cp } => yaml_double_quoted_scalar(pieces: pieces, index: index, escape: c, cp: cp, rest: substring(s: p, start: 1, end: p.length()), acc: acc) } } else if p.length() < width + 1 { YamlScalarRefused { reason: join(["`\\", c, "` needs ", to_string(width), " hexadecimal digits"], "") } @@ -366,14 +377,27 @@ fn yaml_double_quoted_escape(pieces: List, index: Int, p: String, acc: L let cp = yaml_hex_value(s: substring(s: p, start: 1, end: width + 1), i: 0, acc: 0) if cp < 0 { YamlScalarRefused { reason: join(["`\\", substring(s: p, start: 0, end: width + 1), "` is not a hexadecimal escape"], "") } - } else if ((cp >= 55296) && (cp <= 57343)) || (cp > 1114111) { - YamlScalarRefused { reason: join(["`\\", substring(s: p, start: 0, end: width + 1), "` does not name a Unicode scalar value"], "") } } else { - yaml_double_quoted_rest(pieces: pieces, index: index, rest: substring(s: p, start: width + 1, end: p.length()), acc: concat(acc, [from_code_point(cp: cp)])) + yaml_double_quoted_scalar(pieces: pieces, index: index, escape: substring(s: p, start: 0, end: width + 1), cp: cp, rest: substring(s: p, start: width + 1, end: p.length()), acc: acc) } } } +// AN ESCAPE NAMES A UNICODE SCALAR OR THE SCALAR REFUSES. YAML 1.2.2 section 5.7 defines \x, \u and +// \U as the escaped Unicode character, and section 5.1 restricts the character set to Unicode +// scalars, so a surrogate or a value past U+10FFFF is not a YAML character. The one scalar +// authority is std.unicode.scalar from_code_point; its NotUnicodeScalar arm becomes this parser's +// own refusal, naming the escape and which way it failed. +fn yaml_double_quoted_scalar(pieces: List, index: Int, escape: String, cp: Int, rest: String, acc: List) -> YamlScalarResult { + match from_code_point(cp: cp) { + Ok { value: text } => yaml_double_quoted_rest(pieces: pieces, index: index, rest: rest, acc: concat(acc, [text])) + Err { value: SurrogateCodePoint { code_point: _ } } => + YamlScalarRefused { reason: join(["`\\", escape, "` names a surrogate code point, not a Unicode scalar value (sections 5.1, 5.7)"], "") } + Err { value: CodePointOutOfRange { code_point: _ } } => + YamlScalarRefused { reason: join(["`\\", escape, "` is past U+10FFFF, not a Unicode scalar value (sections 5.1, 5.7)"], "") } + } +} + fn yaml_double_quoted_rest(pieces: List, index: Int, rest: String, acc: List) -> YamlScalarResult { if string_contains(s: rest, pattern: "\"") { YamlScalarRefused { reason: yaml_unescaped_quote_reason } @@ -624,7 +648,7 @@ fn yaml_empty_line_count(text: String) -> Int { (split(s: replace(concat("\n", concat(text, "\n")), "\n", concat("\n", yaml_line_start_mark)), delimiter: concat(yaml_line_start_mark, "\n")) |> count) - 1 } -data yaml_line_start_mark: String = from_code_point(cp: 2) +data yaml_line_start_mark: String = "\u{2}" fn yaml_literal_body(chomping: String, cont: String, col: Int) -> YamlBlockResult { let lines = split(s: cont, delimiter: "\n") @@ -700,7 +724,7 @@ type YamlEntryRead // text of one block, and the document it came from cannot already hold it (ingest_yaml_source refuses // U+0001 anywhere). It never appears in a value, a key or a refusal: a decoded scalar may hold U+0001 // (a double-quoted `\x01`), and that is ordinary content. -data yaml_line_join_mark: String = from_code_point(cp: 1) +data yaml_line_join_mark: String = "\u{1}" fn yaml_is_ignorable_line(l: String) -> Bool { let t = trim(l) @@ -852,7 +876,7 @@ fn yaml_map_block(chunks: List, n: Int, base: Int) -> YamlBlockResult { // U+0003 separates the keys. A decoded key may itself hold it (a double-quoted `\x03`), and the // spelled sequence then splits into more keys than the block has; that block's keys are then read one // by one by yaml_map_block_keys rather than trusted to the spelling. -data yaml_key_separator: String = from_code_point(cp: 3) +data yaml_key_separator: String = "\u{3}" // True exactly when the spelled keys split back into `count` keys and no key repeats. fn yaml_key_sequence_is_clean(keys: String, count: Int) -> Bool { @@ -1396,8 +1420,10 @@ fn yaml_line_ending_in_whitespace(lines: List, index: Int) -> Int { fn ingest_yaml_source(src: String) -> YamlIngestResult { if yaml_contains_refused_character(text: src) { - let cp = yaml_first_refused_character(text: src) - YamlIngestRejected { line: yaml_line_containing(lines: yaml_source_lines(src: src), pattern: from_code_point(cp: cp), index: 0), reason: yaml_refused_character_reason(cp: cp) } + match yaml_first_refused(text: src) { + Present { value: c } => YamlIngestRejected { line: yaml_line_containing(lines: yaml_source_lines(src: src), pattern: char_text(c: c), index: 0), reason: yaml_refused_character_reason(cp: c) } + Absent => YamlIngestRejected { line: 0, reason: "a refused character was detected and then not found" } + } } else if yaml_has_leading_tab(src: src) { YamlIngestRejected { line: yaml_line_with_leading_tab(lines: yaml_source_lines(src: src), index: 0), reason: "a tab in a line's leading whitespace is outside the supported subset (YAML indents with spaces only; a literal line may not begin with a tab either)" } } else if yaml_has_trailing_whitespace(src: src) { diff --git a/dag/gunbc/instruments/fabric_ci_evidence.dag b/dag/gunbc/instruments/fabric_ci_evidence.dag index 7b070a5a33d..b2824d4b575 100644 --- a/dag/gunbc/instruments/fabric_ci_evidence.dag +++ b/dag/gunbc/instruments/fabric_ci_evidence.dag @@ -3,6 +3,8 @@ module tools.fabric_ci_evidence import std.types { Bool, Int, List, NonEmptyStr, String } import std.process { ProcessExit, ExitSuccess, exit_failure } import v2.std.optional { Present, Absent } +import std.error_primitives { Ok, Err } +import std.unicode.scalar { NotUnicodeScalar, from_code_point } import extdeps.numeric.base16 { base16_word_value } import std.content_hash { ContentHash, content_hash_of_value } import extdeps.filesystem.filesystem_io { Filesystem } @@ -39,7 +41,17 @@ data fabric_ci_evidence_wire_prefix: NonEmptyStr = "FCIE0X" type FabricCiEvidenceDecode = FabricCiEvidenceDecoded { value: NonEmptyStr } - | FabricCiEvidenceUndecodable + | FabricCiEvidenceUndecodable { cause: FabricCiDecodeRefusal } + +// WHY A WIRE REFUSES, AND WHERE. The wire is the prefix then one six-hex-digit word per Unicode +// scalar, so a word is refused either because it is not six hex digits or because its value is not +// a scalar (std.unicode.scalar NotUnicodeScalar, carried as decoded, never defaulted). `at` is the +// word's offset in the wire. +type FabricCiDecodeRefusal + = FabricCiWireUnframed + | FabricCiWireEmpty + | FabricCiWordNotHex { at: Int } + | FabricCiWordNotScalar { at: Int, cause: NotUnicodeScalar } fn fabric_ci_hex_digit(n: Int) -> String { substring(s: "0123456789ABCDEF", start: n, end: n + 1) @@ -83,18 +95,20 @@ fn fabric_ci_decode_scalar(wire: String, at: Int) -> Int? { type FabricCiDecodeState = FabricCiDecodeBuilding { value: String } - | FabricCiDecodeRefused + | FabricCiDecodeRefused { cause: FabricCiDecodeRefusal } fn fabric_ci_decode_step(wire: String, at: Int, stop: Int, state: FabricCiDecodeState) -> FabricCiDecodeState { match state { - FabricCiDecodeRefused => FabricCiDecodeRefused + FabricCiDecodeRefused { cause: c } => FabricCiDecodeRefused { cause: c } FabricCiDecodeBuilding { value: value } => if at == stop { FabricCiDecodeBuilding { value: value } } else { match fabric_ci_decode_scalar(wire: wire, at: at) { - Absent => FabricCiDecodeRefused + Absent => FabricCiDecodeRefused { cause: FabricCiWordNotHex { at: at } } Present { value: cp } => - if cp > 1114111 || (cp >= 55296 && cp <= 57343) { FabricCiDecodeRefused } - else { fabric_ci_decode_step(wire: wire, at: at + 6, stop: stop, state: FabricCiDecodeBuilding { value: concat(value, from_code_point(cp)) }) } + match from_code_point(cp: cp) { + Err { value: n } => FabricCiDecodeRefused { cause: FabricCiWordNotScalar { at: at, cause: n } } + Ok { value: text } => fabric_ci_decode_step(wire: wire, at: at + 6, stop: stop, state: FabricCiDecodeBuilding { value: concat(value, text) }) + } } } } @@ -105,11 +119,11 @@ fn decode_fabric_ci_evidence_wire(wire: String) -> FabricCiEvidenceDecode { let payload_len = wire.length() - prefix_len if !starts_with(wire, prefix: fabric_ci_evidence_wire_prefix as String) || payload_len <= 0 || payload_len % 6 != 0 { - FabricCiEvidenceUndecodable + FabricCiEvidenceUndecodable { cause: FabricCiWireUnframed } } else { match fabric_ci_decode_step(wire: wire, at: prefix_len, stop: wire.length(), state: FabricCiDecodeBuilding { value: "" }) { - FabricCiDecodeRefused => FabricCiEvidenceUndecodable - FabricCiDecodeBuilding { value: "" } => FabricCiEvidenceUndecodable + FabricCiDecodeRefused { cause: c } => FabricCiEvidenceUndecodable { cause: c } + FabricCiDecodeBuilding { value: "" } => FabricCiEvidenceUndecodable { cause: FabricCiWireEmpty } FabricCiDecodeBuilding { value: value } => FabricCiEvidenceDecoded { value: value as NonEmptyStr } } } @@ -158,7 +172,7 @@ fn fabric_ci_calibration_transport_ignores_write_failure(path: String) -> Proces fn fabric_ci_calibration_assert_transport(wire: String) -> ProcessExit { match decode_fabric_ci_evidence_wire(wire: wire) { - FabricCiEvidenceUndecodable => exit_failure(reason: "FCI-EVIDENCE-0 transport undecodable") + FabricCiEvidenceUndecodable { cause: _ } => exit_failure(reason: "FCI-EVIDENCE-0 transport undecodable") FabricCiEvidenceDecoded { value: decoded } => if (decoded as String) == fabric_ci_calibration_projection_wire(value: FabricCiCalibrationAlpha { payload: "apostrophe-' newline-\n delimiter-|" }) { ExitSuccess @@ -176,7 +190,7 @@ fn fabric_ci_calibration_collapsed_projection_must_red() -> ProcessExit { fn fabric_ci_calibration_assert_beta_transport(wire: String) -> ProcessExit { match decode_fabric_ci_evidence_wire(wire: wire) { - FabricCiEvidenceUndecodable => exit_failure(reason: "FCI-EVIDENCE-0 beta transport undecodable") + FabricCiEvidenceUndecodable { cause: _ } => exit_failure(reason: "FCI-EVIDENCE-0 beta transport undecodable") FabricCiEvidenceDecoded { value: decoded } => if (decoded as String) == fabric_ci_calibration_projection_wire(value: FabricCiCalibrationBeta { payload: "different-value" }) { ExitSuccess } else { exit_failure(reason: "FCI-EVIDENCE-0 status did not distinguish transported values") } diff --git a/dag/gunbc/instruments/fabric_control_plane_live_probe.dag b/dag/gunbc/instruments/fabric_control_plane_live_probe.dag index 90b928cc191..522bff632ba 100644 --- a/dag/gunbc/instruments/fabric_control_plane_live_probe.dag +++ b/dag/gunbc/instruments/fabric_control_plane_live_probe.dag @@ -901,7 +901,7 @@ fn fci1_assert_allocation_available(root: NonEmptyStr) -> ProcessExit { fn fci1_allocation_restoration(root: NonEmptyStr, before_wire: String, held_wire: String) -> AllocationStoreRestoration { match decode_fabric_ci_evidence_wire(wire: before_wire) { - FabricCiEvidenceUndecodable => AllocationStoreRestorationRefused { path: root } + FabricCiEvidenceUndecodable { cause: _ } => AllocationStoreRestorationRefused { path: root } FabricCiEvidenceDecoded { value: before } => { let prestate = fci1_decode_allocation_prestate(wire: before as String) let poststate = fci1_allocation_prestate(root: root) @@ -1047,7 +1047,7 @@ fn fci1_canonical_cleanup_disposition( let observed = fci1_allocation_slot_observation(root: root) let observed_prestate = fci1_slot_observation_prestate(observed: observed) let disposition = match before_decoded { - FabricCiEvidenceUndecodable => CanonicalCleanupRefused { prestate: AllocationSlotUnreadable { path: root }, observed: observed } + FabricCiEvidenceUndecodable { cause: _ } => CanonicalCleanupRefused { prestate: AllocationSlotUnreadable { path: root }, observed: observed } FabricCiEvidenceDecoded { value: before_value } => { let prestate = fci1_decode_allocation_prestate(wire: before_value as String) let initial_disposition = if fci1_slot_prestate_equal(a: prestate, b: observed_prestate) { @@ -1185,7 +1185,7 @@ fn fci1_grade_and_write_allocation_receipt( let held_decoded = fci1_decode_transport_sample(wire: held_wire) let post = fci1_allocation_prestate(root: root) match before_decoded { - FabricCiEvidenceUndecodable => exit_failure(reason: "allocation receipt before observation undecodable") + FabricCiEvidenceUndecodable { cause: _ } => exit_failure(reason: "allocation receipt before observation undecodable") FabricCiEvidenceDecoded { value: before_value } => match held_decoded { RequiredBuildCellLifetimeSampleUndecodable => exit_failure(reason: "allocation receipt held observation undecodable") RequiredBuildCellLifetimeSampleDecoded { sample: held } => { @@ -1269,7 +1269,7 @@ fn fci1_assert_extra_generation_refused_control() -> ProcessExit { fn fci1_decode_transport_sample(wire: String) -> RequiredBuildCellLifetimeSampleDecode { match decode_fabric_ci_evidence_wire(wire: wire) { - FabricCiEvidenceUndecodable => RequiredBuildCellLifetimeSampleUndecodable + FabricCiEvidenceUndecodable { cause: _ } => RequiredBuildCellLifetimeSampleUndecodable FabricCiEvidenceDecoded { value: value } => decode_required_build_cell_lifetime_sample(wire: value as String) } } @@ -1539,7 +1539,7 @@ fn fci1_assert_cell_unchanged(before_wire: String) -> ProcessExit { cpu_quota_per_sec: _, base_owner_group: _, cell_owner_group: _, attempt_owner_group: _, } => match decode_fabric_ci_evidence_wire(wire: before_wire) { - FabricCiEvidenceUndecodable => exit_failure(reason: "persistent cell substrate before-wire undecodable") + FabricCiEvidenceUndecodable { cause: _ } => exit_failure(reason: "persistent cell substrate before-wire undecodable") FabricCiEvidenceDecoded { value: before } => if observed == (before as String) { ExitSuccess } else { exit_failure(reason: join(["persistent cell substrate changed; before=", before as String, "; after=", observed as String], "")) } @@ -1555,7 +1555,7 @@ fn fci1_grade_and_write_cell_receipt(before_wire: String, phase: NonEmptyStr, pa base_owner_group: base_owner, cell_owner_group: cell_owner, attempt_owner_group: attempt_owner, } => match decode_fabric_ci_evidence_wire(wire: before_wire) { - FabricCiEvidenceUndecodable => exit_failure(reason: "persistent cell substrate before-wire undecodable") + FabricCiEvidenceUndecodable { cause: _ } => exit_failure(reason: "persistent cell substrate before-wire undecodable") FabricCiEvidenceDecoded { value: before } => { let write = Filesystem.Write( path: path, diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 5e36acf3f38..56cda463606 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -9,8 +9,8 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R receipts: [ "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", - "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", - "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", + "POPULATION, KIND CHAR (79 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", + "POPULATION, KIND PARSER DECODE (5 identities, re-derived): first filed as 9. RETIRED: extdeps.languages.yaml.ingest::yaml_double_quoted_escape now routes NotUnicodeScalar into YamlScalarRefused, naming the escape and whether it was a surrogate or out of range (YAML 1.2.2 sections 5.1 and 5.7); its six CHAR siblings in the same module moved with it, because imports are per module. tools.fabric_ci_evidence::fabric_ci_decode_step routes it into FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at, cause } }. extdeps.languages.json.parse::json_unescape_decode_piece was DELETED: the .dag json_unescape chain had no consumer, and parse_json decodes through the native json_unescape_checked kernel, which recombines surrogate pairs and refuses an unpaired one (RFC 8259 section 7; RED test.claim.json_parse_witness::an_unpaired_surrogate_refuses_rather_than_vanishing). std.judgment_contract::string_from_code_points was CHAR-kind, not parser decode, because its input was chars(s) of a String; it was deleted for the declared std.coercion unicode_scalar_unfold / unicode_scalar_fold route. REMAINING, re-kinded as UNDER-TYPED UTF-8: each takes the code points that std.encoding utf8_decode_octets has already validated as scalars but returns as List, so the proof is thrown away and no NotUnicodeScalar RED is authorable at the call. The fix is construction (the decoder yields Char; callers use char_text), not routing: extdeps.http.form_urlencoded::form_component, extdeps.standards.rfc_8949::cbor_text_of_octets, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, and extdeps.uri::uri_percent_decode_component (a hand-rolled second UTF-8 decoder, to route through the one std decoder).", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", ], diff --git a/dag/std/judgment_contract.dag b/dag/std/judgment_contract.dag index 87465ee8bb1..75d08686361 100644 --- a/dag/std/judgment_contract.dag +++ b/dag/std/judgment_contract.dag @@ -26,6 +26,7 @@ import std.materialization_ladder { DemandNature } import std.cache_identity { ArtifactKindId } import std.content_hash { ContentHash, Fnv1a64Structural, fnv1a64_structural_hex_digest } import std.dissolution { DissolutionCondition, unbound_dissolution } +import std.coercion { unicode_scalar_fold, unicode_scalar_unfold } // PROGRESS ON THE CARVE-OUT ABOVE, stated narrowly so it is not read as the dissolution: the @@ -169,9 +170,6 @@ type DecodedDeclaredInputs { } -fn string_from_code_points(cs: List) -> String { - join(cs |> map(c => from_code_point(cp: c)), "") -} fn length_prefixed_encode(s: String) -> String { @@ -180,7 +178,7 @@ fn length_prefixed_encode(s: String) -> String { fn length_prefixed_decode(s: String) -> LengthPrefixedField? { - let cs = chars(s: s) + let cs = unicode_scalar_unfold(s: s) let scan = cs |> fold( init: LengthPrefixedScan { i: 0, hit: none }, f: (st, c) => @@ -197,22 +195,22 @@ fn length_prefixed_decode(s: String) -> LengthPrefixedField? { match scan.hit { Absent => none Present { value: hash_at } => { - let len_text = string_from_code_points(cs: cs |> take(n: hash_at)) - let after = string_from_code_points(cs: cs |> skip(n: hash_at + 1)) + let len_text = unicode_scalar_fold(xs: cs |> take(n: hash_at)) + let after = unicode_scalar_fold(xs: cs |> skip(n: hash_at + 1)) match parse_int(s: len_text) { Absent => none Present { value: n } => if n < 0 { none } else { - let after_cs = chars(s: after) + let after_cs = unicode_scalar_unfold(s: after) if (after_cs |> count()) < n { none } else { Present { value: LengthPrefixedField { - value: string_from_code_points(cs: after_cs |> take(n: n)), - rest: string_from_code_points(cs: after_cs |> skip(n: n)) + value: unicode_scalar_fold(xs: after_cs |> take(n: n)), + rest: unicode_scalar_fold(xs: after_cs |> skip(n: n)) } } } diff --git a/dag/std/materialization_provider.dag b/dag/std/materialization_provider.dag index 210df05ae0b..b86944cf20d 100644 --- a/dag/std/materialization_provider.dag +++ b/dag/std/materialization_provider.dag @@ -83,8 +83,7 @@ import std.judgment_contract { output_typed_module_interface, output_universe_module_import_closures, output_universe_test_identity_population, - persisted_output, - string_from_code_points + persisted_output } import std.decl_ref { DeclarationRef, WholeDeclaration } import std.dissolution { DissolutionCondition, unbound_dissolution } diff --git a/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag b/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag new file mode 100644 index 00000000000..e9af5544f57 --- /dev/null +++ b/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag @@ -0,0 +1,28 @@ +module test.claim.fabric_ci_evidence_wire_decode_witness + +import std.types { Bool, NonEmptyStr } +import std.unicode.scalar { SurrogateCodePoint, CodePointOutOfRange } +import tools.fabric_ci_evidence { + FabricCiEvidenceDecoded, FabricCiEvidenceUndecodable, FabricCiWordNotScalar, + decode_fabric_ci_evidence_wire, fabric_ci_evidence_wire, +} + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// THE WIRE IS ONE SIX-HEX-DIGIT WORD PER UNICODE SCALAR AFTER THE FCIE0X PREFIX. A word that names a +// surrogate or a value past U+10FFFF refuses. The refusal is typed (std.unicode.scalar +// NotUnicodeScalar, carried as is) and located at the word's offset in the wire, and it never +// decodes to fabricated text. The positive control round-trips through the real encoder, so the +// accepted path is the producer's own and not a designed fixture. + +test fn a_wire_the_encoder_wrote_decodes_back() -> Bool { + decode_fabric_ci_evidence_wire(wire: fabric_ci_evidence_wire(value: "a\u{10FFFF}" as NonEmptyStr)) + == FabricCiEvidenceDecoded { value: "a\u{10FFFF}" as NonEmptyStr } +} + +test fn red_a_non_scalar_word_refuses_typed_at_its_offset() -> Bool { + (decode_fabric_ci_evidence_wire(wire: "FCIE0X00004100D800") + == FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at: 12, cause: SurrogateCodePoint { code_point: 55296 } } }) + && (decode_fabric_ci_evidence_wire(wire: "FCIE0X110000") + == FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at: 6, cause: CodePointOutOfRange { code_point: 1114112 } } }) +} diff --git a/dag/test/claim/yaml_ingest_witness_test.dag b/dag/test/claim/yaml_ingest_witness_test.dag index beeee9521dd..5efc4e01c07 100644 --- a/dag/test/claim/yaml_ingest_witness_test.dag +++ b/dag/test/claim/yaml_ingest_witness_test.dag @@ -93,6 +93,16 @@ test fn red_an_invalid_escape_refuses_and_names_itself() -> Bool { && refuses_at(src: "a: \"a\" \"b\"\n", line: 1, reason_part: "unescaped") } +// A HEX ESCAPE MUST NAME A UNICODE SCALAR (YAML 1.2.2 sections 5.1, 5.7). A surrogate \uD800 and a +// \U past U+10FFFF each refuse at their line, and the refusal names the escape and which way it +// failed (std.unicode.scalar NotUnicodeScalar). Neither may decode to fabricated text. The +// neighbouring scalars U+D7FF and U+10FFFF still decode. +test fn red_a_non_scalar_hex_escape_refuses_typed_and_located() -> Bool { + refuses_at(src: "a: 1\nb: \"x \\uD800\"\n", line: 2, reason_part: "`\\uD800` names a surrogate code point") + && refuses_at(src: "a: \"\\U00110000\"\n", line: 1, reason_part: "`\\U00110000` is past U+10FFFF") + && reads(src: "a: \"\\uD7FF\\U0010FFFF\"\n", v: one(key: "a", v: str(s: "\u{D7FF}\u{10FFFF}"))) +} + test fn quoted_keys_decode() -> Bool { reads(src: "\"uses\": x\n'on': y\n", v: YamlMapping { entries: [ YamlKeyValue { key: "uses", value: str(s: "x") }, From 749fed4401451303beb9495a5e066596c8503a86 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 10:11:22 +0000 Subject: [PATCH 06/39] XL-2 CHAR follow-up: migrate 79 Char-by-construction from_code_point sites to std.unicode.scalar char_text Retires the CHAR population of RFM bare_from_code_point_binds_the_total_seed_builtin (6 extdeps.languages.yaml.ingest identities transferred to the parser-decode lane). Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/dns/domain_name.dag | 3 +- dag/extdeps/git/git.dag | 3 +- dag/extdeps/git/object_store.dag | 3 +- dag/extdeps/github/actions.dag | 3 +- dag/extdeps/languages/json/emit.dag | 3 +- dag/extdeps/languages/toml/emit.dag | 5 ++-- dag/extdeps/languages/yaml/emit.dag | 3 +- dag/extdeps/needrestart/needrestart.dag | 5 ++-- dag/extdeps/prometheus/client.dag | 3 +- dag/extdeps/unicode/display.dag | 3 +- dag/extdeps/uri.dag | 3 +- dag/gunbc/auth/approval_capability.dag | 3 +- dag/gunbc/harness/harness_turn.dag | 3 +- dag/gunbc/instruments/emit_host_transport.dag | 7 +++-- .../instruments/pr_containment_instrument.dag | 3 +- .../instruments/prose_citation_census.dag | 3 +- dag/gunbc/live_deploy/candidate.dag | 5 ++-- .../namespace_step0_subject_collector.dag | 11 ++++---- dag/gunbc/native_serve.dag | 3 +- ...ode_point_binds_the_total_seed_builtin.dag | 2 +- dag/gunbc/roadmap/roadmap_issue_query.dag | 3 +- dag/gunbc/rust_item_host_observation.dag | 3 +- .../stage0/stage0_rust_host_observation.dag | 3 +- dag/gunbc/v1/v1_interpreter_dispatch_emit.dag | 7 +++-- dag/std/content_hash.dag | 3 +- .../claim/char_at_unicode_witness_test.dag | 8 ++++-- dag/test/claim/git_ls_remote_witness_test.dag | 3 +- .../claim/git_upstream_model_witness_test.dag | 13 +++++---- .../claim/heal_candidate_witness_test.dag | 3 +- ...st_boot_attempt_admission_witness_test.dag | 5 ++-- dag/test/claim/json_emit_witness_test.dag | 14 ++++++---- dag/test/claim/json_parse_witness_test.dag | 28 ++++++++++--------- .../candidate_checkout_witness_test.dag | 3 +- ...deployed_tree_observation_witness_test.dag | 3 +- ...e_step0_subject_collector_witness_test.dag | 21 +++++++------- ...work_boot_manifest_broker_witness_test.dag | 3 +- ...r_containment_disposition_witness_test.dag | 3 +- .../roadmap_publish_observe_witness_test.dag | 3 +- .../serving_front_door_witness_test.dag | 3 +- ...ap_keys_interpreter_order_witness_test.dag | 8 ++++-- ...rant_privileged_operation_witness_test.dag | 11 ++++---- .../terminal_wire_projection_witness_test.dag | 5 ++-- dag/test/claim/yaml_emit_witness_test.dag | 4 ++- dag/test/claim/yaml_ingest_witness_test.dag | 16 ++++++----- 44 files changed, 151 insertions(+), 102 deletions(-) diff --git a/dag/extdeps/dns/domain_name.dag b/dag/extdeps/dns/domain_name.dag index 4223e041e7b..a06042a1e8b 100644 --- a/dag/extdeps/dns/domain_name.dag +++ b/dag/extdeps/dns/domain_name.dag @@ -1,5 +1,6 @@ module extdeps.dns.domain_name +import std.unicode.scalar { char_text } import std.types { NonEmptyStr, String, List, Bool, Int, brand } import std.error_primitives { Result, Ok, Err } @@ -71,7 +72,7 @@ fn fold_dns_case_string_at(s: String, i: Int, acc: String) -> String { let ch = char_at(s, i) let cp = code_point_int(ch: ch) let out = if cp >= 65 && cp <= 90 { - from_code_point(cp + 32) + char_text(c: cp + 32) } else { ch } diff --git a/dag/extdeps/git/git.dag b/dag/extdeps/git/git.dag index 27e15d676ea..a59196f5763 100644 --- a/dag/extdeps/git/git.dag +++ b/dag/extdeps/git/git.dag @@ -1,5 +1,6 @@ module extdeps.git +import std.unicode.scalar { char_text } import extdeps.exec.program { ProgramIdentity, uncataloged_program } import extdeps.external_authority { ExternalAuthority } @@ -136,7 +137,7 @@ type GitDiffNameStatusParseState { entries: List } -data git_diff_name_status_field_separator: String = from_code_point(0) +data git_diff_name_status_field_separator: String = char_text(c: 0) fn git_diff_change_status_from_token(token: String) -> GitDiffChangeStatus { let letter = substring(s: token, start: 0, end: 1) diff --git a/dag/extdeps/git/object_store.dag b/dag/extdeps/git/object_store.dag index 36711934906..13c6b138794 100644 --- a/dag/extdeps/git/object_store.dag +++ b/dag/extdeps/git/object_store.dag @@ -1,5 +1,6 @@ module extdeps.git.object_store +import std.unicode.scalar { char_text } import std.algebra { Cons, trim } import std.types { NonEmptyStr, Bytes, Map, brand, range, Bool, Int, List } @@ -928,7 +929,7 @@ fn git_store_object_canonical_hash_input( ), " ", to_string(count(payload_octets)), - from_code_point(0), + char_text(c: 0), ], "", ) diff --git a/dag/extdeps/github/actions.dag b/dag/extdeps/github/actions.dag index 1e37730c509..aa8c1be213a 100644 --- a/dag/extdeps/github/actions.dag +++ b/dag/extdeps/github/actions.dag @@ -1,5 +1,6 @@ module extdeps.github.actions +import std.unicode.scalar { char_text } import std.decl_ref { DeclarationRef, decl_ref } import extdeps.cron.schedule_model { CronSchedule } import extdeps.github.log_annotations { @@ -342,7 +343,7 @@ fn runner_arch_label(arch: Architecture) -> String { // DIFFERENT labels, which surfaces as a loud divergence rather than a silent match. fn runner_label_match_key(label: String) -> String { join( - label |> chars |> map(c => if c >= 65 && c <= 90 { from_code_point(cp: c + 32) } else { from_code_point(cp: c) }), + label |> chars |> map(c => if c >= 65 && c <= 90 { char_text(c: c + 32) } else { char_text(c: c) }), "", ) } diff --git a/dag/extdeps/languages/json/emit.dag b/dag/extdeps/languages/json/emit.dag index 02a0d47b69b..0d81b0a12b8 100644 --- a/dag/extdeps/languages/json/emit.dag +++ b/dag/extdeps/languages/json/emit.dag @@ -1,5 +1,6 @@ module extdeps.languages.json.emit +import std.unicode.scalar { char_text } import extdeps.external_authority { ExternalAuthority } import extdeps.languages.json.grammar { JsonNumberLexeme, json_int_lexeme, json_number_lexeme } import extdeps.numeric.base16 { int_to_upper_hex } @@ -101,7 +102,7 @@ data json_control_escape_code_points: List = [ ] fn json_escape_replace(s: String, code_point: Int, replacement: String) -> String { - join(split(s: s, delimiter: from_code_point(code_point)), replacement) + join(split(s: s, delimiter: char_text(c: code_point)), replacement) } fn json_escape_named_replacement(code_point: Int) -> String { diff --git a/dag/extdeps/languages/toml/emit.dag b/dag/extdeps/languages/toml/emit.dag index 866a91711cc..94d6ae44370 100644 --- a/dag/extdeps/languages/toml/emit.dag +++ b/dag/extdeps/languages/toml/emit.dag @@ -1,5 +1,6 @@ module extdeps.languages.toml.emit +import std.unicode.scalar { char_text } import std.types { Bool, String, List, Int } import v2.std.collection { list_at_optional } import v2.std.algebra { list_head, skip, HeadFound, HeadAbsent } @@ -77,7 +78,7 @@ fn toml_escape_remaining_control(point: Int) -> String { if (point < 32) || (point == 127) { concat("\\u00", concat(toml_hex_nibble(n: point / 16), toml_hex_nibble(n: point - ((point / 16) * 16)))) } else { - from_code_point(point) + char_text(c: point) } } @@ -152,7 +153,7 @@ fn toml_comment_lines(text: String) -> List { // rather than merely verbose. fn toml_comment_char(point: Int) -> String { if point == 9 { - from_code_point(point) + char_text(c: point) } else { toml_escape_remaining_control(point: point) } diff --git a/dag/extdeps/languages/yaml/emit.dag b/dag/extdeps/languages/yaml/emit.dag index 74f04b1b566..2a3b4886dc9 100644 --- a/dag/extdeps/languages/yaml/emit.dag +++ b/dag/extdeps/languages/yaml/emit.dag @@ -1,5 +1,6 @@ module extdeps.languages.yaml.emit +import std.unicode.scalar { char_text } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } import std.algebra { trim } @@ -321,7 +322,7 @@ fn yaml_emitted_text(text: String) -> YamlEmitResult { if yaml_contains_refused_character(text: text) { let cp = yaml_first_refused_character(text: text) YamlEmitRefused { - path: join(["line ", to_string(yaml_line_containing(lines: yaml_source_lines(src: text), pattern: from_code_point(cp: cp), index: 0)), " of the emitted text"], ""), + path: join(["line ", to_string(yaml_line_containing(lines: yaml_source_lines(src: text), pattern: char_text(c: cp), index: 0)), " of the emitted text"], ""), reason: yaml_refused_character_reason(cp: cp), } } else { diff --git a/dag/extdeps/needrestart/needrestart.dag b/dag/extdeps/needrestart/needrestart.dag index 9a2b9ce049e..35000ea2331 100644 --- a/dag/extdeps/needrestart/needrestart.dag +++ b/dag/extdeps/needrestart/needrestart.dag @@ -1,5 +1,6 @@ module extdeps.needrestart +import std.unicode.scalar { char_text } import std.types { String, NonEmptyStr, List, Bool, Int } import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } import extdeps.uri { Uri, Https } @@ -122,9 +123,9 @@ fn needrestart_unit_name_prefix(raw: String) -> NeedrestartUnitNamePrefixAdmissi // perlfunc quotemeta: every ASCII character that is not a word character is preceded by a backslash. fn needrestart_perl_quotemeta_code_point(cp: Int) -> String { if (cp >= 97 && cp <= 122) || (cp >= 65 && cp <= 90) || (cp >= 48 && cp <= 57) || cp == 95 { - from_code_point(cp: cp) + char_text(c: cp) } else { - concat("\\", from_code_point(cp: cp)) + concat("\\", char_text(c: cp)) } } diff --git a/dag/extdeps/prometheus/client.dag b/dag/extdeps/prometheus/client.dag index 79c7b177c61..908d7550657 100644 --- a/dag/extdeps/prometheus/client.dag +++ b/dag/extdeps/prometheus/client.dag @@ -1,5 +1,6 @@ module extdeps.prometheus.client +import std.unicode.scalar { char_text } import std.types { NonEmptyStr, String, Int, Bool } import std.decimal { ExactDecimal, ExactDecimalAdmitted, ExactDecimalScaleRefused, admit_exact_decimal, decimal_pow10 } import std.checked_arithmetic { checked_int_multiply, CheckedIntReady, CheckedIntOverflow } @@ -157,7 +158,7 @@ fn prometheus_scan_step(acc: SampleLexemeScan, ch: String) -> SampleLexemeScan { fn prometheus_scan_lexeme(body: String) -> SampleLexemeScan { fold(chars(body), init: SampleLexemeScan { mantissa_digits: "", fraction_digits: 0, exponent_text: "", exponent_sign_negative: false, in_fraction: false, in_exponent: false, ok: true }, f: (acc, cp) => - prometheus_scan_step(acc: acc, ch: from_code_point(cp: cp))) + prometheus_scan_step(acc: acc, ch: char_text(c: cp))) } // The scale after the exponent is folded in: fraction digits minus the exponent. A non-negative diff --git a/dag/extdeps/unicode/display.dag b/dag/extdeps/unicode/display.dag index cf3e726cfbf..a835be58aed 100644 --- a/dag/extdeps/unicode/display.dag +++ b/dag/extdeps/unicode/display.dag @@ -1,5 +1,6 @@ module extdeps.unicode.display +import std.unicode.scalar { char_text } import extdeps.unicode.blocks { zero_width_blocks, zero_width_codepoints, wide_blocks } import std.unicode.types { DisplayWidth, @@ -46,7 +47,7 @@ fn truncate_text(text: String, max_width: Int) -> String { f: (acc, c) => if acc.used + char_width(c: c) > max_width { acc } else { - { result: concat(acc.result, from_code_point(c)), used: acc.used + char_width(c: c) } + { result: concat(acc.result, char_text(c: c)), used: acc.used + char_width(c: c) } } ) state.result diff --git a/dag/extdeps/uri.dag b/dag/extdeps/uri.dag index d058412bba7..64880e5d63f 100644 --- a/dag/extdeps/uri.dag +++ b/dag/extdeps/uri.dag @@ -1,5 +1,6 @@ module extdeps.uri +import std.unicode.scalar { char_text } import std.algebra { trim } import std.types { NonEmptyStr, List } @@ -390,7 +391,7 @@ fn uri_validated_scalar_code_point(scalar: UriValidatedScalar) -> Int { fn uri_percent_encode_admitted_scalar_wire(scalar: UriValidatedScalar) -> UriPercentEncodeFoldState { let cp = uri_validated_scalar_code_point(scalar: scalar) if uri_component_is_unreserved(cp: cp) { - UriPercentEncodeBuilding { wire: from_code_point(cp: cp) } + UriPercentEncodeBuilding { wire: char_text(c: cp) } } else if cp < 128 { match uri_utf8_octet_construction(byte: cp) { UriUtf8OctetOutOfRangeRefused { value: v } => diff --git a/dag/gunbc/auth/approval_capability.dag b/dag/gunbc/auth/approval_capability.dag index 63d67ab9cfa..96ce63f1041 100644 --- a/dag/gunbc/auth/approval_capability.dag +++ b/dag/gunbc/auth/approval_capability.dag @@ -1,5 +1,6 @@ module gunbc.auth.approval_capability +import std.unicode.scalar { char_text } import std.types { NonEmptyStr, String, Int, Timestamp } import std.decimal { decimal_digit_char } import std.logic { Bool } @@ -136,7 +137,7 @@ type CapabilityExpectation { // The fields are joined by a unit separator rather than a comma or a colon precisely so that no // value can forge a boundary: an escalation id containing a comma would otherwise let one envelope // serialize identically to a different one, which is a signature collision authored in the data. -data signing_field_separator: String = from_code_point(cp: 31) +data signing_field_separator: String = char_text(c: 31) fn approval_capability_signing_input(c: ApprovalCapabilityClaims) -> NonEmptyStr { join( diff --git a/dag/gunbc/harness/harness_turn.dag b/dag/gunbc/harness/harness_turn.dag index 95dafdeeabb..8ed44de47d9 100644 --- a/dag/gunbc/harness/harness_turn.dag +++ b/dag/gunbc/harness/harness_turn.dag @@ -1,5 +1,6 @@ module gunbc.harness.harness_turn +import std.unicode.scalar { char_text } import std.types { String, Bool, Int, List, FilePath, NonEmptyStr } import std.measure { TokenCount, token_count_value, Second, second, second_count } import std.process { ProcessExit, ExitSuccess, ExitFailure } @@ -394,7 +395,7 @@ fn harness_worktree_files_changed(environment: HarnessToolEnvironment) -> Int? { if !status.success { none } else { - Present { value: list_length(items: split(s: status.entries_nul, delimiter: from_code_point(0)) |> filter(e => e != "")) } + Present { value: list_length(items: split(s: status.entries_nul, delimiter: char_text(c: 0)) |> filter(e => e != "")) } } } diff --git a/dag/gunbc/instruments/emit_host_transport.dag b/dag/gunbc/instruments/emit_host_transport.dag index 2fedb6a9311..244f679942b 100644 --- a/dag/gunbc/instruments/emit_host_transport.dag +++ b/dag/gunbc/instruments/emit_host_transport.dag @@ -1,5 +1,6 @@ module tools.emit_host_transport +import std.unicode.scalar { char_text } import std.occurrence_identity { OccurrenceSynthetic } import std.dissolution { DissolutionCondition, dissolution_description, unbound_dissolution } @@ -59,7 +60,7 @@ data fixture_cargo_toml: String = "[package]\nname = \"emit_host_fixture\"\nvers // go.Toolchain.RunFile, gunbc.WitnessBin.Run), never serialized bash. The former wc -c byte-count // check strengthened to CONTENT equality: the fixtures emit NUL bytes precisely because printable // output could pass a count check with wrong content; the expected string is built in-substrate from -// the same stdout_byte_count authority (repeat_string of from_code_point(0)), and NULs survive the +// the same stdout_byte_count authority (repeat_string of char_text(c: 0)), and NULs survive the // transport's trailing-whitespace trim. Cleanup runs unconditionally (the old set -e script leaked // the tempdir on mid-script failure). // @@ -90,7 +91,7 @@ data fixture_cargo_toml: String = "[package]\nname = \"emit_host_fixture\"\nvers data emit_host_ts_compilation_missing_trigger: DissolutionCondition = unbound_dissolution(description: "🟡 dissolve-on: hermetic TypeScript compilation — run_ts_smoke now routes through typed Filesystem.Write, shell.Mktemp/Remove, typescript.Compiler.Compile and node.Runtime.RunFile; its concatenated heredoc and conditional node provisioning are dissolved. typescript.Compiler.Compile still uses npx to fetch typescript@5.9.2 at runtime: typing the operation does not discharge this compile hermeticity gap. DISSOLVES WHEN a hermetic TypeScript compilation authority compiles the fixture without runtime package fetch and run_ts_smoke consumes it.") fn expected_stdout_nul_run() -> String { - repeat_string(s: from_code_point(0), n: byte_size_count(stdout_byte_count)) + repeat_string(s: char_text(c: 0), n: byte_size_count(stdout_byte_count)) } fn run_rust_smoke() -> Bool { @@ -178,7 +179,7 @@ fn run_ts_smoke() -> Bool { ) let run = node.Runtime.RunFile(workdir: dir.path, script_path: concat(dir.path, "/fixture.js")) let cleanup = shell.Remove.RecursiveForce(path: dir.path) - let expected = concat(from_code_point(ts_host_fixture_expected_sum), repeat_string(s: from_code_point(0), n: byte_size_count(ts_signed_i32_le_byte_count) - 1)) + let expected = concat(char_text(c: ts_host_fixture_expected_sum), repeat_string(s: char_text(c: 0), n: byte_size_count(ts_signed_i32_le_byte_count) - 1)) dir.success && src.success && compile.success && run.success && cleanup.success && (run.stdout == expected) } diff --git a/dag/gunbc/instruments/pr_containment_instrument.dag b/dag/gunbc/instruments/pr_containment_instrument.dag index 1044ae0dbd4..17a4ba7046d 100644 --- a/dag/gunbc/instruments/pr_containment_instrument.dag +++ b/dag/gunbc/instruments/pr_containment_instrument.dag @@ -1,5 +1,6 @@ module tools.pr_containment_instrument +import std.unicode.scalar { char_text } import std.types { Bool, FilePath, GitRef, Int, List, Map, NonEmptyStr, String } import std.algebra { trim } import std.process { ProcessExit, ExitSuccess, exit_failure } @@ -227,7 +228,7 @@ fn observed_merge_driver() -> String { fn base_path_set(paths_nul: String) -> Map { fold( - filter(split(s: paths_nul, delimiter: from_code_point(0)), p => p != ""), + filter(split(s: paths_nul, delimiter: char_text(c: 0)), p => p != ""), init: empty_map(), f: (acc, p) => map_insert(acc, p, true) ) diff --git a/dag/gunbc/instruments/prose_citation_census.dag b/dag/gunbc/instruments/prose_citation_census.dag index 9891c6ecab6..ec27503e1b2 100644 --- a/dag/gunbc/instruments/prose_citation_census.dag +++ b/dag/gunbc/instruments/prose_citation_census.dag @@ -1,5 +1,6 @@ module tools.prose_citation_census +import std.unicode.scalar { char_text } import std.types { Bool, Int, String, GitRef, List, Map } import std.algebra { trim } import std.decl_ref { DeclarationRef, WholeDeclaration } @@ -696,7 +697,7 @@ fn prose_citation_render(census: ProseCitationCensus) -> String { // their own census until they were committed, and the first run that includes them reports their prose // among the sites. fn prose_citation_dag_source_paths(paths_nul: String) -> List { - split(s: paths_nul, delimiter: from_code_point(cp: 0)) + split(s: paths_nul, delimiter: char_text(c: 0)) |> filter(p => ends_with(s: p, suffix: ".dag") && prose_citation_path_under_roots(path: p)) } diff --git a/dag/gunbc/live_deploy/candidate.dag b/dag/gunbc/live_deploy/candidate.dag index 38449b1ffb6..ec5c85b2784 100644 --- a/dag/gunbc/live_deploy/candidate.dag +++ b/dag/gunbc/live_deploy/candidate.dag @@ -1,5 +1,6 @@ module gunbc.live_deploy.candidate +import std.unicode.scalar { char_text } import gunbc.live_deploy.candidate_identity { CandidateRelease } import extdeps.git import gunbc.output_policy { ExpectSuccess } @@ -157,7 +158,7 @@ fn scan_checkout_status_field(acc: CheckoutStatusScan, field: String) -> Checkou fn scan_checkout_status(entries_nul: String) -> CheckoutStatusScan { fold( - split(s: entries_nul, delimiter: from_code_point(0)), + split(s: entries_nul, delimiter: char_text(c: 0)), init: CheckoutStatusScan { staged: [], tracked: [], @@ -171,7 +172,7 @@ fn scan_checkout_status(entries_nul: String) -> CheckoutStatusScan { fn scan_ignored_deployed_paths(paths_nul: String) -> List { fold( - split(s: paths_nul, delimiter: from_code_point(0)), + split(s: paths_nul, delimiter: char_text(c: 0)), init: [], f: (acc, path) => if path != "" && path_is_deployed(path: path) { list_append(acc, [path]) } else { acc }, diff --git a/dag/gunbc/namespace/namespace_step0_subject_collector.dag b/dag/gunbc/namespace/namespace_step0_subject_collector.dag index f674cf8aa83..b73620b8117 100644 --- a/dag/gunbc/namespace/namespace_step0_subject_collector.dag +++ b/dag/gunbc/namespace/namespace_step0_subject_collector.dag @@ -1,5 +1,6 @@ module gunbc.namespace_step0_subject_collector +import std.unicode.scalar { char_text } import std.types { Bool, GitRef, Int, List, NonEmptyStr, String } import std.algebra { trim } import std.content_hash { Fnv1a64Structural, content_hash_atom, content_hash_combine_structural } @@ -243,14 +244,14 @@ fn step0_record_field_step(acc: Step0RecordFields, part: String) -> Step0RecordF fn step0_decode_tree_entry(record: String) -> Step0TreeEntryDecode { let fields = fold( - split(s: record, delimiter: from_code_point(9)), + split(s: record, delimiter: char_text(c: 9)), init: Step0RecordFields { seen: 0, meta: "", path_parts: [] }, f: fn(acc, part) { step0_record_field_step(acc: acc, part: part) } ) if fields.seen < 2 { Step0TreeEntryUndecodable { record: record } } else { - let path = join(fields.path_parts, from_code_point(9)) + let path = join(fields.path_parts, char_text(c: 9)) let meta_fields = split(s: fields.meta, delimiter: " ") match get(xs: meta_fields, index: 0) { Absent => Step0TreeEntryUndecodable { record: record } @@ -288,11 +289,11 @@ fn step0_entry_is_regular_blob(entry: Step0TreeEntry) -> Bool { // arrive as the text this collector hands a parser. Selecting on the .dag suffix should mean this // never fires; it is the arm that keeps "never" from being an assumption. fn step0_content_is_text(content: String) -> Bool { - !contains(s: content, substring: from_code_point(0)) + !contains(s: content, substring: char_text(c: 0)) } fn step0_subject_entries_at(entries_nul: String) -> List { - fold(split(s: entries_nul, delimiter: from_code_point(0)), init: [], f: fn(acc, record) { + fold(split(s: entries_nul, delimiter: char_text(c: 0)), init: [], f: fn(acc, record) { if record == "" { acc } else { acc |> list_push(record) } }) } @@ -315,7 +316,7 @@ fn step0_absent_declared_roots(paths: List) -> List { } fn step0_subject_paths_at(paths_nul: String) -> List { - fold(split(s: paths_nul, delimiter: from_code_point(0)), init: [], f: fn(acc, path) { + fold(split(s: paths_nul, delimiter: char_text(c: 0)), init: [], f: fn(acc, path) { if step0_path_in_subject(path: path) { acc |> list_push(path) } else { acc } }) } diff --git a/dag/gunbc/native_serve.dag b/dag/gunbc/native_serve.dag index bddc473fc97..ddb5017ae08 100644 --- a/dag/gunbc/native_serve.dag +++ b/dag/gunbc/native_serve.dag @@ -1,5 +1,6 @@ module gunbc.native_serve +import std.unicode.scalar { char_text } import std.types { Int, List, String, Bool, CommitSha } import std.measure { ByteSize, byte_size, byte_size_count, Millisecond, millisecond, millisecond_count } import std.algebra { Cons, Empty, trim } @@ -369,7 +370,7 @@ type NativeServeOutgoing { fn native_serve_value_is_field_safe(value: String) -> Bool { (split(s: value, delimiter: "\r") |> count) == 1 && (split(s: value, delimiter: "\n") |> count) == 1 - && (split(s: value, delimiter: from_code_point(0)) |> count) == 1 + && (split(s: value, delimiter: char_text(c: 0)) |> count) == 1 } fn native_serve_unwritable(reason: String) -> NativeServeOutgoing { diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 5e36acf3f38..28cd4f3df14 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -9,7 +9,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R receipts: [ "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", - "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", + "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text and needs no refusal. DISPOSITION: 79 MIGRATED to std.unicode.scalar char_text by the XL-2 CHAR follow-up PR (session sleek-fox-462): extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located. 6 TRANSFERRED, not migrated here, to the PARSER DECODE lane, which migrates extdeps.languages.yaml.ingest whole because importing std.unicode.scalar rebinds the module: extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source.", "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", diff --git a/dag/gunbc/roadmap/roadmap_issue_query.dag b/dag/gunbc/roadmap/roadmap_issue_query.dag index 6ffdfaa9eb5..9c56641b79b 100644 --- a/dag/gunbc/roadmap/roadmap_issue_query.dag +++ b/dag/gunbc/roadmap/roadmap_issue_query.dag @@ -1,5 +1,6 @@ module gunbc.roadmap_issue_query +import std.unicode.scalar { char_text } import std.types { String, Int, Bool, List } import gunbc.roadmap_view_preferences { IssueViewPreferences, ViewSortTerm, ViewAscending } import extdeps.google.issue_tracker { issue_results_sort_key_wire } @@ -12,7 +13,7 @@ import extdeps.languages.json.parse { parse_json_document, JsonDocumentParsed, J type IssueQueryRow { node_id: String, project: String, band: String, search: String, title: String, assignee: String, priority: Int, status: Int, html: String } data issue_query_separator: String = "\n\n" fn issue_query_fold(text: String) -> String { - join(map(text.chars(), cp => from_code_point(if cp >= 65 && cp <= 90 { cp + 32 } else { cp })), "") + join(map(text.chars(), cp => char_text(c: if cp >= 65 && cp <= 90 { cp + 32 } else { cp })), "") } fn issue_query_wire_field(fields: List, position: Int) -> String { match fields.skip(n: position).first() { Present { value } => value Absent => "" } diff --git a/dag/gunbc/rust_item_host_observation.dag b/dag/gunbc/rust_item_host_observation.dag index 7bb2cce7159..8c26217e009 100644 --- a/dag/gunbc/rust_item_host_observation.dag +++ b/dag/gunbc/rust_item_host_observation.dag @@ -1,5 +1,6 @@ module gunbc.rust_item_host_observation +import std.unicode.scalar { char_text } import extdeps.git import std.decimal { decimal_digit_char } import extdeps.git.inspect @@ -1031,7 +1032,7 @@ fn current_rust_item_change_observation() -> RustItemChangeObservation { fn rust_paths_from_nul(raw: String) -> List { filter( - xs: split(s: raw, delimiter: from_code_point(0)), + xs: split(s: raw, delimiter: char_text(c: 0)), predicate: fn(path) { path_is_rust_source(path: path) } ) } diff --git a/dag/gunbc/stage0/stage0_rust_host_observation.dag b/dag/gunbc/stage0/stage0_rust_host_observation.dag index d6e88c27085..93012b1902d 100644 --- a/dag/gunbc/stage0/stage0_rust_host_observation.dag +++ b/dag/gunbc/stage0/stage0_rust_host_observation.dag @@ -1,5 +1,6 @@ module gunbc.stage0_rust_host_observation +import std.unicode.scalar { char_text } import std.algebra { trim, list_snoc_item } import extdeps.git @@ -90,7 +91,7 @@ fn git_refusal_detail(operation: String, stderr: String) -> String { fn rust_paths_from_nul(raw: String) -> List { filter( - xs: split(s: raw, delimiter: from_code_point(0)), + xs: split(s: raw, delimiter: char_text(c: 0)), predicate: fn(path) { let n = string_length(s: path) n >= 3 && substring(s: path, start: n - 3, end: n) == ".rs" diff --git a/dag/gunbc/v1/v1_interpreter_dispatch_emit.dag b/dag/gunbc/v1/v1_interpreter_dispatch_emit.dag index 79af0214217..1a8dae4246c 100644 --- a/dag/gunbc/v1/v1_interpreter_dispatch_emit.dag +++ b/dag/gunbc/v1/v1_interpreter_dispatch_emit.dag @@ -1,5 +1,6 @@ module gunbc.v1_interpreter_dispatch_emit +import std.unicode.scalar { char_text } import std.types { List } import extdeps.languages.rust.string_literal { escape_rust_cooked_string_literal_body } @@ -20,9 +21,9 @@ import v2.std.text { String } fn to_upper_char(ch: Int) -> String { let cp = ch if cp >= 97 && cp <= 122 { - from_code_point(cp: cp - 32) + char_text(c: cp - 32) } else { - from_code_point(cp: ch) + char_text(c: ch) } } @@ -37,7 +38,7 @@ fn capitalize_first(s: String) -> String { if pair.first == 0 { to_upper_char(ch: pair.second) } else { - from_code_point(cp: pair.second) + char_text(c: pair.second) }) |> join(separator: "") } diff --git a/dag/std/content_hash.dag b/dag/std/content_hash.dag index eeee516268e..14ce296e029 100644 --- a/dag/std/content_hash.dag +++ b/dag/std/content_hash.dag @@ -1,5 +1,6 @@ module std.content_hash +import std.unicode.scalar { char_text } import std.types { NonEmptyStr, String, Bool } // CRYPTOGRAPHIC CARRIER WALL (reviews 45441/45460/45496; same law as extdeps.git.object_store @@ -169,7 +170,7 @@ fn content_hash_atom(value: NonEmptyStr) -> Fnv1a64Structural { // preimage is the family kernel `content_hash_atom`, a target-kernel realization until the // fixed-width word and UTF-8 byte substrates let the kernel itself be modeled (gunbc#11637). fn content_hash_combine_preimage(left: Fnv1a64Structural, right: Fnv1a64Structural) -> NonEmptyStr { - concat(concat(left.digest as String, from_code_point(0)), right.digest as String) as NonEmptyStr + concat(concat(left.digest as String, char_text(c: 0)), right.digest as String) as NonEmptyStr } fn content_hash_combine_structural(left: Fnv1a64Structural, right: Fnv1a64Structural) -> Fnv1a64Structural { diff --git a/dag/test/claim/char_at_unicode_witness_test.dag b/dag/test/claim/char_at_unicode_witness_test.dag index e8aa6849a16..3bbc82bdff6 100644 --- a/dag/test/claim/char_at_unicode_witness_test.dag +++ b/dag/test/claim/char_at_unicode_witness_test.dag @@ -1,5 +1,7 @@ module test.claim.char_at_unicode_witness +import std.unicode.scalar { char_text } + data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // CHARAT-0 discriminating control: char_at indexes Unicode code points, not UTF-8 bytes. A @@ -7,7 +9,7 @@ data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // U+00A9 misread as ©) while code-point indexing returns U+00E9. fn ae_b_sample() -> String { - concat("a", concat(from_code_point(cp: 233), "b")) + concat("a", concat(char_text(c: 233), "b")) } test fn char_at_indexes_code_points_on_multibyte_text() -> Bool { @@ -37,7 +39,7 @@ test fn string_length_counts_code_points_not_bytes() -> Bool { // rather than one that has never been seen to fail. fn ab_e_c_sample() -> String { - concat("ab", concat(from_code_point(cp: 233), "c")) + concat("ab", concat(char_text(c: 233), "c")) } test fn char_at_agrees_across_the_ascii_prefix_boundary() -> Bool { @@ -50,5 +52,5 @@ test fn char_at_agrees_across_the_ascii_prefix_boundary() -> Bool { test fn char_at_past_the_multibyte_char_is_not_a_byte_offset() -> Bool { let s = ab_e_c_sample() - char_at(s: s, pos: 3) != from_code_point(cp: 169) && char_at(s: s, pos: 4) == "" + char_at(s: s, pos: 3) != char_text(c: 169) && char_at(s: s, pos: 4) == "" } diff --git a/dag/test/claim/git_ls_remote_witness_test.dag b/dag/test/claim/git_ls_remote_witness_test.dag index c7c76d84225..a1ff10cc933 100644 --- a/dag/test/claim/git_ls_remote_witness_test.dag +++ b/dag/test/claim/git_ls_remote_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.git_ls_remote_witness_test +import std.unicode.scalar { char_text } import std.types { Bool, String, Int, List, CommitSha } import extdeps.git { AdvertisedRef, @@ -16,7 +17,7 @@ data witness_scope_note: String = "What is claimed is the READING of a ref adver data fixture_sha_a: String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" data fixture_sha_b: String = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -fn tab() -> String { from_code_point(cp: 9) } +fn tab() -> String { char_text(c: 9) } fn line_of(sha: String, ref_name: String) -> String { concat(sha, concat(tab(), ref_name)) diff --git a/dag/test/claim/git_upstream_model_witness_test.dag b/dag/test/claim/git_upstream_model_witness_test.dag index 39e542d7afc..54c119c432e 100644 --- a/dag/test/claim/git_upstream_model_witness_test.dag +++ b/dag/test/claim/git_upstream_model_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.git_upstream_model_witness +import std.unicode.scalar { char_text } import extdeps.git { GitAuthor, BlobObj, @@ -667,8 +668,8 @@ test fn witness_git_tree_entry_names_refuse_empty_slash_and_nul() -> Bool { fn ls_tree_z_record(mode: String, object_type: String, oid_hex: String, name: String) -> String { let space = " " - let tab = from_code_point(9) - let nul = from_code_point(0) + let tab = char_text(c: 9) + let nul = char_text(c: 0) concat( concat(join([mode, object_type, oid_hex], space), tab), concat(name, nul), @@ -733,7 +734,7 @@ test fn witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows() -> test fn witness_git_ls_tree_z_preserves_non_utf8_path_octets() -> Bool { let space = " " - let tab = from_code_point(9) + let tab = char_text(c: 9) let header = concat( join( [ @@ -787,7 +788,7 @@ test fn witness_git_object_id_text_has_one_canonical_spelling() -> Bool { test fn witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path() -> Bool { let space = " " - let tab = from_code_point(9) + let tab = char_text(c: 9) let header = concat( join( [ @@ -824,7 +825,7 @@ test fn witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path() test fn witness_git_index_path_preserves_component_boundaries() -> Bool { let space = " " - let tab = from_code_point(9) + let tab = char_text(c: 9) let header = concat( join( [ @@ -861,7 +862,7 @@ test fn witness_git_index_path_preserves_component_boundaries() -> Bool { test fn witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact() -> Bool { let space = " " - let tab = from_code_point(9) + let tab = char_text(c: 9) let header = concat( join( [ diff --git a/dag/test/claim/heal_candidate_witness_test.dag b/dag/test/claim/heal_candidate_witness_test.dag index 0eb2b6fb75a..c4953dd4096 100644 --- a/dag/test/claim/heal_candidate_witness_test.dag +++ b/dag/test/claim/heal_candidate_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.heal_candidate_witness +import std.unicode.scalar { char_text } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import v2.std.optional { Present, Absent } import std.types { String, NonEmptyStr, Bool } @@ -49,7 +50,7 @@ fn oid(hex: String) -> GitObjectId { } fn stage_record(mode: String, hex: String, stage: String, path: String) -> String { - join([mode, " ", hex, " ", stage, from_code_point(9), path, from_code_point(0)], "") + join([mode, " ", hex, " ", stage, char_text(c: 9), path, char_text(c: 0)], "") } fn design_record(mode: String, stage: String) -> String { diff --git a/dag/test/claim/host/host_boot_attempt_admission_witness_test.dag b/dag/test/claim/host/host_boot_attempt_admission_witness_test.dag index 2414dde5b5d..cd777a0d564 100644 --- a/dag/test/claim/host/host_boot_attempt_admission_witness_test.dag +++ b/dag/test/claim/host/host_boot_attempt_admission_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.host_boot_attempt_admission_witness +import std.unicode.scalar { char_text } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import v2.std.algebra { any } import std.types { Bool, Int, List, NonEmptyStr, String } @@ -287,8 +288,8 @@ test fn w_no_named_receipt_leaves_every_field_not_recorded() -> Bool { } // ── THE TRACKED BLOB: only a regular file tracked at the revision can be a receipt ─────────────── -fn tab() -> String { from_code_point(9) } -fn nul() -> String { from_code_point(0) } +fn tab() -> String { char_text(c: 9) } +fn nul() -> String { char_text(c: 0) } fn refusal_tag_of(c: AttemptReceiptRefusal?) -> String { match c { diff --git a/dag/test/claim/json_emit_witness_test.dag b/dag/test/claim/json_emit_witness_test.dag index afb30cbb438..1a7586c0774 100644 --- a/dag/test/claim/json_emit_witness_test.dag +++ b/dag/test/claim/json_emit_witness_test.dag @@ -1,5 +1,7 @@ module test.claim.json_emit_witness +import std.unicode.scalar { char_text } + data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly test fn witness_json_cites_rfc8259() -> Bool { @@ -17,15 +19,15 @@ test fn witness_escape_newline() -> Bool { } test fn witness_escape_tab() -> Bool { - escape_json_string(s: concat("a", concat(from_code_point(cp: 9), "b"))) == "a\\tb" + escape_json_string(s: concat("a", concat(char_text(c: 9), "b"))) == "a\\tb" } test fn witness_escape_carriage_return() -> Bool { - escape_json_string(s: concat("x", concat(from_code_point(cp: 13), "y"))) == "x\\ry" + escape_json_string(s: concat("x", concat(char_text(c: 13), "y"))) == "x\\ry" } test fn witness_escape_control_u0001() -> Bool { - escape_json_string(s: from_code_point(cp: 1)) == "\\u0001" + escape_json_string(s: char_text(c: 1)) == "\\u0001" } // THE PASS DECOMPOSITION'S LOAD-BEARING ORDER, pinned: the backslash pass leads, so a literal @@ -33,12 +35,12 @@ test fn witness_escape_control_u0001() -> Bool { // control range is covered to its top, so cp 31 escapes as \u001f exactly as the per-char fold // produced it. Both rows red the moment a pass is reordered or dropped. test fn witness_escape_backslash_leads_over_newline() -> Bool { - escape_json_string(s: concat(from_code_point(cp: 92), from_code_point(cp: 10))) == "\\\\\\n" + escape_json_string(s: concat(char_text(c: 92), char_text(c: 10))) == "\\\\\\n" } test fn witness_escape_control_top_of_range() -> Bool { - escape_json_string(s: from_code_point(cp: 31)) == "\\u001F" - && escape_json_string(s: from_code_point(cp: 11)) == "\\u000B" + escape_json_string(s: char_text(c: 31)) == "\\u001F" + && escape_json_string(s: char_text(c: 11)) == "\\u000B" } test fn witness_escape_combined_source_text() -> Bool { diff --git a/dag/test/claim/json_parse_witness_test.dag b/dag/test/claim/json_parse_witness_test.dag index f36a3fab6e7..8f83cfcf37f 100644 --- a/dag/test/claim/json_parse_witness_test.dag +++ b/dag/test/claim/json_parse_witness_test.dag @@ -1,5 +1,7 @@ module test.claim.json_parse_witness +import std.unicode.scalar { char_text } + data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // parse_json is the forward reading of RFC 8259 and serialize_json is the backward one, so the @@ -65,13 +67,13 @@ test fn trailing_content_after_a_complete_value_is_refused_as_trailing() -> Bool } test fn a_newline_inside_a_string_survives_the_round_trip() -> Bool { - let expected = concat("a", concat(from_code_point(cp: 10), "b")) + let expected = concat("a", concat(char_text(c: 10), "b")) parsed_string_of(text: "\"a\\nb\"") == expected && round_trips(text: "\"a\\nb\"") } test fn a_tab_inside_a_string_survives_the_round_trip() -> Bool { - let expected = concat("a", concat(from_code_point(cp: 9), "b")) + let expected = concat("a", concat(char_text(c: 9), "b")) parsed_string_of(text: "\"a\\tb\"") == expected && round_trips(text: "\"a\\tb\"") } @@ -86,7 +88,7 @@ test fn a_literal_backslash_t_does_not_become_a_tab() -> Bool { let two_chars = concat("\\", "t") let emitted = serialize_json(v: JsonString { value: two_chars }) parsed_string_of(text: emitted) == two_chars - && parsed_string_of(text: emitted) != from_code_point(cp: 9) + && parsed_string_of(text: emitted) != char_text(c: 9) } test fn a_unicode_escape_is_decoded_not_passed_through() -> Bool { @@ -94,7 +96,7 @@ test fn a_unicode_escape_is_decoded_not_passed_through() -> Bool { } test fn a_control_character_with_no_short_escape_survives_the_round_trip() -> Bool { - let vertical_tab = from_code_point(cp: 11) + let vertical_tab = char_text(c: 11) parsed_string_of(text: "\"\\u000B\"") == vertical_tab && round_trips(text: "\"\\u000B\"") && serialize_json(v: JsonString { value: vertical_tab }) == "\"\\u000B\"" @@ -102,18 +104,18 @@ test fn a_control_character_with_no_short_escape_survives_the_round_trip() -> Bo test fn every_control_character_an_emitter_escapes_comes_back_unchanged() -> Bool { let sample = concat( - from_code_point(cp: 1), - concat(from_code_point(cp: 9), - concat(from_code_point(cp: 10), - concat(from_code_point(cp: 11), - concat(from_code_point(cp: 27), from_code_point(cp: 31))))), + char_text(c: 1), + concat(char_text(c: 9), + concat(char_text(c: 10), + concat(char_text(c: 11), + concat(char_text(c: 27), char_text(c: 31))))), ) parsed_string_of(text: serialize_json(v: JsonString { value: sample })) == sample } test fn a_lowercase_hex_escape_decodes_the_same_as_uppercase() -> Bool { parsed_string_of(text: "\"\\u001b\"") == parsed_string_of(text: "\"\\u001B\"") - && parsed_string_of(text: "\"\\u001B\"") == from_code_point(cp: 27) + && parsed_string_of(text: "\"\\u001B\"") == char_text(c: 27) } fn parses(text: String) -> Bool { @@ -208,9 +210,9 @@ test fn a_forged_verdict_escape_does_not_survive_into_a_string() -> Bool { // a dropped character. Both answer false against the old kernel. test fn a_surrogate_pair_decodes_to_its_one_scalar() -> Bool { - parsed_string_of(text: "\"\\uD83D\\uDE00\"") == from_code_point(cp: 128512) - && parsed_string_of(text: "\"a\\ud83d\\ude00b\"") == "a" + from_code_point(cp: 128512) + "b" - && parsed_string_of(text: "\"\\uDBFF\\uDFFF\"") == from_code_point(cp: 1114111) + parsed_string_of(text: "\"\\uD83D\\uDE00\"") == char_text(c: 128512) + && parsed_string_of(text: "\"a\\ud83d\\ude00b\"") == "a" + char_text(c: 128512) + "b" + && parsed_string_of(text: "\"\\uDBFF\\uDFFF\"") == char_text(c: 1114111) } test fn an_unpaired_surrogate_refuses_rather_than_vanishing() -> Bool { diff --git a/dag/test/claim/live_deploy/candidate_checkout_witness_test.dag b/dag/test/claim/live_deploy/candidate_checkout_witness_test.dag index 4479a4b9490..ccae6196cfe 100644 --- a/dag/test/claim/live_deploy/candidate_checkout_witness_test.dag +++ b/dag/test/claim/live_deploy/candidate_checkout_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.live_deploy.candidate_checkout_witness_test +import std.unicode.scalar { char_text } import std.types { Bool, String, List, Int } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import gunbc.live_deploy.deployed_tree_scope { @@ -34,7 +35,7 @@ data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // untracked-in-dag claim differ in exactly the prefix. fn nul() -> String { - from_code_point(0) + char_text(c: 0) } fn status_of(fields: List) -> String { diff --git a/dag/test/claim/live_deploy/deployed_tree_observation_witness_test.dag b/dag/test/claim/live_deploy/deployed_tree_observation_witness_test.dag index 99298dc9f24..e0e2d4083b2 100644 --- a/dag/test/claim/live_deploy/deployed_tree_observation_witness_test.dag +++ b/dag/test/claim/live_deploy/deployed_tree_observation_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.live_deploy.deployed_tree_observation_witness +import std.unicode.scalar { char_text } import std.types { String, NonEmptyStr, List, Bool } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import extdeps.git @@ -169,7 +170,7 @@ test fn witness_read_tree_argv_is_admitted_by_the_portability_wall() -> Bool { // NUL-separated ignored path list -- rather than with a pre-digested sentence, so a change to the // scanner reds these rather than passing on a shape nothing produces. fn nul() -> String { - from_code_point(0) + char_text(c: 0) } fn nul_join(fields: List) -> String { diff --git a/dag/test/claim/namespace_step0_subject_collector_witness_test.dag b/dag/test/claim/namespace_step0_subject_collector_witness_test.dag index d7abc16b9e1..cb2f3be2573 100644 --- a/dag/test/claim/namespace_step0_subject_collector_witness_test.dag +++ b/dag/test/claim/namespace_step0_subject_collector_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.namespace_step0_subject_collector_witness +import std.unicode.scalar { char_text } import std.types { Bool, Int, List, NonEmptyStr, String } import gunbc.compile_diagnostic_census { CompileDiagnosticCensus, @@ -156,16 +157,16 @@ fn paths_contain(xs: List, want: String) -> Bool { // producing a wider "subject" under the manifest's name. test fn the_subject_filter_takes_dag_sources_under_the_contract_roots_only() -> Bool { let blob = concat( - concat("dag/std/types.dag", from_code_point(0)), + concat("dag/std/types.dag", char_text(c: 0)), concat( - concat("src/v2/std/algebra.dag", from_code_point(0)), + concat("src/v2/std/algebra.dag", char_text(c: 0)), concat( - concat("src/v1/02_parse.dag", from_code_point(0)), + concat("src/v1/02_parse.dag", char_text(c: 0)), concat( - concat("README.md", from_code_point(0)), + concat("README.md", char_text(c: 0)), concat( - concat("src/v1/stage0/src/lib.rs", from_code_point(0)), - concat("docs/plans/namespace-cut-replacement-plan.md", from_code_point(0)) + concat("src/v1/stage0/src/lib.rs", char_text(c: 0)), + concat("docs/plans/namespace-cut-replacement-plan.md", char_text(c: 0)) ) ) ) @@ -249,7 +250,7 @@ test fn a_declared_root_with_no_members_refuses_rather_than_narrowing_the_subjec // than being skipped -- a skipped record is an entry the collector never enumerated, which is the // empty-observation narrow one layer below the vector. test fn a_tree_record_decodes_into_mode_kind_object_and_path() -> Bool { - match step0_decode_tree_entry(record: concat("100644 blob 1111111111111111111111111111111111111111", concat(from_code_point(9), "dag/std/types.dag"))) { + match step0_decode_tree_entry(record: concat("100644 blob 1111111111111111111111111111111111111111", concat(char_text(c: 9), "dag/std/types.dag"))) { Step0TreeEntryUndecodable { record: _ } => false Step0TreeEntryDecoded { entry: entry } => entry.mode == "100644" @@ -379,11 +380,11 @@ test fn an_outside_module_calling_a_public_collector_fn_is_not_refused() -> Bool // corpus has no such file today and that is not the boundary that decides: the RED is authorable // as a fixture, so the wall is owed. fn tabbed_path() -> String { - concat("dag/a", concat(from_code_point(9), "b.dag")) + concat("dag/a", concat(char_text(c: 9), "b.dag")) } fn tabbed_record() -> String { - concat("100644 blob 1111111111111111111111111111111111111111", concat(from_code_point(9), tabbed_path())) + concat("100644 blob 1111111111111111111111111111111111111111", concat(char_text(c: 9), tabbed_path())) } test fn a_pathname_containing_a_tab_decodes_whole_rather_than_truncating() -> Bool { @@ -396,7 +397,7 @@ test fn a_pathname_containing_a_tab_decodes_whole_rather_than_truncating() -> Bo test fn a_pathname_containing_a_tab_stays_in_the_subject() -> Bool { paths_contain( - xs: step0_subject_paths_at(paths_nul: concat(tabbed_path(), from_code_point(0))), + xs: step0_subject_paths_at(paths_nul: concat(tabbed_path(), char_text(c: 0))), want: tabbed_path() ) } diff --git a/dag/test/claim/network_boot_manifest_broker_witness_test.dag b/dag/test/claim/network_boot_manifest_broker_witness_test.dag index 6bcac5c07e3..1223b262ea5 100644 --- a/dag/test/claim/network_boot_manifest_broker_witness_test.dag +++ b/dag/test/claim/network_boot_manifest_broker_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.network_boot_manifest_broker_witness +import std.unicode.scalar { char_text } import std.types { Bool, Int, List, NonEmptyStr, Secret, String, list_length } import std.content_hash { ContentHash, content_hash_of_value } import std.decl_ref { DeclarationRef, WholeDeclaration } @@ -169,7 +170,7 @@ fn identity_with_attempt_and_nonce(attempt_id: IntakeAttemptId, nonce: String) - // the same text for both), so it is red for any preimage that does not // bind field boundaries independently of field content. test fn claims_that_collide_under_a_separator_join_have_distinct_signing_inputs() -> Bool { - let us = from_code_point(cp: 31) + let us = char_text(c: 31) let a = identity_with_attempt_and_nonce(attempt_id: concat("intake", concat(us, "x")) as IntakeAttemptId, nonce: "n") let b = identity_with_attempt_and_nonce(attempt_id: "intake" as IntakeAttemptId, nonce: concat("x", concat(us, "n"))) let separator_joined_a = join([a.attempt_id as String, a.nonce], us) diff --git a/dag/test/claim/pr_containment_disposition_witness_test.dag b/dag/test/claim/pr_containment_disposition_witness_test.dag index 2013d16ed1a..46147cd2a03 100644 --- a/dag/test/claim/pr_containment_disposition_witness_test.dag +++ b/dag/test/claim/pr_containment_disposition_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.pr_containment_disposition_witness +import std.unicode.scalar { char_text } import std.types { Bool, Int, String, List } import tools.pr_containment_instrument { AddedLine, @@ -375,6 +376,6 @@ test fn an_unreadable_file_refuses_every_later_file() -> Bool { // empty path a member of every base tree, which is the one key `map_contains_key` must never // answer true for by accident. test fn the_base_path_set_drops_the_trailing_empty_member() -> Bool { - let s = base_path_set(paths_nul: concat("a.dag", concat(from_code_point(0), concat("b.dag", from_code_point(0))))) + let s = base_path_set(paths_nul: concat("a.dag", concat(char_text(c: 0), concat("b.dag", char_text(c: 0))))) map_contains_key(s, "a.dag") && map_contains_key(s, "b.dag") && !map_contains_key(s, "") } diff --git a/dag/test/claim/roadmap/roadmap_publish_observe_witness_test.dag b/dag/test/claim/roadmap/roadmap_publish_observe_witness_test.dag index cada130dfe0..cf5dea3d985 100644 --- a/dag/test/claim/roadmap/roadmap_publish_observe_witness_test.dag +++ b/dag/test/claim/roadmap/roadmap_publish_observe_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.roadmap_publish_observe_witness_test +import std.unicode.scalar { char_text } import std.types { Bool, String, NonEmptyStr, Int, List, CommitSha } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import gunbc.roadmap_publish_observe { @@ -29,7 +30,7 @@ data witness_scope_note: String = "Every arm of the remote-branch observation is data fixture_sha_a: String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" data fixture_sha_b: String = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -fn tab() -> String { from_code_point(cp: 9) } +fn tab() -> String { char_text(c: 9) } fn line_of(sha: String, ref_name: String) -> String { concat(sha, concat(tab(), ref_name)) diff --git a/dag/test/claim/serving/serving_front_door_witness_test.dag b/dag/test/claim/serving/serving_front_door_witness_test.dag index e0310e8f19a..f3c8b17560b 100644 --- a/dag/test/claim/serving/serving_front_door_witness_test.dag +++ b/dag/test/claim/serving/serving_front_door_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.serving.serving_front_door_witness_test +import std.unicode.scalar { char_text } import v2.std.optional { Present, Absent } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.types { NonEmptyStr, String, Bool, List, EpochSecs, Secret } @@ -320,7 +321,7 @@ test fn a_permit_whose_protocol_was_rewritten_after_signing_is_refused_by_the_ma // signing input A and B share every byte; under the length-prefixed one they do not, so a tag over A // cannot authenticate B. test fn two_claim_sets_that_collide_under_a_separator_join_sign_apart() -> Bool { - let sep = from_code_point(cp: 31) + let sep = char_text(c: 31) let c = claims_on(launch: group_b_launch, group_wire: "group-b") let a = ServingSeatPermitClaims { protocol: c.protocol, group: c.group, partition: c.partition, class: c.class, diff --git a/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag b/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag index 52aa089c1e2..2a48b7cf2cc 100644 --- a/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag +++ b/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag @@ -1,5 +1,7 @@ module test.claim.sorted_map_keys_interpreter_order_witness_test +import std.unicode.scalar { char_text } + data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // sorted_map_keys HAD NO INTERPRETER ARM. It was declared in std.primitives, typed in @@ -50,7 +52,7 @@ fn discriminating_key_map() -> Map { |> map_insert("B", 2) |> map_insert("Z9", 3) |> map_insert("Z10", 4) - |> map_insert(from_code_point(233), 5) + |> map_insert(char_text(c: 233), 5) |> map_insert("z", 6) |> map_insert("a", 7) } @@ -59,7 +61,7 @@ fn reverse_insertion_key_map() -> Map { empty_map() |> map_insert("a", 7) |> map_insert("z", 6) - |> map_insert(from_code_point(233), 5) + |> map_insert(char_text(c: 233), 5) |> map_insert("Z10", 4) |> map_insert("Z9", 3) |> map_insert("B", 2) @@ -67,7 +69,7 @@ fn reverse_insertion_key_map() -> Map { } fn expected_utf8_byte_order() -> List { - ["B", "Z10", "Z9", "a", "b", "z", from_code_point(233)] + ["B", "Z10", "Z9", "a", "b", "z", char_text(c: 233)] } test fn sorted_map_keys_free_call_orders_as_emitted_rust_does() -> Bool { diff --git a/dag/test/claim/spark/spark_grant_privileged_operation_witness_test.dag b/dag/test/claim/spark/spark_grant_privileged_operation_witness_test.dag index b26142d0020..43c71d81b28 100644 --- a/dag/test/claim/spark/spark_grant_privileged_operation_witness_test.dag +++ b/dag/test/claim/spark/spark_grant_privileged_operation_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.spark_grant_privileged_operation_witness +import std.unicode.scalar { char_text } import std.types { Bool, String, NonEmptyStr, List } import extdeps.cloud.gcp.secret_ref { SecretRef, HashPending } import gunbc.spark.bootstrap_credential { @@ -198,7 +199,7 @@ test fn a_credential_keeps_its_own_leading_and_trailing_spaces() -> Bool { // whatever writes the secret version, not to the consumer delivering it -- and if it is wrong, sudo // rejecting it as the wrong credential is the correct layer and the correct remedy. test fn a_whitespace_only_payload_is_delivered_not_redefined_as_absent() -> Bool { - let tabs = join([from_code_point(cp: 9), from_code_point(cp: 9)], "") + let tabs = join([char_text(c: 9), char_text(c: 9)], "") match classify_credential_read(success: true, error: "", content: " ") { BootstrapCredentialReady { secret: a } => a == " " @@ -217,8 +218,8 @@ test fn a_whitespace_only_payload_is_delivered_not_redefined_as_absent() -> Bool // reporting success. sudo -S reads only the first line, so such a secret cannot be delivered by this // protocol at all -- and saying so is the honest arm. test fn a_trailing_line_break_refuses_rather_than_being_stripped() -> Bool { - let lf = from_code_point(cp: 10) - let crlf = join([from_code_point(cp: 13), from_code_point(cp: 10)], "") + let lf = char_text(c: 10) + let crlf = join([char_text(c: 13), char_text(c: 10)], "") fold([join(["password", lf], ""), join(["password", crlf], ""), lf], init: true, f: fn(acc, c) { acc && match classify_credential_read(success: true, error: "", content: c) { BootstrapCredentialNotMaterialized { cause: why } => string_contains(why as String, "line break") @@ -230,7 +231,7 @@ test fn a_trailing_line_break_refuses_rather_than_being_stripped() -> Bool { // An embedded break refuses for the same reason and is called out separately because its harm // differs: sudo would authenticate on the first line and feed the remainder to the command as input. test fn an_embedded_line_break_refuses_instead_of_being_stripped() -> Bool { - let content = join(["pass", from_code_point(cp: 10), "word"], "") + let content = join(["pass", char_text(c: 10), "word"], "") match classify_credential_read(success: true, error: "", content: content) { BootstrapCredentialNotMaterialized { cause: c } => string_contains(c as String, "line break") BootstrapCredentialReady { secret: _ } => false @@ -240,7 +241,7 @@ test fn an_embedded_line_break_refuses_instead_of_being_stripped() -> Bool { // A lone carriage return is a line break wherever it sits, and refuses rather than being deleted // from the middle or the end of a password. test fn a_bare_carriage_return_refuses() -> Bool { - let content = join(["password", from_code_point(cp: 13)], "") + let content = join(["password", char_text(c: 13)], "") match classify_credential_read(success: true, error: "", content: content) { BootstrapCredentialNotMaterialized { cause: _ } => true BootstrapCredentialReady { secret: _ } => false diff --git a/dag/test/claim/terminal_wire_projection_witness_test.dag b/dag/test/claim/terminal_wire_projection_witness_test.dag index d046e453bef..647412b6738 100644 --- a/dag/test/claim/terminal_wire_projection_witness_test.dag +++ b/dag/test/claim/terminal_wire_projection_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.terminal_wire_projection_witness_test +import std.unicode.scalar { char_text } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.types { String, Bool } import std.symbols { Ascii } @@ -259,8 +260,8 @@ test fn w_rendered_text_cannot_smuggle_cursor_control_bytes() -> Bool { ansi_c1_controls.count() == 32 && scan.next_index == 65 && scan.first_failure == -1 && - ansi_text_contains_cursor_control(text: from_code_point(cp: 128)) - && ansi_text_contains_cursor_control(text: from_code_point(cp: 159)) + ansi_text_contains_cursor_control(text: char_text(c: 128)) + && ansi_text_contains_cursor_control(text: char_text(c: 159)) && !ansi_text_contains_cursor_control(text: "\\u{0080}") } diff --git a/dag/test/claim/yaml_emit_witness_test.dag b/dag/test/claim/yaml_emit_witness_test.dag index 390cebf22bc..8a3ea2321fd 100644 --- a/dag/test/claim/yaml_emit_witness_test.dag +++ b/dag/test/claim/yaml_emit_witness_test.dag @@ -1,5 +1,7 @@ module test.claim.yaml_emit_witness +import std.unicode.scalar { char_text } + data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // THE WRITER'S CONTRACT IS DECODED STRUCTURE: for every value it writes, the reader returns that @@ -124,5 +126,5 @@ test fn red_values_the_writer_cannot_write_refuse_with_their_path() -> Bool { && refused_at(v: YamlMapping { entries: [YamlKeyValue { key: "a", value: YamlNull }, YamlKeyValue { key: "a", value: YamlNull }] }, path: "a", reason_part: "twice") && refused_at(v: str(s: "top"), path: "", reason_part: "document root") && refused_at(v: YamlMapping { entries: [] }, path: "", reason_part: "empty mapping") - && refused_at(v: field(k: "a", v: str(s: concat("x", from_code_point(cp: 160)))), path: "line 1 of the emitted text", reason_part: "U+00A0") + && refused_at(v: field(k: "a", v: str(s: concat("x", char_text(c: 160)))), path: "line 1 of the emitted text", reason_part: "U+00A0") } diff --git a/dag/test/claim/yaml_ingest_witness_test.dag b/dag/test/claim/yaml_ingest_witness_test.dag index beeee9521dd..e3c2c8f9e92 100644 --- a/dag/test/claim/yaml_ingest_witness_test.dag +++ b/dag/test/claim/yaml_ingest_witness_test.dag @@ -1,5 +1,7 @@ module test.claim.yaml_ingest_witness +import std.unicode.scalar { char_text } + data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly // EVERY CLAIM HERE COMPARES DECODED STRUCTURE WITH A HAND-WRITTEN VALUE. Nothing goes through the @@ -83,7 +85,7 @@ test fn red_a_single_quoted_scalar_with_trailing_text_refuses() -> Bool { } test fn double_quoted_escapes_decode() -> Bool { - reads(src: "a: \"x\\ny\\t\\\"q\\\" \\\\ \\u00e9 \\x41\"\n", v: one(key: "a", v: str(s: join(["x\ny\t\"q\" \\ ", from_code_point(cp: 233), " A"], "")))) + reads(src: "a: \"x\\ny\\t\\\"q\\\" \\\\ \\u00e9 \\x41\"\n", v: one(key: "a", v: str(s: join(["x\ny\t\"q\" \\ ", char_text(c: 233), " A"], "")))) && reads(src: "a: \"#123456\"\n", v: one(key: "a", v: str(s: "#123456"))) } @@ -210,9 +212,9 @@ test fn literal_keep_chomping_matches_the_independent_reader_for_every_trailing_ // document whose decoded content legitimately held U+0001 (a double-quoted `\x01`) was then refused as // if one of its items had been. Decoded U+0001 is ordinary content, as an item, a value and a key. test fn a_decoded_u0001_is_content_as_an_item_a_value_and_a_key() -> Bool { - reads(src: "a:\n - \"\\x01\"\n - b\n", v: one(key: "a", v: YamlSequence { elements: [str(s: from_code_point(cp: 1)), str(s: "b")] })) - && reads(src: "a: \"\\x01\"\nb: c\n", v: YamlMapping { entries: [YamlKeyValue { key: "a", value: str(s: from_code_point(cp: 1)) }, YamlKeyValue { key: "b", value: str(s: "c") }] }) - && reads(src: "\"\\x01\": a\nb: c\n", v: YamlMapping { entries: [YamlKeyValue { key: from_code_point(cp: 1), value: str(s: "a") }, YamlKeyValue { key: "b", value: str(s: "c") }] }) + reads(src: "a:\n - \"\\x01\"\n - b\n", v: one(key: "a", v: YamlSequence { elements: [str(s: char_text(c: 1)), str(s: "b")] })) + && reads(src: "a: \"\\x01\"\nb: c\n", v: YamlMapping { entries: [YamlKeyValue { key: "a", value: str(s: char_text(c: 1)) }, YamlKeyValue { key: "b", value: str(s: "c") }] }) + && reads(src: "\"\\x01\": a\nb: c\n", v: YamlMapping { entries: [YamlKeyValue { key: char_text(c: 1), value: str(s: "a") }, YamlKeyValue { key: "b", value: str(s: "c") }] }) } // THE FLOW FAST PATH'S REFUSALS ARE TYPED ON THEIR OWN, WITH THE DOCUMENT PRE-CHECK BYPASSED: these @@ -223,9 +225,9 @@ test fn red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck() -> (match yaml_flow_plain_entry(e: "*a") { YamlScalarRefused { reason: r } => string_contains(s: r, pattern: "starts with an indicator") ReadYamlScalar { value: _ } => false }) && (match yaml_flow_plain_entry(e: "!t") { YamlScalarRefused { reason: r } => string_contains(s: r, pattern: "starts with an indicator") ReadYamlScalar { value: _ } => false }) && (match yaml_flow_plain_entry(e: "") { YamlScalarRefused { reason: r } => string_contains(s: r, pattern: "empty flow sequence entry") ReadYamlScalar { value: _ } => false }) - && (match yaml_flow_plain_entry(e: from_code_point(cp: 1)) { ReadYamlScalar { value: v } => v == str(s: from_code_point(cp: 1)) YamlScalarRefused { reason: _ } => false }) + && (match yaml_flow_plain_entry(e: char_text(c: 1)) { ReadYamlScalar { value: v } => v == str(s: char_text(c: 1)) YamlScalarRefused { reason: _ } => false }) && (match yaml_flow_plain_sequence(inner: "a, *b, c") { YamlScalarRefused { reason: r } => string_contains(s: r, pattern: "`*b`") ReadYamlScalar { value: _ } => false }) - && (match yaml_flow_plain_sequence(inner: concat("a, ", from_code_point(cp: 1))) { ReadYamlScalar { value: v } => v == YamlSequence { elements: [str(s: "a"), str(s: from_code_point(cp: 1))] } YamlScalarRefused { reason: _ } => false }) + && (match yaml_flow_plain_sequence(inner: concat("a, ", char_text(c: 1))) { ReadYamlScalar { value: v } => v == YamlSequence { elements: [str(s: "a"), str(s: char_text(c: 1))] } YamlScalarRefused { reason: _ } => false }) } test fn red_folded_scalars_and_indentation_indicators_refuse() -> Bool { @@ -300,6 +302,6 @@ test fn red_document_level_refusals_are_located() -> Bool { && refuses_at(src: "a: !!str 1\n", line: 1, reason_part: "tags") && refuses_at(src: "a:\n\tb: 1\n", line: 2, reason_part: "tab") && refuses_at(src: "a: 1\nb: 2 \n", line: 2, reason_part: "ends in whitespace") - && refuses_at(src: concat("a: 1\nb: x", concat(from_code_point(cp: 160), "y\n")), line: 2, reason_part: "U+00A0") + && refuses_at(src: concat("a: 1\nb: x", concat(char_text(c: 160), "y\n")), line: 2, reason_part: "U+00A0") && refuses_at(src: "a: 1\r\nb: 2\r\n", line: 1, reason_part: "U+000D") } From 6b910ff5a77119152d675d5c91c053830d8087de Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 10:18:15 +0000 Subject: [PATCH 07/39] Octet-as-char meaning fork: declared std.encoding ASCII route; rfc_5280 Time refuses non-ASCII; honest non-UTF-8 fixture + RFM Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/git/object_store.dag | 17 +++---- dag/extdeps/standards/rfc_5280.dag | 26 ++++++++-- ...ode_point_binds_the_total_seed_builtin.dag | 2 +- ..._spelled_through_a_string_path_carrier.dag | 18 +++++++ dag/std/encoding.dag | 47 ++++++++++++++++++- .../ascii_decode_octets_witness_test.dag | 22 +++++++++ .../claim/git_upstream_model_witness_test.dag | 3 +- dag/test/claim/x509_rfc5280_witness_test.dag | 29 +++++++++++- .../git_upstream_model_execution_test.dag | 27 +++++++---- 9 files changed, 163 insertions(+), 28 deletions(-) create mode 100644 dag/gunbc/recurring_failure_mode/non_utf8_path_fixture_spelled_through_a_string_path_carrier.dag create mode 100644 dag/test/claim/ascii_decode_octets_witness_test.dag diff --git a/dag/extdeps/git/object_store.dag b/dag/extdeps/git/object_store.dag index 36711934906..777a37ab8e0 100644 --- a/dag/extdeps/git/object_store.dag +++ b/dag/extdeps/git/object_store.dag @@ -20,6 +20,7 @@ import std.integer { UInt8, NonNegativeInt, PositiveInt, qualified_octet_members import std.render_repeat_string_bootstrap { repeat_string } import std.measure { ByteSize, byte_size, byte_size_count } import std.bytes { bytes_octets, octets_bytes, utf8_encode_bytes } +import std.encoding { ascii_decode_octets, AsciiDecoded, AsciiNonAscii } import std.cache_interface { ContentAddressedByValue, WriteOnce } import extdeps.git { GitAuthor, ObjectType, BlobObj, TreeObj, CommitObj, TagObj } import extdeps.object_storage { ObjectContainer } @@ -1969,16 +1970,16 @@ type GitLsTreeZDecodeOutcome = GitLsTreeZDecoded { entries: List } | GitLsTreeZRefused { cause: GitLsTreeZRefusal } +// A git NUL-framed header field is ASCII text through the declared std.encoding ascii_decode_octets +// route; NUL is ASCII but is the field DELIMITER here, so it is refused by this field's own policy. fn git_ascii_field_text(octets: List) -> NonEmptyStr? { - if all(octets, octet => octet > 0 && octet < 128) { - Present { - value: join( - octets |> map(octet => from_code_point(octet)), - "", - ) as NonEmptyStr, - } - } else { + if !all(octets, octet => octet != 0) { none + } else { + match ascii_decode_octets(octets: octets) { + AsciiDecoded { text } => Present { value: text as NonEmptyStr } + AsciiNonAscii { at: _, octet: _ } => none + } } } diff --git a/dag/extdeps/standards/rfc_5280.dag b/dag/extdeps/standards/rfc_5280.dag index 84a42c62dd0..f1b32495921 100644 --- a/dag/extdeps/standards/rfc_5280.dag +++ b/dag/extdeps/standards/rfc_5280.dag @@ -4,6 +4,7 @@ import std.types { Int, String, List, Timestamp } import std.logic { Bool } import std.bignat { bignat_pad_front } import std.decimal { decimal_digits_only } +import std.encoding { ascii_decode_octets, AsciiDecoded, AsciiNonAscii } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } import extdeps.standards.x690_der { @@ -86,6 +87,7 @@ type X509Refusal = X509DerRefused { cause: DerRefusal } | X509SignatureAlgorithmMismatch { tbs: String, outer: String } | X509TimeTagUnexpected { at: Int, tag: Int } + | X509TimeNotAscii { at: Int, octet: Int } | X509ExtensionMalformed { at: Int } | X509ExtensionDefaultEncoded { at: Int } @@ -131,9 +133,6 @@ fn read_algorithm_identifier(octets: List, e: DerElement) -> AlgorithmIdent } } -fn ascii_of(octets: List) -> String { - fold(octets, init: "", f: (acc, o) => acc + from_code_point(cp: o)) -} // Time ::= CHOICE { utcTime UTCTime, generalTime GeneralizedTime }: THE CHOICE IS CARRIED (review // 69660 of gunbc#11975 -- a bare String lost the arm, and the two arms read their year differently: @@ -150,12 +149,29 @@ type X509TimeRead = X509TimeOk { time: X509Time } | X509TimeRefused { cause: X509Refusal } +// UTCTime and GeneralizedTime are VisibleString subsets (X.680 sections 46-47; RFC 5280 section +// 4.1.2.5), so their contents are ASCII. They cross to text through the declared std.encoding +// ascii_decode_octets route; a non-ASCII octet REFUSES (X509TimeNotAscii, at the octet's offset in +// the value) rather than being spelled as a Latin-1 character. (Before: a total octet-as-char +// fold admitted any octet silently.) +fn read_time_text(octets: List, e: DerElement, utc: Bool) -> X509TimeRead { + match ascii_decode_octets(octets: der_value(octets: octets, e: e)) { + AsciiNonAscii { at, octet } => X509TimeRefused { cause: X509TimeNotAscii { at: at, octet: octet } } + AsciiDecoded { text } => + if utc { + X509TimeOk { time: UtcTime { text: text } } + } else { + X509TimeOk { time: GeneralizedTime { text: text } } + } + } +} + fn read_time(octets: List, e: DerElement) -> X509TimeRead { match der_element_expect_universal(e: e, tag_number: der_tag_utc_time) { - Absent => X509TimeOk { time: UtcTime { text: ascii_of(octets: der_value(octets: octets, e: e)) } } + Absent => read_time_text(octets: octets, e: e, utc: true) Present { value: _ } => match der_element_expect_universal(e: e, tag_number: der_tag_generalized_time) { - Absent => X509TimeOk { time: GeneralizedTime { text: ascii_of(octets: der_value(octets: octets, e: e)) } } + Absent => read_time_text(octets: octets, e: e, utc: false) Present { value: _ } => X509TimeRefused { cause: X509TimeTagUnexpected { at: e.header_at, tag: e.tag_number } } } } diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 5e36acf3f38..98416209370 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -11,7 +11,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", - "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", + "POPULATION, KIND OCTET-AS-CHAR (0 identities; 4 dispositioned) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spelled a BYTE as a character. None migrated to from_code_point. DISPOSITIONS: extdeps.git.object_store::git_ascii_field_text -> std.encoding ascii_decode_octets (declared partial ASCII route; NUL refused as the field delimiter by git policy); extdeps.standards.rfc_5280::ascii_of -> REMOVED, read_time_text consumes std.encoding ascii_decode_octets and a non-ASCII Time octet refuses X509TimeNotAscii (behaviour tightening: the old total fold admitted any octet as Latin-1); test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets -> its 0xFF was already a raw octet (std.bytes octets_bytes), only its TAB constant used the bare name, now std.unicode.scalar char_text; test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back -> its 'raw' name was valid UTF-8 by construction, renamed non_ascii_name over char_text, gap filed as gunbc.recurring_failure_mode non_utf8_path_fixture_spelled_through_a_string_path_carrier. No Latin-1 route was declared: no consumer's upstream specifies one.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", ], evidence: [ diff --git a/dag/gunbc/recurring_failure_mode/non_utf8_path_fixture_spelled_through_a_string_path_carrier.dag b/dag/gunbc/recurring_failure_mode/non_utf8_path_fixture_spelled_through_a_string_path_carrier.dag new file mode 100644 index 00000000000..c5168c2a300 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/non_utf8_path_fixture_spelled_through_a_string_path_carrier.dag @@ -0,0 +1,18 @@ +module gunbc.recurring_failure_mode.non_utf8_path_fixture_spelled_through_a_string_path_carrier + +import std.types { NonEmptyStr } +import std.decl_ref { DeclarationRef, WholeDeclaration } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data non_utf8_path_fixture_spelled_through_a_string_path_carrier: RecurringFailureMode = RecurringFailureMode { + identity: "non_utf8_path_fixture_spelled_through_a_string_path_carrier" as NonEmptyStr, + receipts: [ + "INVALID STATE: a fixture claims to exercise a non-UTF-8 filesystem path but builds the name as host text (a String) and hands it to a String-typed path carrier, so the octets that reach the disk are the UTF-8 encoding of the text -- valid UTF-8 by construction. The claimed property is falsified by the fixture's own construction, and the test stays green. Git pathnames are uninterpreted NUL-free octet strings upstream (git Documentation/gitformat-index 'Entry path name ... NUL-terminated'; core.quotePath: no encoding is assumed), so a non-UTF-8 path is a real input the model must preserve.", + "RECEIPT: test.manual.git_upstream_model_execution git_r0_typed_execution_read_back spelled its fixture as concat(from_code_point(255), \".dag\") (a 'raw' name) and wrote it through extdeps.filesystem Filesystem.Write(path: String): on disk the name was C3 BF 2E 64 61 67. The XL-2 octet-as-char migration renamed it honestly (non_ascii_name, char_text(c: 255)). Non-UTF-8 octets ARE held at the decode interface by test.claim.git_upstream_model_witness witness_git_ls_tree_z_preserves_non_utf8_path_octets, which supplies 0xFF through std.bytes octets_bytes.", + "HARM: no executing path proves a real non-UTF-8 path survives the filesystem -> git -> read-back round trip; under-asserted coverage hidden behind a name that said otherwise (DESIGN section 4d). RUNG FOUND AT: mitigatable (review). CEILING: structurally impossible -- a path whose octets may be non-UTF-8 is carried as octets, so a text spelling cannot stand in for it. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: a filesystem octet-path carrier (extdeps.filesystem write/read/list over a path held as octets, never as String), SUFFICIENT FOR the manual execution fixture to create, git-add and read back a name containing octet 0xFF and assert the octets git reports.", + ], + evidence: [ + DeclarationRef { module_path: "test.manual.git_upstream_model_execution", decl_name: "git_r0_typed_execution_read_back", field: WholeDeclaration }, + DeclarationRef { module_path: "test.claim.git_upstream_model_witness", decl_name: "witness_git_ls_tree_z_preserves_non_utf8_path_octets", field: WholeDeclaration }, + ], +} diff --git a/dag/std/encoding.dag b/dag/std/encoding.dag index b836f3b0ced..243964b6873 100644 --- a/dag/std/encoding.dag +++ b/dag/std/encoding.dag @@ -1,7 +1,8 @@ module std.encoding -import std.algebra { BoundedLattice } -import std.types { Bytes } +import std.algebra { BoundedLattice, FreeMonoid, Empty, list_snoc_item } +import std.coercion { unicode_scalar_fold } +import std.types { Bytes, Char } import std.integer { UInt8Result, UInt8Ready, UInt8OutOfRange, uint8_of_int, QualifiedOctets, QualifiedOctetsResult, QualifiedOctetsReady, QualifiedOctetsRefused, uint8_octets_of_ints, qualified_octet_members } import std.machine_word { Word, Width8, Width32, WordResult, WordReady, WordRefused, WordValueOutOfRange, OctetsResult, OctetsReady, OctetsRefused, word_of_int, word_from_octets, word_to_octets, word_shift_left, word_shift_right, word_and, word_or } import extdeps.toolchain.architecture_profile { BigEndian } @@ -674,3 +675,45 @@ data utf8_decode_bytes_host_realization_marker: Disposition = Scaffold { data base64_group_fill_carrier_debt_marker: Disposition = Terminal { reason: "Base64EncodeBuf = EncEmpty|EncOne|EncTwo and Base64DecodeBuf = DecEmpty|DecOne|DecTwo|DecThree: the hand-rolled Int count accumulator debt is paid; closed sums are declared and all arms are covered by execution in base64_rfc4648_witness_test.dag" } + +// THE ASCII DECODE: a NAMED, PARTIAL octet -> text conversion plan (DESIGN section 4: a crossing that +// may refuse is never implicit). ASCII is ANSI X3.4-1986 / ISO/IEC 646 IRV: the seven-bit code, +// octets 0x00..0x7F, and Unicode 17.0 Basic Latin (U+0000..U+007F) assigns each of those octets the +// scalar with the same number -- so on its domain the route is exact, lossless and needs no table. +// 0x00 (NUL) IS in the domain: it is an ASCII control. A caller for whom NUL is a delimiter rather +// than content (a git NUL-framed field) refuses it under its own policy, not here. +// Octets 0x80..0xFF are NOT ASCII and are NOT read as Latin-1: this route refuses them, naming the +// first offending position and octet. A byte-to-Latin-1 reading would be a different meaning of +// "the character for this byte" and is not declared, because no current consumer's upstream +// specifies it (gunbc.recurring_failure_mode bare_from_code_point_binds_the_total_seed_builtin, +// kind OCTET-AS-CHAR). +type AsciiDecodeOutcome + = AsciiDecoded { text: String } + | AsciiNonAscii { at: Int, octet: Int } + +type AsciiDecodeState + = AsciiDecoding { at: Int, scalars: FreeMonoid } + | AsciiDecodeRefused { at: Int, octet: Int } + +fn ascii_octet(octet: Int) -> Bool { + octet >= 0 && octet < 128 +} + +fn ascii_decode_step(state: AsciiDecodeState, octet: Int) -> AsciiDecodeState { + match state { + AsciiDecodeRefused { at, octet: refused } => AsciiDecodeRefused { at: at, octet: refused } + AsciiDecoding { at, scalars } => + if ascii_octet(octet: octet) { + AsciiDecoding { at: at + 1, scalars: list_snoc_item(xs: scalars, item: octet) } + } else { + AsciiDecodeRefused { at: at, octet: octet } + } + } +} + +fn ascii_decode_octets(octets: List) -> AsciiDecodeOutcome { + match fold(octets, init: AsciiDecoding { at: 0, scalars: Empty }, f: (st, o) => ascii_decode_step(state: st, octet: o)) { + AsciiDecoding { at: _, scalars } => AsciiDecoded { text: unicode_scalar_fold(xs: scalars) } + AsciiDecodeRefused { at, octet } => AsciiNonAscii { at: at, octet: octet } + } +} diff --git a/dag/test/claim/ascii_decode_octets_witness_test.dag b/dag/test/claim/ascii_decode_octets_witness_test.dag new file mode 100644 index 00000000000..5cf4b87fc08 --- /dev/null +++ b/dag/test/claim/ascii_decode_octets_witness_test.dag @@ -0,0 +1,22 @@ +module test.claim.ascii_decode_octets_witness_test + +import std.logic { Bool } +import std.encoding { ascii_decode_octets, AsciiDecoded, AsciiNonAscii } +import std.unicode.scalar { char_text } + +// The declared octet -> text route is exact on 0x00..0x7F (NUL included: it is ASCII) and refuses +// the first octet >= 0x80 by position and value, never reading it as Latin-1. 0xFF is the octet a +// total octet-as-char fold used to spell as U+00FF; here it refuses. +test fn ascii_octets_decode_exactly_including_nul() -> Bool { + match ascii_decode_octets(octets: [0, 9, 65, 127]) { + AsciiDecoded { text } => text == concat(concat(char_text(c: 0), char_text(c: 9)), concat("A", char_text(c: 127))) + AsciiNonAscii { at: _, octet: _ } => false + } +} + +test fn a_high_octet_refuses_at_its_position_rather_than_becoming_latin1() -> Bool { + match ascii_decode_octets(octets: [46, 255, 128]) { + AsciiNonAscii { at: 1, octet: 255 } => true + _ => false + } +} diff --git a/dag/test/claim/git_upstream_model_witness_test.dag b/dag/test/claim/git_upstream_model_witness_test.dag index 39e542d7afc..8c67de5034d 100644 --- a/dag/test/claim/git_upstream_model_witness_test.dag +++ b/dag/test/claim/git_upstream_model_witness_test.dag @@ -131,6 +131,7 @@ import std.content_hash { import std.types { Bytes } import std.bytes { bytes_octets, octets_bytes, utf8_encode_bytes } import std.algebra { Cons, Empty } +import std.unicode.scalar { char_text } // Witness-corpus Git object ids are constructed only through git_sha1_object_id / // git_sha256_object_id (review 45376). The Absent arm below is unreachable for pinned corpus @@ -733,7 +734,7 @@ test fn witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows() -> test fn witness_git_ls_tree_z_preserves_non_utf8_path_octets() -> Bool { let space = " " - let tab = from_code_point(9) + let tab = char_text(c: 9) let header = concat( join( [ diff --git a/dag/test/claim/x509_rfc5280_witness_test.dag b/dag/test/claim/x509_rfc5280_witness_test.dag index ef835be6f1f..ae2e28a6bec 100644 --- a/dag/test/claim/x509_rfc5280_witness_test.dag +++ b/dag/test/claim/x509_rfc5280_witness_test.dag @@ -17,7 +17,7 @@ import extdeps.standards.x690_der { } import extdeps.standards.rfc_5280 { X509Certificate, X509Decoded, X509Refused, decode_certificate, X509Refusal, X509DerRefused, X509SignatureAlgorithmMismatch, X509ExtensionDefaultEncoded, - X509Time, UtcTime, GeneralizedTime, + X509Time, UtcTime, GeneralizedTime, read_time, X509TimeOk, X509TimeRefused, X509TimeNotAscii, x509_extension, X509ExtensionFound, X509ExtensionAbsent, X509ExtensionDuplicated, ecdsa_sig_value, EcdsaSigValueRead, EcdsaSigValueRefused, EcdsaSigValueTooWide, oid_ecdsa_with_sha256, oid_ecdsa_with_sha384, oid_id_ec_public_key, oid_prime256v1, oid_secp384r1, @@ -445,3 +445,30 @@ test fn pem_refuses_anything_but_exactly_one_block() -> Bool { _ => false } } + +// THE TIME CROSSES TO TEXT ONLY AS ASCII (X.680 sections 46-47: UTCTime/GeneralizedTime are +// VisibleString). Supplied DER at the read_time interface, one element each: a UTCTime whose +// second value octet is 0xB2 (Latin-1 superscript two, not a digit and not ASCII) REFUSES naming +// offset 1 and the octet; the same element with ASCII '2' (0x32) reads its text. The real-path +// inhabitance is the_sample_leaf_reads_as_openssl_reads_it, whose validity goes through read_time. +test fn a_non_ascii_time_octet_refuses_and_an_ascii_time_reads() -> Bool { + let red = [23, 3, 50, 178, 90] + let green = [23, 3, 50, 50, 90] + let refused = match der_read_element(octets: red, at: 0) { + DerElementRead { element } => + match read_time(octets: red, e: element) { + X509TimeRefused { cause: X509TimeNotAscii { at: 1, octet: 178 } } => true + _ => false + } + DerRefused { cause: _ } => false + } + let read = match der_read_element(octets: green, at: 0) { + DerElementRead { element } => + match read_time(octets: green, e: element) { + X509TimeOk { time: UtcTime { text } } => text == "22Z" + _ => false + } + DerRefused { cause: _ } => false + } + refused && read +} diff --git a/dag/test/manual/git_upstream_model_execution_test.dag b/dag/test/manual/git_upstream_model_execution_test.dag index 38577cba658..c74ace11189 100644 --- a/dag/test/manual/git_upstream_model_execution_test.dag +++ b/dag/test/manual/git_upstream_model_execution_test.dag @@ -58,6 +58,7 @@ import test.claim.git_upstream_model_witness { git_fixture_repository, } import std.bytes { utf8_encode_bytes } +import std.unicode.scalar { char_text } import v2.std.live_tree { LiveTreeDisposition, ReadsLiveTree } data live_tree_disposition: LiveTreeDisposition = ReadsLiveTree @@ -114,10 +115,16 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { GitR0LiveFixtureExecutionRefused { diagnostic: "cleanup-refused" } } } else { - let raw_name = concat(from_code_point(255), ".dag") + // A NON-ASCII, VALID UTF-8 name, and only that: U+00FF reaches the disk as the octets C3 BF + // because extdeps.filesystem's path carrier is String. This fixture never exercised a + // non-UTF-8 path (it used to be spelled as if it did); real non-UTF-8 octets are held by + // test.claim.git_upstream_model_witness witness_git_ls_tree_z_preserves_non_utf8_path_octets, + // and the missing filesystem round-trip is gunbc.recurring_failure_mode + // non_utf8_path_fixture_spelled_through_a_string_path_carrier. + let non_ascii_name = concat(char_text(c: 255), ".dag") let readme_path = concat(fixture.path, "/readme") let run_path = concat(fixture.path, "/run") - let raw_path = concat(fixture.path, concat("/", raw_name)) + let non_ascii_path = concat(fixture.path, concat("/", non_ascii_name)) let src_path = concat(fixture.path, "/src") let src_keep_path = concat(src_path, "/keep") let sha256_source_path = concat(sha256_fixture.path, "/source") @@ -130,7 +137,7 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { ) let readme_written = Filesystem.Write(path: readme_path, content: "source") let run_written = Filesystem.Write(path: run_path, content: "run") - let raw_written = Filesystem.Write(path: raw_path, content: "source") + let non_ascii_written = Filesystem.Write(path: non_ascii_path, content: "source") let src_created = shell.Mkdir.Parents(path: src_path) let src_keep_written = Filesystem.Write(path: src_keep_path, content: "") let run_executable = gunbc.WitnessBin.Run( @@ -148,7 +155,7 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { let added = gunbc.WitnessBin.Run( workdir: fixture.path, bin_path: "git", - args: ["add", "--", "readme", "run", "link", "src/keep", raw_name], + args: ["add", "--", "readme", "run", "link", "src/keep", non_ascii_name], expect: ExpectSuccess, ) let regular_oid = gunbc.WitnessBin.Run( @@ -447,7 +454,7 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { let executable_is_executable = shell.Test.IsExecutable(path: run_path) let readme_read_back = Filesystem.Read(path: readme_path) let run_read_back = Filesystem.Read(path: run_path) - let raw_read_back = Filesystem.Read(path: raw_path) + let non_ascii_read_back = Filesystem.Read(path: non_ascii_path) let src_keep_read_back = Filesystem.Read(path: src_keep_path) let cleaned_fixture = shell.Remove.RecursiveForce(path: fixture.path) @@ -456,7 +463,7 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { let all_operations_succeeded = initialized.success && readme_written.success && run_written.success - && raw_written.success + && non_ascii_written.success && src_created.success && src_keep_written.success && run_executable.success @@ -498,7 +505,7 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { && executable_is_executable.executable && readme_read_back.success && run_read_back.success - && raw_read_back.success + && non_ascii_read_back.success && src_keep_read_back.success && cleaned_fixture.success && cleaned_sha256.success @@ -528,11 +535,11 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { && trim(s: head_read_back.stdout) == "refs/heads/main" && trim(s: tag_type.stdout) == "tag" && string_contains(s: git_version.stdout, pattern: "git version ") - && string_contains(s: paths.stdout, pattern: raw_name) + && string_contains(s: paths.stdout, pattern: non_ascii_name) && trim(s: link_target.stdout) == "readme" && readme_read_back.content == "source" && run_read_back.content == "run" - && raw_read_back.content == "source" + && non_ascii_read_back.content == "source" && src_keep_read_back.content == "" if all_operations_succeeded @@ -614,7 +621,7 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { path: path_non_ascii, executable: false, content: utf8_encode_bytes( - s: raw_read_back.content, + s: non_ascii_read_back.content, ), }, GitWorktreeRegular { From 4320c187b140a9874d61b23d51e44335c5924ab1 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 10:19:14 +0000 Subject: [PATCH 08/39] witness: import the live-tree disposition explicitly (no bare channel) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/test/claim/unicode_scalar_from_code_point_witness_test.dag | 1 + 1 file changed, 1 insertion(+) diff --git a/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag b/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag index 57921c77b62..b708f29673e 100644 --- a/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag +++ b/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag @@ -2,6 +2,7 @@ module test.claim.unicode_scalar_from_code_point_witness import std.error_primitives { Ok, Err } import std.unicode.scalar { CodePointOutOfRange, SurrogateCodePoint, char_text, from_code_point } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly From 7975d317314a43c32b33ccfa50c593d1437bf8c9 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 10:20:29 +0000 Subject: [PATCH 09/39] Record trim's in-place seam copy honestly and against the seam's dissolution trigger --- dag/std/algebra.dag | 9 ++++++--- dag/std/bytes.dag | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dag/std/algebra.dag b/dag/std/algebra.dag index 066d4e84020..6de57712049 100644 --- a/dag/std/algebra.dag +++ b/dag/std/algebra.dag @@ -1140,9 +1140,12 @@ fn all_algebra_template_names() -> List { // The seam diverges before producing anything; `s` is read in the condition so the declared // input reaches the result (wiring-liveness). The divergence is the condition's `1 / 0`, evaluated // before either arm, so both arms are the same unreached literal there only to type the expression -// -- the shape of std.bytes pure_dag_seam_unreachable_string. That projection cannot be imported -// here (std.bytes imports std.types, which imports std.algebra), so its divergence is spelled -// in place; it was `from_code_point(1 / 0)`, which bound the total seed builtin to type a value that +// -- the shape of std.bytes pure_dag_seam_unreachable_string, but NOT its refusal: this `1 / 0` +// refuses as an unnamed division by zero, where that seam refuses by name. The named seam cannot be +// imported here (std.bytes imports std.types, which imports std.algebra), and that cycle says the +// seam sits at the wrong layer -- bottom is not a bytes fact. Moving it to a leaf module is the +// repair, and it is out of this change's scope because the std.bytes path is mirrored into stage0 +// (std.primitive_projection row, v1_rt panic text). It was `from_code_point(1 / 0)`, which bound the total seed builtin to type a value that // is never produced (gunbc.recurring_failure_mode bare_from_code_point_binds_the_total_seed_builtin). // DISSOLVE-ON: the bottom type std.bytes names -- one divergent seam inhabits every result type. fn trim(s: String) -> String { diff --git a/dag/std/bytes.dag b/dag/std/bytes.dag index 2f9ac0a23a5..3095b11901b 100644 --- a/dag/std/bytes.dag +++ b/dag/std/bytes.dag @@ -53,7 +53,10 @@ fn pure_dag_seam_unreachable_float() -> Float { // String, which is exactly what makes it a fabricated plausible output. The condition forces the // Int seam to evaluate, so divergence happens before any String is produced; both arms are the same // literal because neither is ever reached. DISSOLVE-ON: the same bottom type the Float projection -// names -- one divergent seam inhabits every result type and both projections delete. +// names -- one divergent seam inhabits every result type and both projections delete. One in-place +// copy of this shape is recorded against the same trigger: std.algebra trim, which cannot import +// this module (cycle through std.types) and so diverges on an unnamed `1 / 0`. It dissolves with +// these projections, or sooner if the seam moves to a leaf module std.algebra can import. fn pure_dag_seam_unreachable_string() -> String { if pure_dag_seam_unreachable() == 0 { "" } else { "" } } From 55009199bca3a4f8ebf9ff8f485dccb747c43cd5 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 10:37:13 +0000 Subject: [PATCH 10/39] fabric witness: import LiveTreeDisposition Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag | 1 + 1 file changed, 1 insertion(+) diff --git a/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag b/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag index e9af5544f57..ee0e8d6b5b8 100644 --- a/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag +++ b/dag/test/claim/fabric_ci_evidence_wire_decode_witness_test.dag @@ -1,6 +1,7 @@ module test.claim.fabric_ci_evidence_wire_decode_witness import std.types { Bool, NonEmptyStr } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { SurrogateCodePoint, CodePointOutOfRange } import tools.fabric_ci_evidence { FabricCiEvidenceDecoded, FabricCiEvidenceUndecodable, FabricCiWordNotScalar, From fafb4bc46a15bbdbcc99aa5c7cf52be996790d68 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 10:39:04 +0000 Subject: [PATCH 11/39] yaml ingest: match yaml_first_refused once, dropping the unreachable arm (review 76444) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/languages/yaml/ingest.dag | 43 +++++++++++++-------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/dag/extdeps/languages/yaml/ingest.dag b/dag/extdeps/languages/yaml/ingest.dag index 22c95f02314..02ca327bdb7 100644 --- a/dag/extdeps/languages/yaml/ingest.dag +++ b/dag/extdeps/languages/yaml/ingest.dag @@ -1419,31 +1419,30 @@ fn yaml_line_ending_in_whitespace(lines: List, index: Int) -> Int { } fn ingest_yaml_source(src: String) -> YamlIngestResult { - if yaml_contains_refused_character(text: src) { - match yaml_first_refused(text: src) { - Present { value: c } => YamlIngestRejected { line: yaml_line_containing(lines: yaml_source_lines(src: src), pattern: char_text(c: c), index: 0), reason: yaml_refused_character_reason(cp: c) } - Absent => YamlIngestRejected { line: 0, reason: "a refused character was detected and then not found" } - } - } else if yaml_has_leading_tab(src: src) { - YamlIngestRejected { line: yaml_line_with_leading_tab(lines: yaml_source_lines(src: src), index: 0), reason: "a tab in a line's leading whitespace is outside the supported subset (YAML indents with spaces only; a literal line may not begin with a tab either)" } - } else if yaml_has_trailing_whitespace(src: src) { - YamlIngestRejected { line: yaml_line_ending_in_whitespace(lines: yaml_source_lines(src: src), index: 0), reason: "a line ends in whitespace, which is outside the supported subset (it would make an empty line indistinguishable from literal content)" } - } else { - let lines = yaml_source_lines(src: src) - let at = yaml_first_content_offset(lines: lines, index: 0) - if at < 0 { - YamlIngestRejected { line: 0, reason: "the document has no content node" } - } else { - let root = if at == 0 { join(lines, "\n") } else { join(lines.skip(n: at), "\n") } - if starts_with(s: root, prefix: " ") || starts_with(s: root, prefix: "\t") { - YamlIngestRejected { line: at + 1, reason: "the root block must start at column 0" } + match yaml_first_refused(text: src) { + Present { value: c } => YamlIngestRejected { line: yaml_line_containing(lines: yaml_source_lines(src: src), pattern: char_text(c: c), index: 0), reason: yaml_refused_character_reason(cp: c) } + Absent => + if yaml_has_leading_tab(src: src) { + YamlIngestRejected { line: yaml_line_with_leading_tab(lines: yaml_source_lines(src: src), index: 0), reason: "a tab in a line's leading whitespace is outside the supported subset (YAML indents with spaces only; a literal line may not begin with a tab either)" } + } else if yaml_has_trailing_whitespace(src: src) { + YamlIngestRejected { line: yaml_line_ending_in_whitespace(lines: yaml_source_lines(src: src), index: 0), reason: "a line ends in whitespace, which is outside the supported subset (it would make an empty line indistinguishable from literal content)" } } else { - match yaml_block(text: root, n: 0, seq: yaml_starts_seq(text: root), base: 0) { - YamlBlockParsed { value: v } => IngestedYaml { value: v } - YamlBlockRefused { line: l, reason: why } => YamlIngestRejected { line: at + l + 1, reason: why } + let lines = yaml_source_lines(src: src) + let at = yaml_first_content_offset(lines: lines, index: 0) + if at < 0 { + YamlIngestRejected { line: 0, reason: "the document has no content node" } + } else { + let root = if at == 0 { join(lines, "\n") } else { join(lines.skip(n: at), "\n") } + if starts_with(s: root, prefix: " ") || starts_with(s: root, prefix: "\t") { + YamlIngestRejected { line: at + 1, reason: "the root block must start at column 0" } + } else { + match yaml_block(text: root, n: 0, seq: yaml_starts_seq(text: root), base: 0) { + YamlBlockParsed { value: v } => IngestedYaml { value: v } + YamlBlockRefused { line: l, reason: why } => YamlIngestRejected { line: at + l + 1, reason: why } + } + } } } - } } } From 09b7f3e41f4e8e67941ef28a3477f523795fae07 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 10:57:34 +0000 Subject: [PATCH 12/39] json_hex_nibble importers name the declarer (extdeps.languages.json.grammar), not a re-export through json.parse Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/bmc/ipmi_master_write_read.dag | 2 +- dag/gunbc/machine_intake/ampere_socket_console_observation.dag | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dag/extdeps/bmc/ipmi_master_write_read.dag b/dag/extdeps/bmc/ipmi_master_write_read.dag index 487e2a42c83..f2379490e7a 100644 --- a/dag/extdeps/bmc/ipmi_master_write_read.dag +++ b/dag/extdeps/bmc/ipmi_master_write_read.dag @@ -6,7 +6,7 @@ import std.decl_ref { DeclarationRef, WholeDeclaration } import v2.std.optional { Present } import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } import extdeps.uri { Uri, Https } -import extdeps.languages.json.parse { json_hex_nibble } +import extdeps.languages.json.grammar { json_hex_nibble } data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { diff --git a/dag/gunbc/machine_intake/ampere_socket_console_observation.dag b/dag/gunbc/machine_intake/ampere_socket_console_observation.dag index b7e613dd985..3792b5a2ec5 100644 --- a/dag/gunbc/machine_intake/ampere_socket_console_observation.dag +++ b/dag/gunbc/machine_intake/ampere_socket_console_observation.dag @@ -3,7 +3,7 @@ module gunbc.machine_intake_ampere_socket_console_observation import std.types { Bool, Int, List, NonEmptyStr, String } import std.algebra { trim } import v2.std.optional { Present } -import extdeps.languages.json.parse { json_hex_nibble } +import extdeps.languages.json.grammar { json_hex_nibble } import extdeps.ampere.ras_error_section { AmpereRasSectionHeader, AmpereRasErrorTypeReading, AmpereRasTypeDefined, AmpereRasTypeUndefined, ampere_ras_section_guid, ampere_ras_section_header_of, ampere_ras_error_type_code, ampere_ras_error_type_reading_text, From 9468f83512d49b5f2213d4804e4698a5fecc69a4 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:00:00 +0000 Subject: [PATCH 13/39] Delete the from_code_point seed builtin (v1 purpose test: v2 single authority); migrate v1's own callers to char_text The interpreter dispatches builtins before module fns, so the std declaration was unreachable while the builtin existed. Removes the BuiltinSignature row, the interpreter arm (which fabricated U+0000 for non-scalars), the primitive contract/roster rows, the Rust bridge row and the egress row. Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/languages/rust/emit.dag | 1 - dag/gunbc/primitive_egress/dispositions_text.dag | 1 - ...from_code_point_binds_the_total_seed_builtin.dag | 1 + dag/gunbc/v1/v1_interpreter_primitive_surface.dag | 9 --------- dag/std/primitives.dag | 10 ---------- src/v1/01_tokenize.dag | 3 ++- src/v1/04_method.dag | 1 - src/v1/05_emit.dag | 5 +++-- src/v1/05_emit_core_support.dag | 13 +++++++------ src/v1/stage0/src/v1_interpreter.rs | 6 ------ .../stage0/src/v1_interpreter_dispatch_generated.rs | 3 --- src/v2/lens/text_string_importer_census.dag | 2 -- 12 files changed, 13 insertions(+), 42 deletions(-) diff --git a/dag/extdeps/languages/rust/emit.dag b/dag/extdeps/languages/rust/emit.dag index 2bffcb57d7d..b1b61fd08d0 100644 --- a/dag/extdeps/languages/rust/emit.dag +++ b/dag/extdeps/languages/rust/emit.dag @@ -287,7 +287,6 @@ data rt_function_registry: List = [ { name: "scan_to_eol", bridge_name: "scan_to_eol", passes_by_ref: true, wraps_result: false }, { name: "scan_string_end", bridge_name: "scan_string_end", passes_by_ref: true, wraps_result: false }, { name: "code_point", bridge_name: "code_point", passes_by_ref: false, wraps_result: false }, - { name: "from_code_point", bridge_name: "from_code_point", passes_by_ref: false, wraps_result: false }, { name: "lookup", bridge_name: "lookup", passes_by_ref: true, wraps_result: false }, { name: "get", bridge_name: "list_get_optional", passes_by_ref: true, wraps_result: false }, { name: "index_by", bridge_name: "rc_index_by", passes_by_ref: false, wraps_result: false }, diff --git a/dag/gunbc/primitive_egress/dispositions_text.dag b/dag/gunbc/primitive_egress/dispositions_text.dag index 19114163c71..46a4c5cec8d 100644 --- a/dag/gunbc/primitive_egress/dispositions_text.dag +++ b/dag/gunbc/primitive_egress/dispositions_text.dag @@ -43,7 +43,6 @@ fn dispositions_text_rows() -> List { evidence_row(name: "skip_horizontal_ws", category: TextOps, external_subject: NoExternalSubject, computation: computes(authority: declared_authority(module_path: "std.primitives", decl_name: "skip_horizontal_ws_contract"), inputs: "s: String, start: Int", result: "Int: first offset at or after start that is not space or tab", body: DagBodyRequired), refusals: refusals_unmodeled(detail: "start beyond the length is unmodeled"), realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "skip_horizontal_ws: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), evidence_row(name: "record_source_chars_index_lookup", category: TextOps, external_subject: NoExternalSubject, computation: computes(authority: authority_required(home: "std.algebra: an offset-to-code-point index over FreeMonoid"), inputs: "file: String, offset: Int", result: "the code-point index of a byte offset in an already-acquired source", body: DagBodyRequired), refusals: RefusalsTyped, realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "record_source_chars_index_lookup: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), evidence_row(name: "code_point", category: Encoding, external_subject: NoExternalSubject, computation: computes(authority: declared_authority(module_path: "std.primitives", decl_name: "code_point_contract"), inputs: "c: String (one code point)", result: "Int: the Unicode scalar value", body: DagBodyRequired), refusals: refusals_unmodeled(detail: "a multi-code-point or empty argument has no modeled result"), realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "code_point: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), - evidence_row(name: "from_code_point", category: Encoding, external_subject: NoExternalSubject, computation: computes(authority: declared_authority(module_path: "std.primitives", decl_name: "from_code_point_contract"), inputs: "cp: Int", result: "String of one code point", body: DagBodyRequired), refusals: refusals_unmodeled(detail: "a surrogate or out-of-range Int is a host panic, not a typed refusal"), realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "from_code_point: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), evidence_row(name: "utf8_encode_bytes", category: Encoding, external_subject: NoExternalSubject, computation: computes(authority: authority_required(home: "std.encoding (UTF-8 encoder over the NUMERIC-BIT-0 word substrate)"), inputs: "s: String", result: "Bytes: the UTF-8 encoding; total", body: DagBodyRequired), refusals: RefusalsTyped, realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "utf8_encode_bytes: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), evidence_row(name: "utf8_decode_bytes", category: Encoding, external_subject: NoExternalSubject, computation: computes(authority: authority_required(home: "std.encoding (UTF-8 decoder)"), inputs: "bytes: Bytes", result: "String or a decode refusal at the first invalid sequence", body: DagBodyRequired), refusals: refusals_unmodeled(detail: "the decode refusal is a host error string, not a typed boundary refusal"), realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "utf8_decode_bytes: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), evidence_row(name: "bytes_octets", category: Encoding, external_subject: NoExternalSubject, computation: computes(authority: authority_required(home: "std.bytes"), inputs: "bytes: Bytes", result: "List of octets 0..255; total", body: DagBodyRequired), refusals: RefusalsTyped, realization: NoNativeRealizationClaim, compiler_query: NotACompilerQuery, conflict: NoMeaningConflict, located: "bytes_octets: the realization surfaces the census joins (registry row / contract row / algebra template / rt bridge / interpreter arm as present) and the authority named in the computation standing", next: "the owning lane lands the .dag body under the declared authority and switches one production consumer; the interpreter arm and bridge then delete for that consumer"), diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 5e36acf3f38..994e58aa218 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -13,6 +13,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", + "DISPOSITION OF THE SEED BUILTIN (lively-crane-656 decision, 2026-10-05): the v1 interpreter dispatches builtins BEFORE module functions (v1.interpreter eval_call: eval_builtin before lookup_fn), so std.unicode.scalar from_code_point is unreachable while the builtin of the same name exists; renaming the declaration would be a nickname. So the builtin is DELETED in the same change -- its BuiltinSignature row (v1.compiler.infer_method), its interpreter dispatch arm (gunbc.v1.v1_interpreter_primitive_surface), its primitive contract and roster rows (std.primitives), its Rust bridge row (extdeps.languages.rust.emit) and its egress evidence row (gunbc.primitive_egress.dispositions_text). Its interpreter realization was char::from_u32(cp).unwrap_or(NUL): every surrogate or out-of-range Int became U+0000 text, a silent widen that the deletion removes. Admitted under v1's purpose test (gunbc.v1_maintenance_standing v1_seed_standing): it serves the v2 single authority. CONSEQUENCE: every identity in the population above is UNBOUND once the builtin is gone, so the deletion and the migration of the whole population land as ONE unit, and this row's population is empty when that unit lands.", ], evidence: [ DeclarationRef { module_path: "std.unicode.scalar", decl_name: "from_code_point", field: WholeDeclaration }, diff --git a/dag/gunbc/v1/v1_interpreter_primitive_surface.dag b/dag/gunbc/v1/v1_interpreter_primitive_surface.dag index 7120ded7fd9..b005bb221ee 100644 --- a/dag/gunbc/v1/v1_interpreter_primitive_surface.dag +++ b/dag/gunbc/v1/v1_interpreter_primitive_surface.dag @@ -632,15 +632,6 @@ fn v1_interpreter_authored_roster_arms() -> List List { "parse_int", "char_at", "substring", - "from_code_point", "chars_to_string", "record_source_chars_index_lookup", "resolution_silent_pick_is_enabled", @@ -762,7 +753,6 @@ fn primitive_contract_roster() -> List { str_eq_contract, replace_section_contract, code_point_contract, - from_code_point_contract, scan_while_contract, skip_horizontal_ws_contract, scan_to_eol_contract, diff --git a/src/v1/01_tokenize.dag b/src/v1/01_tokenize.dag index e0c417a8c6b..11c11b4bba9 100644 --- a/src/v1/01_tokenize.dag +++ b/src/v1/01_tokenize.dag @@ -7,6 +7,7 @@ import std.source_annotation { advance_line_prefix_indent_only_text, placement_from_line_prefix } import std.unicode.types { unicode_scalar } +import std.unicode.scalar { char_text } import v1.std.core { make_file_span, @@ -93,7 +94,7 @@ fn make_token(text: String, span: SourceSpan, shape: TokenShape) -> Token { } fn source_char(source: SourceRef, pos: Int) -> String { - from_code_point(cp: source.source_chars[pos]) + char_text(c: source.source_chars[pos]) } fn source_code_point(source: SourceRef, pos: Int) -> Int { diff --git a/src/v1/04_method.dag b/src/v1/04_method.dag index 0b422320ffb..f4d06acb248 100644 --- a/src/v1/04_method.dag +++ b/src/v1/04_method.dag @@ -314,7 +314,6 @@ data builtin_function_registry: Map = { "char_at": BuiltinSignature { params: [BuiltinParam { name: "s", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "pos", ty: NamedTemplate { name: "Int" } }], returns: string_type }, "substring": derived_signature(names: ["s", "start", "end"], method: "substring", returns: string_type), "json_unescape_checked": BuiltinSignature { params: [BuiltinParam { name: "s", ty: NamedTemplate { name: "String" } }], returns: with_optional_cardinality(n: string_type) }, - "from_code_point": BuiltinSignature { params: [BuiltinParam { name: "cp", ty: NamedTemplate { name: "Int" } }], returns: string_type }, "chars_to_string": BuiltinSignature { params: [BuiltinParam { name: "chars", ty: ContainerOf { source: Named { name: "List" }, element: NamedTemplate { name: "Int" } } }, BuiltinParam { name: "start", ty: NamedTemplate { name: "Int" } }, BuiltinParam { name: "end", ty: NamedTemplate { name: "Int" } }], returns: string_type }, "record_source_chars_index_lookup": BuiltinSignature { params: [], returns: unit_type }, "resolution_silent_pick_is_enabled": BuiltinSignature { params: [], returns: bool_type }, diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index 3dc364c1280..13a9abf7cc1 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -3,6 +3,7 @@ module v1.compiler.emit import std.occurrence_identity { OccurrenceSynthetic, OccurrenceMinted, OccurrencePending, OccurrenceProjected, OccurrenceId, NodeOccurrenceIdentity, occurrence_id_eq } import std.coercion { TypeRealizationDecision } +import std.unicode.scalar { char_text } import std.syntax { LiteralValue, BinOp, AlgebraFieldKind } import v1.std.core { @@ -2269,8 +2270,8 @@ fn emit_suffix_escape_ident(converted: String, suffix: String, keywords: List String { - if d < 10 { from_code_point(cp: 48 + d) } - else { from_code_point(cp: 55 + d) } + if d < 10 { char_text(c: 48 + d) } + else { char_text(c: 55 + d) } } fn int_to_upper_hex_inner(n: Int, acc: String) -> String { diff --git a/src/v1/05_emit_core_support.dag b/src/v1/05_emit_core_support.dag index 2cb12d4b4a6..9baa07084ff 100644 --- a/src/v1/05_emit_core_support.dag +++ b/src/v1/05_emit_core_support.dag @@ -10,6 +10,7 @@ import v1.std.core { } import v1.compiler.artifact { RenderTarget } +import std.unicode.scalar { char_text } import gunbc.rust_emitted_edge { EmittedEdge, module_to_filename } import v1.compiler.infer_items { ResolvedGraph, TypedModule, leaf_owner_modules_from_registry } @@ -140,7 +141,7 @@ fn to_snake(name: String) -> String { concat("_", to_lower_char(ch: ch)) } } else { - from_code_point(cp: ch) + char_text(c: ch) } ) result |> join(separator: "") @@ -159,9 +160,9 @@ fn to_lower_char(ch: Int) -> String { let cp = ch if cp >= 65 && cp <= 90 { let lower_cp = cp + 32 - from_code_point(cp: lower_cp) + char_text(c: lower_cp) } else { - from_code_point(cp: ch) + char_text(c: ch) } } @@ -169,9 +170,9 @@ fn to_upper_char(ch: Int) -> String { let cp = ch if cp >= 97 && cp <= 122 { let upper_cp = cp - 32 - from_code_point(cp: upper_cp) + char_text(c: upper_cp) } else { - from_code_point(cp: ch) + char_text(c: ch) } } @@ -206,7 +207,7 @@ fn capitalize_first(s: String) -> String { if pair.first == 0 { to_upper_char(ch: pair.second) } else { - from_code_point(cp: pair.second) + char_text(c: pair.second) } ) |> join(separator: "") } diff --git a/src/v1/stage0/src/v1_interpreter.rs b/src/v1/stage0/src/v1_interpreter.rs index a201aa1f29f..5c7803cec95 100644 --- a/src/v1/stage0/src/v1_interpreter.rs +++ b/src/v1/stage0/src/v1_interpreter.rs @@ -23452,12 +23452,6 @@ macro_rules! v1_builtin_arms { Ok(Some(Value::Int(cp))) }, - arm "free_call.from_code_point" { "from_code_point" } => { - let cp = expect_int($positional.first().copied(), "from_code_point")?; - let c = char::from_u32(cp as u32).unwrap_or('\0'); - Ok(Some(str_value(c.to_string()))) - }, - arm "free_call.is_xid_start" { "is_xid_start" } => { let cp = expect_int($positional.first().copied(), "is_xid_start")?; Ok(Some(Value::Bool(v1_rt::is_xid_start(cp)))) diff --git a/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs b/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs index 84c11837dc2..d28041be8f9 100644 --- a/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs +++ b/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs @@ -37,7 +37,6 @@ pub enum EvalBuiltinArm { FreeCallContains, FreeCallReplace, FreeCallCodePoint, - FreeCallFromCodePoint, FreeCallIsXidStart, FreeCallIsXidContinue, FreeCallIsEmojiIdent, @@ -184,7 +183,6 @@ pub fn lookup_eval_builtin_inner(spelling: &str) -> Option { "contains" => Some(EvalBuiltinArm::FreeCallContains), "replace" => Some(EvalBuiltinArm::FreeCallReplace), "code_point" => Some(EvalBuiltinArm::FreeCallCodePoint), - "from_code_point" => Some(EvalBuiltinArm::FreeCallFromCodePoint), "is_xid_start" => Some(EvalBuiltinArm::FreeCallIsXidStart), "is_xid_continue" => Some(EvalBuiltinArm::FreeCallIsXidContinue), "is_emoji_ident" => Some(EvalBuiltinArm::FreeCallIsEmojiIdent), @@ -335,7 +333,6 @@ macro_rules! eval_builtin_inner_arm { ("free_call.contains") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallContains }; ("free_call.replace") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallReplace }; ("free_call.code_point") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallCodePoint }; - ("free_call.from_code_point") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallFromCodePoint }; ("free_call.is_xid_start") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallIsXidStart }; ("free_call.is_xid_continue") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallIsXidContinue }; ("free_call.is_emoji_ident") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallIsEmojiIdent }; diff --git a/src/v2/lens/text_string_importer_census.dag b/src/v2/lens/text_string_importer_census.dag index b23569737ab..d873a03faf1 100644 --- a/src/v2/lens/text_string_importer_census.dag +++ b/src/v2/lens/text_string_importer_census.dag @@ -53,7 +53,6 @@ import std.primitives { str_eq_contract, replace_section_contract, code_point_contract, - from_code_point_contract, scan_while_contract, skip_horizontal_ws_contract, scan_to_eol_contract, @@ -148,7 +147,6 @@ data host_text_primitive_contracts: List = [ str_eq_contract, replace_section_contract, code_point_contract, - from_code_point_contract, scan_while_contract, skip_horizontal_ws_contract, scan_to_eol_contract, From f7bda8a287f96465a821f67942ad320a23ed0a2d Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:00:02 +0000 Subject: [PATCH 14/39] wip-tmp --- dag/extdeps/http/form_urlencoded.dag | 3 ++- dag/extdeps/standards/rfc_8949.dag | 3 ++- dag/extdeps/uri.dag | 17 ++++++++++------ dag/gunbc/auth/approval_device_wire.dag | 3 ++- dag/gunbc/auth/oidc_id_token_verification.dag | 3 ++- dag/std/encoding.dag | 20 +++++++++++++------ 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/dag/extdeps/http/form_urlencoded.dag b/dag/extdeps/http/form_urlencoded.dag index 0b31f9a0719..34f746e45ba 100644 --- a/dag/extdeps/http/form_urlencoded.dag +++ b/dag/extdeps/http/form_urlencoded.dag @@ -4,6 +4,7 @@ import std.types { String, List, Bool, Int } import std.integer { UInt8 } import std.bytes { utf8_encode_bytes, bytes_octets } import std.encoding { utf8_decode_octets } +import std.coercion { unicode_scalar_fold } import v2.std.algebra { any, filter } // WHATWG URL, application/x-www-form-urlencoded: split pairs before decoding, plus means space, @@ -47,7 +48,7 @@ fn form_component(wire: String) -> String? { FormOctetsRefused => none FormOctetsDecoded { octets } => match utf8_decode_octets(octets: octets) { Absent => none - Present { value: scalars } => Present { value: join(map(scalars, cp => from_code_point(cp: cp)), "") } + Present { value: scalars } => Present { value: unicode_scalar_fold(xs: scalars) } } } } diff --git a/dag/extdeps/standards/rfc_8949.dag b/dag/extdeps/standards/rfc_8949.dag index 03121c7ea73..40b3e8974b5 100644 --- a/dag/extdeps/standards/rfc_8949.dag +++ b/dag/extdeps/standards/rfc_8949.dag @@ -4,6 +4,7 @@ import std.types { Int, String, List } import std.logic { Bool } import std.measure { ByteSize, byte_size, byte_size_count } import std.encoding { utf8_decode_octets } +import std.coercion { unicode_scalar_fold } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } @@ -148,7 +149,7 @@ fn cbor_slice(octets: List, at: Int, n: Int) -> List { fn cbor_text_of_octets(octets: List) -> String? { match utf8_decode_octets(octets: octets) { Absent => none - Present { value: cps } => Present { value: fold(cps, init: "", f: (acc, cp) => acc + from_code_point(cp: cp)) } + Present { value: cps } => Present { value: unicode_scalar_fold(xs: cps) } } } diff --git a/dag/extdeps/uri.dag b/dag/extdeps/uri.dag index d058412bba7..eab01c7a673 100644 --- a/dag/extdeps/uri.dag +++ b/dag/extdeps/uri.dag @@ -2,7 +2,8 @@ module extdeps.uri import std.algebra { trim } -import std.types { NonEmptyStr, List } +import std.types { NonEmptyStr, List, Char } +import std.coercion { unicode_scalar_fold } import std.unicode.types { unicode_scalar_max_code_point, unicode_surrogate_first_code_point, @@ -567,12 +568,16 @@ type UriDecodeUtf8 = UriUtf8Idle | UriUtf8Need { cp: Int, remaining: Int, least: Int } +// Every member of `out` is a Unicode scalar: a literal character of the input, an escaped octet +// below 128, or a completed sequence that passed uri_decode_scalar_admitted. So it is declared +// List and spelled through the total std.coercion unicode_scalar_fold. The admission is the +// guarantee; the seed does not enforce Char's refinement at a field. // Decoded scalars are accumulated in REVERSE (one cons each, one reverse at the end), so decoding is // linear in the input rather than copying the accumulator per scalar. type UriPercentDecodeFold - = UriDecodeText { out: List, utf8: UriDecodeUtf8 } - | UriDecodeAfterPercent { out: List, utf8: UriDecodeUtf8 } - | UriDecodeAfterHighNibble { out: List, utf8: UriDecodeUtf8, high: Int } + = UriDecodeText { out: List, utf8: UriDecodeUtf8 } + | UriDecodeAfterPercent { out: List, utf8: UriDecodeUtf8 } + | UriDecodeAfterHighNibble { out: List, utf8: UriDecodeUtf8, high: Int } | UriDecodeRefused { cause: UriPercentDecodeRefusalCause } fn uri_hex_digit_value(cp: Int) -> Int? { @@ -587,7 +592,7 @@ fn uri_decode_scalar_admitted(cp: Int, least: Int) -> Bool { && (cp < unicode_surrogate_first_code_point || cp > unicode_surrogate_last_code_point) } -fn uri_decode_octet(out: List, utf8: UriDecodeUtf8, b: Int) -> UriPercentDecodeFold { +fn uri_decode_octet(out: List, utf8: UriDecodeUtf8, b: Int) -> UriPercentDecodeFold { match utf8 { UriUtf8Idle => if b < 128 { UriDecodeText { out: Cons { head: b, tail: out }, utf8: UriUtf8Idle } } @@ -636,7 +641,7 @@ fn uri_percent_decode_component(value: String) -> UriPercentDecodeComponent { UriDecodeText { out: out, utf8: u } => match u { UriUtf8Need { cp: _, remaining: _, least: _ } => UriPercentComponentDecodeRefused { cause: UriPercentDecodeNotUtf8 } - UriUtf8Idle => UriPercentComponentDecoded { value: join(reverse(out) |> map(c => from_code_point(cp: c)), "") } + UriUtf8Idle => UriPercentComponentDecoded { value: unicode_scalar_fold(xs: reverse(out)) } } } } diff --git a/dag/gunbc/auth/approval_device_wire.dag b/dag/gunbc/auth/approval_device_wire.dag index 2725e213736..07be9e7966c 100644 --- a/dag/gunbc/auth/approval_device_wire.dag +++ b/dag/gunbc/auth/approval_device_wire.dag @@ -13,6 +13,7 @@ import gunbc.auth.approval_capability { ProposedDecision, ProposeApprove, Propos import std.logic { Bool } import std.integer { QualifiedOctetsReady, QualifiedOctetsRefused, UInt8 } import std.encoding { base64_encode, base64_octets, base64_decode, UrlSafe, utf8_decode_octets } +import std.coercion { unicode_scalar_fold } import std.bytes { utf8_encode_bytes, bytes_octets, pure_dag_seam_unreachable_string } import extdeps.languages.json.emit { JsonValue, JsonObject, JsonString, JsonKeyValue, serialize_json, json_object, json_kv, json_string, json_array } import extdeps.languages.json.parse { @@ -964,7 +965,7 @@ fn decode_path_segment(presented: String) -> PathSegmentDecode { Present { value: cps } => if cps == [] { PathSegmentMalformed { cause: "segment names an empty identity" } } else { - let identity = join(map(cps, cp => from_code_point(cp: cp)), "") as NonEmptyStr + let identity = unicode_scalar_fold(xs: cps) as NonEmptyStr let canonical = path_segment(s: identity) if (canonical as String) == presented { PathSegmentDecoded { identity: identity } } else { PathSegmentNonCanonical { presented: presented as NonEmptyStr, canonical: canonical } } diff --git a/dag/gunbc/auth/oidc_id_token_verification.dag b/dag/gunbc/auth/oidc_id_token_verification.dag index b91e8396b6b..ad5e5f56470 100644 --- a/dag/gunbc/auth/oidc_id_token_verification.dag +++ b/dag/gunbc/auth/oidc_id_token_verification.dag @@ -25,6 +25,7 @@ module gunbc.auth.oidc_id_token_verification import std.types { String, NonEmptyStr, Int, List, FilePath, Email } import std.encoding { base64_decode, base64_encode, base64_octets, UrlSafe, Standard, utf8_decode_octets } +import std.coercion { unicode_scalar_fold } import std.integer { QualifiedOctetsReady, QualifiedOctetsRefused } import std.bytes { pure_dag_seam_unreachable_string } import std.algebra { trim } @@ -147,7 +148,7 @@ fn jwt_segment_json(segment: String) -> JwtSegmentJson { match utf8_decode_octets(octets: octets) { Absent => JwtSegmentJsonRefused { reason: "a segment does not decode as UTF-8" } Present { value: cps } => - match parse_json_document(s: join(map(cps, cp => from_code_point(cp: cp)), "")) { + match parse_json_document(s: unicode_scalar_fold(xs: cps)) { JsonDocumentUnreadable { gap: g } => JwtSegmentJsonRefused { reason: concat("a segment is not one JSON document: ", json_document_gap_text(gap: g)) } JsonDocumentParsed { value: v } => JwtSegmentJsonDecoded { value: v } diff --git a/dag/std/encoding.dag b/dag/std/encoding.dag index b836f3b0ced..b28fe5d0543 100644 --- a/dag/std/encoding.dag +++ b/dag/std/encoding.dag @@ -1,7 +1,7 @@ module std.encoding import std.algebra { BoundedLattice } -import std.types { Bytes } +import std.types { Bytes, Char } import std.integer { UInt8Result, UInt8Ready, UInt8OutOfRange, uint8_of_int, QualifiedOctets, QualifiedOctetsResult, QualifiedOctetsReady, QualifiedOctetsRefused, uint8_octets_of_ints, qualified_octet_members } import std.machine_word { Word, Width8, Width32, WordResult, WordReady, WordRefused, WordValueOutOfRange, OctetsResult, OctetsReady, OctetsRefused, word_of_int, word_from_octets, word_to_octets, word_shift_left, word_shift_right, word_and, word_or } import extdeps.toolchain.architecture_profile { BigEndian } @@ -584,10 +584,10 @@ fn utf8_two_remaining_length(l: Utf8TwoRemainingLength) -> Utf8SequenceLength { } type Utf8DecodeState - = Utf8Ready { out: List } - | Utf8NeedOne { out: List, length: Utf8SequenceLength, acc: Int } - | Utf8NeedTwo { out: List, length: Utf8TwoRemainingLength, acc: Int } - | Utf8NeedThree { out: List, acc: Int } + = Utf8Ready { out: List } + | Utf8NeedOne { out: List, length: Utf8SequenceLength, acc: Int } + | Utf8NeedTwo { out: List, length: Utf8TwoRemainingLength, acc: Int } + | Utf8NeedThree { out: List, acc: Int } | Utf8Refused fn utf8_sequence_octet_count(length: Utf8SequenceLength) -> Int { @@ -652,7 +652,15 @@ fn utf8_admit_octet(d: Utf8DecodeState, b: Int) -> Utf8DecodeState { } } -fn utf8_decode_octets(octets: List) -> List? { +// THE DECODER YIELDS SCALARS, AND SAYS SO IN ITS TYPE. Every member it appends has passed this +// fold's own admission (an octet below 128, or a completed sequence that passes +// utf8_scalar_admissible), so it is a Unicode scalar, and the result is declared List rather +// than List. Returning List threw that proof away and made every caller spell the +// scalars through a partial Int route whose refusal could not fire. A caller now spells the text +// through the total std.coercion unicode_scalar_fold. THE TYPE STATES THE SHAPE, AND THE ADMISSION +// ABOVE IS THE GUARANTEE: the seed does not enforce Char's `where unicode_scalar` refinement at an +// argument or field, so the Char annotation is not itself a proof. +fn utf8_decode_octets(octets: List) -> List? { match fold(octets, init: Utf8Ready { out: [] }, f: (d, octet) => utf8_admit_octet(d: d, b: octet)) { Utf8Ready { out: out } => Present { value: out } Utf8NeedOne { out: _, length: _, acc: _ } => none From f27f5d5065cec9a5ed34c4ad07937a4b84de2d9f Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:00:15 +0000 Subject: [PATCH 15/39] utf8_decode_octets yields List; four callers and uri spell text through unicode_scalar_fold (XL-2 from_code_point, PR 2/2) Co-Authored-By: Claude Opus 5.5 (1M context) --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 56cda463606..0c5debf6728 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -10,7 +10,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", "POPULATION, KIND CHAR (79 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", - "POPULATION, KIND PARSER DECODE (5 identities, re-derived): first filed as 9. RETIRED: extdeps.languages.yaml.ingest::yaml_double_quoted_escape now routes NotUnicodeScalar into YamlScalarRefused, naming the escape and whether it was a surrogate or out of range (YAML 1.2.2 sections 5.1 and 5.7); its six CHAR siblings in the same module moved with it, because imports are per module. tools.fabric_ci_evidence::fabric_ci_decode_step routes it into FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at, cause } }. extdeps.languages.json.parse::json_unescape_decode_piece was DELETED: the .dag json_unescape chain had no consumer, and parse_json decodes through the native json_unescape_checked kernel, which recombines surrogate pairs and refuses an unpaired one (RFC 8259 section 7; RED test.claim.json_parse_witness::an_unpaired_surrogate_refuses_rather_than_vanishing). std.judgment_contract::string_from_code_points was CHAR-kind, not parser decode, because its input was chars(s) of a String; it was deleted for the declared std.coercion unicode_scalar_unfold / unicode_scalar_fold route. REMAINING, re-kinded as UNDER-TYPED UTF-8: each takes the code points that std.encoding utf8_decode_octets has already validated as scalars but returns as List, so the proof is thrown away and no NotUnicodeScalar RED is authorable at the call. The fix is construction (the decoder yields Char; callers use char_text), not routing: extdeps.http.form_urlencoded::form_component, extdeps.standards.rfc_8949::cbor_text_of_octets, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, and extdeps.uri::uri_percent_decode_component (a hand-rolled second UTF-8 decoder, to route through the one std decoder).", + "POPULATION, KIND PARSER DECODE (5 identities, re-derived): first filed as 9. RETIRED: extdeps.languages.yaml.ingest::yaml_double_quoted_escape now routes NotUnicodeScalar into YamlScalarRefused, naming the escape and whether it was a surrogate or out of range (YAML 1.2.2 sections 5.1 and 5.7); its six CHAR siblings in the same module moved with it, because imports are per module. tools.fabric_ci_evidence::fabric_ci_decode_step routes it into FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at, cause } }. extdeps.languages.json.parse::json_unescape_decode_piece was DELETED: the .dag json_unescape chain had no consumer, and parse_json decodes through the native json_unescape_checked kernel, which recombines surrogate pairs and refuses an unpaired one (RFC 8259 section 7; RED test.claim.json_parse_witness::an_unpaired_surrogate_refuses_rather_than_vanishing). std.judgment_contract::string_from_code_points was CHAR-kind, not parser decode, because its input was chars(s) of a String; it was deleted for the declared std.coercion unicode_scalar_unfold / unicode_scalar_fold route. RETIRED BY CONSTRUCTION (the second PR of this lane): std.encoding utf8_decode_octets now yields List, because every member passes the fold's own admission, and its four callers spell the text through the total std.coercion unicode_scalar_fold: extdeps.http.form_urlencoded::form_component, extdeps.standards.rfc_8949::cbor_text_of_octets, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json. extdeps.uri::uri_percent_decode_component accumulates List admitted by its own uri_decode_scalar_admitted and spells it the same way. Its hand-rolled UTF-8 decoder is still a second decoder: it cannot import std.encoding, which reaches extdeps.uri through std.machine_word and extdeps.toolchain.architecture_profile. Consolidating it needs the decoder moved below extdeps.uri. The Char annotations state the shape and not a proof: the seed does not enforce Char's refinement at an argument or field, so the decoders' admissions are the guarantee.", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", ], From 1cd549691c22037d97ec81ed212f0e72b8149a20 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:01:21 +0000 Subject: [PATCH 16/39] RFM: name the decoder-relocation follow-up as the uri duplicate's trigger Co-Authored-By: Claude Opus 5.5 (1M context) --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 0c5debf6728..925e43db252 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -10,7 +10,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", "POPULATION, KIND CHAR (79 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text or a Char constant and needs no refusal: extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located.", - "POPULATION, KIND PARSER DECODE (5 identities, re-derived): first filed as 9. RETIRED: extdeps.languages.yaml.ingest::yaml_double_quoted_escape now routes NotUnicodeScalar into YamlScalarRefused, naming the escape and whether it was a surrogate or out of range (YAML 1.2.2 sections 5.1 and 5.7); its six CHAR siblings in the same module moved with it, because imports are per module. tools.fabric_ci_evidence::fabric_ci_decode_step routes it into FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at, cause } }. extdeps.languages.json.parse::json_unescape_decode_piece was DELETED: the .dag json_unescape chain had no consumer, and parse_json decodes through the native json_unescape_checked kernel, which recombines surrogate pairs and refuses an unpaired one (RFC 8259 section 7; RED test.claim.json_parse_witness::an_unpaired_surrogate_refuses_rather_than_vanishing). std.judgment_contract::string_from_code_points was CHAR-kind, not parser decode, because its input was chars(s) of a String; it was deleted for the declared std.coercion unicode_scalar_unfold / unicode_scalar_fold route. RETIRED BY CONSTRUCTION (the second PR of this lane): std.encoding utf8_decode_octets now yields List, because every member passes the fold's own admission, and its four callers spell the text through the total std.coercion unicode_scalar_fold: extdeps.http.form_urlencoded::form_component, extdeps.standards.rfc_8949::cbor_text_of_octets, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json. extdeps.uri::uri_percent_decode_component accumulates List admitted by its own uri_decode_scalar_admitted and spells it the same way. Its hand-rolled UTF-8 decoder is still a second decoder: it cannot import std.encoding, which reaches extdeps.uri through std.machine_word and extdeps.toolchain.architecture_profile. Consolidating it needs the decoder moved below extdeps.uri. The Char annotations state the shape and not a proof: the seed does not enforce Char's refinement at an argument or field, so the decoders' admissions are the guarantee.", + "POPULATION, KIND PARSER DECODE (5 identities, re-derived): first filed as 9. RETIRED: extdeps.languages.yaml.ingest::yaml_double_quoted_escape now routes NotUnicodeScalar into YamlScalarRefused, naming the escape and whether it was a surrogate or out of range (YAML 1.2.2 sections 5.1 and 5.7); its six CHAR siblings in the same module moved with it, because imports are per module. tools.fabric_ci_evidence::fabric_ci_decode_step routes it into FabricCiEvidenceUndecodable { cause: FabricCiWordNotScalar { at, cause } }. extdeps.languages.json.parse::json_unescape_decode_piece was DELETED: the .dag json_unescape chain had no consumer, and parse_json decodes through the native json_unescape_checked kernel, which recombines surrogate pairs and refuses an unpaired one (RFC 8259 section 7; RED test.claim.json_parse_witness::an_unpaired_surrogate_refuses_rather_than_vanishing). std.judgment_contract::string_from_code_points was CHAR-kind, not parser decode, because its input was chars(s) of a String; it was deleted for the declared std.coercion unicode_scalar_unfold / unicode_scalar_fold route. RETIRED BY CONSTRUCTION (the second PR of this lane): std.encoding utf8_decode_octets now yields List, because every member passes the fold's own admission, and its four callers spell the text through the total std.coercion unicode_scalar_fold: extdeps.http.form_urlencoded::form_component, extdeps.standards.rfc_8949::cbor_text_of_octets, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json. extdeps.uri::uri_percent_decode_component accumulates List admitted by its own uri_decode_scalar_admitted and spells it the same way. Its hand-rolled UTF-8 decoder is still a second decoder: it cannot import std.encoding, which reaches extdeps.uri through std.machine_word and extdeps.toolchain.architecture_profile. TRIGGER (manager-approved follow-up): the UTF-8 decoder moves into a leaf std.unicode.utf8 below extdeps.uri, with the octet admitted by the one octet authority (std.machine_word UInt8, moved down if its bound does not need architecture_profile). That must be SUFFICIENT FOR extdeps.uri uri_percent_decode_component to decode through it with its local UTF-8 fold deleted. The Char annotations state the shape and not a proof: the seed does not enforce Char's refinement at an argument or field, so the decoders' admissions are the guarantee.", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", ], From f4970a2dc33b123e322e7ea3e395f381646ace27 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 11:13:05 +0000 Subject: [PATCH 17/39] Explicit imports where the char_text import turned off the bare channel; RFM char_brand_admits_any_int; CHAR population recorded NAME-MIGRATED, not Char-proven Co-Authored-By: Claude Opus 5.5 (1M context) --- ...ode_point_binds_the_total_seed_builtin.dag | 2 +- .../char_brand_admits_any_int.dag | 21 +++++++++++++++++++ .../claim/char_at_unicode_witness_test.dag | 1 + dag/test/claim/git_ls_remote_witness_test.dag | 1 + dag/test/claim/json_emit_witness_test.dag | 4 ++++ dag/test/claim/json_parse_witness_test.dag | 3 +++ ...ap_keys_interpreter_order_witness_test.dag | 1 + dag/test/claim/yaml_emit_witness_test.dag | 4 ++++ dag/test/claim/yaml_ingest_witness_test.dag | 3 +++ 9 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 dag/gunbc/recurring_failure_mode/char_brand_admits_any_int.dag diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 28cd4f3df14..e7c47918037 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -9,7 +9,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R receipts: [ "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", - "POPULATION, KIND CHAR (85 identities): the code point is a Char by construction (a literal control/separator constant, or a scalar taken from a text unfold), so the migration is std.unicode.scalar char_text and needs no refusal. DISPOSITION: 79 MIGRATED to std.unicode.scalar char_text by the XL-2 CHAR follow-up PR (session sleek-fox-462): extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located. 6 TRANSFERRED, not migrated here, to the PARSER DECODE lane, which migrates extdeps.languages.yaml.ingest whole because importing std.unicode.scalar rebinds the module: extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source.", + "POPULATION, KIND CHAR (85 identities): the code point is a scalar by the CALLER'S construction (a literal control/separator constant, a scalar taken from a text unfold, or ASCII case arithmetic over one), NOT by type: most of these callers hold a plain Int, and acceptance admits an Int at the Char parameter of char_text (gunbc.recurring_failure_mode char_brand_admits_any_int). So the migration to std.unicode.scalar char_text adds no refusal and proves nothing about Char. DISPOSITION: 79 NAME-MIGRATED -- no bare binding of the seed builtin remains at these identities -- and explicitly NOT Char-proven, by the XL-2 CHAR follow-up PR (session sleek-fox-462): extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located. 6 TRANSFERRED, not migrated here, to the PARSER DECODE lane, which migrates extdeps.languages.yaml.ingest whole because importing std.unicode.scalar rebinds the module: extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source.", "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", diff --git a/dag/gunbc/recurring_failure_mode/char_brand_admits_any_int.dag b/dag/gunbc/recurring_failure_mode/char_brand_admits_any_int.dag new file mode 100644 index 00000000000..364f9498929 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/char_brand_admits_any_int.dag @@ -0,0 +1,21 @@ +module gunbc.recurring_failure_mode.char_brand_admits_any_int + +import std.types { NonEmptyStr } +import std.decl_ref { DeclarationRef, WholeDeclaration } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data char_brand_admits_any_int: RecurringFailureMode = RecurringFailureMode { + identity: "char_brand_admits_any_int" as NonEmptyStr, + receipts: [ + "INVALID STATE: a plain Int, including a non-scalar, is accepted at a position declared std.types Char (type Char = Int where unicode_scalar, brand(\"Char\")). So Char is a BRAND, not a type: DESIGN section 4b -- a brand is cosmetic until construction and acceptance enforce the distinction. This is BELOW THE FLOOR (values inhabit declared types), not a differentiator gap.", + "HARM: every totality that rests on 'a Char is a scalar by construction' is unproven. std.unicode.scalar char_text is declared total over Char and spells its argument through std.coercion unicode_scalar_fold with no refusal, so a surrogate reaching it fabricates text silently. The 'Char by construction' reading of a call site cannot be checked by any reviewer or gate today.", + "MEASURED, BOTH ROUTES (2026-10-05, the XL-2 CHAR follow-up PR, session sleek-fox-462). SEED (v1, frozen): gunbc run resolves char_text(c: 55296) -- a surrogate literal -- and char_text(c: x) for x: Int from text.chars() and for cp + 32 with no diagnostic at the Char parameter: ADMITTED, silently. v2 INFER (through v2.test.claim.compiler.infer_fold_member_instance fmi_assemble then fmi_infer_tree, the route the gunbc#13187 controls use): over a fixture declaring the REAL shape, type Char = Int where unicode_scalar, brand(\"Char\"), infer does not judge at all -- every case, including the Char-typed positive control, ends in a runtime pattern-match failure ('non-exhaustive pattern match on: C') before a verdict, so v2 establishes nothing for Char. Over the same fixture with the brand clause removed (a plain refinement), v2 REFUSES both the Int variable and the surrogate literal with application_argument_does_not_inhabit -- so the refinement judge exists and the brand spelling is what v2 cannot read.", + "RUNG FOUND AT: below the ladder on the seed route (silent admission); v2 is loud but judges nothing (a crash, not a refusal). The class's rung is the MINIMUM across in-scope paths (DESIGN section 4b(1)), so it is silent wrongness until the seed route is retired or refuses.", + "CEILING: structurally impossible -- Char a confined type whose ONLY constructor is the checked scalar constructor, so an unchecked Int has no route into Char. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: C4 constructor confinement admits Char only through its checked constructor on the native route (gunbc#13123, sole_constructor + admit_callers), SUFFICIENT FOR char_text(c: 55296) and an Int variable at a Char position to refuse on the native route while a Char produced by the checked constructor is admitted. The same pattern is the parked nominal type-declaration plan gunbc#13024. No parallel remedy is declared here.", + "DEPENDENTS (each rests on this class and is unproven until the trigger holds): std.unicode.scalar char_text totality (gunbc#13378); the planned 'UTF-8 decoder yields Char' change; the 79 NAME-MIGRATED identities of gunbc.recurring_failure_mode bare_from_code_point_binds_the_total_seed_builtin, KIND CHAR, which are recorded there as not Char-proven for this reason.", + ], + evidence: [ + DeclarationRef { module_path: "std.types", decl_name: "Char", field: WholeDeclaration }, + DeclarationRef { module_path: "std.unicode.scalar", decl_name: "char_text", field: WholeDeclaration }, + ], +} diff --git a/dag/test/claim/char_at_unicode_witness_test.dag b/dag/test/claim/char_at_unicode_witness_test.dag index 3bbc82bdff6..2c4e8cc0303 100644 --- a/dag/test/claim/char_at_unicode_witness_test.dag +++ b/dag/test/claim/char_at_unicode_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.char_at_unicode_witness +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly diff --git a/dag/test/claim/git_ls_remote_witness_test.dag b/dag/test/claim/git_ls_remote_witness_test.dag index a1ff10cc933..3829da1e653 100644 --- a/dag/test/claim/git_ls_remote_witness_test.dag +++ b/dag/test/claim/git_ls_remote_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.git_ls_remote_witness_test +import v2.std.live_tree { LiveTreeDisposition } import std.unicode.scalar { char_text } import std.types { Bool, String, Int, List, CommitSha } import extdeps.git { diff --git a/dag/test/claim/json_emit_witness_test.dag b/dag/test/claim/json_emit_witness_test.dag index 1a7586c0774..a0dd8d3b8f4 100644 --- a/dag/test/claim/json_emit_witness_test.dag +++ b/dag/test/claim/json_emit_witness_test.dag @@ -1,5 +1,9 @@ module test.claim.json_emit_witness +import extdeps.external_authority { ExternalAuthority } +import extdeps.languages.json.emit { escape_json_string, json_array, json_bool, json_int, json_int_list, json_kv, json_null, json_number_from_lexeme_string, json_object, json_str_list, json_unicode_escape_hex4, quote_json_string, serialize_json } +import extdeps.languages.json.grammar { json_int_lexeme, json_number_lexeme, json_number_lexeme_valid, json_production_rows } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly diff --git a/dag/test/claim/json_parse_witness_test.dag b/dag/test/claim/json_parse_witness_test.dag index 8f83cfcf37f..e6018302bbe 100644 --- a/dag/test/claim/json_parse_witness_test.dag +++ b/dag/test/claim/json_parse_witness_test.dag @@ -1,5 +1,8 @@ module test.claim.json_parse_witness +import extdeps.languages.json.emit { JsonString, serialize_json } +import extdeps.languages.json.parse { JsonDocumentParsed, JsonDocumentUnreadable, json_string_value_or_empty, parse_json_document } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly diff --git a/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag b/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag index 2a48b7cf2cc..d7ebf3b7e2f 100644 --- a/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag +++ b/dag/test/claim/sorted_map_keys_interpreter_order_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.sorted_map_keys_interpreter_order_witness_test +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly diff --git a/dag/test/claim/yaml_emit_witness_test.dag b/dag/test/claim/yaml_emit_witness_test.dag index 8a3ea2321fd..b7b8cb12bf2 100644 --- a/dag/test/claim/yaml_emit_witness_test.dag +++ b/dag/test/claim/yaml_emit_witness_test.dag @@ -1,5 +1,9 @@ module test.claim.yaml_emit_witness +import extdeps.languages.yaml.emit { EmittedYaml, YamlEmitRefused, emit_yaml } +import extdeps.languages.yaml.ingest { IngestedYaml, ingest_yaml_source } +import extdeps.languages.yaml.types { YamlBool, YamlFloat, YamlInt, YamlKeyValue, YamlMapping, YamlNull, YamlSequence, YamlString, YamlValue } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly diff --git a/dag/test/claim/yaml_ingest_witness_test.dag b/dag/test/claim/yaml_ingest_witness_test.dag index e3c2c8f9e92..f2b60b0a014 100644 --- a/dag/test/claim/yaml_ingest_witness_test.dag +++ b/dag/test/claim/yaml_ingest_witness_test.dag @@ -1,5 +1,8 @@ module test.claim.yaml_ingest_witness +import extdeps.languages.yaml.ingest { IngestedYaml, ReadYamlScalar, YamlIngestRejected, YamlScalarRefused, ingest_yaml_source, yaml_flow_plain_entry, yaml_flow_plain_sequence } +import extdeps.languages.yaml.types { YamlBool, YamlFloat, YamlInt, YamlKeyValue, YamlMapping, YamlNull, YamlSequence, YamlString, YamlValue } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly From 1075f5eec00500b1416b8df16bcc555cbc456253 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:14:28 +0000 Subject: [PATCH 18/39] v1 tokenize: source_char crosses the index through source_code_point (the deleted builtin admitted an Optional index silently) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/01_tokenize.dag | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/v1/01_tokenize.dag b/src/v1/01_tokenize.dag index 11c11b4bba9..110096a1447 100644 --- a/src/v1/01_tokenize.dag +++ b/src/v1/01_tokenize.dag @@ -94,7 +94,7 @@ fn make_token(text: String, span: SourceSpan, shape: TokenShape) -> Token { } fn source_char(source: SourceRef, pos: Int) -> String { - char_text(c: source.source_chars[pos]) + char_text(c: source_code_point(source: source, pos: pos)) } fn source_code_point(source: SourceRef, pos: Int) -> Int { @@ -539,8 +539,9 @@ fn process_escapes(chars: List) -> EscapeProcessResult { // wherever the emitter acts on the declared type it emits a coercion the realization cannot // satisfy: passing `chars[i]` straight to a declared fn parameter emits `.expect(...)` on an `i64` // (E0599). Untouched positions — a let binding, a comparison, arithmetic, a builtin call — happen -// to line up, which is why the corpus has exactly one prior index-as-argument site and it calls the -// BUILTIN `from_code_point`. This accessor is the same shape as `source_code_point` and +// to line up. The one index-as-argument site used to call the BUILTIN `from_code_point`, which +// admitted the Optional index silently; that builtin is deleted (std.unicode.scalar), and source_char +// now crosses through source_code_point like every other site. This accessor is the same shape as `source_code_point` and // `source_char` above: a declared `-> Int` return is what carries the value across a fn boundary. // It works because return position is not checked against the body (recorded on the finalization // carrier, #7481), so it is borrowed load-bearing behavior, not a guarantee. Dissolves together From 2b70fa6cd94498a946a1b8e3b10ed5e3e8b35ea0 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 10:19:14 +0000 Subject: [PATCH 19/39] witness: import the live-tree disposition explicitly (no bare channel) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/test/claim/unicode_scalar_from_code_point_witness_test.dag | 1 + 1 file changed, 1 insertion(+) diff --git a/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag b/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag index 57921c77b62..b708f29673e 100644 --- a/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag +++ b/dag/test/claim/unicode_scalar_from_code_point_witness_test.dag @@ -2,6 +2,7 @@ module test.claim.unicode_scalar_from_code_point_witness import std.error_primitives { Ok, Err } import std.unicode.scalar { CodePointOutOfRange, SurrogateCodePoint, char_text, from_code_point } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly From 07a21d9342aa89790580d83a4865d2247faf08f1 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 11:27:23 +0000 Subject: [PATCH 20/39] git_ls_remote witness: import SubstrateInputsOnly (claims ran nothing without it) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/test/claim/git_ls_remote_witness_test.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/test/claim/git_ls_remote_witness_test.dag b/dag/test/claim/git_ls_remote_witness_test.dag index 3829da1e653..4a335f35f8d 100644 --- a/dag/test/claim/git_ls_remote_witness_test.dag +++ b/dag/test/claim/git_ls_remote_witness_test.dag @@ -1,6 +1,6 @@ module test.claim.git_ls_remote_witness_test -import v2.std.live_tree { LiveTreeDisposition } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import std.unicode.scalar { char_text } import std.types { Bool, String, Int, List, CommitSha } import extdeps.git { From d88ee05ddecb0fa3ea29c23fbb4dd670c3b9460b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:29:44 +0000 Subject: [PATCH 21/39] RFM receipts: the builtin's silent U+0000 (with REDs); name-migrated-not-Char-proven dependents; bare-name silent bind + eval-only type refusal Co-Authored-By: Claude Opus 5.5 (1M context) --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 1 + .../bare_name_resolved_only_by_the_flat_namespace.dag | 1 + ...ment_predicate_enforced_only_where_the_value_is_a_literal.dag | 1 + 3 files changed, 3 insertions(+) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 994e58aa218..52c629967f3 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -14,6 +14,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "POPULATION, KIND OCTET-AS-CHAR (4 identities) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spell a BYTE (0..255) as a Latin-1 character, not a Unicode scalar as text. They do NOT migrate to from_code_point; they need their own declared byte route (octet -> text, or a byte-carrier that never becomes text): extdeps.git.object_store::git_ascii_field_text, extdeps.standards.rfc_5280::ascii_of, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets, test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back.", "POPULATION, KIND STD SEAM (2 identities): a deliberate unreachable seam whose argument is not a code point at all; each is re-derived against its seam's own refusal, not migrated mechanically: std.algebra::trim, std.encoding::utf8_decode_bytes.", "DISPOSITION OF THE SEED BUILTIN (lively-crane-656 decision, 2026-10-05): the v1 interpreter dispatches builtins BEFORE module functions (v1.interpreter eval_call: eval_builtin before lookup_fn), so std.unicode.scalar from_code_point is unreachable while the builtin of the same name exists; renaming the declaration would be a nickname. So the builtin is DELETED in the same change -- its BuiltinSignature row (v1.compiler.infer_method), its interpreter dispatch arm (gunbc.v1.v1_interpreter_primitive_surface), its primitive contract and roster rows (std.primitives), its Rust bridge row (extdeps.languages.rust.emit) and its egress evidence row (gunbc.primitive_egress.dispositions_text). Its interpreter realization was char::from_u32(cp).unwrap_or(NUL): every surrogate or out-of-range Int became U+0000 text, a silent widen that the deletion removes. Admitted under v1's purpose test (gunbc.v1_maintenance_standing v1_seed_standing): it serves the v2 single authority. CONSEQUENCE: every identity in the population above is UNBOUND once the builtin is gone, so the deletion and the migration of the whole population land as ONE unit, and this row's population is empty when that unit lands.", + "SILENT WRONGNESS THE DELETION REMOVES (DESIGN section 5): the deleted builtin's interpreter arm realized from_code_point as char::from_u32(cp).unwrap_or(NUL), so every surrogate or out-of-range Int was answered with plausible U+0000 text and no diagnostic -- outside the guarantee ladder. RED, enrolled: test.claim.unicode_scalar_from_code_point_witness from_code_point_RED_a_surrogate_refuses_as_surrogate (0xD800 -> SurrogateCodePoint, where the builtin answered NUL) and from_code_point_RED_past_the_last_scalar_refuses_as_out_of_range (0x110000 -> CodePointOutOfRange, where the builtin answered NUL); on the decode route, v2.test.claim.body_lowering.string_literal_value_lowering a_non_scalar_unicode_escape_refuses_at_the_scalar_boundary.", ], evidence: [ DeclarationRef { module_path: "std.unicode.scalar", decl_name: "from_code_point", field: WholeDeclaration }, diff --git a/dag/gunbc/recurring_failure_mode/bare_name_resolved_only_by_the_flat_namespace.dag b/dag/gunbc/recurring_failure_mode/bare_name_resolved_only_by_the_flat_namespace.dag index 5a247fafd45..b64a1e548a7 100644 --- a/dag/gunbc/recurring_failure_mode/bare_name_resolved_only_by_the_flat_namespace.dag +++ b/dag/gunbc/recurring_failure_mode/bare_name_resolved_only_by_the_flat_namespace.dag @@ -22,6 +22,7 @@ data bare_name_resolved_only_by_the_flat_namespace: RecurringFailureMode = Recur "NEXT-RUNG TRIGGER, as the capability: every `gunbc.ci.ci_spec` workflow entry is compiled per-entry by a required phase of an existing required lane -- sufficient that an entry which refuses on its own blocks a merge. The design is a floor phase over the entries derived from `gunbc.ci.ci_spec`, with no new job. The trigger is gated on measuring the fold's price first (eager-owl-205, 2026-09-28): the phase runs on every floor, and one per-entry compile over the microvm closure OOMed and timed out on BuildBuddy.", "THE CASE WITH NO IMPORT TO ADD: CONSTRUCTORS OF THE `T?` SUGAR (found on gunbc#13048). extdeps.external_authority `cited_figure_read_obligation(..) -> NonEmptyStr?` returns bare `Absent` and `Present { value: o }`, and no dag/extdeps module imports either name. The seed binds them; the v2 resolver does not: the module's own native resolve refuses resolve_reason_unbound_symbol with resolve_unbound_name_is_declared_in_several_modules at `Absent` (measured through #13028's closure-provider refusal roster, the only refused root in a 15-module std closure). The v2 std modules that did the same had an import to add (v2.std.optional Optional/Present/Absent, #13048), but a module that writes only `T?` names no Optional at all, so for it the language must answer the question this row has not had to: DOES THE `T?` SUGAR BRING ITS CONSTRUCTORS INTO SCOPE, and if so, WHICH declaration do they bind to when several modules declare a Present/Absent? Until that is decided, every dag/extdeps module that constructs or matches a `T?` value refuses its own v2 resolve and drops out of any closure index that needs it. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: a declared binding of the `?` sugar's constructors (to one Optional authority) that v2 resolve consults -- or a ruling that `T?` users must import that authority, with the import then added -- SUFFICIENT FOR extdeps.external_authority to resolve natively.", + "RECEIPT (gunbc#13378, 2026-10-05), A WORSE SHAPE OF THIS CLASS: SILENT BIND TO A DIFFERENT CONTRACT, AND A BELOW-FLOOR TYPING GAP. With the v1 seed builtin from_code_point deleted and std.unicode.scalar from_code_point (Int -> Result) declared, unmigrated callers that never import it -- e.g. gunbc.namespace_step0_subject_collector step0_subject_paths_at, split(s: paths_nul, delimiter: from_code_point(0)) -- did NOT refuse as unbound: the whole-tree flat namespace bound the bare name to the new partial declaration. The seed then ACCEPTED a Result where split declares String (the ordinary compiler floor: values inhabit declared types) and refused only at EVAL, `gunbc run --entry dag/gunbc/instruments/generated_artifact_gate.dag --function main_wet` -> `TypeError { msg: \"split expects a string argument, got Variant\" }`. So a bare caller is not reliably unbound when a same-named declaration exists anywhere in the pool, and the type mismatch it creates is caught by evaluation, not by inference. v1 is semantics-frozen (gunbc.v1_maintenance_standing), so this is recorded rather than fixed there; the remedy for this population is the migration itself, and the evidence that no caller binds this way is the UnimportedBareProvider floor refusal plus a bare-channel resolve over the out-of-gate modules.", ], evidence: [ diff --git a/dag/gunbc/recurring_failure_mode/refinement_predicate_enforced_only_where_the_value_is_a_literal.dag b/dag/gunbc/recurring_failure_mode/refinement_predicate_enforced_only_where_the_value_is_a_literal.dag index e32292c79c6..83d1f2738f4 100644 --- a/dag/gunbc/recurring_failure_mode/refinement_predicate_enforced_only_where_the_value_is_a_literal.dag +++ b/dag/gunbc/recurring_failure_mode/refinement_predicate_enforced_only_where_the_value_is_a_literal.dag @@ -16,6 +16,7 @@ data refinement_predicate_enforced_only_where_the_value_is_a_literal: RecurringF "RUNG FOUND AT AND CURRENT RUNG: silent wrongness, OUTSIDE the ladder, and that is the MINIMUM across all three in-scope routes, which is the rung (DESIGN 4b(1)). Citing the literal wall would be inflation twice over: it is mechanically preventable at best, and the alias receipt shows it defeated by one line. CEILING: structurally guaranteed (3), not impossible (4). non_empty and path_segment_is_safe are total decidable functions of a fully-modeled String, and the compiler already computes the first -- decidable_where_string_predicate_holds runs non_empty today -- so the judgment is not the missing piece; what is missing is that it is attempted only for literals, and that brand carries no predicate to a value's provenance. (4) is out of reach while these are refined ALIASES, because an alias has no constructor to seal, which is why the ceiling stops at (3) rather than at unwritability.", "NEXT-RUNG TRIGGER, capability grain: the refinement judgment decides a value's predicate from its PROVENANCE rather than from its spelling at the seam -- a value whose origin does not establish the predicate is refused at a refined position, at every seam that threads an expected type, with alias-mediated and list-element positions judged exactly as the direct spelling is. Sufficient for flipping every zero-delta assertion in test.claim.refinement_seam_enforcement_witness to expect refusals. NOT satisfied by: widening the literal arm to more literal shapes; promoting WhereRefinementUnenforced from advisory to blocking, which refuses correct code rather than judging it; or adding a predicate to brand() alone, which leaves every non-branded refinement where it is. A SEPARATE AND SMALLER TRIGGER CLOSES THE FORGERY HALF ALONE, and it is worth naming because it does not touch a load-bearing stage: each branded path-segment id becomes a sealed sole_constructor record whose only mint runs path_segment_is_safe, at which point the two prose 'only constructor' claims become walls. That closes forgery for those brands and closes nothing else.", "WHERE THE FIX LIVES, FLAGGED AND NOT STARTED per the census lane's brief: v1.compiler.infer (where_refinement_diags_for_predicate, where_refinement_mismatch_diags) and the disposition policy in v1.std.core -- the v1 seed's inference stage, which DESIGN names as load-bearing, and which is semantics-frozen under gunbc.v1_maintenance_standing so a change there must pass its PURPOSE admission test. READ, NOT MEASURED, and labelled as a code reading rather than a receipt: src/v2/compiler/04_infer.dag carries no where-refinement predicate judgment of any kind, so on the v2 route the wall is not weak but ABSENT, and the question for the fix lane is whether it is BUILT there rather than repaired in the seed. Probing the v2 route by execution is the first step of that lane, not a claim this row makes.", + "DEPENDENTS (gunbc#13378): sites migrated from the deleted seed builtin from_code_point to std.unicode.scalar char_text(c: Char) pass a non-literal Int where Char (= Int where unicode_scalar) is declared, and this row's census means the seed ADMITS them without judging the predicate. They are therefore NAME-MIGRATED, NOT CHAR-PROVEN, and become judged when this row's trigger lands: v1.compiler.tokenize source_char (source_code_point result); v1.compiler.emit hex_digit_char (48 + d / 55 + d); v1.compiler.emit_core_support to_snake, to_lower_char, to_upper_char, capitalize_first; v2.extdeps.languages.dag dag_string_encode_scalar (escape-row spelled value). Sites whose argument already comes from a Char-typed unfold are proven by construction and are not listed.", ], evidence: [], } From 2768bab14c737487b4fe159995400bb502453859 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 11:41:14 +0000 Subject: [PATCH 22/39] Retire the git_ls_remote SubstrateInputsOnly debt row: ImportsFixed Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag b/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag index d2aed32523c..b541b40c993 100644 --- a/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag +++ b/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag @@ -1285,7 +1285,7 @@ data unimported_bare_provider_dispositions: List Date: Mon, 5 Oct 2026 11:58:57 +0000 Subject: [PATCH 23/39] v1 runtime: delete v1_rt::from_code_point (its last bridge row is gone; emitted code reaches the std declaration) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/runtime_rust.dag | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/v1/runtime_rust.dag b/src/v1/runtime_rust.dag index 968c091dbe8..37d4a456757 100644 --- a/src/v1/runtime_rust.dag +++ b/src/v1/runtime_rust.dag @@ -663,9 +663,6 @@ fn rt_unicode_ops() -> String { " }\n", " Some(v)\n", "}\n\n", - "pub fn from_code_point(cp: i64) -> String {\n", - " char::from_u32(cp as u32).map(|c| c.to_string()).unwrap_or_default()\n", - "}\n\n", "pub fn is_xid_start(cp: i64) -> bool {\n", " char::from_u32(cp as u32).map(unicode_ident::is_xid_start).unwrap_or(false)\n", "}\n\n", From ed8f41c80d99cb5b83913a29db9053bc78e57708 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 11:59:12 +0000 Subject: [PATCH 24/39] RFM: record that the interpreted (NUL) and emitted (empty) realizations disagreed Co-Authored-By: Claude Opus 5.5 (1M context) --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 3259a774d9c..09da62e9824 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -14,7 +14,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "POPULATION, KIND OCTET-AS-CHAR (0 identities; 4 dispositioned) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spelled a BYTE as a character. None migrated to from_code_point. DISPOSITIONS: extdeps.git.object_store::git_ascii_field_text -> std.encoding ascii_decode_octets (declared partial ASCII route; NUL refused as the field delimiter by git policy); extdeps.standards.rfc_5280::ascii_of -> REMOVED, read_time_text consumes std.encoding ascii_decode_octets and a non-ASCII Time octet refuses X509TimeNotAscii (behaviour tightening: the old total fold admitted any octet as Latin-1); test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets -> its 0xFF was already a raw octet (std.bytes octets_bytes), only its TAB constant used the bare name, now std.unicode.scalar char_text; test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back -> its 'raw' name was valid UTF-8 by construction, renamed non_ascii_name over char_text, gap filed as gunbc.recurring_failure_mode non_utf8_path_fixture_spelled_through_a_string_path_carrier. No Latin-1 route was declared: no consumer's upstream specifies one.", "POPULATION, KIND STD SEAM (2 identities, BOTH REMOVED): a deliberate unreachable seam whose argument was not a code point at all, re-derived against its seam's own refusal rather than migrated: from_code_point only typed an unreached String. Dispositions: std.encoding::utf8_decode_bytes now returns std.bytes pure_dag_seam_unreachable_string (the named seam refusal); std.algebra::trim cannot import std.bytes (std.bytes -> std.types -> std.algebra would cycle), so it spells that projection's shape in place -- the condition diverges on 1 / 0 before an unreached literal arm. Neither binds the seed builtin; both dissolve with the bottom type std.bytes names.", "DISPOSITION OF THE SEED BUILTIN (lively-crane-656 decision, 2026-10-05): the v1 interpreter dispatches builtins BEFORE module functions (v1.interpreter eval_call: eval_builtin before lookup_fn), so std.unicode.scalar from_code_point is unreachable while the builtin of the same name exists; renaming the declaration would be a nickname. So the builtin is DELETED in the same change -- its BuiltinSignature row (v1.compiler.infer_method), its interpreter dispatch arm (gunbc.v1.v1_interpreter_primitive_surface), its primitive contract and roster rows (std.primitives), its Rust bridge row (extdeps.languages.rust.emit) and its egress evidence row (gunbc.primitive_egress.dispositions_text). Its interpreter realization was char::from_u32(cp).unwrap_or(NUL): every surrogate or out-of-range Int became U+0000 text, a silent widen that the deletion removes. Admitted under v1's purpose test (gunbc.v1_maintenance_standing v1_seed_standing): it serves the v2 single authority. CONSEQUENCE: every identity in the population above is UNBOUND once the builtin is gone, so the deletion and the migration of the whole population land as ONE unit, and this row's population is empty when that unit lands.", - "SILENT WRONGNESS THE DELETION REMOVES (DESIGN section 5): the deleted builtin's interpreter arm realized from_code_point as char::from_u32(cp).unwrap_or(NUL), so every surrogate or out-of-range Int was answered with plausible U+0000 text and no diagnostic -- outside the guarantee ladder. RED, enrolled: test.claim.unicode_scalar_from_code_point_witness from_code_point_RED_a_surrogate_refuses_as_surrogate (0xD800 -> SurrogateCodePoint, where the builtin answered NUL) and from_code_point_RED_past_the_last_scalar_refuses_as_out_of_range (0x110000 -> CodePointOutOfRange, where the builtin answered NUL); on the decode route, v2.test.claim.body_lowering.string_literal_value_lowering a_non_scalar_unicode_escape_refuses_at_the_scalar_boundary.", + "SILENT WRONGNESS THE DELETION REMOVES (DESIGN section 5): the deleted builtin's interpreter arm realized from_code_point as char::from_u32(cp).unwrap_or(NUL), so every surrogate or out-of-range Int was answered with plausible U+0000 text and no diagnostic -- outside the guarantee ladder. AND THE TWO ROUTES DISAGREED: the emitted-Rust realization (v1.compiler.runtime_rust v1_rt from_code_point, reached through the extdeps.languages.rust.emit rt_function_registry bridge row) was char::from_u32(cp).map(..).unwrap_or_default(), i.e. EMPTY text for the same inputs the interpreter answered with U+0000 -- one name, two fabricated answers by route. Both realizations and the bridge row are deleted in this unit; the stage0 mirrors are regenerated with no v1_rt::from_code_point reference. RED, enrolled: test.claim.unicode_scalar_from_code_point_witness from_code_point_RED_a_surrogate_refuses_as_surrogate (0xD800 -> SurrogateCodePoint, where the builtin answered NUL) and from_code_point_RED_past_the_last_scalar_refuses_as_out_of_range (0x110000 -> CodePointOutOfRange, where the builtin answered NUL); on the decode route, v2.test.claim.body_lowering.string_literal_value_lowering a_non_scalar_unicode_escape_refuses_at_the_scalar_boundary.", ], evidence: [ DeclarationRef { module_path: "std.unicode.scalar", decl_name: "from_code_point", field: WholeDeclaration }, From 7364012eb32b5d74c02647b6b50919890f553290 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 12:13:49 +0000 Subject: [PATCH 25/39] RFM: state the row's description over time (found / intermediate / landed) Co-Authored-By: Claude Opus 5.5 (1M context) --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 09da62e9824..41fb1932bf2 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -7,7 +7,7 @@ import gunbc.recurring_failure_mode { RecurringFailureMode } data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = RecurringFailureMode { identity: "bare_from_code_point_binds_the_total_seed_builtin" as NonEmptyStr, receipts: [ - "INVALID STATE: a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", + "STATE OVER TIME: until this row's landing unit, the sentence below described every listed caller; within the unit the builtin is deleted (see DISPOSITION), so on any intermediate head an unmigrated bare caller binds NEITHER contract reliably -- the flat namespace may bind it to the partial declaration, and a stale stage0 mirror may still type it against the deleted signature -- which is why the unit lands only when the population is empty. INVALID STATE (as found): a caller spells an Int code point as text through the BARE name from_code_point, which binds the v1 seed builtin (v1.compiler.infer_method BuiltinSignature \"from_code_point\", Int -> String, TOTAL) rather than the one declaration std.unicode.scalar from_code_point (PARTIAL, Result). The seed builtin is a frozen X in a staged replacement (DESIGN section 3): it answers the same name with a total contract, so a surrogate or out-of-range Int yields fabricated text instead of a typed refusal, and the name has two contracts.", "HARM: no typed refusal for non-scalar input at the parser-decode sites; one name carrying two contracts (and, at the OCTET sites, two MEANINGS). FREEZE: no NEW bare from_code_point caller may be added -- a new caller imports std.unicode.scalar (from_code_point when it holds an Int that may not be a scalar and handles the refusal; char_text when it holds a Char). The freeze is held by review today; a lens over bare-name binding is its next mechanism. RUNG FOUND AT: mitigatable. CEILING: structurally impossible -- no caller binds the seed builtin, so the name has one contract. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: every identity below is migrated or removed (a closed population at identity grain, each removal with its disposition), SUFFICIENT FOR no .dag caller in dag/ or src/v2 to bind the seed builtin by the bare name. RECEIPT: the PR that declared std.unicode.scalar and migrated v2.extdeps.languages.dag, v2.extdeps.languages.swift.rows, v2.std.compilers.semantic_decl_emission and five v2 claim modules.", "POPULATION, KIND CHAR (85 identities): the code point is a scalar by the CALLER'S construction (a literal control/separator constant, a scalar taken from a text unfold, or ASCII case arithmetic over one), NOT by type: most of these callers hold a plain Int, and acceptance admits an Int at the Char parameter of char_text (gunbc.recurring_failure_mode char_brand_admits_any_int). So the migration to std.unicode.scalar char_text adds no refusal and proves nothing about Char. DISPOSITION: 79 NAME-MIGRATED -- no bare binding of the seed builtin remains at these identities -- and explicitly NOT Char-proven, by the XL-2 CHAR follow-up PR (session sleek-fox-462): extdeps.dns.domain_name::fold_dns_case_string_at, extdeps.git::git_diff_name_status_field_separator, extdeps.git.object_store::git_store_object_canonical_hash_input, extdeps.github.actions::runner_label_match_key, extdeps.languages.json.emit::json_escape_replace, extdeps.languages.toml.emit::toml_escape_remaining_control, extdeps.languages.toml.emit::toml_comment_char, extdeps.languages.yaml.emit::yaml_emitted_text, extdeps.needrestart::needrestart_perl_quotemeta_code_point, extdeps.prometheus.client::prometheus_scan_lexeme, extdeps.unicode.display::truncate_text, extdeps.uri::uri_percent_encode_admitted_scalar_wire, gunbc.auth.approval_capability::signing_field_separator, gunbc.harness.harness_turn::harness_worktree_files_changed, tools.emit_host_transport::expected_stdout_nul_run, tools.emit_host_transport::run_ts_smoke, tools.pr_containment_instrument::base_path_set, tools.prose_citation_census::prose_citation_dag_source_paths, gunbc.live_deploy.candidate::scan_checkout_status, gunbc.live_deploy.candidate::scan_ignored_deployed_paths, gunbc.namespace_step0_subject_collector::step0_decode_tree_entry, gunbc.namespace_step0_subject_collector::step0_content_is_text, gunbc.namespace_step0_subject_collector::step0_subject_entries_at, gunbc.namespace_step0_subject_collector::step0_subject_paths_at, gunbc.native_serve::native_serve_value_is_field_safe, gunbc.roadmap_issue_query::issue_query_fold, gunbc.rust_item_host_observation::rust_paths_from_nul, gunbc.stage0_rust_host_observation::rust_paths_from_nul, gunbc.v1_interpreter_dispatch_emit::to_upper_char, gunbc.v1_interpreter_dispatch_emit::capitalize_first, std.content_hash::content_hash_combine_preimage, test.claim.char_at_unicode_witness::ae_b_sample, test.claim.char_at_unicode_witness::ab_e_c_sample, test.claim.char_at_unicode_witness::char_at_past_the_multibyte_char_is_not_a_byte_offset, test.claim.git_ls_remote_witness_test::tab, test.claim.git_upstream_model_witness::ls_tree_z_record, test.claim.git_upstream_model_witness::witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_observes_mode_identity_stage_and_raw_path, test.claim.git_upstream_model_witness::witness_git_index_path_preserves_component_boundaries, test.claim.git_upstream_model_witness::witness_git_ls_files_stage_z_path_containing_space_and_tab_survives_intact, test.claim.heal_candidate_witness::stage_record, test.claim.host_boot_attempt_admission_witness::tab, test.claim.host_boot_attempt_admission_witness::nul, test.claim.json_emit_witness::witness_escape_tab, test.claim.json_emit_witness::witness_escape_carriage_return, test.claim.json_emit_witness::witness_escape_control_u0001, test.claim.json_emit_witness::witness_escape_backslash_leads_over_newline, test.claim.json_emit_witness::witness_escape_control_top_of_range, test.claim.json_parse_witness::a_newline_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_tab_inside_a_string_survives_the_round_trip, test.claim.json_parse_witness::a_literal_backslash_t_does_not_become_a_tab, test.claim.json_parse_witness::a_control_character_with_no_short_escape_survives_the_round_trip, test.claim.json_parse_witness::every_control_character_an_emitter_escapes_comes_back_unchanged, test.claim.json_parse_witness::a_lowercase_hex_escape_decodes_the_same_as_uppercase, test.claim.json_parse_witness::a_surrogate_pair_decodes_to_its_one_scalar, test.claim.live_deploy.candidate_checkout_witness_test::nul, test.claim.live_deploy.deployed_tree_observation_witness::nul, test.claim.namespace_step0_subject_collector_witness::the_subject_filter_takes_dag_sources_under_the_contract_roots_only, test.claim.namespace_step0_subject_collector_witness::a_tree_record_decodes_into_mode_kind_object_and_path, test.claim.namespace_step0_subject_collector_witness::tabbed_path, test.claim.namespace_step0_subject_collector_witness::tabbed_record, test.claim.namespace_step0_subject_collector_witness::a_pathname_containing_a_tab_stays_in_the_subject, test.claim.network_boot_manifest_broker_witness::claims_that_collide_under_a_separator_join_have_distinct_signing_inputs, test.claim.pr_containment_disposition_witness::the_base_path_set_drops_the_trailing_empty_member, test.claim.roadmap_publish_observe_witness_test::tab, test.claim.serving.serving_front_door_witness_test::two_claim_sets_that_collide_under_a_separator_join_sign_apart, test.claim.sorted_map_keys_interpreter_order_witness_test::discriminating_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::reverse_insertion_key_map, test.claim.sorted_map_keys_interpreter_order_witness_test::expected_utf8_byte_order, test.claim.spark_grant_privileged_operation_witness::a_whitespace_only_payload_is_delivered_not_redefined_as_absent, test.claim.spark_grant_privileged_operation_witness::a_trailing_line_break_refuses_rather_than_being_stripped, test.claim.spark_grant_privileged_operation_witness::an_embedded_line_break_refuses_instead_of_being_stripped, test.claim.spark_grant_privileged_operation_witness::a_bare_carriage_return_refuses, test.claim.terminal_wire_projection_witness_test::w_rendered_text_cannot_smuggle_cursor_control_bytes, test.claim.yaml_emit_witness::red_values_the_writer_cannot_write_refuse_with_their_path, test.claim.yaml_ingest_witness::double_quoted_escapes_decode, test.claim.yaml_ingest_witness::a_decoded_u0001_is_content_as_an_item_a_value_and_a_key, test.claim.yaml_ingest_witness::red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck, test.claim.yaml_ingest_witness::red_document_level_refusals_are_located. 6 TRANSFERRED, not migrated here, to the PARSER DECODE lane, which migrates extdeps.languages.yaml.ingest whole because importing std.unicode.scalar rebinds the module: extdeps.languages.yaml.ingest::yaml_refused_characters, extdeps.languages.yaml.ingest::yaml_first_refused_character, extdeps.languages.yaml.ingest::yaml_line_start_mark, extdeps.languages.yaml.ingest::yaml_line_join_mark, extdeps.languages.yaml.ingest::yaml_key_separator, extdeps.languages.yaml.ingest::ingest_yaml_source.", "POPULATION, KIND PARSER DECODE (9 identities): the code point is decoded from external input and may be a surrogate or out of range, so each migrates to std.unicode.scalar from_code_point and routes NotUnicodeScalar into that parser's own typed refusal arm (never an unwrap-to-default): extdeps.http.form_urlencoded::form_component, extdeps.languages.json.parse::json_unescape_decode_piece, extdeps.languages.yaml.ingest::yaml_double_quoted_escape, extdeps.standards.rfc_8949::cbor_text_of_octets, extdeps.uri::uri_percent_decode_component, gunbc.auth.approval_device_wire::decode_path_segment, gunbc.auth.oidc_id_token_verification::jwt_segment_json, tools.fabric_ci_evidence::fabric_ci_decode_step, std.judgment_contract::string_from_code_points.", From 8511cab866eab35629d83124a31f6f787ca2ccc1 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 12:19:32 +0000 Subject: [PATCH 26/39] git_upstream_model_witness: the ls-tree -z fixture's U+00FF is a Char (expects C3 BF), so char_text, not from_code_point Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/test/claim/git_upstream_model_witness_test.dag | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dag/test/claim/git_upstream_model_witness_test.dag b/dag/test/claim/git_upstream_model_witness_test.dag index 811bb38f035..05850ba82d3 100644 --- a/dag/test/claim/git_upstream_model_witness_test.dag +++ b/dag/test/claim/git_upstream_model_witness_test.dag @@ -720,7 +720,10 @@ test fn witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows() -> mode: "100644", object_type: "blob", oid_hex: git_object_id_wire_hex(oid: sha1_blob_regular) as String, - name: concat(from_code_point(255), ".dag"), + // U+00FF as TEXT (a Char, not a byte): utf8_encode_bytes yields C3 BF, which is the + // expected name_non_ascii. Raw 0xFF is the subject of + // witness_git_ls_tree_z_preserves_non_utf8_path_octets, supplied via octets_bytes. + name: concat(char_text(c: 255), ".dag"), ), ), ) From bb5c44b501614f60d5160a10fba0afeb34af4961 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 5 Oct 2026 12:26:19 +0000 Subject: [PATCH 27/39] Hoist two body annotations above their declarations (DESIGN 4c: only leading module-scope // blocks) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/test/claim/git_upstream_model_witness_test.dag | 5 ++--- dag/test/manual/git_upstream_model_execution_test.dag | 9 +++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/dag/test/claim/git_upstream_model_witness_test.dag b/dag/test/claim/git_upstream_model_witness_test.dag index 05850ba82d3..0ac3481e3ff 100644 --- a/dag/test/claim/git_upstream_model_witness_test.dag +++ b/dag/test/claim/git_upstream_model_witness_test.dag @@ -677,6 +677,8 @@ fn ls_tree_z_record(mode: String, object_type: String, oid_hex: String, name: St ) } +// The last record's U+00FF is TEXT (a Char): utf8_encode_bytes yields C3 BF, the expected +// name_non_ascii. Raw 0xFF is witness_git_ls_tree_z_preserves_non_utf8_path_octets's subject. test fn witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows() -> Bool { let text = concat( concat( @@ -720,9 +722,6 @@ test fn witness_git_ls_tree_z_wire_decodes_into_mode_path_and_identity_rows() -> mode: "100644", object_type: "blob", oid_hex: git_object_id_wire_hex(oid: sha1_blob_regular) as String, - // U+00FF as TEXT (a Char, not a byte): utf8_encode_bytes yields C3 BF, which is the - // expected name_non_ascii. Raw 0xFF is the subject of - // witness_git_ls_tree_z_preserves_non_utf8_path_octets, supplied via octets_bytes. name: concat(char_text(c: 255), ".dag"), ), ), diff --git a/dag/test/manual/git_upstream_model_execution_test.dag b/dag/test/manual/git_upstream_model_execution_test.dag index c74ace11189..9e49603ee60 100644 --- a/dag/test/manual/git_upstream_model_execution_test.dag +++ b/dag/test/manual/git_upstream_model_execution_test.dag @@ -99,6 +99,9 @@ fn complete_fixture_repository() -> GitRepositoryState { } } +// The fixture's non-ASCII name is valid UTF-8 (U+00FF reaches disk as C3 BF), because +// extdeps.filesystem carries paths as String; non-UTF-8 octets are witnessed at the decode +// interface instead (gunbc.recurring_failure_mode non_utf8_path_fixture_spelled_through_a_string_path_carrier). fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { let fixture = shell.Mktemp.Dir() if !fixture.success { @@ -115,12 +118,6 @@ fn git_r0_typed_execution_read_back() -> GitR0LiveFixtureOutcome { GitR0LiveFixtureExecutionRefused { diagnostic: "cleanup-refused" } } } else { - // A NON-ASCII, VALID UTF-8 name, and only that: U+00FF reaches the disk as the octets C3 BF - // because extdeps.filesystem's path carrier is String. This fixture never exercised a - // non-UTF-8 path (it used to be spelled as if it did); real non-UTF-8 octets are held by - // test.claim.git_upstream_model_witness witness_git_ls_tree_z_preserves_non_utf8_path_octets, - // and the missing filesystem round-trip is gunbc.recurring_failure_mode - // non_utf8_path_fixture_spelled_through_a_string_path_carrier. let non_ascii_name = concat(char_text(c: 255), ".dag") let readme_path = concat(fixture.path, "/readme") let run_path = concat(fixture.path, "/run") From 40056833a35972d655a7cb8d55e07dfa0d815ebf Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 13:21:14 +0000 Subject: [PATCH 28/39] std.coercion: import the three types it names (NonEmptyStr, DeclarationRef, LiteralHomomorphism) std.coercion had no imports and resolved them only through the whole-tree flat namespace. Once extdeps.uri reached it (char_text / unicode_scalar_fold), every fixture census importing extdeps.uri carried blocking UnresolvedType rows, which regressed guarantee_probe_corpus's sole_constructor_forged_literal_red_refuses, sole_constructor_mint_fn_hole_still_compile_clean and sole_constructor_forged_red_does_not_satisfy_green_expectation (green at merge base 864c9ce0c9). Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/std/coercion.dag | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dag/std/coercion.dag b/dag/std/coercion.dag index 7388e26d707..d2e51c280f8 100644 --- a/dag/std/coercion.dag +++ b/dag/std/coercion.dag @@ -1,5 +1,9 @@ module std.coercion +import std.types { NonEmptyStr } +import std.decl_ref { DeclarationRef } +import std.literal_elaboration { LiteralHomomorphism } + type TypeCheckpoint { dag_name: String target_type: String From 5c06cef9b590994ae4b11f87b1f3ff78a45ff540 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 13:51:38 +0000 Subject: [PATCH 29/39] stage0 partition: place std.unicode.scalar in the std-core unit (beside its consumer extdeps.uri) with its import edges; regenerate the partition Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/stage0/stage0_crate_partition_generated.dag | 1 + src/v2/workflow/rust_crate_partition.dag | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/dag/gunbc/stage0/stage0_crate_partition_generated.dag b/dag/gunbc/stage0/stage0_crate_partition_generated.dag index 457b32bbb87..70d580830b5 100644 --- a/dag/gunbc/stage0/stage0_crate_partition_generated.dag +++ b/dag/gunbc/stage0/stage0_crate_partition_generated.dag @@ -59,6 +59,7 @@ data generated_partition_crate_rows: List = [ "std_checked_arithmetic", "std_induction", "std_graph", + "std_unicode_scalar", "extdeps_uri", "extdeps_external_authority", "extdeps_posix_clock_gettime", diff --git a/src/v2/workflow/rust_crate_partition.dag b/src/v2/workflow/rust_crate_partition.dag index 40d4aa797ba..4c07d58927f 100644 --- a/src/v2/workflow/rust_crate_partition.dag +++ b/src/v2/workflow/rust_crate_partition.dag @@ -327,6 +327,7 @@ fn stage0_std_core_modules() -> List { "std_checked_arithmetic", "std_induction", "std_graph", + "std_unicode_scalar", "extdeps_uri", "extdeps_external_authority", "extdeps_posix_clock_gettime", @@ -563,6 +564,12 @@ fn stage0_cross_unit_import_edges() -> List { stage0_module_dag_edge(from: "std_realization_schedule", to: "std_measure"), stage0_module_dag_edge(from: "std_realization_schedule", to: "std_witness_admission"), stage0_module_dag_edge(from: "extdeps_uri", to: "std_unicode_types"), + stage0_module_dag_edge(from: "extdeps_uri", to: "std_unicode_scalar"), + stage0_module_dag_edge(from: "std_unicode_scalar", to: "std_algebra"), + stage0_module_dag_edge(from: "std_unicode_scalar", to: "std_coercion"), + stage0_module_dag_edge(from: "std_unicode_scalar", to: "std_error_primitives"), + stage0_module_dag_edge(from: "std_unicode_scalar", to: "std_types"), + stage0_module_dag_edge(from: "std_unicode_scalar", to: "std_unicode_types"), stage0_module_dag_edge(from: "std_unicode_types", to: "std_types"), stage0_module_dag_edge(from: "extdeps_external_authority", to: "extdeps_uri"), stage0_module_dag_edge(from: "extdeps_posix_clock_gettime", to: "extdeps_external_authority"), From dae3da9cab445c1c920cae77cc84bbfa4419467c Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 14:14:37 +0000 Subject: [PATCH 30/39] Migrate the two bare from_code_point callers main added after the census (regen_scope_worktree split delimiter and its witness's nul): char_text; record them on the RFM row Found by review 76569 (witness) and the follow-up sweep (production site). Co-Authored-By: Claude Opus 5.5 (1M context) --- .../bare_from_code_point_binds_the_total_seed_builtin.dag | 1 + dag/test/claim/regen_scope_worktree_witness_test.dag | 3 ++- src/v2/workflow/regen_scope_worktree.dag | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag index 117cc471c85..6f8a6dbb809 100644 --- a/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag +++ b/dag/gunbc/recurring_failure_mode/bare_from_code_point_binds_the_total_seed_builtin.dag @@ -14,6 +14,7 @@ data bare_from_code_point_binds_the_total_seed_builtin: RecurringFailureMode = R "POPULATION, KIND OCTET-AS-CHAR (0 identities; 4 dispositioned) -- A SECOND MEANING, A MEANING FORK (DESIGN section 3): these spelled a BYTE as a character. None migrated to from_code_point. DISPOSITIONS: extdeps.git.object_store::git_ascii_field_text -> std.encoding ascii_decode_octets (declared partial ASCII route; NUL refused as the field delimiter by git policy); extdeps.standards.rfc_5280::ascii_of -> REMOVED, read_time_text consumes std.encoding ascii_decode_octets and a non-ASCII Time octet refuses X509TimeNotAscii (behaviour tightening: the old total fold admitted any octet as Latin-1); test.claim.git_upstream_model_witness::witness_git_ls_tree_z_preserves_non_utf8_path_octets -> its 0xFF was already a raw octet (std.bytes octets_bytes), only its TAB constant used the bare name, now std.unicode.scalar char_text; test.manual.git_upstream_model_execution::git_r0_typed_execution_read_back -> its 'raw' name was valid UTF-8 by construction, renamed non_ascii_name over char_text, gap filed as gunbc.recurring_failure_mode non_utf8_path_fixture_spelled_through_a_string_path_carrier. No Latin-1 route was declared: no consumer's upstream specifies one.", "POPULATION, KIND STD SEAM (2 identities, BOTH REMOVED): a deliberate unreachable seam whose argument was not a code point at all, re-derived against its seam's own refusal rather than migrated: from_code_point only typed an unreached String. Dispositions: std.encoding::utf8_decode_bytes now returns std.bytes pure_dag_seam_unreachable_string (the named seam refusal); std.algebra::trim cannot import std.bytes (std.bytes -> std.types -> std.algebra would cycle), so it spells that projection's shape in place -- the condition diverges on 1 / 0 before an unreached literal arm. Neither binds the seed builtin; both dissolve with the bottom type std.bytes names.", "DISPOSITION OF THE SEED BUILTIN (lively-crane-656 decision, 2026-10-05): the v1 interpreter dispatches builtins BEFORE module functions (v1.interpreter eval_call: eval_builtin before lookup_fn), so std.unicode.scalar from_code_point is unreachable while the builtin of the same name exists; renaming the declaration would be a nickname. So the builtin is DELETED in the same change -- its BuiltinSignature row (v1.compiler.infer_method), its interpreter dispatch arm (gunbc.v1.v1_interpreter_primitive_surface), its primitive contract and roster rows (std.primitives), its Rust bridge row (extdeps.languages.rust.emit) and its egress evidence row (gunbc.primitive_egress.dispositions_text). Its interpreter realization was char::from_u32(cp).unwrap_or(NUL): every surrogate or out-of-range Int became U+0000 text, a silent widen that the deletion removes. Admitted under v1's purpose test (gunbc.v1_maintenance_standing v1_seed_standing): it serves the v2 single authority. CONSEQUENCE: every identity in the population above is UNBOUND once the builtin is gone, so the deletion and the migration of the whole population land as ONE unit, and this row's population is empty when that unit lands.", + "LATE ARRIVALS, CHAR KIND, dispositioned in the unit: two bare callers reached this branch from main AFTER the census was taken (both a NUL separator, so char_text, no refusal): v2.workflow.regen_scope_worktree (the split delimiter at its one from_code_point site) and test.claim.regen_scope_worktree_witness::nul (found by review 76569). This is why the landing evidence is the compiler's bare-channel report over the combined head, not this census: a census is closed only at the head it is taken on.", "SILENT WRONGNESS THE DELETION REMOVES (DESIGN section 5): the deleted builtin's interpreter arm realized from_code_point as char::from_u32(cp).unwrap_or(NUL), so every surrogate or out-of-range Int was answered with plausible U+0000 text and no diagnostic -- outside the guarantee ladder. AND THE TWO ROUTES DISAGREED: the emitted-Rust realization (v1.compiler.runtime_rust v1_rt from_code_point, reached through the extdeps.languages.rust.emit rt_function_registry bridge row) was char::from_u32(cp).map(..).unwrap_or_default(), i.e. EMPTY text for the same inputs the interpreter answered with U+0000 -- one name, two fabricated answers by route. Both realizations and the bridge row are deleted in this unit; the stage0 mirrors are regenerated with no v1_rt::from_code_point reference. RED, enrolled: test.claim.unicode_scalar_from_code_point_witness from_code_point_RED_a_surrogate_refuses_as_surrogate (0xD800 -> SurrogateCodePoint, where the builtin answered NUL) and from_code_point_RED_past_the_last_scalar_refuses_as_out_of_range (0x110000 -> CodePointOutOfRange, where the builtin answered NUL); on the decode route, v2.test.claim.body_lowering.string_literal_value_lowering a_non_scalar_unicode_escape_refuses_at_the_scalar_boundary.", ], evidence: [ diff --git a/dag/test/claim/regen_scope_worktree_witness_test.dag b/dag/test/claim/regen_scope_worktree_witness_test.dag index 5ae28e97898..0b35ff8b1e5 100644 --- a/dag/test/claim/regen_scope_worktree_witness_test.dag +++ b/dag/test/claim/regen_scope_worktree_witness_test.dag @@ -1,6 +1,7 @@ module test.claim.regen_scope_worktree_witness import std.types { Bool, String, List } +import std.unicode.scalar { char_text } import v2.workflow.regen_scope_worktree { RegenScopeWorktreeAdmission, ScopeWorktreeAdmitted, ScopeWorktreeHasUncommittedDag, ScopeWorktreeUnobservable, regen_scope_worktree_admission, regen_scope_worktree_refusal @@ -35,7 +36,7 @@ test fn the_local_no_event_baseline_diffs_from_the_merge_base() -> Bool { } } -data nul: String = from_code_point(0) +data nul: String = char_text(c: 0) test fn a_clean_tree_admits_the_scoped_round() -> Bool { match regen_scope_worktree_admission(status_success: true, entries_nul: "", stderr: "") { diff --git a/src/v2/workflow/regen_scope_worktree.dag b/src/v2/workflow/regen_scope_worktree.dag index 0f1c9c3b1e3..043115e9ec0 100644 --- a/src/v2/workflow/regen_scope_worktree.dag +++ b/src/v2/workflow/regen_scope_worktree.dag @@ -1,6 +1,7 @@ module v2.workflow.regen_scope_worktree import std.types { Bool, String, List } +import std.unicode.scalar { char_text } import extdeps.git import extdeps.git.inspect @@ -50,7 +51,7 @@ fn regen_scope_status_field_path(field: String) -> String { } fn regen_scope_uncommitted_dag_paths(entries_nul: String) -> List { - split(s: entries_nul, delimiter: from_code_point(0)) + split(s: entries_nul, delimiter: char_text(c: 0)) |> filter(f => f != "" && ends_with(s: f, suffix: ".dag")) |> map(f => regen_scope_status_field_path(field: f)) } From 14956bb4fab4a7d94c427424a4a65633b0c29395 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 14:35:49 +0000 Subject: [PATCH 31/39] stage0: install the emitted std_unicode_scalar mirror and its lib.rs module declaration (required-regen named them) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/lib.rs | 11 ++++ src/v1/stage0/src/std_unicode_scalar.rs | 72 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/v1/stage0/src/std_unicode_scalar.rs diff --git a/src/v1/stage0/src/lib.rs b/src/v1/stage0/src/lib.rs index 1f3a31a67b0..767f7a4339a 100644 --- a/src/v1/stage0/src/lib.rs +++ b/src/v1/stage0/src/lib.rs @@ -345,6 +345,17 @@ pub mod std_serialization; suspicious_double_ref_op, clippy::all )] +pub mod std_unicode_scalar; +#[allow( + unused_imports, + unused_variables, + unused_mut, + unused_parens, + dead_code, + non_shorthand_field_patterns, + suspicious_double_ref_op, + clippy::all +)] pub mod std_workspace_artifact; #[allow( unused_imports, diff --git a/src/v1/stage0/src/std_unicode_scalar.rs b/src/v1/stage0/src/std_unicode_scalar.rs new file mode 100644 index 00000000000..3f4cadd4487 --- /dev/null +++ b/src/v1/stage0/src/std_unicode_scalar.rs @@ -0,0 +1,72 @@ +// Generated by v1 compiler -- do not edit. +// Source module: std.unicode.scalar + +use self::NotUnicodeScalar::*; +pub use crate::std_algebra::list_snoc_item; +pub use crate::std_algebra::FreeMonoid; +pub use crate::std_coercion::unicode_scalar_fold; +pub use crate::std_error_primitives::Result; +use crate::std_error_primitives::Result::{Err, Ok}; +pub use crate::std_types::Char; +pub use crate::std_unicode_types::{ + unicode_scalar, unicode_surrogate_first_code_point, unicode_surrogate_last_code_point, +}; +use crate::v1_rt; +use crate::v1_rt::{VecCompat, VecJoin}; +use crate::NonEmptyBTreeSet; +use crate::NonEmptyVec; +use im::{vector as vec, HashMap, OrdSet as BTreeSet, Vector as Vec}; +use std::rc::Rc; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum NotUnicodeScalar { + SurrogateCodePoint { code_point: i64 }, + CodePointOutOfRange { code_point: i64 }, +} +impl NotUnicodeScalar { + pub fn code_point(&self) -> i64 { + match self { + NotUnicodeScalar::SurrogateCodePoint { + code_point: __val, .. + } => __val.clone(), + NotUnicodeScalar::CodePointOutOfRange { + code_point: __val, .. + } => __val.clone(), + } + } +} + +pub fn from_code_point(cp: i64) -> Rc>> { + if crate::std_unicode_types::unicode_scalar(cp.clone()) { + Rc::new(Result::Ok { + value: crate::std_coercion::unicode_scalar_fold(crate::std_algebra::list_snoc_item( + Rc::new(vec![]), + cp.clone(), + )), + }) + } else { + if ((cp.clone() >= unicode_surrogate_first_code_point()) + && (cp.clone() <= unicode_surrogate_last_code_point())) + { + Rc::new(Result::Err { + value: Rc::new(NotUnicodeScalar::SurrogateCodePoint { + code_point: cp.clone(), + }), + }) + } else { + Rc::new(Result::Err { + value: Rc::new(NotUnicodeScalar::CodePointOutOfRange { + code_point: cp.clone(), + }), + }) + } + } +} + +pub fn char_text(c: i64) -> String { + crate::std_coercion::unicode_scalar_fold(crate::std_algebra::list_snoc_item( + Rc::new(vec![]), + c.clone(), + )) +} From e38bca26b8aa5a4b32fda16c7d4272a17d98f289 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 14:47:32 +0000 Subject: [PATCH 32/39] stage0: install the mirrors required-regen named (round 1) --- src/v1/stage0/src/emitted_population.rs | 1 + .../stage0/src/extdeps_languages_rust_emit.rs | 2 +- src/v1/stage0/src/extdeps_uri.rs | 21 +++++++------------ .../gunbc_stage0_crate_partition_generated.rs | 2 +- src/v1/stage0/src/std_content_hash.rs | 3 ++- src/v1/stage0/src/v1_compiler_emit.rs | 5 +++-- .../src/v1_compiler_emit_core_support.rs | 13 ++++++------ src/v1/stage0/src/v1_compiler_infer_method.rs | 9 -------- src/v1/stage0/src/v1_compiler_runtime_rust.rs | 2 +- src/v1/stage0/src/v1_compiler_tokenize.rs | 3 ++- 10 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/v1/stage0/src/emitted_population.rs b/src/v1/stage0/src/emitted_population.rs index fe1a9940cb9..a250ca98999 100644 --- a/src/v1/stage0/src/emitted_population.rs +++ b/src/v1/stage0/src/emitted_population.rs @@ -94,6 +94,7 @@ // src/std_termination.rs // src/std_trait_derive_shape.rs // src/std_types.rs +// src/std_unicode_scalar.rs // src/std_unicode_types.rs // src/std_witness_admission.rs // src/std_workspace_artifact.rs diff --git a/src/v1/stage0/src/extdeps_languages_rust_emit.rs b/src/v1/stage0/src/extdeps_languages_rust_emit.rs index 0ec6134ed39..cc3ca7a94c1 100644 --- a/src/v1/stage0/src/extdeps_languages_rust_emit.rs +++ b/src/v1/stage0/src/extdeps_languages_rust_emit.rs @@ -637,7 +637,7 @@ pub struct RuntimeFunction { pub fn rt_function_registry() -> Rc>> { thread_local! { static CACHED: Rc>> = { - serde_json::from_str("[{\"name\": \"concat\", \"bridge_name\": \"concat\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"char_at\", \"bridge_name\": \"char_at\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"string_length\", \"bridge_name\": \"string_length\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"substring\", \"bridge_name\": \"substring\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"string_contains\", \"bridge_name\": \"string_contains\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"scan_while\", \"bridge_name\": \"scan_while\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"skip_horizontal_ws\", \"bridge_name\": \"skip_horizontal_ws\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"scan_to_eol\", \"bridge_name\": \"scan_to_eol\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"scan_string_end\", \"bridge_name\": \"scan_string_end\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"code_point\", \"bridge_name\": \"code_point\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"from_code_point\", \"bridge_name\": \"from_code_point\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"lookup\", \"bridge_name\": \"lookup\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"get\", \"bridge_name\": \"list_get_optional\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"index_by\", \"bridge_name\": \"rc_index_by\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"empty_map\", \"bridge_name\": \"rc_empty_map\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"empty_set\", \"bridge_name\": \"rc_empty_set\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"set_insert\", \"bridge_name\": \"rc_set_insert\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"set_union\", \"bridge_name\": \"rc_set_union\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"set_contains\", \"bridge_name\": \"set_contains\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_insert\", \"bridge_name\": \"rc_map_insert\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"map_merge\", \"bridge_name\": \"rc_map_merge\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"list_concat\", \"bridge_name\": \"rc_list_concat\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"str_eq\", \"bridge_name\": \"str_eq\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"filesystem_read\", \"bridge_name\": \"filesystem_read\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"list_push\", \"bridge_name\": \"rc_list_push\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"map_get\", \"bridge_name\": \"map_get\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_keys\", \"bridge_name\": \"map_keys\", \"passes_by_ref\": true, \"wraps_result\": true}, {\"name\": \"sorted_map_keys\", \"bridge_name\": \"sorted_map_keys\", \"passes_by_ref\": true, \"wraps_result\": true}, {\"name\": \"map_values\", \"bridge_name\": \"map_values\", \"passes_by_ref\": true, \"wraps_result\": true}, {\"name\": \"parse_int\", \"bridge_name\": \"parse_int\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"map_contains_key\", \"bridge_name\": \"map_contains_key\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_has\", \"bridge_name\": \"map_has\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_is_empty\", \"bridge_name\": \"map_is_empty\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"reverse\", \"bridge_name\": \"reverse\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"replace\", \"bridge_name\": \"replace\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"chars_to_string\", \"bridge_name\": \"chars_to_string\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"record_source_chars_index_lookup\", \"bridge_name\": \"record_source_chars_index_lookup\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_is_enabled\", \"bridge_name\": \"resolution_silent_pick_is_enabled\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"name_resolution_policy_is_namespace_only\", \"bridge_name\": \"name_resolution_policy_is_namespace_only\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"type_ref_hit_ne_bind_measure_active\", \"bridge_name\": \"type_ref_hit_ne_bind_measure_active\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_record_global_bare_lcp_pick\", \"bridge_name\": \"resolution_silent_pick_record_global_bare_lcp_pick\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_record_global_bare_lcp_tie\", \"bridge_name\": \"resolution_silent_pick_record_global_bare_lcp_tie\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_record_fn_parent_first_hit\", \"bridge_name\": \"resolution_silent_pick_record_fn_parent_first_hit\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"append\", \"bridge_name\": \"append\", \"passes_by_ref\": false, \"wraps_result\": true}, {\"name\": \"contains\", \"bridge_name\": \"contains\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"starts_with\", \"bridge_name\": \"starts_with\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"ends_with\", \"bridge_name\": \"ends_with\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"trim\", \"bridge_name\": \"trim\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"count\", \"bridge_name\": \"count\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"clamp\", \"bridge_name\": \"clamp\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"atom_identity_hash\", \"bridge_name\": \"atom_identity_hash\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"hash_combine\", \"bridge_name\": \"hash_combine\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"trace_mark\", \"bridge_name\": \"trace_mark\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"observed_monotonic_nanos\", \"bridge_name\": \"observed_monotonic_nanos\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"observed_thread_cpu_nanos\", \"bridge_name\": \"observed_thread_cpu_nanos\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"rc_ptr_eq\", \"bridge_name\": \"rc_ptr_eq\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"rc_vec_ptr_eq\", \"bridge_name\": \"rc_vec_ptr_eq\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"is_xid_start\", \"bridge_name\": \"is_xid_start\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"is_xid_continue\", \"bridge_name\": \"is_xid_continue\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"is_emoji_ident\", \"bridge_name\": \"is_emoji_ident\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"symbol_lexeme\", \"bridge_name\": \"symbol_lexeme\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"symbol_intern_lexeme\", \"bridge_name\": \"symbol_intern_lexeme\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"bytes_octets\", \"bridge_name\": \"bytes_octets\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"utf8_encode_bytes\", \"bridge_name\": \"utf8_encode_bytes\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"pure_dag_seam_unreachable\", \"bridge_name\": \"pure_dag_seam_unreachable\", \"passes_by_ref\": false, \"wraps_result\": false}]") + serde_json::from_str("[{\"name\": \"concat\", \"bridge_name\": \"concat\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"char_at\", \"bridge_name\": \"char_at\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"string_length\", \"bridge_name\": \"string_length\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"substring\", \"bridge_name\": \"substring\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"string_contains\", \"bridge_name\": \"string_contains\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"scan_while\", \"bridge_name\": \"scan_while\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"skip_horizontal_ws\", \"bridge_name\": \"skip_horizontal_ws\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"scan_to_eol\", \"bridge_name\": \"scan_to_eol\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"scan_string_end\", \"bridge_name\": \"scan_string_end\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"code_point\", \"bridge_name\": \"code_point\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"lookup\", \"bridge_name\": \"lookup\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"get\", \"bridge_name\": \"list_get_optional\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"index_by\", \"bridge_name\": \"rc_index_by\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"empty_map\", \"bridge_name\": \"rc_empty_map\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"empty_set\", \"bridge_name\": \"rc_empty_set\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"set_insert\", \"bridge_name\": \"rc_set_insert\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"set_union\", \"bridge_name\": \"rc_set_union\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"set_contains\", \"bridge_name\": \"set_contains\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_insert\", \"bridge_name\": \"rc_map_insert\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"map_merge\", \"bridge_name\": \"rc_map_merge\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"list_concat\", \"bridge_name\": \"rc_list_concat\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"str_eq\", \"bridge_name\": \"str_eq\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"filesystem_read\", \"bridge_name\": \"filesystem_read\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"list_push\", \"bridge_name\": \"rc_list_push\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"map_get\", \"bridge_name\": \"map_get\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_keys\", \"bridge_name\": \"map_keys\", \"passes_by_ref\": true, \"wraps_result\": true}, {\"name\": \"sorted_map_keys\", \"bridge_name\": \"sorted_map_keys\", \"passes_by_ref\": true, \"wraps_result\": true}, {\"name\": \"map_values\", \"bridge_name\": \"map_values\", \"passes_by_ref\": true, \"wraps_result\": true}, {\"name\": \"parse_int\", \"bridge_name\": \"parse_int\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"map_contains_key\", \"bridge_name\": \"map_contains_key\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_has\", \"bridge_name\": \"map_has\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"map_is_empty\", \"bridge_name\": \"map_is_empty\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"reverse\", \"bridge_name\": \"reverse\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"replace\", \"bridge_name\": \"replace\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"chars_to_string\", \"bridge_name\": \"chars_to_string\", \"passes_by_ref\": true, \"wraps_result\": false}, {\"name\": \"record_source_chars_index_lookup\", \"bridge_name\": \"record_source_chars_index_lookup\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_is_enabled\", \"bridge_name\": \"resolution_silent_pick_is_enabled\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"name_resolution_policy_is_namespace_only\", \"bridge_name\": \"name_resolution_policy_is_namespace_only\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"type_ref_hit_ne_bind_measure_active\", \"bridge_name\": \"type_ref_hit_ne_bind_measure_active\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_record_global_bare_lcp_pick\", \"bridge_name\": \"resolution_silent_pick_record_global_bare_lcp_pick\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_record_global_bare_lcp_tie\", \"bridge_name\": \"resolution_silent_pick_record_global_bare_lcp_tie\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"resolution_silent_pick_record_fn_parent_first_hit\", \"bridge_name\": \"resolution_silent_pick_record_fn_parent_first_hit\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"append\", \"bridge_name\": \"append\", \"passes_by_ref\": false, \"wraps_result\": true}, {\"name\": \"contains\", \"bridge_name\": \"contains\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"starts_with\", \"bridge_name\": \"starts_with\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"ends_with\", \"bridge_name\": \"ends_with\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"trim\", \"bridge_name\": \"trim\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"count\", \"bridge_name\": \"count\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"clamp\", \"bridge_name\": \"clamp\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"atom_identity_hash\", \"bridge_name\": \"atom_identity_hash\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"hash_combine\", \"bridge_name\": \"hash_combine\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"trace_mark\", \"bridge_name\": \"trace_mark\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"observed_monotonic_nanos\", \"bridge_name\": \"observed_monotonic_nanos\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"observed_thread_cpu_nanos\", \"bridge_name\": \"observed_thread_cpu_nanos\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"rc_ptr_eq\", \"bridge_name\": \"rc_ptr_eq\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"rc_vec_ptr_eq\", \"bridge_name\": \"rc_vec_ptr_eq\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"is_xid_start\", \"bridge_name\": \"is_xid_start\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"is_xid_continue\", \"bridge_name\": \"is_xid_continue\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"is_emoji_ident\", \"bridge_name\": \"is_emoji_ident\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"symbol_lexeme\", \"bridge_name\": \"symbol_lexeme\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"symbol_intern_lexeme\", \"bridge_name\": \"symbol_intern_lexeme\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"bytes_octets\", \"bridge_name\": \"bytes_octets\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"utf8_encode_bytes\", \"bridge_name\": \"utf8_encode_bytes\", \"passes_by_ref\": false, \"wraps_result\": false}, {\"name\": \"pure_dag_seam_unreachable\", \"bridge_name\": \"pure_dag_seam_unreachable\", \"passes_by_ref\": false, \"wraps_result\": false}]") .expect("valid data definition") }; } diff --git a/src/v1/stage0/src/extdeps_uri.rs b/src/v1/stage0/src/extdeps_uri.rs index f73aa7f53eb..e6adad7c66c 100644 --- a/src/v1/stage0/src/extdeps_uri.rs +++ b/src/v1/stage0/src/extdeps_uri.rs @@ -18,7 +18,9 @@ use self::UriUnicodeScalarConstruction::*; use self::UriUtf8OctetConstruction::*; use self::UriValidatedScalarConstruction::*; pub use crate::std_algebra::trim; -pub use crate::std_types::{List, NonEmptyStr}; +pub use crate::std_coercion::unicode_scalar_fold; +pub use crate::std_types::{Char, List, NonEmptyStr}; +pub use crate::std_unicode_scalar::char_text; pub use crate::std_unicode_types::{ unicode_scalar_max_code_point, unicode_surrogate_first_code_point, unicode_surrogate_last_code_point, @@ -771,7 +773,7 @@ pub fn uri_percent_encode_admitted_scalar_wire( let cp = uri_validated_scalar_code_point(scalar.clone()); if uri_component_is_unreserved(cp.clone()) { Rc::new(UriPercentEncodeFoldState::UriPercentEncodeBuilding { - wire: v1_rt::from_code_point(cp.clone()), + wire: crate::std_unicode_scalar::char_text(cp.clone()), }) } else { if (cp.clone() < 128) { @@ -1096,15 +1098,15 @@ impl UriDecodeUtf8 { #[serde(tag = "_variant")] pub enum UriPercentDecodeFold { UriDecodeText { - out: Rc>, + out: Rc>, utf8: Rc, }, UriDecodeAfterPercent { - out: Rc>, + out: Rc>, utf8: Rc, }, UriDecodeAfterHighNibble { - out: Rc>, + out: Rc>, utf8: Rc, high: i64, }, @@ -1341,14 +1343,7 @@ pub fn uri_percent_decode_component(value: String) -> Rc { Rc::new(UriPercentDecodeComponent::UriPercentComponentDecoded { - value: Rc::new({ - let mut __result = Vec::new(); - for c in v1_rt::reverse(out.clone()).iter().cloned() { - __result.push(v1_rt::from_code_point(c.clone())); - } - __result - }) - .join(&"".to_string()), + value: crate::std_coercion::unicode_scalar_fold(v1_rt::reverse(out.clone())), }) } }, diff --git a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs index 795b5bc85a5..1ef4e8475b3 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs @@ -53,7 +53,7 @@ pub fn generated_partition_crate_rows() -> Rc package_name: "v1-stage0-std-core".to_string(), crate_dir: "src/v1/stage0_std_core".to_string(), kind: GeneratedPartitionCrateKind::GeneratedLayeredCoreCrate, - modules: Rc::new(vec!["std_content_hash".to_string(), "std_coercion".to_string(), "extdeps_currency_currency".to_string(), "std_decl_ref".to_string(), "std_keyed_row".to_string(), "std_keyed_roster".to_string(), "std_roster_frontier".to_string(), "std_dissolution".to_string(), "std_disposition".to_string(), "std_error_primitives".to_string(), "std_emit_model".to_string(), "std_measure".to_string(), "std_types".to_string(), "std_unicode_types".to_string(), "std_algebra".to_string(), "std_nat".to_string(), "std_node".to_string(), "std_syntax".to_string(), "std_computation".to_string(), "std_termination".to_string(), "std_checked_arithmetic".to_string(), "std_induction".to_string(), "std_graph".to_string(), "extdeps_uri".to_string(), "extdeps_external_authority".to_string(), "extdeps_posix_clock_gettime".to_string(), "extdeps_ietf_http_semantics".to_string(), "std_process_termination".to_string(), "std_primitive_projection".to_string(), "extdeps_container_oci_digest".to_string(), "extdeps_units_dimensionless".to_string(), "extdeps_units_iec_80000_13".to_string(), "extdeps_units_iso8601".to_string(), "extdeps_units_iso_80000_3".to_string(), "std_occurrence_identity".to_string(), "std_source_annotation".to_string(), "std_kernel_type_name".to_string(), "std_target_representation".to_string(), "std_literal_elaboration".to_string(), "std_operator_realization".to_string(), "std_import".to_string(), "v1_std_core".to_string(), "gunbc_rust_emitted_edge".to_string()]), + modules: Rc::new(vec!["std_content_hash".to_string(), "std_coercion".to_string(), "extdeps_currency_currency".to_string(), "std_decl_ref".to_string(), "std_keyed_row".to_string(), "std_keyed_roster".to_string(), "std_roster_frontier".to_string(), "std_dissolution".to_string(), "std_disposition".to_string(), "std_error_primitives".to_string(), "std_emit_model".to_string(), "std_measure".to_string(), "std_types".to_string(), "std_unicode_types".to_string(), "std_algebra".to_string(), "std_nat".to_string(), "std_node".to_string(), "std_syntax".to_string(), "std_computation".to_string(), "std_termination".to_string(), "std_checked_arithmetic".to_string(), "std_induction".to_string(), "std_graph".to_string(), "std_unicode_scalar".to_string(), "extdeps_uri".to_string(), "extdeps_external_authority".to_string(), "extdeps_posix_clock_gettime".to_string(), "extdeps_ietf_http_semantics".to_string(), "std_process_termination".to_string(), "std_primitive_projection".to_string(), "extdeps_container_oci_digest".to_string(), "extdeps_units_dimensionless".to_string(), "extdeps_units_iec_80000_13".to_string(), "extdeps_units_iso8601".to_string(), "extdeps_units_iso_80000_3".to_string(), "std_occurrence_identity".to_string(), "std_source_annotation".to_string(), "std_kernel_type_name".to_string(), "std_target_representation".to_string(), "std_literal_elaboration".to_string(), "std_operator_realization".to_string(), "std_import".to_string(), "v1_std_core".to_string(), "gunbc_rust_emitted_edge".to_string()]), reexport_packages: Rc::new(vec!["v1-stage0-runtime".to_string()]), carries_non_empty_wrappers: false, }), Rc::new(GeneratedPartitionCrateRow { diff --git a/src/v1/stage0/src/std_content_hash.rs b/src/v1/stage0/src/std_content_hash.rs index 92bd57b93eb..5c368dabf98 100644 --- a/src/v1/stage0/src/std_content_hash.rs +++ b/src/v1/stage0/src/std_content_hash.rs @@ -5,6 +5,7 @@ use self::ContentHash::*; use self::ContentHashComparison::*; use self::HashFamily::*; pub use crate::std_types::{Bool, NonEmptyStr}; +pub use crate::std_unicode_scalar::char_text; use crate::v1_rt; use crate::v1_rt::{VecCompat, VecJoin}; use crate::NonEmptyBTreeSet; @@ -202,7 +203,7 @@ pub fn content_hash_combine_preimage( right: Rc, ) -> String { v1_rt::concat( - v1_rt::concat(left.digest.clone(), v1_rt::from_code_point(0)), + v1_rt::concat(left.digest.clone(), crate::std_unicode_scalar::char_text(0)), right.digest.clone(), ) } diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 2f04a101181..180a0332e6d 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -35,6 +35,7 @@ use crate::std_syntax::LiteralValue::*; pub use crate::std_syntax::{AlgebraFieldKind, BinOp, LiteralValue}; pub use crate::std_types::is_container_type; pub use crate::std_types::SourceSpan; +pub use crate::std_unicode_scalar::char_text; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::{Dag, Go, Python, Rust}; pub use crate::v1_compiler_coercion::{ @@ -4907,9 +4908,9 @@ pub fn emit_suffix_escape_ident( pub fn hex_digit_char(d: i64) -> String { if (d.clone() < 10) { - v1_rt::from_code_point(v1_rt::int_add(48, d.clone())) + crate::std_unicode_scalar::char_text(v1_rt::int_add(48, d.clone())) } else { - v1_rt::from_code_point(v1_rt::int_add(55, d.clone())) + crate::std_unicode_scalar::char_text(v1_rt::int_add(55, d.clone())) } } diff --git a/src/v1/stage0/src/v1_compiler_emit_core_support.rs b/src/v1/stage0/src/v1_compiler_emit_core_support.rs index cd3986c091a..1ff56f4ba40 100644 --- a/src/v1/stage0/src/v1_compiler_emit_core_support.rs +++ b/src/v1/stage0/src/v1_compiler_emit_core_support.rs @@ -3,6 +3,7 @@ pub use crate::gunbc_rust_emitted_edge::module_to_filename; pub use crate::gunbc_rust_emitted_edge::EmittedEdge; +pub use crate::std_unicode_scalar::char_text; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::*; pub use crate::v1_compiler_infer_env::TypeEnv; @@ -289,7 +290,7 @@ pub fn to_snake(name: String) -> String { v1_rt::concat("_".to_string(), to_lower_char(ch.clone())) } } else { - v1_rt::from_code_point(ch.clone()) + crate::std_unicode_scalar::char_text(ch.clone()) } }); } @@ -326,10 +327,10 @@ pub fn to_lower_char(ch: i64) -> String { if ((cp.clone() >= 65) && (cp.clone() <= 90)) { { let lower_cp = v1_rt::int_add(cp.clone(), 32); - v1_rt::from_code_point(lower_cp.clone()) + crate::std_unicode_scalar::char_text(lower_cp.clone()) } } else { - v1_rt::from_code_point(ch.clone()) + crate::std_unicode_scalar::char_text(ch.clone()) } } } @@ -340,10 +341,10 @@ pub fn to_upper_char(ch: i64) -> String { if ((cp.clone() >= 97) && (cp.clone() <= 122)) { { let upper_cp = v1_rt::int_sub(cp.clone(), 32); - v1_rt::from_code_point(upper_cp.clone()) + crate::std_unicode_scalar::char_text(upper_cp.clone()) } } else { - v1_rt::from_code_point(ch.clone()) + crate::std_unicode_scalar::char_text(ch.clone()) } } } @@ -390,7 +391,7 @@ pub fn capitalize_first(s: String) -> String { __result.push(if (pair.0.clone() == 0) { to_upper_char(pair.1.clone()) } else { - v1_rt::from_code_point(pair.1.clone()) + crate::std_unicode_scalar::char_text(pair.1.clone()) }); } __result diff --git a/src/v1/stage0/src/v1_compiler_infer_method.rs b/src/v1/stage0/src/v1_compiler_infer_method.rs index 8dd9026b126..670952ac571 100644 --- a/src/v1/stage0/src/v1_compiler_infer_method.rs +++ b/src/v1/stage0/src/v1_compiler_infer_method.rs @@ -469,15 +469,6 @@ pub fn builtin_function_registry() -> Rc>> }), })]), returns: crate::v1_std_core::with_optional_cardinality(string_type()), - })); - __m.insert("from_code_point".to_string(), Rc::new(BuiltinSignature { - params: Rc::new(vec![Rc::new(BuiltinParam { - name: "cp".to_string(), - ty: Rc::new(AlgebraTypeTemplate::NamedTemplate { - name: "Int".to_string(), - }), - })]), - returns: string_type(), })); __m.insert("chars_to_string".to_string(), Rc::new(BuiltinSignature { params: Rc::new(vec![Rc::new(BuiltinParam { diff --git a/src/v1/stage0/src/v1_compiler_runtime_rust.rs b/src/v1/stage0/src/v1_compiler_runtime_rust.rs index a150f68a59b..e0c2f84b9f4 100644 --- a/src/v1/stage0/src/v1_compiler_runtime_rust.rs +++ b/src/v1/stage0/src/v1_compiler_runtime_rust.rs @@ -88,7 +88,7 @@ pub fn rt_scanner_ops() -> String { } pub fn rt_unicode_ops() -> String { - v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("pub fn code_point(c: String) -> i64 {\n".to_string(), " c.chars().next().map(|ch| ch as i64).unwrap_or(0)\n".to_string()), "}\n\n".to_string()), "// THE VALIDATED JSON UNESCAPE, ONE NATIVE PASS — the interpreted piece-walk this primitive\n".to_string()), "// replaces cost ~155M interpreted steps over the 104 MB project envelope (~40 minutes at the\n".to_string()), "// measured interpreter constant), which was the read's wall once every quadratic above it was\n".to_string()), "// gone. The escape set is RFC 8259 section 7 exactly, so review 45642's refusal (an unknown\n".to_string()), "// escape refuses before a value is built) holds at native speed. A \\u high surrogate must be\n".to_string()), "// followed by a \\u low surrogate and the pair decodes to its one scalar (RFC 8259 section 7);\n".to_string()), "// an unpaired surrogate of either half refuses. It used to decode through from_code_point,\n".to_string()), "// whose empty string for a surrogate dropped every non-BMP character silently (DESIGN 5).\n".to_string()), "// The caller owns the span: this kernel takes the already-scanned body and answers the\n".to_string()), "// decoded value or None.\n".to_string()), "pub fn json_unescape_checked(s: &str) -> Option {\n".to_string()), " if !s.contains('\\\\') {\n".to_string()), " return Some(s.to_string());\n".to_string()), " }\n".to_string()), " let mut out = String::with_capacity(s.len());\n".to_string()), " let mut chars = s.chars();\n".to_string()), " while let Some(c) = chars.next() {\n".to_string()), " if c != '\\\\' {\n".to_string()), " out.push(c);\n".to_string()), " continue;\n".to_string()), " }\n".to_string()), " match chars.next() {\n".to_string()), " Some('\"') => out.push('\"'),\n".to_string()), " Some('\\\\') => out.push('\\\\'),\n".to_string()), " Some('/') => out.push('/'),\n".to_string()), " Some('b') => out.push('\\x08'),\n".to_string()), " Some('f') => out.push('\\x0c'),\n".to_string()), " Some('n') => out.push('\\n'),\n".to_string()), " Some('r') => out.push('\\r'),\n".to_string()), " Some('t') => out.push('\\t'),\n".to_string()), " Some('u') => {\n".to_string()), " let cp = json_unescape_hex4(&mut chars)?;\n".to_string()), " if (0xD800..=0xDBFF).contains(&cp) {\n".to_string()), " if chars.next() != Some('\\\\') || chars.next() != Some('u') {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " let lo = json_unescape_hex4(&mut chars)?;\n".to_string()), " if !(0xDC00..=0xDFFF).contains(&lo) {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " out.push(char::from_u32(0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00))?);\n".to_string()), " } else {\n".to_string()), " out.push(char::from_u32(cp)?);\n".to_string()), " }\n".to_string()), " }\n".to_string()), " _ => return None,\n".to_string()), " }\n".to_string()), " }\n".to_string()), " Some(out)\n".to_string()), "}\n\n".to_string()), "fn json_unescape_hex4(chars: &mut std::str::Chars<'_>) -> Option {\n".to_string()), " let mut v: u32 = 0;\n".to_string()), " for _ in 0..4 {\n".to_string()), " v = v * 16 + chars.next()?.to_digit(16)?;\n".to_string()), " }\n".to_string()), " Some(v)\n".to_string()), "}\n\n".to_string()), "pub fn from_code_point(cp: i64) -> String {\n".to_string()), " char::from_u32(cp as u32).map(|c| c.to_string()).unwrap_or_default()\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_start(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_start).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_continue(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_continue).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_emoji_ident(cp: i64) -> bool {\n".to_string()), " use unicode_properties::emoji::UnicodeEmoji;\n".to_string()), " use unicode_properties::emoji::EmojiStatus;\n".to_string()), " char::from_u32(cp as u32).map(|c| matches!(c.emoji_status(), EmojiStatus::EmojiPresentation | EmojiStatus::EmojiPresentationAndModifierBase | EmojiStatus::EmojiPresentationAndEmojiComponent | EmojiStatus::EmojiPresentationAndModifierAndEmojiComponent) && !unicode_ident::is_xid_continue(c)).unwrap_or(false)\n".to_string()), "}\n\n".to_string()) + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("pub fn code_point(c: String) -> i64 {\n".to_string(), " c.chars().next().map(|ch| ch as i64).unwrap_or(0)\n".to_string()), "}\n\n".to_string()), "// THE VALIDATED JSON UNESCAPE, ONE NATIVE PASS — the interpreted piece-walk this primitive\n".to_string()), "// replaces cost ~155M interpreted steps over the 104 MB project envelope (~40 minutes at the\n".to_string()), "// measured interpreter constant), which was the read's wall once every quadratic above it was\n".to_string()), "// gone. The escape set is RFC 8259 section 7 exactly, so review 45642's refusal (an unknown\n".to_string()), "// escape refuses before a value is built) holds at native speed. A \\u high surrogate must be\n".to_string()), "// followed by a \\u low surrogate and the pair decodes to its one scalar (RFC 8259 section 7);\n".to_string()), "// an unpaired surrogate of either half refuses. It used to decode through from_code_point,\n".to_string()), "// whose empty string for a surrogate dropped every non-BMP character silently (DESIGN 5).\n".to_string()), "// The caller owns the span: this kernel takes the already-scanned body and answers the\n".to_string()), "// decoded value or None.\n".to_string()), "pub fn json_unescape_checked(s: &str) -> Option {\n".to_string()), " if !s.contains('\\\\') {\n".to_string()), " return Some(s.to_string());\n".to_string()), " }\n".to_string()), " let mut out = String::with_capacity(s.len());\n".to_string()), " let mut chars = s.chars();\n".to_string()), " while let Some(c) = chars.next() {\n".to_string()), " if c != '\\\\' {\n".to_string()), " out.push(c);\n".to_string()), " continue;\n".to_string()), " }\n".to_string()), " match chars.next() {\n".to_string()), " Some('\"') => out.push('\"'),\n".to_string()), " Some('\\\\') => out.push('\\\\'),\n".to_string()), " Some('/') => out.push('/'),\n".to_string()), " Some('b') => out.push('\\x08'),\n".to_string()), " Some('f') => out.push('\\x0c'),\n".to_string()), " Some('n') => out.push('\\n'),\n".to_string()), " Some('r') => out.push('\\r'),\n".to_string()), " Some('t') => out.push('\\t'),\n".to_string()), " Some('u') => {\n".to_string()), " let cp = json_unescape_hex4(&mut chars)?;\n".to_string()), " if (0xD800..=0xDBFF).contains(&cp) {\n".to_string()), " if chars.next() != Some('\\\\') || chars.next() != Some('u') {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " let lo = json_unescape_hex4(&mut chars)?;\n".to_string()), " if !(0xDC00..=0xDFFF).contains(&lo) {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " out.push(char::from_u32(0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00))?);\n".to_string()), " } else {\n".to_string()), " out.push(char::from_u32(cp)?);\n".to_string()), " }\n".to_string()), " }\n".to_string()), " _ => return None,\n".to_string()), " }\n".to_string()), " }\n".to_string()), " Some(out)\n".to_string()), "}\n\n".to_string()), "fn json_unescape_hex4(chars: &mut std::str::Chars<'_>) -> Option {\n".to_string()), " let mut v: u32 = 0;\n".to_string()), " for _ in 0..4 {\n".to_string()), " v = v * 16 + chars.next()?.to_digit(16)?;\n".to_string()), " }\n".to_string()), " Some(v)\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_start(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_start).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_continue(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_continue).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_emoji_ident(cp: i64) -> bool {\n".to_string()), " use unicode_properties::emoji::UnicodeEmoji;\n".to_string()), " use unicode_properties::emoji::EmojiStatus;\n".to_string()), " char::from_u32(cp as u32).map(|c| matches!(c.emoji_status(), EmojiStatus::EmojiPresentation | EmojiStatus::EmojiPresentationAndModifierBase | EmojiStatus::EmojiPresentationAndEmojiComponent | EmojiStatus::EmojiPresentationAndModifierAndEmojiComponent) && !unicode_ident::is_xid_continue(c)).unwrap_or(false)\n".to_string()), "}\n\n".to_string()) } pub fn rt_freemonoid_host_ops() -> String { diff --git a/src/v1/stage0/src/v1_compiler_tokenize.rs b/src/v1/stage0/src/v1_compiler_tokenize.rs index 5898ce8fa0a..f05afba7ea9 100644 --- a/src/v1/stage0/src/v1_compiler_tokenize.rs +++ b/src/v1/stage0/src/v1_compiler_tokenize.rs @@ -13,6 +13,7 @@ pub use crate::std_source_annotation::{ pub use crate::std_source_annotation::{AnnotationPlacement, UnboundAnnotationCapture}; pub use crate::std_syntax::ParseEnvironment; pub use crate::std_types::SourceSpan; +pub use crate::std_unicode_scalar::char_text; pub use crate::std_unicode_types::unicode_scalar; pub use crate::v1_compiler_languages::canonical_emoji_char_escape; pub use crate::v1_compiler_languages::EmojiCharEscape; @@ -117,7 +118,7 @@ pub fn make_token(text: String, span: Rc, shape: TokenShape) -> Rc, pos: i64) -> String { - v1_rt::from_code_point(source.source_chars.clone()[(pos.clone()) as usize].clone()) + crate::std_unicode_scalar::char_text(source_code_point(source.clone(), pos.clone())) } pub fn source_code_point(source: Rc, pos: i64) -> i64 { From 4d93cea0a7ba5d1a7e201c78ab50212ab32c5547 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 15:00:00 +0000 Subject: [PATCH 33/39] stage0 std-core crate: declare std_unicode_scalar (byte-identical to what --emit-partition-crates renders: written=0 after rebuild) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0_std_core/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v1/stage0_std_core/src/lib.rs b/src/v1/stage0_std_core/src/lib.rs index 6e2f7f1cab6..a2ecc95d625 100644 --- a/src/v1/stage0_std_core/src/lib.rs +++ b/src/v1/stage0_std_core/src/lib.rs @@ -90,6 +90,9 @@ pub mod std_induction; #[path = "../../stage0/src/std_graph.rs"] pub mod std_graph; #[rustfmt::skip] +#[path = "../../stage0/src/std_unicode_scalar.rs"] +pub mod std_unicode_scalar; +#[rustfmt::skip] #[path = "../../stage0/src/extdeps_uri.rs"] pub mod extdeps_uri; #[rustfmt::skip] From 7ac592f5939476fceb6736095be7485fb1e377c3 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 15:08:22 +0000 Subject: [PATCH 34/39] stage0: install the mirrors required-regen named (lib.rs, v1_rt.rs: v1_rt::from_code_point removed) --- src/v1/stage0/src/lib.rs | 11 ----------- src/v1/stage0/src/v1_rt.rs | 6 ------ 2 files changed, 17 deletions(-) diff --git a/src/v1/stage0/src/lib.rs b/src/v1/stage0/src/lib.rs index 767f7a4339a..1f3a31a67b0 100644 --- a/src/v1/stage0/src/lib.rs +++ b/src/v1/stage0/src/lib.rs @@ -345,17 +345,6 @@ pub mod std_serialization; suspicious_double_ref_op, clippy::all )] -pub mod std_unicode_scalar; -#[allow( - unused_imports, - unused_variables, - unused_mut, - unused_parens, - dead_code, - non_shorthand_field_patterns, - suspicious_double_ref_op, - clippy::all -)] pub mod std_workspace_artifact; #[allow( unused_imports, diff --git a/src/v1/stage0/src/v1_rt.rs b/src/v1/stage0/src/v1_rt.rs index 3434514159f..697b14bf433 100644 --- a/src/v1/stage0/src/v1_rt.rs +++ b/src/v1/stage0/src/v1_rt.rs @@ -1049,12 +1049,6 @@ fn json_unescape_hex4(chars: &mut std::str::Chars<'_>) -> Option { Some(v) } -pub fn from_code_point(cp: i64) -> String { - char::from_u32(cp as u32) - .map(|c| c.to_string()) - .unwrap_or_default() -} - pub fn is_xid_start(cp: i64) -> bool { char::from_u32(cp as u32) .map(unicode_ident::is_xid_start) From ff24e98847ee33092311b829d6e6c6984bb6b70c Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 16:51:35 +0000 Subject: [PATCH 35/39] stage0 partition: re-export std_unicode_scalar through the emit-core surface (v1_compiler_emit_core_support uses it) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/stage0/stage0_crate_partition_generated.dag | 1 + src/v2/workflow/rust_crate_partition.dag | 2 ++ 2 files changed, 3 insertions(+) diff --git a/dag/gunbc/stage0/stage0_crate_partition_generated.dag b/dag/gunbc/stage0/stage0_crate_partition_generated.dag index 70d580830b5..6c0bc201f22 100644 --- a/dag/gunbc/stage0/stage0_crate_partition_generated.dag +++ b/dag/gunbc/stage0/stage0_crate_partition_generated.dag @@ -192,6 +192,7 @@ data generated_partition_crate_rows: List = [ kind: GeneratedEmitCoreCrate, modules: [ "gunbc_rust_emitted_edge", + "std_unicode_scalar", "v1_compiler_artifact", "v1_compiler_infer_env", "v1_compiler_infer_items", diff --git a/src/v2/workflow/rust_crate_partition.dag b/src/v2/workflow/rust_crate_partition.dag index 4c07d58927f..75cb033aaa4 100644 --- a/src/v2/workflow/rust_crate_partition.dag +++ b/src/v2/workflow/rust_crate_partition.dag @@ -458,6 +458,7 @@ fn stage0_v1_artifact_modules() -> List { fn stage0_r3_emit_reexport_surface_modules() -> List { [ "gunbc_rust_emitted_edge", + "std_unicode_scalar", "v1_compiler_artifact", "v1_compiler_infer_env", "v1_compiler_infer_items", @@ -628,6 +629,7 @@ fn stage0_cross_unit_import_edges() -> List { stage0_module_dag_edge(from: "v1_compiler_parse", to: "v1_std_core"), stage0_module_dag_edge(from: "gunbc_rust_emitted_edge", to: "std_types"), stage0_module_dag_edge(from: "v1_compiler_emit_core_support", to: "gunbc_rust_emitted_edge"), + stage0_module_dag_edge(from: "v1_compiler_emit_core_support", to: "std_unicode_scalar"), ] } From 86046908facb8451d285ddddf4a6af55374f5c51 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 17:01:54 +0000 Subject: [PATCH 36/39] stage0: regen round 1 (partition re-export of std_unicode_scalar) --- src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs index 1ef4e8475b3..037b24df71d 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs @@ -88,7 +88,7 @@ pub fn generated_partition_crate_rows() -> Rc package_name: "v1-stage0-emit-core".to_string(), crate_dir: "src/v1/stage0_emit_core".to_string(), kind: GeneratedPartitionCrateKind::GeneratedEmitCoreCrate, - modules: Rc::new(vec!["gunbc_rust_emitted_edge".to_string(), "v1_compiler_artifact".to_string(), "v1_compiler_infer_env".to_string(), "v1_compiler_infer_items".to_string(), "v1_compiler_infer_service".to_string(), "v1_compiler_infer_types".to_string(), "v1_compiler_languages".to_string(), "v1_compiler_parse".to_string(), "v1_rt".to_string(), "v1_std_core".to_string()]), + modules: Rc::new(vec!["gunbc_rust_emitted_edge".to_string(), "std_unicode_scalar".to_string(), "v1_compiler_artifact".to_string(), "v1_compiler_infer_env".to_string(), "v1_compiler_infer_items".to_string(), "v1_compiler_infer_service".to_string(), "v1_compiler_infer_types".to_string(), "v1_compiler_languages".to_string(), "v1_compiler_parse".to_string(), "v1_rt".to_string(), "v1_std_core".to_string()]), reexport_packages: Rc::new(vec![]), carries_non_empty_wrappers: false, })]) From 860c27a8504d0a9ccadb514465cc986b787e7a38 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 17:12:51 +0000 Subject: [PATCH 37/39] stage0: regen round 2 (partition re-export of std_unicode_scalar) --- src/v1/stage0_emit_core/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/v1/stage0_emit_core/src/lib.rs b/src/v1/stage0_emit_core/src/lib.rs index 0fb332f6a31..b1fe1704370 100644 --- a/src/v1/stage0_emit_core/src/lib.rs +++ b/src/v1/stage0_emit_core/src/lib.rs @@ -24,6 +24,10 @@ pub mod gunbc_rust_emitted_edge { pub use v1_stage0_std_core::gunbc_rust_emitted_edge::*; } +pub mod std_unicode_scalar { + pub use v1_stage0_std_core::std_unicode_scalar::*; +} + pub mod v1_compiler_artifact { pub use v1_stage0_v1_artifact::v1_compiler_artifact::*; } From 41f0948d65f5fce09283e002e8cd99833febd7ff Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 19:36:44 +0000 Subject: [PATCH 38/39] stage0: regen round 1 on the merged head --- src/v1/stage0/src/v1_compiler_emit.rs | 5 +++-- src/v1/stage0/src/v1_compiler_runtime_rust.rs | 2 +- src/v1/stage0/src/v1_compiler_tokenize.rs | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 7700517388f..c69b0ea6276 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -35,6 +35,7 @@ use crate::std_syntax::LiteralValue::*; pub use crate::std_syntax::{AlgebraFieldKind, BinOp, LiteralValue}; pub use crate::std_types::is_container_type; pub use crate::std_types::SourceSpan; +pub use crate::std_unicode_scalar::char_text; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::{Dag, Go, Python, Rust}; pub use crate::v1_compiler_coercion::{ @@ -4910,9 +4911,9 @@ pub fn emit_suffix_escape_ident( pub fn hex_digit_char(d: i64) -> String { if (d.clone() < 10) { - v1_rt::from_code_point(v1_rt::int_add(48, d.clone())) + crate::std_unicode_scalar::char_text(v1_rt::int_add(48, d.clone())) } else { - v1_rt::from_code_point(v1_rt::int_add(55, d.clone())) + crate::std_unicode_scalar::char_text(v1_rt::int_add(55, d.clone())) } } diff --git a/src/v1/stage0/src/v1_compiler_runtime_rust.rs b/src/v1/stage0/src/v1_compiler_runtime_rust.rs index fb2f5c5ae85..7155ea83da5 100644 --- a/src/v1/stage0/src/v1_compiler_runtime_rust.rs +++ b/src/v1/stage0/src/v1_compiler_runtime_rust.rs @@ -88,7 +88,7 @@ pub fn rt_scanner_ops() -> String { } pub fn rt_unicode_ops() -> String { - v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("pub fn code_point(c: String) -> i64 {\n".to_string(), " c.chars().next().map(|ch| ch as i64).unwrap_or(0)\n".to_string()), "}\n\n".to_string()), "// THE VALIDATED JSON UNESCAPE, ONE NATIVE PASS — the interpreted piece-walk this primitive\n".to_string()), "// replaces cost ~155M interpreted steps over the 104 MB project envelope (~40 minutes at the\n".to_string()), "// measured interpreter constant), which was the read's wall once every quadratic above it was\n".to_string()), "// gone. The escape set is RFC 8259 section 7 exactly, so review 45642's refusal (an unknown\n".to_string()), "// escape refuses before a value is built) holds at native speed. A \\u high surrogate must be\n".to_string()), "// followed by a \\u low surrogate and the pair decodes to its one scalar (RFC 8259 section 7);\n".to_string()), "// an unpaired surrogate of either half refuses. It used to decode through from_code_point,\n".to_string()), "// whose empty string for a surrogate dropped every non-BMP character silently (DESIGN 5).\n".to_string()), "// The caller owns the span: this kernel takes the already-scanned body and answers the\n".to_string()), "// decoded value or None.\n".to_string()), "pub fn json_unescape_checked(s: &str) -> Option {\n".to_string()), " if !s.contains('\\\\') {\n".to_string()), " return Some(s.to_string());\n".to_string()), " }\n".to_string()), " let mut out = String::with_capacity(s.len());\n".to_string()), " let mut chars = s.chars();\n".to_string()), " while let Some(c) = chars.next() {\n".to_string()), " if c != '\\\\' {\n".to_string()), " out.push(c);\n".to_string()), " continue;\n".to_string()), " }\n".to_string()), " match chars.next() {\n".to_string()), " Some('\"') => out.push('\"'),\n".to_string()), " Some('\\\\') => out.push('\\\\'),\n".to_string()), " Some('/') => out.push('/'),\n".to_string()), " Some('b') => out.push('\\x08'),\n".to_string()), " Some('f') => out.push('\\x0c'),\n".to_string()), " Some('n') => out.push('\\n'),\n".to_string()), " Some('r') => out.push('\\r'),\n".to_string()), " Some('t') => out.push('\\t'),\n".to_string()), " Some('u') => {\n".to_string()), " let cp = json_unescape_hex4(&mut chars)?;\n".to_string()), " if (0xD800..=0xDBFF).contains(&cp) {\n".to_string()), " if chars.next() != Some('\\\\') || chars.next() != Some('u') {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " let lo = json_unescape_hex4(&mut chars)?;\n".to_string()), " if !(0xDC00..=0xDFFF).contains(&lo) {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " out.push(char::from_u32(0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00))?);\n".to_string()), " } else {\n".to_string()), " out.push(char::from_u32(cp)?);\n".to_string()), " }\n".to_string()), " }\n".to_string()), " _ => return None,\n".to_string()), " }\n".to_string()), " }\n".to_string()), " Some(out)\n".to_string()), "}\n\n".to_string()), "fn json_unescape_hex4(chars: &mut std::str::Chars<'_>) -> Option {\n".to_string()), " let mut v: u32 = 0;\n".to_string()), " for _ in 0..4 {\n".to_string()), " v = v * 16 + chars.next()?.to_digit(16)?;\n".to_string()), " }\n".to_string()), " Some(v)\n".to_string()), "}\n\n".to_string()), "pub fn from_code_point(cp: i64) -> String {\n".to_string()), " char::from_u32(cp as u32).map(|c| c.to_string()).unwrap_or_default()\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_start(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_start).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_continue(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_continue).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_emoji_ident(cp: i64) -> bool {\n".to_string()), " use unicode_properties::emoji::UnicodeEmoji;\n".to_string()), " use unicode_properties::emoji::EmojiStatus;\n".to_string()), " char::from_u32(cp as u32).map(|c| matches!(c.emoji_status(), EmojiStatus::EmojiPresentation | EmojiStatus::EmojiPresentationAndModifierBase | EmojiStatus::EmojiPresentationAndEmojiComponent | EmojiStatus::EmojiPresentationAndModifierAndEmojiComponent) && !unicode_ident::is_xid_continue(c)).unwrap_or(false)\n".to_string()), "}\n\n".to_string()) + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("pub fn code_point(c: String) -> i64 {\n".to_string(), " c.chars().next().map(|ch| ch as i64).unwrap_or(0)\n".to_string()), "}\n\n".to_string()), "// THE VALIDATED JSON UNESCAPE, ONE NATIVE PASS — the interpreted piece-walk this primitive\n".to_string()), "// replaces cost ~155M interpreted steps over the 104 MB project envelope (~40 minutes at the\n".to_string()), "// measured interpreter constant), which was the read's wall once every quadratic above it was\n".to_string()), "// gone. The escape set is RFC 8259 section 7 exactly, so review 45642's refusal (an unknown\n".to_string()), "// escape refuses before a value is built) holds at native speed. A \\u high surrogate must be\n".to_string()), "// followed by a \\u low surrogate and the pair decodes to its one scalar (RFC 8259 section 7);\n".to_string()), "// an unpaired surrogate of either half refuses. It used to decode through from_code_point,\n".to_string()), "// whose empty string for a surrogate dropped every non-BMP character silently (DESIGN 5).\n".to_string()), "// The caller owns the span: this kernel takes the already-scanned body and answers the\n".to_string()), "// decoded value or None.\n".to_string()), "pub fn json_unescape_checked(s: &str) -> Option {\n".to_string()), " if !s.contains('\\\\') {\n".to_string()), " return Some(s.to_string());\n".to_string()), " }\n".to_string()), " let mut out = String::with_capacity(s.len());\n".to_string()), " let mut chars = s.chars();\n".to_string()), " while let Some(c) = chars.next() {\n".to_string()), " if c != '\\\\' {\n".to_string()), " out.push(c);\n".to_string()), " continue;\n".to_string()), " }\n".to_string()), " match chars.next() {\n".to_string()), " Some('\"') => out.push('\"'),\n".to_string()), " Some('\\\\') => out.push('\\\\'),\n".to_string()), " Some('/') => out.push('/'),\n".to_string()), " Some('b') => out.push('\\x08'),\n".to_string()), " Some('f') => out.push('\\x0c'),\n".to_string()), " Some('n') => out.push('\\n'),\n".to_string()), " Some('r') => out.push('\\r'),\n".to_string()), " Some('t') => out.push('\\t'),\n".to_string()), " Some('u') => {\n".to_string()), " let cp = json_unescape_hex4(&mut chars)?;\n".to_string()), " if (0xD800..=0xDBFF).contains(&cp) {\n".to_string()), " if chars.next() != Some('\\\\') || chars.next() != Some('u') {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " let lo = json_unescape_hex4(&mut chars)?;\n".to_string()), " if !(0xDC00..=0xDFFF).contains(&lo) {\n".to_string()), " return None;\n".to_string()), " }\n".to_string()), " out.push(char::from_u32(0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00))?);\n".to_string()), " } else {\n".to_string()), " out.push(char::from_u32(cp)?);\n".to_string()), " }\n".to_string()), " }\n".to_string()), " _ => return None,\n".to_string()), " }\n".to_string()), " }\n".to_string()), " Some(out)\n".to_string()), "}\n\n".to_string()), "fn json_unescape_hex4(chars: &mut std::str::Chars<'_>) -> Option {\n".to_string()), " let mut v: u32 = 0;\n".to_string()), " for _ in 0..4 {\n".to_string()), " v = v * 16 + chars.next()?.to_digit(16)?;\n".to_string()), " }\n".to_string()), " Some(v)\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_start(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_start).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_xid_continue(cp: i64) -> bool {\n".to_string()), " char::from_u32(cp as u32).map(unicode_ident::is_xid_continue).unwrap_or(false)\n".to_string()), "}\n\n".to_string()), "pub fn is_emoji_ident(cp: i64) -> bool {\n".to_string()), " use unicode_properties::emoji::UnicodeEmoji;\n".to_string()), " use unicode_properties::emoji::EmojiStatus;\n".to_string()), " char::from_u32(cp as u32).map(|c| matches!(c.emoji_status(), EmojiStatus::EmojiPresentation | EmojiStatus::EmojiPresentationAndModifierBase | EmojiStatus::EmojiPresentationAndEmojiComponent | EmojiStatus::EmojiPresentationAndModifierAndEmojiComponent) && !unicode_ident::is_xid_continue(c)).unwrap_or(false)\n".to_string()), "}\n\n".to_string()) } pub fn rt_freemonoid_host_ops() -> String { diff --git a/src/v1/stage0/src/v1_compiler_tokenize.rs b/src/v1/stage0/src/v1_compiler_tokenize.rs index 0fde8441e1e..88d93c45391 100644 --- a/src/v1/stage0/src/v1_compiler_tokenize.rs +++ b/src/v1/stage0/src/v1_compiler_tokenize.rs @@ -13,6 +13,7 @@ pub use crate::std_source_annotation::{ pub use crate::std_source_annotation::{AnnotationPlacement, UnboundAnnotationCapture}; pub use crate::std_syntax::ParseEnvironment; pub use crate::std_types::SourceSpan; +pub use crate::std_unicode_scalar::char_text; pub use crate::std_unicode_types::unicode_scalar; pub use crate::v1_compiler_languages::canonical_emoji_char_escape; pub use crate::v1_compiler_languages::EmojiCharEscape; @@ -833,7 +834,7 @@ pub fn scan_token( }); } } - let ch_text = v1_rt::from_code_point(ch.clone()); + let ch_text = crate::std_unicode_scalar::char_text(ch.clone()); match v1_rt::lookup(&single_punct(), ch_text.clone()) { Some(sh) => emit( pos.clone(), From 5fd449cc96e467fa911b36bde18a5cfc0ce035ec Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 19:47:48 +0000 Subject: [PATCH 39/39] stage0: regen round 2 on the merged head --- src/v1/stage0/src/v1_rt.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/v1/stage0/src/v1_rt.rs b/src/v1/stage0/src/v1_rt.rs index c3a9e9bf3e1..63e033d7146 100644 --- a/src/v1/stage0/src/v1_rt.rs +++ b/src/v1/stage0/src/v1_rt.rs @@ -1068,12 +1068,6 @@ fn json_unescape_hex4(chars: &mut std::str::Chars<'_>) -> Option { Some(v) } -pub fn from_code_point(cp: i64) -> String { - char::from_u32(cp as u32) - .map(|c| c.to_string()) - .unwrap_or_default() -} - pub fn is_xid_start(cp: i64) -> bool { char::from_u32(cp as u32) .map(unicode_ident::is_xid_start)