Commit a56786d
Tranche A remediation + GNPL design documents (#6)
## What this is
`gnpl` was reserved as Lithoglyph's **narration/projection** language,
then filled by a
squash-import of the GQLdt *query* language from the
`nextgen-databases/lithoglyph/`
monorepo. The import was not a mistake — it faithfully executed a
migration plan that
defined GNPL narrowly, as a rename of "Glyph query language".
That reading is superseded. **Narration/projection is the primary
purpose**; practical
value to Lithoglyph-as-a-database is second. This PR encodes that, and
fixes the
remediation backlog that had accumulated behind a CI job which had never
actually run.
**Structure: two layers, one repo.** Nothing is extracted, nothing
discarded.
```
GNPL ──lowers to──▶ GQLdt ──FFI──▶ Lithoglyph
(what account) (what is) (the data store)
```
No `src/Gnpl/` code in this pass, by design — the skeleton is a
follow-up.
---
## Measured findings
Everything below was run, not inferred.
### `lake build` succeeds
Status was previously **unknown**, because CI died before reaching it.
Run locally with the
full-mathlib cost budgeted:
- exit 0, 34/35 targets, `Build completed successfully`
- **zero `sorry` warnings from Lean's own checker**, zero errors
This unblocks the deferred skeleton.
### CI was building the wrong Zig tree
`bridge/` builds clean on Zig 0.16 and emits
`zig-out/lib/liblith_bridge.a` — exactly the
artifact `lakefile.lean` links (`-Lbridge/zig-out/lib -llith_bridge`).
`bridge/zig/` **fails to compile its own build script**: it uses
`addStaticLibrary` and
`linkLibC`, removed from the Zig Build API after 0.14. CI had been
pointed at it. There are
three distinct skeletons in this repo — `bridge/`, `bridge/zig/`,
`ffi/zig/` — and only the
first is real.
### The build gate was never real
`actions/cache@0c45773b…` is deprecated and **hard-fails**, aborting the
job *before*
`lake build`. So a red ❌ on `Build and Test Lean 4` has never meant "the
Lean code is
broken" — it meant the cache action refused to start.
### The naming gate could only ever pass
```bash
grep -i "gql-dt" STATE.scm ECOSYSTEM.scm 2>/dev/null && echo "Found old naming (gql-dt instead of gql-dt)"
```
It compares a string to itself, over two files that do not exist, with
`2>/dev/null`
swallowing the miss. Deleted rather than repaired.
### The link checker was suppressing its own findings
`.github/markdown-link-check-config.json` carried an ignorePattern for
`^https://github.com/hyperpolymath/lith` — which silently exempted
**every** dead
`lith*` link in the repo. Verified via `gh`: `gql-dt`, `lith`,
`lithoglyph`,
`lithoglyph-studio`, `lithoglyph-debugger` **do not exist**. Narrowed to
`^http://localhost`.
### Licence clobber, with chronology
`git log -- LICENSE` shows only two commits ever touched it:
| Commit | Effect |
|---|---|
| `a144d9f` (2026-06-24) | "normalise to MPL-2.0 (code) + CC-BY-SA-4.0
(docs)" — verbatim MPL-2.0 |
| `102c79e` (the import) | **overwrote** it with PALIMPSEST-MPL 1.0,
carried in from the monorepo |
The result was an `SPDX-License-Identifier: MPL-2.0` header sitting
above a PMPL body — the
same header/body inversion previously found in `idaptik-ums`. All 50
code files already
declared MPL-2.0; only the docs and the vscode manifest dissented.
**And the clobber had a regeneration mechanism.**
`.machine_readable/6a2/AGENTIC.a2ml:22` instructed agents: *"Never use
AGPL license (use
PMPL-1.0-or-later)"*. Fixing `LICENSE` alone would have been undone by
the next agent pass.
That directive is now corrected.
PMPL is a real licence (`hyperpolymath/palimpsest-license`) — it is
simply not this repo's.
`LICENSE` restored verbatim from `a144d9f`.
---
## Changes
### Proof gate — `scripts/check-lean-proofs.sh` (new)
The old gate was `! grep -r "sorry\|admit" src/`. It fires on five
legitimate constructs in
this repo, none of which are incomplete proofs:
| Location | What it actually is |
|---|---|
| `TypeInference.lean:162` | `\| admit : ProofStrategy` — a
**constructor** |
| `TypeInference.lean:171` | `.admit` — a reference to it |
| `TypeInference.lean:179` | the string literal `"sorry"` |
| `TypeSafeQueries.lean:90` | a **commented-out** `:= by sorry` |
| `Lexer.lean:230` | `("sorry", .kwSorry)` — a keyword table entry |
Two modes:
- **`--build-log FILE` (authoritative)** — reads Lean's own diagnostics
(`uses '?sorry'?`, `sorryAx`, `declaration uses`). **Exits 1 if the log
is missing**; a
gate must never report success from a file that does not exist.
- **default (textual pre-check)** — strips `/- -/` blocks, `"strings"`
and `--` comments
before matching, and exempts constructor declarations.
**Canary-tested five ways, all correct:** current `src/` passes → seeded
`theorem canary_one : True := by sorry` fails → seeded `example : 1 = 1
:= by admit` fails
→ real build log passes → seeded warning log fails → missing log fails.
A gate that has
never gone red is not evidence of anything.
### CI — `.github/workflows/lean-build.yml`
- `actions/cache` → live v4 SHA (`5a3ec84e…`)
- `goto-bus-stop/setup-zig@2a9625d…` → `mlugg/setup-zig@d1434d08…`; the
old SHA does not
exist and that action has **no v2 tag at all**
- `zig-ffi` repointed at `bridge/`, asserts
`zig-out/lib/liblith_bridge.a` exists, runs
`zig build test` (dropped a nonexistent `test-integration` step)
- build step now `set -o pipefail; lake build 2>&1 | tee
lake-build.log`, feeds the log to
the proof gate, and uploads it as an artifact
- spec filenames corrected to the real `spec/GQL-DT-Lexical.md` /
`GQL-DT-Railroad-Diagrams.md`
(a naming mismatch, not a missing spec) and now collect all misses
rather than exiting on
the first
- tautological naming gate deleted
### Identity
- **`README.adoc`** was the unmodified RSR template — *"This is your
repo - don't forget to
rename me!"*. Rewritten to lead with the two-layer story, so a visitor
immediately
understands why a repo named `gnpl` contains code namespaced `GqlDt`.
- **`MOVED.md`** removed. It claimed this content moved *to*
`hyperpolymath/lith` — a repo
that does not exist, and the reverse of what happened.
- `gqldt.ipkg`, `0-AI-MANIFEST.a2ml`, `META.a2ml` repointed at
`github.com/hyperpolymath/gnpl`.
### Toolchains — `mise.toml` (new)
Declares what this repo actually uses: `zig = "0.16.0"`, `idris2`, per
the estate ABI
(Idris2) / FFI (Zig) standard. Lean is **deliberately not pinned here**
— `lean-toolchain`
(`leanprover/lean4:v4.15.0`) is the single source of truth and elan
reads it; a second pin
would be a second thing to drift.
---
## Design documents
### `docs/THEORY.adoc` — the untethered case
What a narration/projection language is and what gap it fills. It
credits each neighbour
and says precisely where it stops:
| Neighbour | Where it stops |
|---|---|
| Bitemporal DBs (SQL:2011, Datomic, XTDB) | one consistent world *per
coordinate*; two irreconcilable witnesses remain a data-quality defect |
| Provenance semirings (Green/Tannen; Buneman) | annotates *a result* —
"where did this tuple come from", not an account *of the matter* |
| Argumentation (Dung, ASPIC+, Dempster–Shafer) | reasoning formalisms,
not database languages; no narrative arrangement |
| AGM belief revision | belief *sets*, not accounts; silent on where
entrenchment comes from |
| Event / situation calculus | reasons about what follows from events
*taken as known*; no contested evidence, no perspective |
| Computational narratology | commitment is aesthetic, not evidential —
it may invent |
| Narratology (Genette) | descriptive literary theory; nothing
mechanised |
The claim is scoped, and **six novelty claims are explicitly
disclaimed**. The document
says outright: *GNPL is a synthesis, not a discovery.* Its value stands
or falls on whether
the synthesis is usable.
Governing invariant, mirroring GQLdt's existing rule at the data layer:
> **No narration without warrant.** The type system forbids constructing
an `Account`
> containing an assertion not derivable from its `Fabula` under the
stated `Focalization`.
Ends with seven open questions, so the deferred work starts from an
agenda rather than a
blank page.
### `docs/LITHOGLYPH.adoc` — the tethered case
Grounded in three facts verifiable in code, not asserted:
1. `Form.Blocks` maintains an append-only journal, with journal entries
written **before**
block mutations (`lithoglyph/ARCHITECTURE.adoc`).
2. `Provenance/Rationale.lean` — *"you cannot construct a `Tracked`
value without providing
a non-empty rationale"*, enforced at the type level.
3. `bridge/lith_types.zig` already marshals `ActorIdC`, `RationaleC`,
`ProvenanceC`,
`TrackedValueC` across the C ABI.
**Three of six GNPL constructs already exist** — including the two
hardest to retrofit.
The argument from sunk cost: mandatory rationale is currently a *tax*
consumed by nothing,
and features like that get quietly filled with boilerplate. GNPL is the
consumer that makes
it pay.
It also flags a live hazard: `PromptScoresC.computeOverall` and
`Confidence.avg` are
**unweighted means**. Neither is probabilistically principled, and both
would be
load-bearing if used as an AGM entrenchment ordering. Must be resolved
before any
retraction result reaches a user.
---
## Out of scope — flagged, not fixed
- **Stale Zig skeletons.** `bridge/zig/` and `ffi/zig/` are
near-duplicates on the removed
pre-0.15 Build API; nothing links against either. Deleting them is a
separate call.
- **`RSR_OUTLINE.adoc`** still says "AGPL + Palimpsest dual license"
(lines 72, 160). That is
RSR *template* scaffolding describing the template standard, not this
repo's declaration.
- **Sibling extractions.** This clobber rode in on a routine
squash-import. Worth checking
whether `glyphbase` and the pending `lithoglyphdb` carry the same
PMPL-over-MPL overwrite.
- **Estate-shared CI.** `Governance` (scorecard-SARIF policy;
trusted-base "no
`docs/proof-debt.md` but 19 escape hatches") and `Hypatia` (`ImageOS`
`ubuntu24`
unmappable) are `hyperpolymath/standards` reusable-workflow issues.
Fixing them from
inside `gnpl` would be papering over an upstream fault.
## Companion PR
A second PR against `hyperpolymath/nextgen-databases` corrects
`lithoglyph/MOVED.md`, which
claims `core-factor/gql/` was migrated here. It was not — that is 5
Factor files, and this
repo contains zero `.factor` files. The Factor half is being treated as
legacy and
superseded by a typed narration layer lowering to GQLdt, rather than
migrated.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
# Update — corrections after verifying against the estate checkers
Two claims in the body above were wrong, and correcting them turned up
the most
significant finding in this PR. Recorded here rather than silently
edited.
## Correction 1: the Governance failures were **not** estate-shared
I listed Governance under "out of scope — upstream". I then cloned
`hyperpolymath/standards` and ran its checkers locally against this
repo. **Both Governance
failures are repo-local and fixable here.** Only Hypatia is genuinely
upstream.
Filed upstream, with evidence:
- **hyperpolymath/standards#516** — Hypatia: the pinned
`erlef/setup-beam` SHA cannot map
`ImageOS=ubuntu24`, so the scanner never runs *for any caller*.
SHA-pinning holding
callers at a pre-fix revision.
- **hyperpolymath/standards#517** — `check-trusted-base.sh`: Lean
`\bsorry\b` matches
string literals and keyword tables (low severity; no false *passes*).
## Correction 2: "no incomplete proofs" was true but **materially
incomplete**
The body above says Lean reports zero `sorry`. That is accurate and I
verified it in CI.
It is **not** the same as "the proofs are done", and I should not have
let it stand alone.
**Lean's `sorry` warning does not fire on `axiom`.** Running the estate
trusted-base
checker found **19 escape hatches — 16 real `axiom` declarations** (plus
the 3 detector
false positives in #517).
**None of the 16 is a necessary axiom.** Every one is a stub. Two
consequences:
**Five sit in executable position.** `parseToIR`, `deserializeIR`,
`many`, `many1`, `sepBy`
are declared `axiom`, so they have **no implementation at all**. Code
calling them
typechecks and cannot run. *"34/35 targets build" is a statement about
typechecking, not
about a working parser.*
**One is a vacuous soundness theorem.** `TypeSafe.lean:194`:
```lean
-- Proof that execution preserves type safety
-- Stubbed due to satisfiesConstraints signature issue
axiom executePreservesTypes {schema : Schema} (stmt : InsertStmt schema) :
∀ i, i < stmt.values.length →
let ⟨_t, _v⟩ := stmt.values.get! i
True -- Placeholder
```
It reduces to `… → True`. It reads as a type-safety soundness theorem
and discharges
nothing. Marked **D1, close first** — the only item that *actively
misinforms*.
And the sharpest one: the `TypeSafeQueries.lean` worked examples — the
ones commented
`✓ Type-safe INSERT with valid score`, demonstrating that an
out-of-range score gives
`-- Type error: failed to prove 150 ≤ 100` — **are themselves axioms**.
They assert the
existence of the well-typed value rather than constructing it,
demonstrating the opposite
of what the comments claim.
None of this is a regression introduced here. It is the inherited state
of the imported
GQLdt sources, recorded honestly for the first time.
### `docs/proof-debt.md` (new)
All 19 enumerated with `file:line` under the policy schema — §(a)
discharged, §(b) budgeted,
§(c) necessary, §(d) debt, and an §(e) section for the detector false
positives so the count
reconciles (19 = 16 + 3). Grouped into four work items with plans: D1
the vacuous theorem,
D2 the unimplemented combinators, D3 the asserted examples (lowest
effort, highest
credibility gain — do first after D1), D4 the one item with a reasoned
justification.
**§(b) is deliberately empty and must stay empty until a test driver
exists.** Without a
refutation budget, "covered by tests" is unfalsifiable — the policy's
own point.
Checker now passes honestly: `All 19 escape hatch(es) are documented.`
### Scorecard SARIF — a real local violation
`Check Workflow Staleness` asserted: *"OSSF Scorecard must not upload
SARIF to GitHub Code
Scanning unless it runs for every PR head commit."* True here:
`scorecard.yml` triggers on
push-to-main/schedule/dispatch — **never `pull_request`** — yet ran
`github/codeql-action/upload-sarif`. Code Scanning would show findings
corresponding to no
PR head commit.
Scan retained, upload switched to a build artifact, `security-events:
write` dropped.
Verified locally: *"All workflow staleness checks passed."*
## Also fixed: a third gate that could not fail
The first CI run went green — and the log showed why that was not
entirely earned:
```
Run Lean tests error: gqldt: no test driver configured
conclusion: success
```
The step was `lake test || echo "No tests configured yet"`. `lake test`
exits non-zero both
when tests **fail** and when no driver is configured; `|| echo`
swallowed both, so a real
test failure could never have turned the job red. Same shape as the
naming gate deleted
earlier in this PR.
Now a genuine failure exits 1, and only `no test driver configured` is
tolerated — surfaced
as a `::warning::` recording that **this repository has no executable
test coverage**,
rather than passing silently. Verified in CI: the `elif` branch is taken
and the annotation
is emitted.
## README
The status table said the core *"builds"*; it now says *"typechecks"*,
with added rows for
the 16 outstanding axioms and the absence of tests, and the proof-gate
section carries:
> A green proof gate here means "nothing is admitted mid-proof". It does
**not** mean
> "nothing is assumed."
`README.md` still opened with the pre-re-scope, query-first title,
contradicting
`README.adoc`. Confirmed via `gh api repos/hyperpolymath/gnpl/readme`
that GitHub renders
**`README.adoc`**, and `casket-pages.yml` prefers it too — so the
landing page was already
correct. `README.md` is reframed as the GQLdt-layer document with a
banner pointing at
`README.adoc`.
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>1 parent 2cb0d36 commit a56786d
34 files changed
Lines changed: 1435 additions & 354 deletions
File tree
- .github
- workflows
- .machine_readable/6a2
- docs
- scripts
- spec
- vscode-extension
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | 3 | | |
7 | 4 | | |
8 | 5 | | |
| |||
11 | 8 | | |
12 | 9 | | |
13 | 10 | | |
14 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
15 | 15 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
34 | 37 | | |
35 | | - | |
| 38 | + | |
36 | 39 | | |
37 | 40 | | |
38 | 41 | | |
| |||
41 | 44 | | |
42 | 45 | | |
43 | 46 | | |
| 47 | + | |
| 48 | + | |
44 | 49 | | |
45 | | - | |
46 | | - | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
47 | 59 | | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | 60 | | |
52 | | - | |
53 | | - | |
54 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
55 | 68 | | |
56 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
57 | 85 | | |
58 | 86 | | |
59 | 87 | | |
| |||
63 | 91 | | |
64 | 92 | | |
65 | 93 | | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
66 | 97 | | |
67 | | - | |
| 98 | + | |
68 | 99 | | |
69 | | - | |
| 100 | + | |
70 | 101 | | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
71 | 107 | | |
72 | | - | |
| 108 | + | |
73 | 109 | | |
74 | 110 | | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
75 | 118 | | |
76 | | - | |
| 119 | + | |
77 | 120 | | |
78 | 121 | | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | 122 | | |
84 | 123 | | |
85 | 124 | | |
| |||
91 | 130 | | |
92 | 131 | | |
93 | 132 | | |
94 | | - | |
95 | 133 | | |
96 | 134 | | |
97 | 135 | | |
98 | 136 | | |
99 | 137 | | |
100 | 138 | | |
| 139 | + | |
| 140 | + | |
101 | 141 | | |
102 | 142 | | |
| 143 | + | |
103 | 144 | | |
104 | 145 | | |
105 | 146 | | |
106 | | - | |
107 | | - | |
| 147 | + | |
| 148 | + | |
108 | 149 | | |
109 | 150 | | |
110 | | - | |
| 151 | + | |
111 | 152 | | |
112 | 153 | | |
| 154 | + | |
113 | 155 | | |
114 | 156 | | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
124 | 163 | | |
125 | 164 | | |
126 | 165 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
12 | 21 | | |
13 | 22 | | |
14 | 23 | | |
15 | 24 | | |
16 | | - | |
17 | 25 | | |
18 | 26 | | |
19 | 27 | | |
| |||
26 | 34 | | |
27 | 35 | | |
28 | 36 | | |
29 | | - | |
30 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
31 | 40 | | |
32 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
13 | | - | |
| 12 | + | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
374 | 374 | | |
375 | 375 | | |
376 | 376 | | |
377 | | - | |
| 377 | + | |
378 | 378 | | |
379 | 379 | | |
380 | 380 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
169 | 169 | | |
170 | 170 | | |
171 | 171 | | |
172 | | - | |
| 172 | + | |
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
| |||
557 | 557 | | |
558 | 558 | | |
559 | 559 | | |
560 | | - | |
| 560 | + | |
0 commit comments