Tricu 2.0.0

Sorry for squashing all of this but 🤷
This commit is contained in:
2026-05-25 12:43:15 -05:00
parent 2e2db07bd6
commit fdebb6c13d
105 changed files with 10139 additions and 1938 deletions

337
docs/view-contracts.md Normal file
View File

@@ -0,0 +1,337 @@
# View Contracts and View Trees
## 1. Purpose
View Contracts are the portable checking layer for Tree Calculus programs.
The checker does not consume detached metadata about a separate executable. Its
canonical input is a typed, checkable tree artifact: ordinary tree data that
contains both the executable program payloads and the view/contract structure
needed to validate and transform them.
The checker consumes this artifact and returns either:
```text
checked-execution artifact
```
or:
```text
structured diagnostic
```
A checked-execution artifact is interpreted by `runChecked`. Unguarded programs
are represented as `checkedPure rootPayload`; guarded programs contain explicit
checked guard/bind nodes.
This keeps checking independent of any particular host implementation. A typed
artifact may be produced by any frontend, compiler, hand-written generator, or
future self-hosted `tricu` toolchain.
## 2. Design Principle
The model follows the same discipline as interaction trees.
Interaction trees use tagged structural envelopes with explicit executable
payloads:
```tri
io action = pair "tricuIO" (pair version action)
pure x = pair 0 x
bind action k = pair 1 (pair action k)
```
The interpreter understands the outer structure, but it does not recursively
mistake every subtree for interpreter metadata. A continuation `k` is an opaque
executable tree until the interpreter reaches the `bind` step that applies it.
View trees use the same rule:
```text
structure says how to check;
opaque executable fields are only executed/applied by the checker at the
appropriate step.
```
This is the key distinction that allows Views to carry guards without confusing
ordinary program trees with View metadata.
## 3. Views
A View is an extrinsic contract over an ordinary Tree Calculus value. Tree
Calculus values do not carry native runtime types; a View describes how a value
may be treated by the checker or by a checked boundary.
Core View forms:
```text
Any
Ref ref
Fn [argView...] resultView
List elemView
Maybe elemView
Pair leftView rightView
Result errView okView
Guarded baseView guard
```
`Ref` supports both generated/numeric and symbolic references. Symbolic refs are
preferred for user-authored views:
```tri
UserId = viewRef "UserId"
```
A guarded view refines a base view with an executable guard:
```tri
UserId = viewGuarded (viewRef "UserId") userIdGuard
```
The guard is ordinary program code. The View validator checks that the guarded
view envelope is well-formed, and recursively validates the `baseView`, but it
must treat the guard payload/reference as opaque executable data, not as another
View.
## 4. Guards
Guards are ordinary `tricu` values/functions grouped with the Views they refine.
Example:
```tri
userIdGuard = value :
-- ordinary program that validates value
UserId = viewGuarded (viewRef "UserId") userIdGuard
loadUser id@UserId = ...
```
Guards return the standard checked-runtime protocol:
```tri
guardOk value
guardFail
```
Guards do not author diagnostics. The checked-exec runner owns guard failure and
malformed-guard diagnostics using boundary context from the checked artifact.
Guards are injected by the checker. They are not discovered by the runtime as a
separate metadata layer. The checking process transforms a view tree into an
executable tree with the necessary guard applications inserted.
## 5. View Tree Artifact
The primary checker-facing artifact is a view executable term graph.
Conceptually:
```text
ViewTree
version
root node id
nodes
```
Each node is tagged tree data. Nodes combine executable payloads, view claims,
and structural relationships in one graph.
Representative node forms:
```text
Value node view executableTree
Apply node calleeNode argNode expectedOrInferredView
Require node requiredView sourceNode
External node name view
```
This is not a mandatory final encoding; it is the semantic target. The important
property is that executable trees and checking structure are carried together in
a single portable artifact.
A node may contain opaque executable fields. Those fields are tree terms, but
they are not recursively decoded as view-tree nodes or Views unless the node's
semantics explicitly says so.
## 6. Checker Semantics
The checker is an interpreter over the view tree.
For each node it may:
1. validate the node envelope;
2. validate Views referenced by the node;
3. check compatibility between expected and actual Views;
4. recursively check child nodes;
5. inject guards required by guarded Views;
6. produce the executable tree for that node;
7. memoize node results by node id.
The root node result is a checked-execution program.
In abstract form:
```text
checkViewTree : ViewTree -> Result CheckedExec Diagnostic
```
or, in self-hosted terms:
```tri
checkViewTree viewTree = ... -- ok checkedExec / err diagnostic
```
## 7. Compatibility and Guard Injection
Structural compatibility is about Views. Guard injection is about producing the
checked-execution tree.
For example, if a node is required to satisfy:
```tri
viewGuarded (viewRef "UserId") userIdGuard
```
then the checker verifies the underlying View relationship and emits executable
code that applies `userIdGuard` at the appropriate checked boundary.
The checker, not the runtime metadata system, owns this transformation.
## 8. Source Annotations
Source annotations are one frontend syntax for producing view-tree nodes.
Examples:
```tri
Nat = viewRef "Nat"
Box a = viewPair (viewRef "Box") a
idNat x@Nat =@Nat x
idBox x@(Box String) =@(Box String) x
```
Annotations are value-level View expressions. Names such as `Nat` and `Box` are
ordinary program values/functions that evaluate to Views.
A frontend that supports this syntax should lower the source into a view tree
that contains the relevant executable terms, views, and checking structure. The
artifact must not depend on source names or on the frontend implementation that
produced it.
## 9. Contract Expressions
Contract-expression helpers remain useful as authoring/building tools, but they
are not the fundamental artifact model.
Preferred style for expression-oriented authoring is pipeline-first:
```tri
mapBoolStringUse = cFn <|
[(viewFn [(viewBool)] viewString) (viewList viewBool)] (viewList viewString)
|> cApply (cFn [(viewBool)] viewString)
|> cApply (cValue (viewList viewBool))
|> cRequire (viewList viewString)
```
These helpers should be understood as convenient ways to build typed/checkable
structure, not as a permanent replacement for view-tree artifacts.
## 10. Artifact Direction
The target direction is to make the view tree the canonical checked-program
artifact.
Older split concepts remain useful internally or during development:
```text
tree term
view value
typed-program node
module/export manifest
```
But the durable design should avoid treating contracts as detached facts about a
separate program. The portable checker input is the checkable program itself.
In short:
```text
Do not store code over here and contracts over there.
Store a view tree: executable code plus the structure needed to check and guard it.
```
## 11. IO Interaction Trees
`tricu` IO is represented as ordinary interaction-tree data:
```tri
io action = pair "tricuIO" (pair version action)
pure value = pair 0 value
bind action k = pair 1 (pair action k)
```
View Contracts do not change that representation. A checked program may produce
an ordinary IO interaction tree, and the existing IO driver can execute it
unchanged.
For source evaluation with contracts enabled, `tricu eval --io` performs an
additional frontend instrumentation pass over visible IO continuations. When a
continuation returns a `pure (...)` value that mentions source-annotated
functions, the frontend lowers that pure expression into the existing portable
checked-exec protocol before returning the next IO action.
This means source sugar works for practical checked IO paths such as:
```tri
acceptNames xs@(NonEmptyList String) =@String "accepted"
main = io (bind (pure []) (xs : pure (acceptNames xs)))
```
and for explicit higher-order boundaries:
```tri
useHandler handler@(Fn [(NonEmptyList String)] String) xs@(List String) =@String
handler xs
main = io (bind (pure []) (xs : pure (useHandler acceptNames xs)))
```
The IO runtime does not perform View inference or guard injection at every step.
The source/frontend pass constructs checked-exec boundaries once; the runtime
only evaluates the resulting interaction tree.
Current limitations:
- This is source-visible instrumentation, not whole-program function-flow
tracking.
- Higher-order guarantees require explicit annotated boundaries.
- Raw prebuilt interaction trees, imported executable artifacts, and content-store
terms are not automatically re-instrumented unless they pass through this
source-lowering path.
- The IO action shape itself is only shallowly checkable unless users provide
guarded Views for the relevant boundaries.
- Continuation result Views are not inferred from external effects; dynamic IO
values should cross annotated/guarded boundaries when runtime enforcement is
required.
Making IO checking more complete is future work. In particular, a future design
may validate every continuation-produced action structurally, carry checked
wrappers with higher-order function values, or define a portable checked-IO
artifact instead of relying on Haskell/frontend source instrumentation.
## 12. Host Independence
No part of the core View Tree design is specific to Haskell or to the current implementation.
Any producer may emit a view-tree artifact if it follows the portable tree-data
encoding. Any checker implementation may consume it if it implements the typed
node semantics.
The current implementation can produce and consume these artifacts, but it is
not the semantic authority. The artifact format and the self-hosted checker
semantics are the authority.