Skip to content

. - #3

Merged
briansrls merged 1 commit into
mainfrom
codex/graph-viz-test-helpers
Jan 29, 2026
Merged

.#3
briansrls merged 1 commit into
mainfrom
codex/graph-viz-test-helpers

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

No description provided.

@briansrls
briansrls merged commit 80a29ca into main Jan 29, 2026
briansrls pushed a commit that referenced this pull request Feb 3, 2026
…fragility

TODO_hacks.md:
- Hack #5: cardinality Empty tests use concrete empty values (false/0/"")
  not actual absence. BoundaryMocks has no way to represent "absent."
  Blocks meaningful B.3 boundary testing for scalar types.
- Hack #4 amendment: Value::List filter_map silently drops non-string
  elements (separate from catch-all issue).
- Hack #3 note: runtime check() already handles lists correctly;
  codegen to_check_code() just needs to mirror it.
- Notes: typed matchers as finite logic language; Hack #5 priority.

consolidation.md:
- §5: type_id == "List" dual encoding across 4+ locations. Canonical
  model is element type + cardinality. Migration strategy documented.
- §6: Codebase fragility — builder functions as strings (rename-unsafe),
  buck-out/gen in 16 locations (no single constant), CODEGEN_SOURCES
  hardcoded directory list (staleness gap).
- Tasks updated for all new items.

https://claude.ai/code/session_01FcPT2VEZdE1W7QdL7SjJgC
briansrls pushed a commit that referenced this pull request Feb 13, 2026
Addresses feedback from 2026-02-12 PR review across 6 key areas:

