pi-fovea 0.29.2 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LAWS.bend +110 -0
- package/PROOF.bend +118 -0
- package/README.md +20 -4
- package/THIRD_PARTY_NOTICES.md +12 -0
- package/dist/cli.mjs +835 -697
- package/docs/cli.md +53 -0
- package/docs/licenses/bend-apache-2.0.txt +202 -0
- package/docs/proofs.md +256 -0
- package/docs/releasing.md +58 -0
- package/package.json +22 -6
- package/proofs/basis.bend +29 -0
- package/proofs/counts-proof.bend +71 -0
- package/proofs/counts.bend +24 -0
- package/proofs/disclosure.bend +31 -0
- package/proofs/heat.bend +54 -0
- package/proofs/kernel-abi.json +6 -0
- package/proofs/kernel-types.d.ts +3 -0
- package/proofs/kernel.bend +25 -0
- package/proofs/nat-proof.bend +65 -0
- package/scripts/check-proofs.mjs +123 -0
- package/scripts/compile-bend.mjs +61 -0
- package/src/core/disclosure.ts +20 -0
- package/src/core/heat.ts +20 -10
- package/src/core/render.ts +16 -12
- package/src/verified/generated/kernel.d.ts +9 -0
- package/src/verified/generated/kernel.js +81 -0
- package/src/verified/generated/manifest.json +29 -0
- package/src/verified/policy.ts +37 -0
package/LAWS.bend
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import Base
|
|
2
|
+
import ./proofs/disclosure.bend as D
|
|
3
|
+
import ./proofs/heat.bend as H
|
|
4
|
+
import ./proofs/kernel.bend as K
|
|
5
|
+
import ./proofs/basis.bend as B
|
|
6
|
+
|
|
7
|
+
# Proposed specifications extracted from render.ts and heat.ts. Review these independently
|
|
8
|
+
# of PROOF.bend; do not weaken a law to make an implementation pass.
|
|
9
|
+
|
|
10
|
+
# Disclosure: these six laws cover the entire five-Boolean input domain.
|
|
11
|
+
law scope_wins:
|
|
12
|
+
for excluded: Bool
|
|
13
|
+
for seen: Bool
|
|
14
|
+
for repeat: Bool
|
|
15
|
+
for nucleus: Bool
|
|
16
|
+
{K.disclosure(False{}, excluded, seen, repeat, nucleus) == D.Drop{} : D.Decision}
|
|
17
|
+
|
|
18
|
+
law exclusion_wins:
|
|
19
|
+
for scope: Bool
|
|
20
|
+
for seen: Bool
|
|
21
|
+
for repeat: Bool
|
|
22
|
+
for nucleus: Bool
|
|
23
|
+
{K.disclosure(scope, True{}, seen, repeat, nucleus) == D.Drop{} : D.Decision}
|
|
24
|
+
|
|
25
|
+
law fresh_revealed:
|
|
26
|
+
for repeat: Bool
|
|
27
|
+
for nucleus: Bool
|
|
28
|
+
{K.disclosure(True{}, False{}, False{}, repeat, nucleus) == D.Reveal{} : D.Decision}
|
|
29
|
+
|
|
30
|
+
law seen_suppressed:
|
|
31
|
+
for nucleus: Bool
|
|
32
|
+
{K.disclosure(True{}, False{}, True{}, False{}, nucleus) == D.Suppress{} : D.Decision}
|
|
33
|
+
|
|
34
|
+
law periphery_suppressed:
|
|
35
|
+
for repeat: Bool
|
|
36
|
+
{K.disclosure(True{}, False{}, True{}, repeat, False{}) == D.Suppress{} : D.Decision}
|
|
37
|
+
|
|
38
|
+
law nucleus_repeated:
|
|
39
|
+
for seen: Bool
|
|
40
|
+
{K.disclosure(True{}, False{}, seen, True{}, True{}) == D.Reveal{} : D.Decision}
|
|
41
|
+
|
|
42
|
+
# Executed natural-number accounting. This does NOT prove token estimation,
|
|
43
|
+
# renderer formatting, or binary-search monotonicity. Keep boundary tests.
|
|
44
|
+
law shown_bounded_by_total:
|
|
45
|
+
for +total: Nat
|
|
46
|
+
for requested: Nat
|
|
47
|
+
{Nat.is_le(K.shownCount(total, requested), total) == True{} : Bool}
|
|
48
|
+
|
|
49
|
+
law shown_bounded_by_request:
|
|
50
|
+
for total: Nat
|
|
51
|
+
for +requested: Nat
|
|
52
|
+
{Nat.is_le(K.shownCount(total, requested), requested) == True{} : Bool}
|
|
53
|
+
|
|
54
|
+
law counts_conserved:
|
|
55
|
+
for +total: Nat
|
|
56
|
+
for +requested: Nat
|
|
57
|
+
{Nat.add(K.shownCount(total, requested), K.remainingCount(total, requested)) == total : Nat}
|
|
58
|
+
|
|
59
|
+
law full_prefix_omits_nothing:
|
|
60
|
+
for +total: Nat
|
|
61
|
+
{K.remainingCount(total, total) == 0n : Nat}
|
|
62
|
+
|
|
63
|
+
law cap_idempotent:
|
|
64
|
+
for +total: Nat
|
|
65
|
+
for +cap: Nat
|
|
66
|
+
{K.shownCount(K.shownCount(total, cap), cap) == K.shownCount(total, cap) : Nat}
|
|
67
|
+
|
|
68
|
+
# Exact nonnegative rational transport model, not IEEE-754 or the exponential.
|
|
69
|
+
law heat_vector_add_mass:
|
|
70
|
+
for +xs: +List<Nat>
|
|
71
|
+
for +ys: +List<Nat>
|
|
72
|
+
{H.sum(H.add(xs, ys)) == Nat.add(H.sum(xs), H.sum(ys)) : Nat}
|
|
73
|
+
|
|
74
|
+
law heat_scale_mass:
|
|
75
|
+
for +mass: Nat
|
|
76
|
+
for +weights: +List<Nat>
|
|
77
|
+
{H.sum(H.scale(mass, weights)) == Nat.mul(mass, H.sum(weights)) : Nat}
|
|
78
|
+
|
|
79
|
+
# D = 1 + denominator is strictly positive. For source numerators a over Q,
|
|
80
|
+
# transport returns numerators over D*Q; this equality conserves rational mass.
|
|
81
|
+
law heat_transport_mass:
|
|
82
|
+
for +columns: +List<H.Column>
|
|
83
|
+
for +denominator: Nat
|
|
84
|
+
for normalized: H.Normalized(columns, 1n+denominator)
|
|
85
|
+
{H.sum(H.transport(columns)) == Nat.mul(H.input_mass(columns), 1n+denominator) : Nat}
|
|
86
|
+
|
|
87
|
+
law heat_singleton_mass:
|
|
88
|
+
for +mass: Nat
|
|
89
|
+
{H.sum(H.transport([H.Source{mass, [1n]}])) == mass : Nat}
|
|
90
|
+
|
|
91
|
+
# Executed basis-extension commands. Float64 evaluation remains host code.
|
|
92
|
+
law basis_empty_refused:
|
|
93
|
+
for order: Nat
|
|
94
|
+
{K.basisStep(0n, order) == B.Empty{} : B.Step}
|
|
95
|
+
|
|
96
|
+
law basis_complete_retained:
|
|
97
|
+
for +have: Nat
|
|
98
|
+
for +order: Nat
|
|
99
|
+
for complete: {Nat.is_le(1n+have, order) == False{} : Bool}
|
|
100
|
+
{K.basisStep(1n+have, order) == B.Done{} : B.Step}
|
|
101
|
+
|
|
102
|
+
law basis_first_order:
|
|
103
|
+
for order: Nat
|
|
104
|
+
{K.basisStep(1n, 1n+order) == B.First{} : B.Step}
|
|
105
|
+
|
|
106
|
+
law basis_next_exact:
|
|
107
|
+
for +have: Nat
|
|
108
|
+
for +order: Nat
|
|
109
|
+
for missing: {Nat.is_le(2n+have, order) == True{} : Bool}
|
|
110
|
+
{K.basisStep(2n+have, order) == B.Next{2n+have, 1n+have, have} : B.Step}
|
package/PROOF.bend
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import Base
|
|
2
|
+
import ./LAWS.bend as Laws
|
|
3
|
+
import ./proofs/disclosure.bend as D
|
|
4
|
+
import ./proofs/counts.bend as C
|
|
5
|
+
import ./proofs/counts-proof.bend as CP
|
|
6
|
+
import ./proofs/heat.bend as H
|
|
7
|
+
import ./proofs/nat-proof.bend as N
|
|
8
|
+
import ./proofs/kernel.bend as K
|
|
9
|
+
import ./proofs/basis.bend as B
|
|
10
|
+
|
|
11
|
+
def Laws.scope_wins(excluded, seen, repeat, nucleus):
|
|
12
|
+
{==}
|
|
13
|
+
|
|
14
|
+
def Laws.exclusion_wins(scope, seen, repeat, nucleus):
|
|
15
|
+
match scope:
|
|
16
|
+
case False{}:
|
|
17
|
+
{==}
|
|
18
|
+
case True{}:
|
|
19
|
+
{==}
|
|
20
|
+
|
|
21
|
+
def Laws.fresh_revealed(repeat, nucleus):
|
|
22
|
+
{==}
|
|
23
|
+
|
|
24
|
+
def Laws.seen_suppressed(nucleus):
|
|
25
|
+
{==}
|
|
26
|
+
|
|
27
|
+
def Laws.periphery_suppressed(repeat):
|
|
28
|
+
match repeat:
|
|
29
|
+
case False{}:
|
|
30
|
+
{==}
|
|
31
|
+
case True{}:
|
|
32
|
+
{==}
|
|
33
|
+
|
|
34
|
+
def Laws.nucleus_repeated(seen):
|
|
35
|
+
match seen:
|
|
36
|
+
case False{}:
|
|
37
|
+
{==}
|
|
38
|
+
case True{}:
|
|
39
|
+
{==}
|
|
40
|
+
|
|
41
|
+
def Laws.shown_bounded_by_total(total, requested):
|
|
42
|
+
+requested = requested
|
|
43
|
+
%Equal.sym(Nat, C.fastShown(total, requested), C.shown(total, requested), CP.shown_equiv(total, requested)) : {Nat.is_le(_, total) == True{} : Bool}
|
|
44
|
+
CP.bounded_total(total, requested)
|
|
45
|
+
|
|
46
|
+
def Laws.shown_bounded_by_request(total, requested):
|
|
47
|
+
+total = total
|
|
48
|
+
%Equal.sym(Nat, C.fastShown(total, requested), C.shown(total, requested), CP.shown_equiv(total, requested)) : {Nat.is_le(_, requested) == True{} : Bool}
|
|
49
|
+
CP.bounded_request(total, requested)
|
|
50
|
+
|
|
51
|
+
def Laws.counts_conserved(total, requested):
|
|
52
|
+
%Equal.sym(Nat, C.fastShown(total, requested), C.shown(total, requested), CP.shown_equiv(total, requested)) : {Nat.add(_, C.fastRemaining(total, requested)) == total : Nat}
|
|
53
|
+
%Equal.sym(Nat, C.fastRemaining(total, requested), C.remaining(total, requested), CP.remaining_equiv(total, requested)) : {Nat.add(C.shown(total, requested), _) == total : Nat}
|
|
54
|
+
CP.conserved(total, requested)
|
|
55
|
+
|
|
56
|
+
def Laws.full_prefix_omits_nothing(total):
|
|
57
|
+
%Equal.sym(Nat, C.fastRemaining(total, total), C.remaining(total, total), CP.remaining_equiv(total, total)) : {_ == 0n : Nat}
|
|
58
|
+
CP.full(total)
|
|
59
|
+
|
|
60
|
+
def Laws.cap_idempotent(total, cap):
|
|
61
|
+
%Equal.sym(Nat, C.fastShown(C.fastShown(total, cap), cap), C.shown(C.fastShown(total, cap), cap), CP.shown_equiv(C.fastShown(total, cap), cap)) : {_ == C.fastShown(total, cap) : Nat}
|
|
62
|
+
%Equal.sym(Nat, C.fastShown(total, cap), C.shown(total, cap), CP.shown_equiv(total, cap)) : {C.shown(_, cap) == C.fastShown(total, cap) : Nat}
|
|
63
|
+
%Equal.sym(Nat, C.fastShown(total, cap), C.shown(total, cap), CP.shown_equiv(total, cap)) : {C.shown(C.shown(total, cap), cap) == _ : Nat}
|
|
64
|
+
CP.idempotent(total, cap)
|
|
65
|
+
|
|
66
|
+
def Laws.heat_vector_add_mass(xs, ys):
|
|
67
|
+
match xs ys:
|
|
68
|
+
case Nil{} _:
|
|
69
|
+
{==}
|
|
70
|
+
case x <> tail Nil{}:
|
|
71
|
+
Equal.sym(Nat, Nat.add(H.sum(x <> tail), 0n), H.sum(x <> tail), N.add_zero(H.sum(x <> tail)))
|
|
72
|
+
case x <> xt y <> yt:
|
|
73
|
+
%N.add_shuffle(x, y, H.sum(xt), H.sum(yt)) : {Nat.add(Nat.add(x, y), H.sum(H.add(xt, yt))) == _ : Nat}
|
|
74
|
+
%Laws.heat_vector_add_mass(xt, yt) : {Nat.add(Nat.add(x, y), H.sum(H.add(xt, yt))) == Nat.add(Nat.add(x, y), _) : Nat}
|
|
75
|
+
{==}
|
|
76
|
+
|
|
77
|
+
def Laws.heat_scale_mass(mass, weights):
|
|
78
|
+
match mass:
|
|
79
|
+
case 0n:
|
|
80
|
+
{==}
|
|
81
|
+
case 1n+p:
|
|
82
|
+
%Laws.heat_scale_mass(p, weights) : {H.sum(H.add(weights, H.scale(p, weights))) == Nat.add(H.sum(weights), _) : Nat}
|
|
83
|
+
Laws.heat_vector_add_mass(weights, H.scale(p, weights))
|
|
84
|
+
|
|
85
|
+
def Laws.heat_transport_mass(columns, denominator, normalized):
|
|
86
|
+
match columns:
|
|
87
|
+
case Nil{}:
|
|
88
|
+
{==}
|
|
89
|
+
case H.Source{mass, weights} <> tail:
|
|
90
|
+
(column_norm, tail_norm) = normalized
|
|
91
|
+
%N.mul_add(mass, H.input_mass(tail), 1n+denominator) : {H.sum(H.add(H.scale(mass, weights), H.transport(tail))) == _ : Nat}
|
|
92
|
+
%Equal.cong(Nat, Nat, x => Nat.mul(mass, x), H.sum(weights), 1n+denominator, column_norm) : {H.sum(H.add(H.scale(mass, weights), H.transport(tail))) == Nat.add(_, Nat.mul(H.input_mass(tail), 1n+denominator)) : Nat}
|
|
93
|
+
%Laws.heat_scale_mass(mass, weights) : {H.sum(H.add(H.scale(mass, weights), H.transport(tail))) == Nat.add(_, Nat.mul(H.input_mass(tail), 1n+denominator)) : Nat}
|
|
94
|
+
%Laws.heat_transport_mass(tail, denominator, tail_norm) : {H.sum(H.add(H.scale(mass, weights), H.transport(tail))) == Nat.add(H.sum(H.scale(mass, weights)), _) : Nat}
|
|
95
|
+
Laws.heat_vector_add_mass(H.scale(mass, weights), H.transport(tail))
|
|
96
|
+
|
|
97
|
+
def Laws.heat_singleton_mass(mass):
|
|
98
|
+
%N.mul_one(mass) : {H.sum(H.transport([H.Source{mass, [1n]}])) == _ : Nat}
|
|
99
|
+
%N.add_zero(mass) : {H.sum(H.transport([H.Source{mass, [1n]}])) == Nat.mul(_, 1n) : Nat}
|
|
100
|
+
Laws.heat_transport_mass([H.Source{mass, [1n]}], 0n, ({==}, Unit{}))
|
|
101
|
+
|
|
102
|
+
def Laws.basis_empty_refused(order):
|
|
103
|
+
{==}
|
|
104
|
+
|
|
105
|
+
def Laws.basis_complete_retained(have, order, complete):
|
|
106
|
+
%Equal.sym(Bool, Nat.is_le(1n+have, order), False{}, complete) : {B.choose(_, 1n+have) == B.Done{} : B.Step}
|
|
107
|
+
{==}
|
|
108
|
+
|
|
109
|
+
def Laws.basis_first_order(order):
|
|
110
|
+
match order:
|
|
111
|
+
case 0n:
|
|
112
|
+
{==}
|
|
113
|
+
case 1n+p:
|
|
114
|
+
{==}
|
|
115
|
+
|
|
116
|
+
def Laws.basis_next_exact(have, order, missing):
|
|
117
|
+
%Equal.sym(Bool, Nat.is_le(2n+have, order), True{}, missing) : {B.choose(_, 2n+have) == B.Next{2n+have, 1n+have, have} : B.Step}
|
|
118
|
+
{==}
|
package/README.md
CHANGED
|
@@ -132,7 +132,7 @@ pi install /absolute/path/to/pi-fovea
|
|
|
132
132
|
|
|
133
133
|
</details>
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
The standalone **`@monotykamary/fovea`** package provides the same engine for any agent shell or CI, without installing Pi:
|
|
136
136
|
|
|
137
137
|
```sh
|
|
138
138
|
fovea sketch /path/to/repo 900
|
|
@@ -142,13 +142,19 @@ fovea rules /path/to/repo
|
|
|
142
142
|
fovea status /path/to/repo
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
Install the CLI globally —
|
|
145
|
+
Install the CLI globally — its bundled JavaScript runs on plain Node.js (no Pi or tsx required):
|
|
146
146
|
|
|
147
147
|
```sh
|
|
148
|
-
npm i -g
|
|
148
|
+
npm i -g @monotykamary/fovea # or: bun add -g @monotykamary/fovea
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
The executable is still `fovea`. The legacy `npm i -g pi-fovea` remains supported;
|
|
152
|
+
choose one global package because both provide that executable. Installing the
|
|
153
|
+
Pi extension through `pi install npm:pi-fovea` can coexist with the standalone CLI.
|
|
154
|
+
|
|
151
155
|
From a checkout, `bun run fovea` runs the live source via `tsx`, and `bun run build:cli` rebuilds `dist/cli.mjs` (the `prepack` hook keeps the published bundle in sync).
|
|
156
|
+
`bun run pack:cli` produces the scoped CLI tarball at `dist/fovea-cli.tgz` using the
|
|
157
|
+
root package version. See [CLI usage](docs/cli.md) and [release checks and publishing](docs/releasing.md).
|
|
152
158
|
|
|
153
159
|
## Many projects, one conversation
|
|
154
160
|
|
|
@@ -544,12 +550,22 @@ calls and proof checking are not modeled; Bend 1/HVM syntax is not supported.
|
|
|
544
550
|
|
|
545
551
|
```sh
|
|
546
552
|
bun install
|
|
547
|
-
bun run check:fast #
|
|
553
|
+
bun run check:fast # Bend laws + artifact parity + typecheck + affected tests
|
|
548
554
|
bun run test:smoke # curated scan-to-render floor, seconds
|
|
549
555
|
bun run bench # rate–distortion and refresh bench against ../pi-fabric
|
|
550
556
|
bun run bench tests/fixtures/mini # self-contained smoke run
|
|
551
557
|
```
|
|
552
558
|
|
|
559
|
+
Development checks require **Bend 2.0.26** (`bend guide`). See [laws, proofs, and
|
|
560
|
+
which tests they can replace](docs/proofs.md). Bend is development-only; the
|
|
561
|
+
extension and published CLI need no Bend installation or generation step.
|
|
562
|
+
Production executes the committed Bend-compiled disclosure, prefix-accounting,
|
|
563
|
+
and heat-basis command kernels. After changing their sources or adapters, run
|
|
564
|
+
`bun run proofs:generate`; `bun run proofs:artifact` checks the receipt without
|
|
565
|
+
Bend. CLI builds check that receipt; publishing also proves and reproduces the
|
|
566
|
+
artifact. The Float64 heat solver still relies on numerical tests, not a proof
|
|
567
|
+
of its approximation or rounding errors.
|
|
568
|
+
|
|
553
569
|
The [warm-path performance report](docs/performance.md) compares the coverage-complete implementation with the optimized version. `bun run corpus:performance <coverage-work> <before-source> <after-source> [rounds]` runs alternating, isolated comparisons with a shared extraction snapshot, independent Git indexes, and exact graph, focus/dwell/sketch, and overflow-content checks. It does not trade fewer candidates or weaker freshness checks for speed. For Node, run `NODE_OPTIONS='--import tsx' node scripts/performance-corpus.mjs ...`; development dependencies are required.
|
|
554
570
|
|
|
555
571
|
Warm matching derives query terms once and caches normalized symbol names by weak node identity, checking renames before reuse. Focus builds only the heat orders currently needed; dwell appends missing orders without replacing its existing basis. No new kernel or review state is introduced. Independent cold extraction can select different literal-join locations when capture order varies, so this paired benchmark deliberately makes no cold-extraction speedup claim.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
## Bend 2.0.26
|
|
4
|
+
|
|
5
|
+
The generated policy kernel contains Bend's emitted JavaScript trampoline and
|
|
6
|
+
compiled Base primitives from [Bend 2.0.26](https://github.com/bendlang/bend/tree/v2.0.26),
|
|
7
|
+
Copyright 2026 HigherOrderCO, licensed under Apache-2.0. Pi Fovea removes the
|
|
8
|
+
CLI invocations, adds library exports, and tree-shakes/minifies unused runtime
|
|
9
|
+
code using the bridge pattern developed in Pi Fabric.
|
|
10
|
+
|
|
11
|
+
The complete license is distributed at
|
|
12
|
+
[docs/licenses/bend-apache-2.0.txt](docs/licenses/bend-apache-2.0.txt).
|