Skip to content

feat(tg-11): epistemic types — Epi[k, ρ, τ], non-factive by construction - #98

Merged
hyperpolymath merged 1 commit into
mainfrom
feat/epistemic-types
Jul 29, 2026
Merged

feat(tg-11): epistemic types — Epi[k, ρ, τ], non-factive by construction#98
hyperpolymath merged 1 commit into
mainfrom
feat/epistemic-types

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Wires hyperpolymath/epistemic-types into the mechanised core, following the route TG-10 took for echo. Lean 0 errors, sorry/axiom gate clean.

The commitment: a warrant is not knowledge

Epi[κ, ρ, τ] — at standpoint κ, evidence of type ρ purporting to support a claim of type τ. The claim type appears in the type and no elimination rule delivers it. evidence is the sole projection, and it yields ρ.

That mirrors upstream precisely:

  • Warrant.agda gives the record only an Evidence field — deliberately not Evidence → A, because that "would make every warrant factive" — and puts extraction in a separate SoundWarrant.
  • Base.agda splits FactiveModality (with reflect : E κ A → A) from BeliefModality (without), rather than treating belief as knowledge with a missing proof.

The absence here is that same design choice, mechanised.

Six capstones

Theorem What it establishes
epi_evidence_recovers evidence ∘ warrant returns the token
epi_claim_is_opaque two warrants, same evidence, different claims, observationally identical
epi_only_yields_evidence from Epi[κ,ρ,τ] the only elimination is at ρ
epi_distinguishes_standpoints κ₁ ≠ κ₂ gives genuinely different types
epi_roundtrip_typed type safety of intro + projection
epi_over_echo_typed Epi[κ, Echo[ρ,τ], σ] — the modalities nest

epi_claim_is_opaque is the exact dual of echo_distinguishes_collapsed: echo reveals what close forgot; a warrant withholds what it purports. Holding evidence is not holding the fact.

epi_over_echo_typed mirrors EpistemicEcho in EchoBridge.agda, which is explicit that these are different modalities — echo grades irrecoverability, epi indexes standpoints — and that they compose without collapsing.

Metatheory extended, not weakened

Progress, Preservation, Determinism, TypeSafety, infer_sound, infer_complete all cover the new fragment, plus a new canonical_epi lemma.

Worth noting where non-factivity actually lands: in preservation, the evidenceVal case inverts tEvidence then tEpiVal and returns the token's typing (he), never the claim's (hc). Non-factivity is discharged by the type system rather than asserted in a comment.

Both engines

OCaml mirrors it — TEpi former, Warrant/EpiVal/Evidence, VEpi runtime value, typing and evaluation. TG-3 extended with 4 pins (including that evidence yields the evidence type, never the claim); differential regenerated and kernel-checked: 496 obligations, 0 errors. TG-3 self-check 1008 → 1012.

⚠ Registered honestly — A-TG-11.1

What the simply-typed shadow does not model:

  • standpoints are Nat, not an arbitrary index set K;
  • upstream's LawfulModality functor laws, FactiveModality.reflect and ReturnModality.return are omitted (all opt-in there);
  • the real gap — the claim is carried in the value rather than erased, because erasing it would break uniqueness of typing in a system without quantities.

A QTT treatment (quantity 0 on the claim) would be the faithful version — which is the same conclusion the linear/affine discussion reached independently.

Tests

6 typecheck cases, including two negatives: that evidence never returns the claim type when the two differ, and that evidence of a non-warrant is rejected. Typecheck suite 129 → 135; all suites green; corpus and RSR gates pass.

🤖 Generated with Claude Code

…ruction

Wires hyperpolymath/epistemic-types into the mechanised core, following the
route TG-10 took for echo. Lean 0 errors, sorry/axiom gate clean.

## The commitment: a warrant is not knowledge