1. Fix probe→observer recursion (#1): Intermediate observers are now
   promoted to probes unconditionally (not gated on Exact matchers).
   Tests are seeded from baseline DryRun, so concrete values aren't
   needed. This enables compositional segment testing A→B + B→C.

2. Fix extract_observers() seen/merge bug (#2): NodeExamples with only
   input-dependent matchers (Exact/Contains) no longer suppress valid
   chain-safe matchers from live_expected_outputs for the same node.
   Switched to merge-by-node approach using BTreeMap union.

3. Make gaps fail CI (#3): Coverage gaps now generate a failing
   test_observability_invariant_no_gaps test instead of just a header
   comment. Aligns behavior with the stated invariant.

4. Make lowering failures loud (#4): DAG lowering errors now generate a
   failing test_probe_observer_lowering_failed test instead of silently
   returning None and skipping all chain tests.

5. Seed policy fail-closed (#5/#8): Inverted seed_policy_for_type to
   whitelist known-safe primitive types (String, Bool, Int, etc.) and
   default unknown types to ExplicitSeedRequired. New types and aliases
   no longer silently fall into placeholder generation.

6. Additional hardening:
   - Add input_mocks as a probe source (#6) for DAGs seeded via entry
     input ports
   - Track weak observers (Any/IsRequest/IsResponse) in coverage
     reports (#5) so teams can identify low-value assertions
   - Promoted probes now appear in analysis results
   - ParamType::from(&str) panics on unknown types instead of silently
     defaulting to Str (#9)
   - Int parsing returns ParseError::InvalidInt instead of unwrap_or(0)

https://claude.ai/code/session_014cTfu4arnDzFZCELaR26P4
briansrls added a commit that referenced this pull request Mar 1, 2026
Hack #1 - PipeMethod stringly-typed spread:
  Add PipeMethod::as_str() and Display impl as single source of truth.
  Delete three duplicate pipe_method_name() functions from lib.rs, expr.rs,
  fn_codegen.rs. All callsites now use method.as_str().

Hack #2 - Silent fallbacks in resource_defs.rs:
  Replace silent return-fallback with .expect() on compile_from_context,
  data_values.get, and serde_json::from_value. Delete ResourceDslData::fallback()
  and three FALLBACK_* constants. DSL syntax errors now fail the build immediately.

  Same treatment applied to gitignore.rs: silent fallback → expect().

Hack #3 - #[path] crate boundary (documented):
  core/resolve uses #[path] to compile resolve_service.rs from gunbc-dag.
  Physical move requires extracting gunbc-dag dependencies from the module
  first (use super::* reverse dependency). Documented as Lane A task.

Hack #4 - compile-on-demand spread (documented):
  7 files use compile_from_context at runtime. Now all fail-closed (no silent
  fallbacks). The include_str!/StdLibHost migration is a Lane A Phase A3 task.

Co-authored-by: Brian Searls <briansrls@users.noreply.github.com>
briansrls added a commit that referenced this pull request Mar 1, 2026
#2 (pragma_lint silent fallback): Delete default_pragma_lint_policy() and
   hardcoded fallback. Policy file must exist — panic with actionable message.

#3 (param_source_ string heuristic): Add NodeKind::ParamSource variant.
   Lowerer tags param_source nodes. Executor checks node.kind instead of
   node_id.starts_with("param_source_").

#4 (Value::Skipped coercion): map/join over Skipped produce empty list/string
   (temporary — required until C10-full wires all return expressions).
   Tagged as RT-N workaround.

LowerError::InvalidFileOp from previous commit now fail-closed.

Note: pragma-lint-policy.txt needs regeneration (gunbc-pragma blocked by C10).

Co-authored-by: Brian Searls <briansrls@users.noreply.github.com>
briansrls added a commit that referenced this pull request Mar 1, 2026
PR comment #1 (param field access wiring):
  Already fixed in previous commit — ExprComputeOp.execute() destructures
  Value::Map inputs into field-level env entries (line__is_blank etc).
  Param source nodes feed the full record; the compute node unpacks it.

PR comment #2 (passthrough Skipped fallback):
  Restore partial fail-closed enforcement. Required outputs now return
  ExecError when other passthroughs arrived but this one is missing
  (indicating a genuine lowerer wiring gap). When NO passthroughs arrived
  (entire callable was skipped/guarded), fall back to Skipped.

PR comment #3 (derive_file_spec panic):
  Change return type from Option to Result<FileOperationSpec, LowerError>.
  Invalid file operations now return a typed LowerError instead of panicking.
  Caller maps Err to None (skip operation with diagnostic).

Co-authored-by: Brian Searls <briansrls@users.noreply.github.com>
briansrls added a commit that referenced this pull request Mar 3, 2026
…tions

- Reorder candidates in default_value_for_slot to try REST before Shell/File
  (mirrors probe_best_response fix from earlier commit)
- Mark 3 observations resolved in tasks.md: classify_module doc (#3),
  from path standardization (#8), probe_best_response ordering (#10)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Mar 13, 2026
…nt Map

Addresses review invariant #3 (No fallbacks that fabricate).
extract_projection previously fabricated a Value::Map from the output
when the expected field wasn't found. Now returns Result<Value, String>
so callers handle the error explicitly.

PopResult gains an Error variant; run_machine propagates it.

Also confirms all 5 review findings against the code:
1. Three parallel stmt evaluators (eval_body, eval_block_as_body,
   eval_pure_block_stmts) — No parallel implementations violation
2. ANF verifier permits Calls in Blocks — Boundary contract loophole
3. Projection fabrication — Fixed in this commit
4. Duplicate PC (heap vs native stack) — Architecture issue
5. O(N) Rc clone — Performance issue

The correct fix for #1, #2, #4 is slice-based continuations (stack
bubbling), documented in DESIGN-eval-redesign.md as the next step.

Co-authored-by: Brian Searls <briansrls@users.noreply.github.com>
briansrls added a commit that referenced this pull request Mar 23, 2026
…map feedback (#193)

* Remove aspirational tests that describe target state not yet implemented

Delete 4 failing tests and their 5 now-dead helper functions:
- phase6_fold_lambda_uses_reconciled_accumulator_type (R3: fold type refinement)
- phase6_anonymous_record_literal_fails_closed_without_named_type (R2)
- phase6_anonymous_record_literal_does_not_rank_shape_candidates (R2)
- phase6_go_runtime_bridge_methods_keep_method_style_receivers (P1.10)

These tests were written to describe Phase 1 target behavior. They will
be re-added when the corresponding roadmap items (R2, R3, P1.10) land.

Co-authored-by: briansrls <briansrls@gmail.com>

* Fix lingering v2.compiler.pipeline references to v2.compiler.compile

M1 naming cleanup renamed 06_pipeline.dag to compile.dag (module
v2.compiler.compile), but emit_main_rs, emit_main_mod_uses, and
emit_compile_match_arm still referenced the old module name.

Co-authored-by: briansrls <briansrls@gmail.com>

* Align L1 ratchet script categories with ROADMAP.md

Break the connective count into '.connective direct access' and
'Conj/Disj references' (previously double-counted). Add
classify_type_structure as a separate tracked category. Fix
set -euo pipefail + grep exit code interaction via || true.

Script and roadmap table now measure the same 7 categories.
Ratchet set to 374 (current actual total).

Co-authored-by: briansrls <briansrls@gmail.com>

* Clarify milestone status labels: tree-green vs prior-branch vs structural

Feedback #2: readers could not tell which milestones are verified on the
current tree versus achieved on an earlier green branch. Added a status
column and a note explaining that prior-branch milestones re-verify once
stage0 self-compile is green. Updated P3.1 and M1 accordingly.

Co-authored-by: briansrls <briansrls@gmail.com>

* Add InferredNode migration boundary subsection (P1.9)

Feedback #3: the representation change was conceptually clear but the
mechanical migration plan was implicit. Added a table listing every
type, API, and layer that changes when P1.9 lands, plus the ordering
constraint that it must be an atomic commit.

Co-authored-by: briansrls <briansrls@gmail.com>

* Split normalization scope: Phase 1 (hardcoded arity) vs Phase 3 (declarations)

Feedback #4: the roadmap described normalization as populating structural
properties from .dag declarations, but P1.14 defers declaration-driven
population to Phase 3. Made the two scopes explicit so readers see that
Phase 1 normalization uses the hardcoded arity bridge, and Phase 3
normalization replaces it with generic slot substitution.

Co-authored-by: briansrls <briansrls@gmail.com>

* Narrow Phase 1 fabrication gate to Rust bootstrap-critical path

Feedback #5: 'no emit fabrication sites' in the Phase 1 checklist was
overstated — the document defers Go interface{}, Python _unimplemented(),
and Go unhandled-expr to Phase 4. Narrowed the Phase 1 state and exit
criteria to specify 'no silent/fail-open fabrication on the bootstrap-
critical Rust emit path' and explicitly list the Phase 4 deferrals.

Co-authored-by: briansrls <briansrls@gmail.com>

* Sharpen v1 retirement gate and scrambled-name test definition

Feedback #6:
- Phase 3 gate now includes a concrete feature-off proof (build + test
  without v1-bootstrap) rather than just saying 'can be removed.'
- Scrambled-name test explicitly defined as comparing inferred structure
  (typed graph shapes), not emitted artifacts. Emit is excluded because
  it legitimately reads names for target-language identifiers.

Co-authored-by: briansrls <briansrls@gmail.com>

* Add LanguageSpec checklist, DAG artifact schema, and TypeVar name-opacity note

Feedback #7: Phase 4 contracts were named but not specified. Added:
- P4.1 Contract: compact checklist of what belongs in LanguageSpec,
  grouped by purpose, with completeness test and existing values.
- P4.4 Contract: DAG artifact schema (version + modules + diagnostics),
  versioning mechanism, and note that it reuses the existing Value
  serialization format.
- TypeVar name-opacity explanation in generics design: slot names are
  structural placeholders consumed by normalization pre-inference, not
  type identities that inference branches on.

Co-authored-by: briansrls <briansrls@gmail.com>

* R2: Anonymous record tuple index emits compile_error!() for index >= 4

Stopgap: the hardcoded 0-3 index mapping now emits compile_error!()
instead of silently falling back to "0" for higher indices and for
field-not-found. The real fix (proper field access for any arity)
remains a backlog item.

Co-authored-by: briansrls <briansrls@gmail.com>

* R4: map_insert reads key type from actual argument instead of hardcoding String

The ExprCall bridge path for map_insert on a bare Map receiver now
reads the key type from the first argument (remaining |> first) rather
than fabricating leaf_node(name: "String"). The leaf_node fallback
remains only for the unreachable None branch (count >= 2 guard).

Co-authored-by: briansrls <briansrls@gmail.com>

* R3: Extract shared refine_collection_result_type for map/flat_map/fold

Both ExprCall (bridge path) and ExprMethodCall computed map/flat_map/fold
result types through independent inline blocks (~20 lines each). Extracted
into a single refine_collection_result_type helper that both paths call.

The ExprCall path still owns map_insert/map_merge refinement (those are
Call-bridge-specific, not duplicated in MethodCall).

Co-authored-by: briansrls <briansrls@gmail.com>

* P1.10: Delete dead runtime_bridge_method_name from core

The function had zero callers — each emitter owns its own
per-target bridge method name rendering (rust_bridge_fn_name,
go_bridge_method_name, py_bridge_method_name). These per-target
maps are legitimate rendering decisions (Go=PascalCase,
Python=with_update for BridgeWith) and remain as-is.

The 4-parallel-map problem is now 3 per-target maps with no
dead shared intermediary.

Co-authored-by: briansrls <briansrls@gmail.com>

* P1.19: Delete duplicate mock extraction; import has_mock_prefix from shared emit

Deleted starts_with_prefix (duplicated has_mock_prefix from 05_emit.dag).
extract_mock_props now uses the imported has_mock_prefix. The Rust-only
copy of mock prefix detection is eliminated.

Co-authored-by: briansrls <briansrls@gmail.com>

* P1.20: Replace testgen fabrication sites with compile_error!()

- emit_simple_expr wildcard: todo!() -> compile_error!()
- emit_data_value_json wildcard: "null" -> {"__error__": ...}
- Default::default() dry-run fallbacks -> compile_error!()

All three silent fabrication sites now fail loudly instead of
producing valid-looking but wrong test/mock code.

Co-authored-by: briansrls <briansrls@gmail.com>

* P1.21: Add testgen verification gate + fix emit_typed_data_value_json fabrication

New test v2_testgen_emits_valid_rust verifies:
- emit_simple_expr uses compile_error!() not todo!()
- dry-run fallbacks use compile_error!() not Default::default()
- mock extraction uses shared has_mock_prefix, not Rust-only duplicate
- shared emit defines TestProjection and extract_test_projections
- emit_data_value_json does not silently fabricate "null"

Also fixes emit_typed_data_value_json wildcard (second copy of the
same fabrication pattern, line 438 in 05_emit.dag).

Co-authored-by: briansrls <briansrls@gmail.com>

* R1: Delete 30-line RC3 emit safety net for Optional field access

field_summary_for_type in inference already correctly produces
OptionalUnwrap for .value on Optional bases. The emit-side
compensation (checking return_type and base_summary for Optional)
was dead code — no test exercises a path where StoredField is
produced for .value on an Optional base. All 116 tests pass.

Co-authored-by: briansrls <briansrls@gmail.com>

* Tighten L1 ratchet 374 -> 372 after R1 emit safety net deletion

Co-authored-by: briansrls <briansrls@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Mar 27, 2026
Review fixes:
- Fix variable shadowing: let_value/let_body renamed to val_expr/body_expr
  in 04_infer.dag ExprLet handling (reviewer comment #1)
- Delete 4 unused accessor functions: call_arg_nodes, record_field_nodes,
  list_elements, string_interp_parts (reviewer comment #2)
- Comments #3 (collection kind match) and #4 (variant connective) were
  already fixed in earlier commits

Documentation:
- Updated Phase 5 Exit Criteria with full breakdown of remaining 147:
  - 8 type-name comparisons: 5 access (blocked on inline test std loading),
    1 is_kernel_type, 1 string element, 1 Tuple
  - 139 type constructors: factory functions (bridge debt)
- Documented the specific blocker: inline tests don't load std modules,
  so types resolve as bare kernel seed leaves, not algebra compositions.
  The algebra infrastructure exists (FreeMonoid.index, OrderedRing, structural
  method lookup B4) but can't be verified end-to-end in inline tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Mar 28, 2026
Three decidability improvements to the complexity engine:

1. RecursionPattern classification: get_or_compute_summary now detects
   self-recursion via the placeholder mechanism, classifies as
   LinearRecursion (1 self-call) or DivideAndConquer (>1 self-calls),
   and produces bounded CostSum instead of CostUnknown.

2. Body budget removal: the 500-node estimate_expr_size guard produced
   false CostUnknown violations on infer_expr and cost_of_expr (the
   two largest and most important functions). The caching/placeholder
   mechanism already prevents exponential analysis, and the decidability
   invariant guarantees termination. Ratchet: 2 → 0.

3. ROADMAP updates: iteration primitive audit complete (all bounded),
   trace_pop_frame resolved as dead code (Gap #3: 4-layer analysis of
   dead code detection, reachability-gated analysis, persistent data
   structures).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 7, 2026
Address 6 of 7 review comments on PR #336:

1. branching_proof_safe: validate all dimensions of branching fallback
   proof (not just first). proof_safe_for_branching correctly checks
   first dimension only (structural first bounds total recursive entries).

2. CallGraph M4 debt: strengthened comment noting string keys are
   module-qualified from typed IR, blocked on Map<K,V> non-String keys.

3. complexity_diagnostics: now reads violations from ComplexityReport
   instead of returning hardcoded []. Violations are non-blocking
   (included in diagnostics for visibility, don't block emission).

4+5. size_bound_param: Forever and ExplicitCount now return None
   (fail-closed) instead of fabricating synthetic identifiers.
   bounded_recursive_cost uses "__unresolved" binder + records
   violation via check_bound_violation.

7. ComplexityReport preserves intern_table (no longer emptied).
   violations: List<String> field surfaces unresolvable bounds.

6. Added cx_unresolvable_bound_produces_violation and
   cx_non_recursive_has_no_violation ratchet tests.

Self-compile: 51 files emitted, 251 complexity violations (all
"unresolvable recursion bound" — analyzer limitations, not program
errors). Violations ratchet down as recursion detection improves.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 8, 2026
…List"

Addresses review comment #3: classify_field_recursion was comparing
field_type_name == "List" directly, violating structural dispatch.
Now uses is_container_type() and container_expected_arity() from
std/types.dag to dispatch on container kind structurally:

- Arity-1 containers (List, Set, NonEmptyList, NonEmptySet): element
  type at position 0 → ListRecursion (or SetRecursion for sets, but
  currently all arity-1 map to ListRecursion since Set<self> recursion
  is the same structural pattern)
- Arity-2 containers (Map): value type at position 1 → MapValueRecursion

Adding a new container type to std/types.dag now automatically extends
recursive field detection with zero changes to the classify function.

Review comments #1 (no downstream consumer) and #2 (string proxies)
are acknowledged as known constraints — #1 resolves when CX-L2 lands,
#2 resolves with M4 (Node.name deletion).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 9, 2026
…MAP (review feedback)

#2 ExprLet scope: annotate_descent gave the value initializer access to
its own binding (inner_ctx applied to all children). Fixed: value sees
outer ctx, only body sees inner_ctx. Ratchet 528→485 (43 false descent
evidence entries eliminated). Regression test added.

#3 ROADMAP sync: KF-8 marked DEFERRED, heap-space marked TODO, binary
search stack corrected to O(1) via TCO (not O(log n)).

#4 Rename: time_bound → recurrence_bound. This is a structural
recurrence bound (work_exponent=0), not full runtime. Full time =
recurrence * per_step_cost.

#5 TCO guarantee: documented that stack O(1) for tail-recursive
functions assumes the target language guarantees tail-call elimination.

365 tests pass, clippy clean, stage0 fixed point verified (485 diagnostics).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 10, 2026
…ations

Three review issues fixed:

1. Remove parallel Provenance type. Option B now threads the existing
   SubValueRelation through bindings — single authority, no dual
   representation. The sound foundation already exists; the fix is
   placement (on TypeBinding), not a new type algebra.

2. Remove source_param: String. Source tracking follows from the
   scope chain (binding structure), not a new string-keyed field.
   CallbackContract uses param index (Int), not name (String).
   Aligns with M4 structural identity direction.

3. Rewrite open question #3 from annotation syntax (@returns) to
   structural .dag contracts (like AlgebraMethodSemantics). Aligns
   with INVARIANTS.md: annotations are not facts.

Also syncs ROADMAP.md to match (removes source_param: String,
clarifies single-authority framing).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 11, 2026
Addresses invariant violation feedback on PR #384:

1. Wire contract: no longer collapses to module-wide string. Passes
   wire_contract_item (Node?) per-enum for per-type resolution.

2. Response format (text vs json): reverted is_string_like heuristic.
   Needs WireFormat fact on response declarations in std/.

3. Shell multi-field return: reverted name-based channel fabrication.
   Needs channel→field mapping in transport definition.

Both #2 and #3 now emit compile_error! on the unmodeled cases,
making the gap explicit rather than silently fabricating.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 15, 2026
…rate shortcuts

Five-item pass from the latest ChatGPT review. The headline is #5 —
replacing `TypeShape::Primitive(Prim)` with a newtype around
`DeclarationId`. That was an M0-inheritance bug that propagated
through every subsequent substrate refactor unnoticed because Port
machinery was never in scope for the type substrate rework. After
this commit the declaration table is the SINGLE source of type
identity across the v3 compiler; no name-keyed bridge remains.

#1 — Delete `lower_fn_item_pending`; unoverload `ArrowBody::Pending`:
- Block-bodied `fn` items in std/ files no longer create Arrow
  declarations at all. They're skipped in `collect_symbols` (matched
  on `body: None`), so the declaration table never allocates a slot
  for them. `ArrowBody::Pending` reverts to its thesis meaning
  (primitive realization lag only) — no overloaded "user body not
  lowered yet" interpretation.
- Call sites that target block-bodied fns fail-closed at inference
  because no declaration exists with their name.

#2 — Remove `resolve_pending_identifiers` tolerance:
- Split the sweep into a tolerant bootstrap variant and a strict
  user-code variant. Bootstrap tolerates dangling stubs (the
  canonical `dsl/std/*.dag` files reference types like `Tuple` that
  live in std/ modules outside the M1(2.6) load set). User-code
  `lower()` captures a `user_start` snapshot and runs the strict
  variant over stubs allocated during user lowering — every
  Identifier stub at `id >= user_start` must resolve or it's a
  fail-closed `ResolveError`.
- `Atom(Identifier { resolved: None })` now means exactly one thing
  at the user-code boundary: "not yet resolved, pre-sweep".

#3 — Move `allocate_type_params` into `collect_symbols`:
- Pass 1 of lowering (`collect_symbols_phase`) now allocates top-level
  declarations AND their TypeParam children in one pass, populating
  `Declaration.type_params` before any body-lowering runs. Pass 2
  (`lower_bodies_phase`) reads `local_scope_from_parent` instead of
  re-allocating type params.
- Bootstrap is restructured into two phases: all files Phase-1 first
  (so every cross-file template has its type_params slot populated),
  then all files Phase-2 with a shared symbols map rebuilt from the
  post-Phase-1 declaration table. `build_template_arguments` no
  longer hits forward-reference gaps that would have required
  half-valid placeholder parameters for real declarations.
- `fixup_instantiation_template_params` is deleted. The half-valid
  state it repaired no longer exists for real declarations. Stub
  templates (bootstrap dangling refs) still use self-reference
  placeholders, but the stub itself is caught by the sweep and the
  Instantiation stays dead in bootstrap bodies — no repair pass.

#4 — Move `inject_realization_stub` into `#[cfg(test)]`:
- Production `bootstrap()` no longer injects realization declarations.
  The §6.5 smoke test moves into a `#[cfg(test)]` module inside
  `bootstrap.rs` where it builds its own synthetic realization chain
  (TestRealization meta-type, anonymous instance, anonymous
  realization Arrow) without polluting `Dag::new()`.
- `Dag::realization_smoke_arrow` / `set_realization_smoke_arrow`
  deleted — production Dag has no such slot.
- `assert_realization_shape` also moved to test-only.

#5 — Replace `TypeShape::Primitive(Prim)` with newtype over `DeclarationId`:
- `types.rs`: `TypeShape` is now `{ declaration: DeclarationId }`,
  `Copy + Eq + Hash`. `Prim` enum deleted.
- `infer.rs`: `primitive_shape(dag, name)` helper replaces all
  `TypeShape::Primitive(Prim::X)` constructions. Literal node
  dispatch looks up Int/Bool/String by name. `declaration_to_type_shape`
  + `type_shape_to_declaration` deleted — bridging is now a trivial
  `TypeShape::new(decl_id)`. `walk_to_type_shape` stops at the first
  named top-level declaration and returns it as the TypeShape; no
  name-keyed primitive matching.
- `lower.rs`: `lower_type_for_port(ty, dag)` looks up primitive
  names via `declaration_by_name`. `sentinel_type_shape` helper for
  the mark-unresolved fallback.
- `m0_acceptance.rs`: ~25 assertions updated via `primitive_shape(&dag, "X")`.

Test status: 1 unit test (bootstrap realization smoke) + 41 M0 + 3
M1 substrate + 4 real-stdlib parse smoke = **49/49 green**. Clippy
clean.

Name-bridge audit: `grep -rn` in `src/v3/compiler/src/` turns up:
- `OPERATOR_FIELD_MAP` (10 entries, documented dissolution trigger
  to M2 when surface grammar exposes algebra field access directly)
— one localized constant, not a pervasive pattern. No other
name-keyed bridges remain.

Review items now closed:
- FAIL-CLOSED: declaration-graph failures go through phantom ports
  (tolerant in bootstrap, strict in user code)
- ILLEGAL STATES: Pending unoverloaded, ExternalRealization typed
  edge checked at both construction and dispatch, TemplateArgument
  half-valid state eliminated for real templates
- FACTS FLOW FORWARD: declaration identity flows end-to-end from
  bootstrap source through inference to port types; no name-keyed
  collapse at the port boundary
- COPROD DISSOLUTION: ArrowBody back to terminal-2 + scaffold-1
  (Pending only for realization lag); AtomPayload Identifier phase
  coproduct tracked in ROADMAP as M2 substrate refactor
- SINGLE AUTHORITY: `inject_primitive_operators` and
  `inject_realization_stub` both out of production bootstrap; the
  declaration table is the only source of type identity
- API-LEVEL ENFORCEMENT: `lower()` runs the strict sweep before
  returning, so no caller discipline is required

Still deferred (tracked in ROADMAP):
- AtomPayload `Identifier { resolved: Option }` → split variants
  (M2 substrate refactor)
- Flat namespace via `declaration_by_name` (M2 module system)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 15, 2026
Four structural dissolutions from the round 6 ledger audit, plus the
corresponding ledger rewrites. After this commit the only 🟡 or
🔴 items left are those that are structurally deferred to later
milestones (M2 module system, M3 Pending ratchet).

#1 — VariantPayload::Unit dissolved
- Unit variant collapsed into `Positional(vec![])`. Unit and
  zero-arity positional were structurally indistinguishable at
  the substrate level; the dedicated Unit arm was cosmetic.
- VariantPayload is now a 2-variant enum (Positional, Record),
  reclassified 🟢 terminal.
- `parse_variant` emits `Positional(Vec::new())` for bare
  variants; `lower_type_sum` drops the Unit match arm.

#2 — SurfaceItem::Module/Import/DataDecl dissolved
- Parser absorbs module / import / data declarations at parse
  time instead of emitting them as SurfaceItem variants. Their
  M1(2.6) semantic effect was "no-op at lowering," so carrying
  them through as SurfaceItem scaffolds was pure scaffolding
  debt.
- New parser helpers `absorb_module_item` / `absorb_import_item`
  / `absorb_data_item` consume the token stream without
  emitting a SurfaceItem.
- `parse_item` returns `Result<Option<SurfaceItem>, Diagnostic>`:
  None means "absorbed, no item to emit."
- SurfaceItem drops from 9 variants to 6 (Let, Fn, TypeAtom,
  TypeRecord, TypeSum, TypeAlias), reclassified 🟢 terminal
  modulo the M2 Type* collapse question.
- `lower_item` / `collect_symbols_phase` / `item_span` all drop
  the Module/Import/DataDecl arms.

#3 — SurfaceExpr literal trio dissolved
- The three surface-expression literal variants
  (IntLit/BoolLit/StringLit) collapse into a single
  `Literal { value: SurfaceLiteral, span }` variant. The new
  `SurfaceLiteral` enum is parse-local (Int/Bool/String),
  preserving the G3 guardrail that parse.rs doesn't mention Dag
  types — `SurfaceLiteral` mirrors `LiteralBits` but lives in
  the parse layer.
- SurfaceExpr drops from 6 variants to 4 (Literal, Var, Call,
  If), reclassified 🟢 terminal.
- `lower_expr` collapses its three literal arms into one match
  with an inner `match value { SurfaceLiteral::* }`.
- `is_recursive`, `descent_provable`, `collect_calls`,
  `expr_span`, `is_strictly_smaller` all updated.

#4 — AtomPayload::Identifier phase coproduct split
- `Atom(Identifier { name: String, resolved: Option<DeclarationId> })`
  replaced by two structural variants:
    - `Atom(UnresolvedIdentifier(String))` — pre-sweep, name
      reference pending resolution.
    - `Atom(ResolvedIdentifier(DeclarationId))` — post-sweep,
      typed edge to referent declaration.
- The pre/post-sweep phase is now a coproduct variant, not a
  field value. Pattern matches for the two cases live on
  different arms instead of on `Some`/`None`.
- `resolve_pending_identifiers` rewrites the connective on
  resolution instead of mutating an `Option` in place. The
  sweep is a structural phase transition, not a field update.
- All pattern-match sites updated: `placeholder_connective`,
  `alloc_identifier_stub`, `build_template_arguments`'s stub
  check, `run_identifier_sweep`, `unresolved_operator_name`,
  `resolve_arrow_walk`, `walk_to_type_shape`,
  `target_display_name`, `assert_target_name` in tests.
- AtomPayload is now 4 variants (Literal, UnresolvedIdentifier,
  ResolvedIdentifier, TypeParam), reclassified 🟢 terminal. The
  former compression debt the ledger flagged (`Option<_>` hiding
  a phase coproduct) is eliminated.

Test status: 1 unit test (bootstrap realization smoke) + 41 M0 +
3 M1 substrate + 7 real-stdlib parse smoke = 52/52 green. Clippy
clean. Net -71 lines (parse.rs net -94, lower.rs net -58 via
simpler match arms, dag.rs +28 for the split AtomPayload).

Ledger audit after this commit:
- 🟢 terminal at M1(2.6): TypeConnective, AtomPayload,
  CardinalityBound, LiteralBits, ArrowBody (terminal-2 modulo
  the Pending scaffold), SurfaceItem, SurfaceType, SurfaceExpr,
  SurfaceLiteral, VariantPayload.
- 🟡 scaffold with thesis-defined dissolution trigger:
  ArrowBody::Pending (§8.11 ratchet to zero by M3).
- 🔴 deferred to M2+: flat namespace via declaration_by_name
  (needs module-scoped declaration table). Tracked in ROADMAP.

No remaining compression debt in the parse or declaration layers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 15, 2026
Codex blockers on 636947f: FnExternalBody and Data items compile
cleanly in ordinary user code, leaving ArrowBody::Unparsed and
ValueBody::Unparsed scaffolds in user-range declarations with no
later rejection. `fn foo(x: Int) -> Int { junk }` and
`data foo: Int = { junk }` both round-tripped through compile_to_dag
without a diagnostic, violating THESIS.md static grounding and
modeling-discipline.md principle 1 FAIL-CLOSED.

Context: these scaffolds exist so the std/bootstrap files with
match/record/pipe/lambda bodies can parse cleanly (their bodies
stay as preserved source spans, dissolved when the parser grows
to cover the remaining grammar — DOWNSTREAM_REQUIREMENTS.md
class-5 gaps #3 and #5). Bootstrap-range declarations still need
them. Ordinary user code never should.

Fix: add `reject_user_unparsed_scaffolds(dag, strict_from)` sweep
in lower.rs that walks declarations at id `>= strict_from` (the
user-lowered range after bootstrap) and emits fail-closed
diagnostics for:
- `TypeConnective::Arrow { body: ArrowBody::Unparsed(span), .. }`
- `Declaration.value_body == Some(ValueBody::Unparsed(span))`

Called from `lower()` alongside `resolve_pending_identifiers_strict`.
Bootstrap-range declarations (id < strict_from) are still
tolerated — those scaffolds exist by design until the parser
catches up.

Regression tests:
- `m18_r14_user_block_bodied_fn_is_rejected`: user-code
  `fn foo(x: Int) -> Int { junk }` returns Err from compile_to_dag.
- `m18_r14_user_data_with_opaque_body_is_rejected`: user-code
  `data foo: Int = { junk }` returns Err.

Coverage: 41 M0 + 29 M1 substrate (27 existing + 2 new R14) +
7 real-stdlib smoke + 1 realization smoke = 78 green. Clippy
clean (collapsible-match warning fixed in the same pass).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 15, 2026
Ship the substrate + lens foundation needed for PR-B's Rust emitter.
The 100% structural scope from the plan: data items with record-
literal bodies lower to a new ValueBody::Structural variant carrying
the field labels + literal bits; `dsl/extdeps/languages/rust.dag`
loads as a bootstrap fixture declaring Realization and 18 Rust-side
realization facts; a cost lens lands as the third observational lens
in the lens_depth/lens_provenance template.

Phase 1 — Parser (SurfaceExpr::Record + data body integration):
  - New SurfaceExpr::Record { fields, span } variant.
  - parse_data_item uses a 3-token lookahead (`{` → Ident → `:`) to
    distinguish record-literal bodies from unparseable bodies.
    Fallback path (brace-skip) preserved for non-record bodies.
  - New parse_record_literal helper.
  - Walk helpers (is_recursive/descent_provable/collect_calls) gain
    Record arms.

Phase 2 — Substrate (ValueBody::Structural variant):
  - ValueBody grows Structural { fields: Vec<(String, LiteralBits)> }.
    Dissolution ledger updated with 4-pattern receipt; the new variant
    is terminal at PR-B scope (class-5 gap #3 tracks the upgrade to
    nested records / port-carried field values).
  - reject_user_unparsed_scaffolds narrowed to match only Unparsed;
    Structural passes through unchecked as the structurally-grounded
    form, not a scaffold.

Phase 3 — Lowering (data body inhabitance checking):
  - walk_to_conj_decl helper mirrors walk_to_disj_decl from R15;
    walks Instantiation/ResolvedIdentifier edges to a Conj.
  - lower_record_to_structural enforces: type walks to Conj, no extra
    fields, no missing fields, scalar-literal field values only, and
    each literal's type matches the declared field type. Fails
    fail-closed with diagnostics anchored to the offending span.
  - Type check uses declaration_by_name("Int"/"Bool"/"String")
    directly — the primitive cache isn't populated until the end of
    bootstrap, AFTER lower_bodies_phase runs for rust.dag.
  - lower_data_item populates meta_tag from the type annotation even
    on the Unparsed fallback path; structural bodies take precedence.
  - SurfaceExpr::Record in user-code expression position emits a
    fail-closed diagnostic naming class-5 gap #3 as the follow-up;
    M1(3) only supports record literals in data-body position.

Phase 4 — rust.dag + bootstrap fixture:
  - New dsl/extdeps/languages/rust.dag with the Realization meta-type
    (target_name/op_name/carrier/cost — all scalar fields matching
    ValueBody::Structural's literal-only constraint) and 18 data
    items: 3 primitive mappings, 10 operator realizations, 3
    structural templates (Bind/Branch/Main).
  - bootstrap.rs appends rust.dag after string_type.dag so String is
    resolved by the time Realization.target_name lowers.
  - rust_main_wrap's carrier uses `%Q` as a literal-double-quote
    placeholder — the v3 tokenizer has no escape sequences, so `\"`
    inside a string is impossible.

Phase 5 — lens_cost.rs (third observational lens):
  - Pure-reader CostLens following the lens_depth/lens_provenance
    template. Transform costs 1 + sum(inputs); Branch costs 1 + cond
    + max(paths) (runtime fires exactly one path); Loop costs 1 +
    source + init; Value / parameters are leaves; Bind passes through.
  - 6 acceptance tests: literals, single transform, chained transform,
    branch max-of-paths, branch asymmetric paths, Bind pass-through.

Tests — m1_substrate_test.rs:
  - m1_3_prb_data_item_record_body_lowers_structurally uses local
    names (LocalMeta/test_local_item) to avoid colliding with
    rust.dag's bootstrap names; find_named would otherwise return
    the bootstrap declaration first.
  - m1_3_prb_data_item_with_extra_field_is_rejected and
    m1_3_prb_data_item_with_wrong_field_type_is_rejected use
    LocalMeta/LocalMeta2 for the same reason.
  - m1_3_prb_rust_dag_bootstrap_loads_structurally asserts
    rust_int_add lowers with Structural value_body pointing at the
    Realization Conj via meta_tag, and that all four field slots
    carry the expected literal bits.
  - child_declarations_are_anonymous inverts its Realization
    assertion: pre-PR-B bootstrap loaded only dsl/std/*, so the
    realization meta-type was absent. M1(3) PR-B introduces rust.dag
    as the first extdeps fixture, so Realization IS present now —
    this is the thesis-aligned end-state.
  - m17_r9_data_item_has_unparsed_value_body_scaffold test adds a
    Structural panic arm for exhaustiveness.

90/90 tests green, clippy clean.

Phases 6 (emit_rust.rs) and 7 (docs close-out) land next.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 15, 2026
…rate shortcuts

Five-item pass from the latest ChatGPT review. The headline is #5 —
replacing `TypeShape::Primitive(Prim)` with a newtype around
`DeclarationId`. That was an M0-inheritance bug that propagated
through every subsequent substrate refactor unnoticed because Port
machinery was never in scope for the type substrate rework. After
this commit the declaration table is the SINGLE source of type
identity across the v3 compiler; no name-keyed bridge remains.

#1 — Delete `lower_fn_item_pending`; unoverload `ArrowBody::Pending`:
- Block-bodied `fn` items in std/ files no longer create Arrow
  declarations at all. They're skipped in `collect_symbols` (matched
  on `body: None`), so the declaration table never allocates a slot
  for them. `ArrowBody::Pending` reverts to its thesis meaning
  (primitive realization lag only) — no overloaded "user body not
  lowered yet" interpretation.
- Call sites that target block-bodied fns fail-closed at inference
  because no declaration exists with their name.

#2 — Remove `resolve_pending_identifiers` tolerance:
- Split the sweep into a tolerant bootstrap variant and a strict
  user-code variant. Bootstrap tolerates dangling stubs (the
  canonical `dsl/std/*.dag` files reference types like `Tuple` that
  live in std/ modules outside the M1(2.6) load set). User-code
  `lower()` captures a `user_start` snapshot and runs the strict
  variant over stubs allocated during user lowering — every
  Identifier stub at `id >= user_start` must resolve or it's a
  fail-closed `ResolveError`.
- `Atom(Identifier { resolved: None })` now means exactly one thing
  at the user-code boundary: "not yet resolved, pre-sweep".

#3 — Move `allocate_type_params` into `collect_symbols`:
- Pass 1 of lowering (`collect_symbols_phase`) now allocates top-level
  declarations AND their TypeParam children in one pass, populating
  `Declaration.type_params` before any body-lowering runs. Pass 2
  (`lower_bodies_phase`) reads `local_scope_from_parent` instead of
  re-allocating type params.
- Bootstrap is restructured into two phases: all files Phase-1 first
  (so every cross-file template has its type_params slot populated),
  then all files Phase-2 with a shared symbols map rebuilt from the
  post-Phase-1 declaration table. `build_template_arguments` no
  longer hits forward-reference gaps that would have required
  half-valid placeholder parameters for real declarations.
- `fixup_instantiation_template_params` is deleted. The half-valid
  state it repaired no longer exists for real declarations. Stub
  templates (bootstrap dangling refs) still use self-reference
  placeholders, but the stub itself is caught by the sweep and the
  Instantiation stays dead in bootstrap bodies — no repair pass.

#4 — Move `inject_realization_stub` into `#[cfg(test)]`:
- Production `bootstrap()` no longer injects realization declarations.
  The §6.5 smoke test moves into a `#[cfg(test)]` module inside
  `bootstrap.rs` where it builds its own synthetic realization chain
  (TestRealization meta-type, anonymous instance, anonymous
  realization Arrow) without polluting `Dag::new()`.
- `Dag::realization_smoke_arrow` / `set_realization_smoke_arrow`
  deleted — production Dag has no such slot.
- `assert_realization_shape` also moved to test-only.

#5 — Replace `TypeShape::Primitive(Prim)` with newtype over `DeclarationId`:
- `types.rs`: `TypeShape` is now `{ declaration: DeclarationId }`,
  `Copy + Eq + Hash`. `Prim` enum deleted.
- `infer.rs`: `primitive_shape(dag, name)` helper replaces all
  `TypeShape::Primitive(Prim::X)` constructions. Literal node
  dispatch looks up Int/Bool/String by name. `declaration_to_type_shape`
  + `type_shape_to_declaration` deleted — bridging is now a trivial
  `TypeShape::new(decl_id)`. `walk_to_type_shape` stops at the first
  named top-level declaration and returns it as the TypeShape; no
  name-keyed primitive matching.
- `lower.rs`: `lower_type_for_port(ty, dag)` looks up primitive
  names via `declaration_by_name`. `sentinel_type_shape` helper for
  the mark-unresolved fallback.
- `m0_acceptance.rs`: ~25 assertions updated via `primitive_shape(&dag, "X")`.

Test status: 1 unit test (bootstrap realization smoke) + 41 M0 + 3
M1 substrate + 4 real-stdlib parse smoke = **49/49 green**. Clippy
clean.

Name-bridge audit: `grep -rn` in `src/v3/compiler/src/` turns up:
- `OPERATOR_FIELD_MAP` (10 entries, documented dissolution trigger
  to M2 when surface grammar exposes algebra field access directly)
— one localized constant, not a pervasive pattern. No other
name-keyed bridges remain.

Review items now closed:
- FAIL-CLOSED: declaration-graph failures go through phantom ports
  (tolerant in bootstrap, strict in user code)
- ILLEGAL STATES: Pending unoverloaded, ExternalRealization typed
  edge checked at both construction and dispatch, TemplateArgument
  half-valid state eliminated for real templates
- FACTS FLOW FORWARD: declaration identity flows end-to-end from
  bootstrap source through inference to port types; no name-keyed
  collapse at the port boundary
- COPROD DISSOLUTION: ArrowBody back to terminal-2 + scaffold-1
  (Pending only for realization lag); AtomPayload Identifier phase
  coproduct tracked in ROADMAP as M2 substrate refactor
- SINGLE AUTHORITY: `inject_primitive_operators` and
  `inject_realization_stub` both out of production bootstrap; the
  declaration table is the only source of type identity
- API-LEVEL ENFORCEMENT: `lower()` runs the strict sweep before
  returning, so no caller discipline is required

Still deferred (tracked in ROADMAP):
- AtomPayload `Identifier { resolved: Option }` → split variants
  (M2 substrate refactor)
- Flat namespace via `declaration_by_name` (M2 module system)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Apr 15, 2026
Four structural dissolutions from the round 6 ledger audit, plus the
corresponding ledger rewrites. After this commit the only 🟡 or
🔴 items left are those that are structurally deferred to later
milestones (M2 module system, M3 Pending ratchet).

#1 — VariantPayload::Unit dissolved
- Unit variant collapsed into `Positional(vec![])`. Unit and
  zero-arity positional were structurally indistinguishable at
  the substrate level; the dedicated Unit arm was cosmetic.
- VariantPayload is now a 2-variant enum (Positional, Record),
  reclassified 🟢 terminal.
- `parse_variant` emits `Positional(Vec::new())` for bare
  variants; `lower_type_sum` drops the Unit match arm.

#2 — SurfaceItem::Module/Import/DataDecl dissolved
- Parser absorbs module / import / data declarations at parse
  time instead of emitting them as SurfaceItem variants. Their
  M1(2.6) semantic effect was "no-op at lowering," so carrying
  them through as SurfaceItem scaffolds was pure scaffolding
  debt.
- New parser helpers `absorb_module_item` / `absorb_import_item`
  / `absorb_data_item` consume the token stream without
  emitting a SurfaceItem.
- `parse_item` returns `Result<Option<SurfaceItem>, Diagnostic>`:
  None means "absorbed, no item to emit."
- SurfaceItem drops from 9 variants to 6 (Let, Fn, TypeAtom,
  TypeRecord, TypeSum, TypeAlias), reclassified 🟢 terminal
  modulo the M2 Type* collapse question.
- `lower_item` / `collect_symbols_phase` / `item_span` all drop
  the Module/Import/DataDecl arms.

#3 — SurfaceExpr literal trio dissolved
- The three surface-expression literal variants
  (IntLit/BoolLit/StringLit) collapse into a single
  `Literal { value: SurfaceLiteral, span }` variant. The new
  `SurfaceLiteral` enum is parse-local (Int/Bool/String),
  preserving the G3 guardrail that parse.rs doesn't mention Dag
  types — `SurfaceLiteral` mirrors `LiteralBits` but lives in
  the parse layer.
- SurfaceExpr drops from 6 variants to 4 (Literal, Var, Call,
  If), reclassified 🟢 terminal.
- `lower_expr` collapses its three literal arms into one match
  with an inner `match value { SurfaceLiteral::* }`.
- `is_recursive`, `descent_provable`, `collect_calls`,
  `expr_span`, `is_strictly_smaller` all updated.

#4 — AtomPayload::Identifier phase coproduct split
- `Atom(Identifier { name: String, resolved: Option<DeclarationId> })`
  replaced by two structural variants:
    - `Atom(UnresolvedIdentifier(String))` — pre-sweep, name
      reference pending resolution.
    - `Atom(ResolvedIdentifier(DeclarationId))` — post-sweep,
      typed edge to referent declaration.
- The pre/post-sweep phase is now a coproduct variant, not a
  field value. Pattern matches for the two cases live on
  different arms instead of on `Some`/`None`.
- `resolve_pending_identifiers` rewrites the connective on
  resolution instead of mutating an `Option` in place. The
  sweep is a structural phase transition, not a field update.
- All pattern-match sites updated: `placeholder_connective`,
  `alloc_identifier_stub`, `build_template_arguments`'s stub
  check, `run_identifier_sweep`, `unresolved_operator_name`,
  `resolve_arrow_walk`, `walk_to_type_shape`,
  `target_display_name`, `assert_target_name` in tests.
- AtomPayload is now 4 variants (Literal, UnresolvedIdentifier,
  ResolvedIdentifier, TypeParam), reclassified 🟢 terminal. The
  former compression debt the ledger flagged (`Option<_>` hiding
  a phase coproduct) is eliminated.

Test status: 1 unit test (bootstrap realization smoke) + 41 M0 +
3 M1 substrate + 7 real-stdlib parse smoke = 52/52 green. Clippy
clean. Net -71 lines (parse.rs net -94, lower.rs net -58 via
simpler match arms, dag.rs +28 for the split AtomPayload).

Ledger audit after this commit:
- 🟢 terminal at M1(2.6): TypeConnective, AtomPayload,
  CardinalityBound, LiteralBits, ArrowBody (terminal-2 modulo
  the Pending scaffold), SurfaceItem, SurfaceType, SurfaceExpr,
  SurfaceLiteral, VariantPayload.
- 🟡 scaffold with thesis-defined dissolution trigger:
  ArrowBody::Pending (§8.11 ratchet to zero by M3).
- 🔴 deferred to M2+: flat namespace via declaration_by_name
  (needs module-scoped declaration table). Tracked in ROADMAP.

No remaining compression debt in the parse or declaration layers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant