Repository navigation
XL-2: kernel String concat through the free-monoid roster; v2 templates in parse (hole-aware body) - #13693
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ac34899b9a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| left: NotFollowedByPattern { | ||
| element: ChoicePattern { left: CharPattern { char: 92 }, right: dag_string_hole_opener_pattern() } | ||
| }, |
There was a problem hiding this comment.
Keep extended string escapes lexable
When a string contains a valid \xNN or \u{...} escape, the simple-escape branch does not match and this new predicate rejects the fallback branch solely because the next character is a backslash. Those forms are explicitly handled by dag_string_decode_* and are used in files such as dag/extdeps/render/ansi.dag and src/v2/extdeps/languages/bash_command_fold.dag, so the v2 tokenizer can no longer ingest those modules. Exclude only interpolation openers here, or otherwise add the extended escape patterns before rejecting backslashes.
Useful? React with 👍 / 👎.
The string-template alternative added a choice without a matching close, so closure-load refused the language model at parse-failed with no position.
|
Parse failure on head |
The hole opener must be excluded from a string body so `{ident` starts a
template; excluding every backslash as well dropped `\x`/`\u{` which decode
already handles and which the prior body class still admitted.
|
Review 78468 (claude, APPROVE on
Codex inline on |
…fns. Caller admission treated a concat bound to collection_concat_shape as an unresolved declaration (infer_reason_caller_admission_callee_unresolved at the application). The row is the signature, not a callable with admit_callers, so the wall now imposes nothing there. The real-path kernel-String concat claim is green; drop its ActiveFillDebt. Co-authored-by: Cursor <cursoragent@cursor.com>
v1 scan_string_body takes `\u{` as the escape prefix before interpolation, so a letter-hex form is never a hole. The v2 body pattern now does the same. Discriminating red: `\u{E9}` is one string literal; digit-hex remains one.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Review 78485 (first finding): agreed. Fix on Second finding: HOLD: |
The receipt's `\u{` was itself a hole opener under v1 scan_string_body, so the module failed to parse and self-host refused EmissionRefused.
Co-authored-by: Cursor <cursoragent@cursor.com>
…t as absent. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Review 78494: agreed. Fix on Reds: Review 78485 ( |
Co-authored-by: Cursor <cursoragent@cursor.com>
XL-2 (#13693) also edited 04_infer; keep both its structure-bound admission and this branch's Cardinality peel.
* XL-2 PR2: lower string templates to free-monoid concat; holes are resolve references. Well-formed templates rewrite to collection_concat_shape chains so they type through the #13693 roster row. Unreadable or unlowerable shapes still refuse located. Co-authored-by: Cursor <cursoragent@cursor.com> * Rename template inhabitance claim: bind+infer, not eval. The old name asserted concatenated bytes via a constant host_text_concatenation check that never ran v2 eval. v2 eval of a lowered template is a typed located refusal until a concat arm exists; record that as the frontier. Co-authored-by: Cursor <cursoragent@cursor.com> * Make string templates unwritable unless they are text then (hole, text)+. A flat List of text|hole plus a well-formedness fold was a second representation of the grammar (DESIGN section 5). The reader now constructs StringTemplate { head, segments } or is Absent; the validator is gone. Co-authored-by: Cursor <cursoragent@cursor.com> * Enroll executed eval and translate refusals for a lowered template. v2 eval of a data-hole template refuses eval_rejected_grounding_not_derived; translate to rust refuses translate_rejected_grounding_not_derived. Neither path emits concatenated host bytes. Co-authored-by: Cursor <cursoragent@cursor.com> * Make a hole-free string template unwritable: segments is FreeSemigroup. List plus Empty => Absent was still validation. std.algebra FreeSemigroup is the nonempty carrier; StringTemplate.segments uses it, so an empty-segment inhabitant has no constructor. Co-authored-by: Cursor <cursoragent@cursor.com> * Bind template concat to std.algebra.collection_concat_shape by declaration identity. A generated operator is a marked declaration_reference_node of the roster row, not a bare atom whose spelling resolve_atom_unscoped could bind to a local collection_concat_shape. Drop the declaration-name roster fallback so authored collection_concat_shape(...) is never an implicit primitive. Co-authored-by: Cursor <cursoragent@cursor.com> * Derive the template concat path only from the named roster row. Remove the fabricated dotted-string fallback, and admit a pre-marked declaration reference at resolve only when it is that row's identity; any other marked path refuses unbound. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Re-derives XL-2 on current main (does not rebase #13430 / #13638 / #13284). Kernel
Stringconcatenation is admitted through the free-monoid structure (not a coined concat type, and not Int's additive monoid):v2.std.algebra_structure_signaturefree_monoid_structure_type_nodebounds the collection-roster carrierMon aBinderStructureEdge, andv2.compiler.inferinfer_application_structure_boundsadmits an instance only through the one inhabitance authority (dag_free_monoid_free_monoid_inhabitance/list_append,dag_host_text_free_monoid_inhabitance/v2.std.node.host_text_concatenation). Host text andv2.std.textString(FreeMonoid<Char>) stay distinct; the host-text row's generator isstd.types.Char(Ruling 3 / the 2026-09-27 text ruling).The dag surface also gains a string-template lex/grammar production (
^dag_string_template), disjoint from a plain string literal by hole opener. Templates are the host-text crossing, not a seedto_stringhack: a hole is an expression, not interpolated text. Lowering of a template shell to a concat chain is not in this PR (no02_parse/body_lowering_folddecode); that remains a follow-up so a hole is a resolve reference.Parse fix (this session,
f11289a):dag_grammar_primary_expr_corewas missing a matching close after the template alternative (expected RParen, found RBraceat that function). Isolated compile:gunbc compile --source-dir <only dag.dag> --output-dir /tmp/x --target dag— frontend succeeds after the paren repair. That was the witnesses self-hostparse-failed/EmissionRefusedonac34899.Real-path claim (was red)
fmb_kernel_text_concat_is_accepted_through_its_rowrefusedinfer_reason_caller_admission_callee_unresolved, located at theconcat(a, b)application (correction suggested at the callee DeclarationReference).Chain (DESIGN 6b): resolve binds bare
concattostd.algebra.collection_concat_shape; infer types the call from the roster signature (collection_roster_signature_arrow). Caller admission then treated that mark as an indexed fn, looked it up in the subject's symbol index, and refused Unresolved — the row is a template value, not a callable withadmit_callers. Earliest unjustified boundary:infer_caller_admission_roster_from_declarations/ the unmarked-facts arm ofinfer_caller_admission_application_diags. Notcall_result_of_a_declared_return_type_unjudged_in_v2_infer(kernel String result is judged). Fix: roster primitive-call heads impose no admission clause. Deleted theActiveFillDebtrow for this claim.claim_batch (witnesses does not run claim files)
PASS, process exit 0.
[witness] ... eval_steps=523863.PASS ×3, process exit 0.
Re-derived from / not carried
BinderStructureEdgevsBinderTypeEdge, host-text inhabitance row, infer bound check, roster signature over carrierM+ generatorE, claimsv2.test.claim.compiler.free_monoid_structure_bound/ concat / count updates, RFM receipts.v2.extdeps.languages.dag.IdentStarthole-opener widening (Codex on XL-2 PR2b: string templates — disjoint lexer, one ^dag_string_template node, concat-chain lowering #13430; ASCIIIdentStartChar+(/!/-as on the old head); v1 fused adjacent holes (seed defect, not reproduced); tplscan scratch;ServiceSetAsidedelete-first (XL-2 3c: enumerate ServiceSetAside consumers before delete-first #13637 plans-only — census on main: the type and accumulators still live inv2.compiler.body_lowering_fold, diagnostics feednormalize_censusand the service/resource lowering claims; no delete in this change).ServiceSetAside census (asked by #13637)
Still present on main / this branch:
ServiceSetAside/ServiceSetAsideKindinbody_lowering_fold,service_set_aside_diagnostics,normalize_censusadvisory path, claims undersrc/v2/test/claim/normalize/service_*andresource_declaration_lowering_test. RFMservice_interface_member_has_no_carrierstill names the trigger. Not a delete-first in XL-2.Receipts (head
8b6999f29eb6)gunbc test //gunbc/instruments:self-host— witnesses job 38084429587 step "emit and build //gunbc/instruments:self-host" success (process exit 0).gunbc test //gunbc/instruments:v2-native-cli— same run, step "emit and build //gunbc/instruments:v2-native-cli" success (process exit 0).f11289ac61e: witnesses run 38082349398 also success; this head is the escape-body follow-up after review 78468.Permission denied (publickey); instruments are the required-job steps above, not a local systemd-run.Test plan
Seed:
CTRL_BUILD_MODE=local CARGO_TARGET_DIR=/tmp/cargo-target-eager-ram-629 cargo build --release -p v1-compiler --bin gunbcand--bin claim_batch(control:cargo check -Z definitely-not-a-real-flagrefused on stable as required).Isolated parse of
src/v2/extdeps/languages/dag.dagafterf11289a: frontend green (remaining diagnostics on a one-file dir are unresolved imports).claim_batch --source-root dag --source-root src/v2 --entry src/v2/test/claim/compiler/free_monoid_structure_bound_test.dag:fmb_kernel_text_concatenation_executes,fmb_bound_admits_kernel_text,fmb_int_refuses_at_the_free_monoid_bound,fmb_bool_refuses_at_the_free_monoid_bound,fmb_structure_bound_is_not_judged_as_a_kind_at_resolve,fmb_kernel_text_has_generator_char,fmb_int_has_no_free_monoid_generator,fmb_malformed_inhabitance_row_refuses_with_its_own_cause,fmb_mixed_carriers_refuse,fmb_list_of_edge_has_generator_edge,fmb_fixed_element_disagreeing_with_the_generator_refuses,fmb_structure_shaped_kind_is_still_kind_checkedfmb_kernel_text_concat_is_accepted_through_its_row. The real-path claim now passes on 71162bc. Its refusal wasinfer_reason_caller_admission_callee_unresolved, fixed at caller admission (a roster primitive-call head imposes no admit_callers clause; see the chain above), and its former ActiveFillDebt row is deleted.srv1:
ssh srv1from this session isPermission denied (publickey). Instruments//gunbc/instruments:self-hostand//gunbc/instruments:v2-native-cliare left to the requiredwitnessesjob on this head (f11289a), not run in the 24 GiB session container.Review 78460 (claude) approved
ac34899; that approval is stale relative tof11289a(parse-only). No GitHub REQUEST_CHANGES.Review 78485 (unicode escape vs hole)
dag_string_unicode_escape_prefix_patternconsumes\u{as v1scan_string_bodydoes. claim_batch--entry src/v2/test/claim/tokenize/string_literal_raw_newline_test.dag --functions unicode_escape_letter_hex_lexes_as_one_string_literal,unicode_escape_digit_hex_lexes_as_one_string_literalPASS ×2, exit 0.