Skip to content

W7.1 investigation — E0425 root cause is dropped let statements in t27c Rust emitter (findings-only)#44

Draft
gHashTag wants to merge 2 commits into
mainfrom
w7/compiler/e0425-fix
Draft

W7.1 investigation — E0425 root cause is dropped let statements in t27c Rust emitter (findings-only)#44
gHashTag wants to merge 2 commits into
mainfrom
w7/compiler/e0425-fix

Conversation

@gHashTag

@gHashTag gHashTag commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Draft — investigation report only. No code change on this branch. Regen + re-sweep happen in a follow-up commit after the upstream t27c fix lands.

Upstream tracking

Upstream issue filed: gHashTag/t27#1401 — codegen: Rust emitter drops all let statements.

Root cause

t27c's Rust text-emitter drops every let statement from generated function bodies. Every body-reference to a let-bound name becomes an undeclared identifier (E0425).

2609 of 2813 E0425 sites = 93% of all Rust errors, 49 of 68 modules — one upstream defect, one fix.

Reproducer (one function)

Spec specs/access_control.t27:74-77:

fn check_access(policy: u32, role: u32) -> u32 {
    let min_role = get_min_role(policy);
    if (!role_meets_minimum(role, min_role)) { return DENY; }

Gen gen/rust/access_control.rs:66-69:

pub fn check_access(policy: u32, role: u32) -> u32 {
    if !(role_meets_minimum(role, min_role)) { return DENY; }

The let line is absent. Next line uses min_role → E0425.

Systemic scope (post-review addition)

  • specs/*.t27: 12+ modules with 40-66 lets each (topology_visualizer 66, integration_framework 62, ...)
  • gen/rust/*.rs: all 68 files have exactly 0 lets
  • grep -rcw 'let' gen/rust/*.rs | grep -v ':0$' returns empty across the tree

Not cherry-picked; universal.

Full document

docs/W7_1_INVESTIGATION.md @ commit 3f1d98a — full findings including systemic-scope section, suspected upstream location, regression success criterion, cross-repo dependency notes.

Next gate

Upstream fix in t27c lands (external timeline, tracked via t27#1401) → tri-net regen + re-sweep → this PR promoted from draft with the actual codegen delta.

Meanwhile W7.3 (w7/testing/fuzz-baseline — grammar fuzzer v2) can start in parallel on current broken-tree per Option B testing-layer.

phi^2 + phi^-2 = 3

Merge timing (2026-07-05)

Draft holds until upstream fix lands OR one of the terminal events on t27#1401:

  • won't fix / wontfix label or closing comment from maintainer
  • Closing PR (merged or closed) linked to t27#1401
  • Explicit reject in issue comments

Silent-neglect backstop: 2026-07-19 12:24 UTC (14 days from t27#1401 publication at 2026-07-05 12:24 UTC). If no assignee / no label / no maintainer reply by that timestamp, PR #44 converts to findings-only merge without waiting for codegen delta.

Whichever comes first: terminal event OR backstop timer.

phi^2 + phi^-2 = 3

Perplexity Computer added 2 commits July 5, 2026 12:16
…nts in t27c Rust emitter

Findings-only doc, no code change on this branch yet. Establishes root
cause for the 2609-site E0425 defect documented in the W6.2 audit:
t27c Rust text-emitter drops every `let` statement from function bodies.

Reproducer (one function): specs/access_control.t27:74-77 has
'let min_role = get_min_role(policy);' followed by a use of `min_role`;
gen/rust/access_control.rs:66-69 has the `let` gone and the use
becomes E0425.

Scope check across 10 spec/gen pairs on feat/strategic-audit-2026-07-04:
every module whose spec has 'let' emits zero 'let' in Rust (7/10 modules;
the other 3 have no 'let' in the spec so are unaffected by this defect).

Suspected upstream location: Rust emitter's Stmt::Let handling is
missing or falls through the default arm. Mirrors ExprCast omission
from t27#1320.

Expected impact after upstream fix: Rust OK count moves from 19/68
substantially higher. Regression check must include an error-code
histogram delta, not just a fail-count pass, because previously-masked
E0308/other classes will surface once E0425 stops blocking.

Next step: open upstream issue in gHashTag/t27 (external-repo write —
draft body prepared here, awaiting explicit go-ahead).

phi^2 + phi^-2 = 3
Two precision-add's after PR #44 review by peer-agent:

1. Add 'Systemic scope — full corpus' section: 10-module table was a
   spot-check that understated breadth. Independent grep across full
   68-module corpus shows at least 12 modules carry 40-66 let's each
   (topology_visualizer 66, integration_framework 62, traffic_animator
   57, auto_config 54, api_documenter 50, cache_management 49), and
   all 68 gen/rust files emit exactly zero let's. Defect is universal,
   not cherry-picked.

2. Line 109 (was 100): 'E0308 (cross-width comparison), E0308 (mismatched
   types)' listed E0308 twice with two descriptions. Cross-width IS
   mismatched-types. Consolidated to 'E0308 (mismatched types, including
   cross-width comparison)'.

Prepares doc for external-facing use as upstream issue text.

phi^2 + phi^-2 = 3
gHashTag added a commit that referenced this pull request Jul 5, 2026
* feat(W7.3-E1): grammar-directed T27 fuzz generator (YARPGen-style)

Заменяет W6.1 lexical fuzzer (tautological на shared front-end) на
grammar-directed generator, эмитящий синтаксически валидные T27 модули.

Coverage (initial subset):
  Module   ::= UseDecl* ConstDecl* FnDecl+
  FnDecl   ::= fn ident (params?) -> Type { LetStmt* Return }
  Expr     ::= Literal | Ident | BinOp | Cast | Cmp
  Types    ::= u8 | u16 | u32 | u64 | usize | bool

- Depth-bounded (max 6), seed-reproducible через ChaCha20Rng.
- Standalone Cargo workspace в tests/fuzz/grammar_v2/ — не тянет
  зависимости в trios-mesh crate.
- Smoke: 5 модулей на seed 0xC0FFEE — грамматически валидны,
  binops с correct type-matching, shifts clamped к <8u32.

Caveat: E1 только генерирует. Round-trip harness (E2) и backend
differential (E3, blocked на upstream Stmt::Let fix из t27#1401) —
следующие коммиты в этой же ветке.

Success criterion (post-E2): 100% parse, >=95% roundtrip-eq, 0 panics.

См. docs/W7_3_FUZZ_BASELINE_PLAN.md.

Refs: t27#1401 (E3 dependency), PR #44 (W7.1 root cause)

phi^2 + phi^-2 = 3

* feat(W7.3-E2): parse-invariance harness + N=1000 baseline (100/100/0)

Baseline result: 1000/1000 parse_ok, 1000/1000 whitespace-invariant,
0 panics, 9.9 sec. Все три success criteria \u0438\u0437 plan'a \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b.

## \u0427\u0442\u043e \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u043c\u043c\u0438\u0442\u0435

- tests/fuzz/grammar_v2/roundtrip.py: E2 harness. \u0422\u0440\u0438 invariant\u0430:
    1. parse-success (t27c parse exit 0),
    2. determinism (\u0434\u0432\u0430\u0436\u0434\u044b parse \u2192 identical AST),
    3. whitespace-invariance (extra_spaces/newlines/trailing_ws mutations
       \u2192 identical normalized AST).
  Normalization strips 'line: N,' fields (source-position metadata),
  collapses whitespace.

- tests/fuzz/grammar_v2/src/gen.rs: max_stmts_per_fn 8 \u2192 20.
  \u0421\u0432\u043e\u0434\u0438\u0442 doc-code drift (plan \u0433\u043e\u0432\u043e\u0440\u0438\u043b 20, code \u0431\u044b\u043b 8),
  \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0439 GLM peer-review @ 6c0c93d.

- docs/W7_3_FUZZ_BASELINE.md: \u043e\u0442\u0447\u0451\u0442 N=1000 run \u0441 \u043c\u0435\u0442\u0440\u0438\u043a\u0430\u043c\u0438,
  \u0447\u0435\u0441\u0442\u043d\u044b\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438-wrinkle (\u043f\u0435\u0440\u0432\u044b\u0439 smoke \u0434\u0430\u043b 75%
  invariance-fail \u0438\u0437-\u0437\u0430 line-tracking; fix \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d) \u0438
  full reproducibility recipe.

- docs/W7_3_FUZZ_BASELINE_PLAN.md: E2 status \u2192 LANDED, pretty-printer
  \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442 \u043e\u0431\u044a\u044f\u0441\u043d\u0451\u043d (t27c \u043d\u0435 \u044d\u043a\u0441\u043f\u043e\u0437\u0438\u0442 public pretty-
  printer), + Tracked TODOs before E3 (params, Call, Index, If,
  dead-let reduction) \u0441 backstop 2026-07-19.

## \u041e\u0442\u0432\u0435\u0442 \u043d\u0430 GLM peer-review

- \u2713 max_stmts drift \u0441\u0432\u0435\u0434\u0451\u043d (8 \u2192 20 \u0432 code).
- \u2713 Coverage-gap zero-param \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d \u043a\u0430\u043a Tracked TODO \u0432 plan.
- \u2713 Dead-let \u043e\u0431\u0441\u0435\u0440\u0432\u0430\u0446\u0438\u044f \u2192 Tracked TODO.

## Discipline note

E1 review @ 6c0c93d + E2 review \u2014 minimum reviewable unit \u043f\u043e GLM
observation ('E1 without E2 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u0435\u043c'). \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u043c\u0435\u0441\u0442\u0435
\u0433\u043e\u0442\u043e\u0432\u044b \u043a peer-review \u043a\u0430\u043a coherent \u0435\u0434\u0438\u043d\u0438\u0446\u0430.

phi^2 + phi^-2 = 3

---------

Co-authored-by: Perplexity Computer <agent@perplexity.ai>
gHashTag added a commit that referenced this pull request Jul 5, 2026
…2; NAMED_CONST] (#47)

W7.3 grammar-expansion increment #1 — collection-typed params using [u32; NAMED_CONST] syntax matching the tri-net/specs audit corpus.

Path-confirmed via t27c gen-rust: 1000/1000 gen-rust succeeded, 1924 [u32; NAMED_CONST] in .t27 input → 1924 Vec<> in Rust output, exact one-to-one. W6.2 Class 2 defect surface (Vec<> param-position) exercised by construction.

Independently verified by GLM re-review at 9bbc103:
- Documented 1000-spec sweep: 1924 Vec<> in gen-rust output
- Independent t27c run on specs/anomaly_detector.t27: rc=0, 7 Vec<> confirmed

Discipline chain observations (this PR):
- Anchor #4 recorded: any claim verified against ground truth requires scoping the verification tool to the same corpus as the claim.
- SHA-advance rule (PR #45): applied at 247427d9bbc103 with delta bullet-list in PR body.
- No-paste-review rule (PR #43): GLM approved against committed body text with SHA citation.

Commits (post-squash provenance):
- 2080510  fix(W7.3): word-boundary anchor normalize_ast regex
- 247427d  feat(W7.3): grammar-expansion target #1 — collection-typed params (Zig-style, OBSOLETED)
- 9bbc103  fix(W7.3): rewrite collection-params to [u32; NAMED_CONST] per audit-corpus ground truth

Base: main @ 3272583 (PR #46, E1+E2 frozen baseline). E3 still timer-blocked (backstop 2026-07-19 12:24 UTC per PR #44).

phi^2 + phi^-2 = 3
gHashTag pushed a commit that referenced this pull request Jul 9, 2026
Iteration 5 of the 2026-07-10 wave. CI-integrity, mechanical, no design.

1. lefthook pre-push `cargo-build` was a no-op gate: `cargo build | tail -3`
   makes `$?` the exit code of `tail` (always 0), so a failed build passed
   the pre-push check. This is precisely how the broken 2026-07-07 build was
   pushed to main. Fixed to check cargo's exit directly (`if ! cargo build`).

2. Added a `cargo-audit` job (rustsec/audit-check@v2) so dependency
   advisories gate CI. Separate job — surfaces advisories without blocking
   build/test.

Accuracy note (anti-anchor): ci.yml already ran fmt + clippy -D warnings +
build + test, so the recon's "CI has no gates" was imprecise; the real hole
was the always-passing lefthook gate + no audit + no branch protection on
main (a GitHub setting, not a repo file — flagged for the owner).

Not touched: spec-drift-guard.yml still diffs deleted gen/zig + gen/c; that
guard is entangled with the t27c emitter fix (Lane A / PR #44) and should be
reduced to the rust backend only once t27c regenerates cleanly.

Refs #58, #59.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

phi^2 + phi^-2 = 3
gHashTag pushed a commit that referenced this pull request Jul 23, 2026
…fore building it

The three NAT bricks (STUN #42, punch #43, ICE session #44) all assume the peers
already hold each other's candidate lists. Whatever rendezvous carries that list
must NOT be trusted to read or forge it: an injected candidate redirects the call
to a machine the attacker controls (classic ICE candidate-injection / call hijack;
WebRTC blocks it with signed SDP + a DTLS fingerprint). This is a prerequisite for
a rendezvous, not an afterthought — shipping candidate exchange unsealed is a
call-hijack hole.

CandidateOffer.swift (pure; reuses MeshCrypto.inviteAuthKey + Ice serialization):
seal [version][tiebreaker:8][expiry:8][Ice candidate list] under a room-derived
key, with an expiry so a captured offer cannot be replayed later, and an ICE
controlling/controlled tiebreaker. The offer key is domain-separated from the
invite key by one HKDF step so a candidate offer and an invite can never be
cross-interpreted.

Verified in smoke/harness/candidate_offer.swift (11th verify.sh test, 13 checks,
verify: 11 passed, 0 failed): honest round-trip recovers the list + tiebreaker;
wrong room passphrase -> nil (confidential); flipped auth-tag byte -> nil
(unforgeable); the offer does NOT open under the raw invite key (domain
separation); past-TTL -> nil (stale, un-replayable); role resolves oppositely for
the two peers. Clock is injected so expiry is deterministic; only static room-key
derivation is used, so no MeshCrypto() is built and the Keychain is untouched.

Four harness-proven NAT/exchange modules now exist (StunClient, HolePunch,
IceSession, CandidateOffer); none are in project.yml / wired into CallManager yet —
that integration, fed by a rendezvous carrying these sealed offers, is next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gHashTag pushed a commit that referenced this pull request Jul 23, 2026
…r -> sealed offer)

Four waves built harness-proven but UNWIRED NAT modules (StunClient #42, HolePunch
#43, IceSession #44, CandidateOffer #45). Proven-in-a-harness is not
proven-in-the-product, and four modules outside the binary is a growing debt. This
wave puts them in the shipping Mac app and proves they run there, WITHOUT touching
the working same-subnet call.

  * project.yml: register the four modules + a new NatDiagnostics; xcodegen
    regenerated the tracked pbxproj (clean +20 lines, only the 5 files, no churn).
  * NatDiagnostics.run(): off-main at launch (.onAppear), gathers host + STUN
    server-reflexive candidates and seals a CandidateOffer under the current room,
    then logs it. Additive only — nothing in the call/media path changes.

Verified LIVE in the built binary (not a harness): launched with TRINET_LOG and
read back
  TRINET NAT: candidates host=["192.168.1.104"] srflx=182.232.218.171:59434
              -> sealed offer 83B (room=lobby)
so StunClient.hostCandidates + gatherServerReflexive (real public address via
Google STUN) + CandidateOffer.make all execute inside the app; the app did not
crash, so the working call is intact.

Deferred deliberately: the iOS embed (static file list is fragile) and the real
integration — deliver the offer via a rendezvous and run Ice.connect before the
media socket. The app now HOLDS its sealed candidate offer; delivering it and
connecting on it is next.

Co-Authored-By: Claude Opus 4.8 <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