You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(tg-11): surface syntax for epistemic types + fix a second statement-order bug (#99)
TG-11 (#98) landed the type former, typing, evaluation and six proofs —
but there was **no way to write one**. Zero occurrences of the
constructors in `lexer.mll` or `parser.mly`, against 4 for echo. Fully
implemented and unreachable.
## Surface syntax
```tangle
def w = warrant[0](42, braid[s1, s2]) -- at standpoint 0
def token = evidence(w) -- the ONLY elimination
```
The standpoint is bracketed because it's an *index*, not an operand —
the same reading as a braid generator's subscript. No grammar conflicts.
**Non-factivity reaches the syntax.** There is deliberately no keyword
extracting the claim: `claim(w)` parses as an ordinary call to an
undefined function, never as a language form. A test pins that
distinction — if a `Claim` form ever appears, it contradicts
`epi_only_yields_evidence`.
## A *second* copy of the statement-order bug
Writing the first epistemic program surfaced it immediately:
```
def w = warrant[0](42, braid[s1])
def tok = evidence(w)
→ In definition 'tok': evidence requires an Epi[k, rho, tau], got Word[0]
```
That `Word[0]` is the pass-1a **placeholder** — `tok` was being checked
*before* `w` was refined. Same root cause as #95 (`stmts := prog @
!stmts` then `List.rev` on the flattened list), but in a **second
copy**, in `lib/check.ml`.
**That copy feeds `tanglec --check` and the LSP.** Both have been
analysing programs with their statements reversed.
And it was never epistemic-specific:
```
def e = echoClose(braid[s1])
def r = residue(e)
→ residue requires Echo[_, _], got Word[0]
```
**Any cross-definition reference to a non-`Word` type was mis-typed.**
Echo has been broken this way for as long as the recovering path has
existed.
The test suites missed *both* copies for the same reason: they call
`Parser.program` directly and never exercise the recovering path.
## Tests
**Parser** — warrant with bracketed standpoint; evidence; TG-4
round-trip; the no-claim-form guard.
**Check** — three cross-definition cases (plain, echo, epistemic), all
of which would have failed before this.
## Example
`examples/epistemic.tangle`, wired into the corpus gate's must-run set —
warrants at three standpoints, evidence recovery, and the echo
composition `residue(evidence(we))`. All assertions pass.
It also documents *why* the claim is unreachable: if it were
extractable, anything anyone attested would become true by fiat —
precisely the bug you don't want in a provenance system.
All gates green: Lean 0 errors, full suite, corpus, RSR.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
0 commit comments