`Epi[k, rho, tau]` = at standpoint k, evidence of type rho purporting to
support a claim of type tau. The claim type appears in the type and NO
elimination rule delivers it. `evidence` is the sole projection and yields
rho.

That mirrors upstream exactly. `Warrant.agda` gives the record only an
`Evidence` field — deliberately not `Evidence -> A`, because that "would make
every warrant factive" — and puts extraction in a separate `SoundWarrant`.
`Base.agda` likewise splits `FactiveModality` (with `reflect`) from
`BeliefModality` (without), rather than treating belief as knowledge with a
missing proof. The absence here is that same choice, mechanised.

## Six capstones

  epi_evidence_recovers        evidence . warrant returns the token
  epi_claim_is_opaque          two warrants, same evidence, DIFFERENT claims
                               are observationally identical — the dual of
                               echo_distinguishes_collapsed: echo REVEALS what
                               close forgot, a warrant WITHHOLDS what it
                               purports
  epi_only_yields_evidence     from Epi[k,rho,tau] the only elimination is rho
  epi_distinguishes_standpoints  k1 /= k2 gives different types
  epi_roundtrip_typed          type safety of intro + projection
  epi_over_echo_typed          Epi[k, Echo[rho,tau], sigma] — the two modalities
                               NEST; mirrors EpistemicEcho in EchoBridge.agda,
                               which is explicit that echo grades
                               irrecoverability while epi indexes standpoints

## Metatheory extended, not weakened

Progress, Preservation, Determinism, TypeSafety, infer_sound and
infer_complete all cover the new fragment. New `canonical_epi` lemma. In
preservation, the `evidenceVal` case inverts tEvidence then tEpiVal and
returns the TOKEN's typing, never the claim's — non-factivity discharged by
the type system rather than asserted.

## Both engines

OCaml mirrors it: `TEpi` former, `Warrant`/`EpiVal`/`Evidence` constructors,
`VEpi` runtime value, typing and evaluation. TG-3 extended with 4 pins
(including that `evidence` yields the evidence type, never the claim);
differential regenerated and kernel-checked — 496 obligations, 0 errors.
TG-3 self-check 1008 -> 1012.

## Registered honestly

TG-11 in PROOF-NEEDS.md; assumption A-TG-11.1 records what the simply-typed
shadow does NOT model: standpoints are Nat rather than an arbitrary index set,
the upstream functor laws / reflect / return are omitted (all opt-in there),
and — the real gap — the claim is CARRIED rather than erased, because erasing
it would break uniqueness of typing in a system without quantities. A QTT
treatment (quantity 0 on the claim) would be the faithful version.

Tests: 6 typecheck cases including two negatives — that evidence never returns
the claim type, and that `evidence` of a non-warrant is rejected. Typecheck
suite 129 -> 135; all suites green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

Note

Automatic reviews are paused because your trial's included automatic processing has been used for this period. Upgrade now, or comment "Gitar review" to run a review anytime.
Learn more

Code Review ✅ Approved

Integrates non-factive epistemic types into the mechanised core and OCaml engine, complete with six capstones and extended metatheory. No issues found.

Auto-approved and auto-merge armed: No blocking issues found.
Please see Auto-approve Docs for details on setting custom approval criteria. — merges when pipeline and required approvals pass.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@gitar-bot

gitar-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

⚠️ Gitar auto-approved this PR but could not enable auto-merge: auto-merge is disabled for this repository — enable "Allow auto-merge" in the repository settings.

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR and enabled auto-merge (configure)

@gitar-bot gitar-bot Bot added the gitar-approved Added by Gitar label Jul 29, 2026
@hyperpolymath
hyperpolymath merged commit cf56397 into main Jul 29, 2026
22 checks passed
@hyperpolymath
hyperpolymath deleted the feat/epistemic-types branch July 29, 2026 05:49
hyperpolymath added a commit that referenced this pull request Jul 29, 2026
…ent-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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gitar-approved Added by Gitar

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant