diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock
index ca2db9b..091aacc 100644
--- a/.github/workflows/actions.lock
+++ b/.github/workflows/actions.lock
@@ -22,10 +22,9 @@ workflows:
'.github/workflows/label-triage.yml': []
'.github/workflows/labels.yml': []
'.github/workflows/lean-build.yml':
- - 'actions/cache@v4.2.3'
- 'actions/checkout@v4.1.1'
- - 'actions/upload-artifact@v4.3.0'
- - 'gaurav-nelson/github-action-markdown-link-check@1.0.15'
+ - 'actions/upload-artifact@v4.6.2'
+ - 'leanprover/lean-action@v1.6.0'
- 'mlugg/setup-zig@v2.2.1'
'.github/workflows/push-email-notify.yml':
- 'hyperpolymath/smtp-notify-action@v0.2.0'
@@ -35,16 +34,16 @@ workflows:
- 'ossf/scorecard-action@v2.4.3'
'.github/workflows/secret-scanner.yml': []
dependencies:
- 'actions/cache@v4.2.3':
- ref: 'v4.2.3'
- commit: 'sha1-5a3ec84eff668545956fd18022155c47e93e2684'
- owner_id: 44036562
- repo_id: 215566462
'actions/cache@v4.3.0':
ref: 'v4.3.0'
commit: 'sha1-0057852bfaa89a56745cba8c7296529d2fc39830'
owner_id: 44036562
repo_id: 215566462
+ 'actions/cache@v5':
+ ref: 'v5'
+ commit: 'sha1-caa296126883cff596d87d8935842f9db880ef25'
+ owner_id: 44036562
+ repo_id: 215566462
'actions/checkout@v4.1.1':
ref: 'v4.1.1'
commit: 'sha1-b4ffde65f46336ab88eb53be808477a3936bae11'
@@ -97,11 +96,6 @@ dependencies:
commit: 'sha1-2f0cc07b4b9bea248ae098aba9e1a8a1de5ec24c'
owner_id: 47606891
repo_id: 331103973
- 'gaurav-nelson/github-action-markdown-link-check@1.0.15':
- ref: '1.0.15'
- commit: 'sha1-d53a906aa6b22b8979d33bc86170567e619495ec'
- owner_id: 23069445
- repo_id: 178552370
'github/codeql-action@v4.31.10':
ref: 'v4.31.10'
commit: 'sha1-cdefb33c0f6224e58673d9004f47f7cb3e328b89'
@@ -117,6 +111,13 @@ dependencies:
commit: 'sha1-ede1191ef6ff3ac02c4f4d9efdf837ee517e11d7'
owner_id: 6759885
repo_id: 1352485172
+ 'leanprover/lean-action@v1.6.0':
+ ref: 'v1.6.0'
+ commit: 'sha1-50fcf42d2e460296f1a34b402e990d1b24f8b596'
+ owner_id: 7233018
+ repo_id: 795738301
+ uses:
+ - 'actions/cache@v5'
'mlugg/setup-zig@v2.2.1':
ref: 'v2.2.1'
commit: 'sha1-d1434d08867e3ee9daa34448df10607b98908d29'
diff --git a/.github/workflows/casket-pages.yml b/.github/workflows/casket-pages.yml
index 0a52af3..664dd57 100644
--- a/.github/workflows/casket-pages.yml
+++ b/.github/workflows/casket-pages.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
@@ -52,31 +53,22 @@ jobs:
- name: Build site
run: |
mkdir -p site _site
- # Generate index.md from README if site/index.md doesn't exist
+ # Generate the landing page from the available project introduction.
if [ ! -f site/index.md ]; then
- if [ -f README.adoc ]; then
- # Convert AsciiDoc to Markdown (basic conversion)
- echo "---" > site/index.md
- echo "title: $(basename $PWD)" >> site/index.md
- echo "date: $(date +%Y-%m-%d)" >> site/index.md
- echo "---" >> site/index.md
- cat README.adoc >> site/index.md
- elif [ -f README.md ]; then
- echo "---" > site/index.md
- echo "title: $(basename $PWD)" >> site/index.md
- echo "date: $(date +%Y-%m-%d)" >> site/index.md
- echo "---" >> site/index.md
- cat README.md >> site/index.md
- else
- echo "---" > site/index.md
- echo "title: $(basename $PWD)" >> site/index.md
- echo "date: $(date +%Y-%m-%d)" >> site/index.md
- echo "---" >> site/index.md
- echo "" >> site/index.md
- echo "# $(basename $PWD)" >> site/index.md
- echo "" >> site/index.md
- echo "Documentation coming soon." >> site/index.md
- fi
+ {
+ echo "---"
+ echo "title: $(basename "$PWD")"
+ echo "date: $(date +%Y-%m-%d)"
+ echo "---"
+ if [ -f README.adoc ]; then
+ cat README.adoc
+ elif [ -f README.md ]; then
+ cat README.md
+ else
+ echo "# $(basename "$PWD")"
+ echo "Documentation coming soon."
+ fi
+ } > site/index.md
fi
cd .casket-ssg && cabal run casket-ssg -- build ../site ../_site
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index bde8b32..95285ca 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
@@ -23,7 +24,7 @@ jobs:
fail-fast: false
matrix:
include:
- - language: javascript-typescript
+ - language: actions
build-mode: none
steps:
diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml
index 087ba04..faff36b 100644
--- a/.github/workflows/governance.yml
+++ b/.github/workflows/governance.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
@@ -35,4 +36,4 @@ permissions:
jobs:
governance:
- uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@main
+ uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@fcb566cfb8a86cea2d3666bf65a4f177a49b1313
diff --git a/.github/workflows/hypatia-scan.yml b/.github/workflows/hypatia-scan.yml
index 43f66b4..4c551f5 100644
--- a/.github/workflows/hypatia-scan.yml
+++ b/.github/workflows/hypatia-scan.yml
@@ -1,180 +1,24 @@
-# SPDX-License-Identifier: MPL-2.0
-# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
-# Hypatia Neurosymbolic CI/CD Security Scan
+# SPDX-License-Identifier: MPL-2.0
name: Hypatia Security Scan
-
on:
push:
- branches: [ main, master, develop ]
+ branches: [main, master, develop]
pull_request:
- branches: [ main, master ]
+ branches: [main, master]
schedule:
- - cron: '0 0 * * 0' # Weekly on Sunday
+ - cron: '0 0 * * 0'
workflow_dispatch:
-
-permissions: read-all
-
+permissions:
+ actions: read
+ contents: read
+ security-events: write
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
scan:
- name: Hypatia Neurosymbolic Analysis
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4.1.1
- with:
- fetch-depth: 0 # Full history for better pattern analysis
-
- - name: Setup Elixir for Hypatia scanner
- uses: erlef/setup-beam@v1.17.5
- with:
- elixir-version: '1.19.4'
- otp-version: '28.3'
-
- - name: Clone Hypatia
- run: |
- if [ ! -d "$HOME/hypatia" ]; then
- git clone https://github.com/hyperpolymath/hypatia.git "$HOME/hypatia"
- fi
-
- - name: Build Hypatia scanner (if needed)
- working-directory: ${{ env.HOME }}/hypatia
- run: |
- if [ ! -f hypatia-v2 ]; then
- echo "Building hypatia-v2 scanner..."
- mix deps.get
- mix escript.build
- mv hypatia ../hypatia-v2
- fi
-
- - name: Run Hypatia scan
- id: scan
- run: |
- echo "Scanning repository: ${{ github.repository }}"
-
- # Run scanner
- HYPATIA_FORMAT=json "$HOME/hypatia/hypatia-cli.sh" scan . > hypatia-findings.json
-
- # Count findings
- FINDING_COUNT=$(jq '. | length' hypatia-findings.json 2>/dev/null || echo 0)
- echo "findings_count=$FINDING_COUNT" >> $GITHUB_OUTPUT
-
- # Extract severity counts
- CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' hypatia-findings.json)
- HIGH=$(jq '[.[] | select(.severity == "high")] | length' hypatia-findings.json)
- MEDIUM=$(jq '[.[] | select(.severity == "medium")] | length' hypatia-findings.json)
-
- echo "critical=$CRITICAL" >> $GITHUB_OUTPUT
- echo "high=$HIGH" >> $GITHUB_OUTPUT
- echo "medium=$MEDIUM" >> $GITHUB_OUTPUT
-
- echo "## Hypatia Scan Results" >> $GITHUB_STEP_SUMMARY
- echo "- Total findings: $FINDING_COUNT" >> $GITHUB_STEP_SUMMARY
- echo "- Critical: $CRITICAL" >> $GITHUB_STEP_SUMMARY
- echo "- High: $HIGH" >> $GITHUB_STEP_SUMMARY
- echo "- Medium: $MEDIUM" >> $GITHUB_STEP_SUMMARY
-
- - name: Upload findings artifact
- uses: actions/upload-artifact@v4.6.2
- with:
- name: hypatia-findings
- path: hypatia-findings.json
- retention-days: 90
-
- - name: Submit findings to gitbot-fleet (Phase 2)
- if: steps.scan.outputs.findings_count > 0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GITHUB_REPOSITORY: ${{ github.repository }}
- GITHUB_SHA: ${{ github.sha }}
- run: |
- echo "π€ Submitting ${{ steps.scan.outputs.findings_count }} findings to gitbot-fleet..."
-
- # Clone gitbot-fleet to temp directory
- FLEET_DIR="/tmp/gitbot-fleet-$$"
- git clone https://github.com/hyperpolymath/gitbot-fleet.git "$FLEET_DIR"
-
- # Run submission script
- bash "$FLEET_DIR/scripts/submit-finding.sh" hypatia-findings.json
-
- # Cleanup
- rm -rf "$FLEET_DIR"
-
- echo "β
Finding submission complete"
-
- - name: Check for critical issues
- if: steps.scan.outputs.critical > 0
- run: |
- echo "β οΈ Critical security issues found!"
- echo "Review hypatia-findings.json for details"
- # Don't fail the build yet - just warn
- # exit 1
-
- - name: Generate scan report
- run: |
- cat << EOF > hypatia-report.md
- # Hypatia Security Scan Report
-
- **Repository:** ${{ github.repository }}
- **Scan Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")
- **Commit:** ${{ github.sha }}
-
- ## Summary
-
- | Severity | Count |
- |----------|-------|
- | Critical | ${{ steps.scan.outputs.critical }} |
- | High | ${{ steps.scan.outputs.high }} |
- | Medium | ${{ steps.scan.outputs.medium }} |
- | **Total**| ${{ steps.scan.outputs.findings_count }} |
-
- ## Next Steps
-
- 1. Review findings in the artifact: hypatia-findings.json
- 2. Auto-fixable issues will be addressed by robot-repo-automaton (Phase 3)
- 3. Manual review required for complex issues
-
- ## Learning
-
- These findings feed Hypatia's learning engine to improve future rules.
-
- ---
- *Powered by [Hypatia](https://github.com/hyperpolymath/hypatia) - Neurosymbolic CI/CD Intelligence*
- EOF
-
- cat hypatia-report.md >> $GITHUB_STEP_SUMMARY
-
- - name: Comment on PR with findings
- if: github.event_name == 'pull_request' && steps.scan.outputs.findings_count > 0
- uses: actions/github-script@v7.0.1
- with:
- script: |
- const fs = require('fs');
- const findings = JSON.parse(fs.readFileSync('hypatia-findings.json', 'utf8'));
-
- const critical = findings.filter(f => f.severity === 'critical').length;
- const high = findings.filter(f => f.severity === 'high').length;
-
- let comment = `## π Hypatia Security Scan\n\n`;
- comment += `**Findings:** ${findings.length} issues detected\n\n`;
- comment += `| Severity | Count |\n|----------|-------|\n`;
- comment += `| π΄ Critical | ${critical} |\n`;
- comment += `| π High | ${high} |\n`;
- comment += `| π‘ Medium | ${findings.length - critical - high} |\n\n`;
-
- if (critical > 0) {
- comment += `β οΈ **Action Required:** Critical security issues found!\n\n`;
- }
-
- comment += `View findings
\n\n`;
- comment += `\`\`\`json\n${JSON.stringify(findings.slice(0, 10), null, 2)}\n\`\`\`\n`;
- comment += ` \n\n`;
- comment += `*Powered by Hypatia Neurosymbolic CI/CD Intelligence*`;
-
- github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- body: comment
- });
+ uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@fcb566cfb8a86cea2d3666bf65a4f177a49b1313
+ with:
+ block-on-high: true
+ secrets: inherit
diff --git a/.github/workflows/label-triage.yml b/.github/workflows/label-triage.yml
index 9886e92..814a192 100644
--- a/.github/workflows/label-triage.yml
+++ b/.github/workflows/label-triage.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
name: Label Triage
diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml
index c80b676..83ab941 100644
--- a/.github/workflows/labels.yml
+++ b/.github/workflows/labels.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
name: Labels
diff --git a/.github/workflows/lean-build.yml b/.github/workflows/lean-build.yml
index c90959c..8357399 100644
--- a/.github/workflows/lean-build.yml
+++ b/.github/workflows/lean-build.yml
@@ -1,192 +1,83 @@
-# SPDX-License-Identifier: MPL-2.0
-# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
-# Lean 4 Build and Test Workflow
+# SPDX-License-Identifier: MPL-2.0
name: Lean 4 Build
-
on:
- push:
- branches: [ main, master, develop ]
pull_request:
- branches: [ main, master ]
+ push:
+ branches: [main]
workflow_dispatch:
-
-permissions: read-all
-
+permissions:
+ contents: read
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
build:
name: Build and Test Lean 4
runs-on: ubuntu-latest
-
+ timeout-minutes: 20
steps:
- - name: Checkout repository
- uses: actions/checkout@v4.1.1
-
- - name: Install elan (Lean version manager)
- run: |
- curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh -s -- -y --default-toolchain none
- echo "$HOME/.elan/bin" >> $GITHUB_PATH
-
- - name: Verify Lean toolchain
- run: |
- elan --version
- lean --version
- lake --version
-
- # Was actions/cache@0c45773bβ¦ β a deprecated version that GitHub hard-fails.
- # That failure aborted this job BEFORE `lake build` ever ran, which is why
- # CI never once reported whether this project compiles.
- - name: Cache Lean dependencies
- uses: actions/cache@v4.2.3
+ - uses: actions/checkout@v4.1.1
with:
- path: |
- .lake
- ~/.elan
- key: ${{ runner.os }}-lean-${{ hashFiles('lake-manifest.json') }}
- restore-keys: |
- ${{ runner.os }}-lean-
-
- # Tee the build so the proof gate can read Lean's own diagnostics.
- # pipefail so a build failure is not masked by the pipe into tee.
- - name: Build Lean 4 project
+ persist-credentials: false
+ - name: Install pinned Lean toolchain
+ uses: leanprover/lean-action@v1.6.0
+ with:
+ auto-config: 'false'
+ build: 'false'
+ test: 'false'
+ lint: 'false'
+ use-mathlib-cache: 'false'
+ use-github-cache: 'false'
+ - name: Build library, executable suites and narration axiom audit
run: |
- set -o pipefail
+ set -euo pipefail
lake build 2>&1 | tee lake-build.log
-
- # `lake test` exits non-zero BOTH when tests fail and when no test driver
- # is configured. The previous step was `lake test || echo "..."`, which
- # swallowed both β so a genuine test failure could never turn this job red.
- # Tolerate only the "no test driver" case, and surface it as a warning
- # rather than a silent pass: no driver means no executable test coverage.
- - name: Run Lean tests
+ - name: Run every registered suite, including real narration processes
run: |
- set -o pipefail
- if lake test 2>&1 | tee lake-test.log; then
- echo "β
lake test passed"
- elif grep -q "no test driver configured" lake-test.log; then
- echo "::warning::No Lean test driver is configured, so this repository has NO executable test coverage. Add a @[test_driver] to lakefile.lean."
- else
- echo "::error::lake test failed"
- exit 1
- fi
-
- # Authoritative proof gate. Lean itself emits "declaration uses 'sorry'";
- # the previous gate was `! grep -r "sorry\|admit" src/`, which fired on a
- # lexer keyword table, a string literal, a comment and two constructor
- # references β and could not see a sorry reached through a tactic block.
- - name: Check for incomplete proofs (authoritative)
+ set -euo pipefail
+ lake test 2>&1 | tee lake-test.log
+ - name: Check Lean incomplete-proof diagnostics
run: ./scripts/check-lean-proofs.sh --build-log lake-build.log
-
- - name: Upload build log
+ - uses: actions/upload-artifact@v4.6.2
if: always()
- uses: actions/upload-artifact@v4.3.0
with:
- name: lake-build-log
- path: lake-build.log
- retention-days: 30
-
+ name: lean-validation
+ path: |
+ lake-build.log
+ lake-test.log
+ if-no-files-found: error
zig-ffi:
name: Build Zig FFI Bridge
runs-on: ubuntu-latest
-
+ timeout-minutes: 15
steps:
- - name: Checkout repository
- uses: actions/checkout@v4.1.1
-
- # Was goto-bus-stop/setup-zig@2a9625dβ¦ β that SHA does not exist and the
- # action is unmaintained (it has no v2 tag at all), so this job could
- # never start. mlugg/setup-zig is the maintained successor.
- - name: Setup Zig
- uses: mlugg/setup-zig@v2.2.1
+ - uses: actions/checkout@v4.1.1
with:
- version: 0.16.0
-
- # Was `working-directory: bridge/zig`. That is a stale skeleton on the
- # pre-0.15 Build API (`addStaticLibrary`, `linkLibC`) which no longer
- # compiles, and nothing links against it. The real bridge is `bridge/`:
- # `lakefile.lean` links `-Lbridge/zig-out/lib -llith_bridge`, and
- # `bridge/build.zig` is what produces `liblith_bridge.a` at that path.
- - name: Build Zig bridge
- working-directory: bridge
- run: zig build
-
- - name: Verify the artifact Lean links against exists
- working-directory: bridge
- run: test -f zig-out/lib/liblith_bridge.a
-
- # bridge/build.zig declares exactly two steps: "shared" and "test".
- # The old workflow also ran `zig build test-integration`, which is not a
- # step in any build.zig here and would always have failed.
- - name: Run Zig tests
+ persist-credentials: false
+ - uses: mlugg/setup-zig@v2.2.1
+ with:
+ version: '0.16.0'
+ - name: Build and test bridge
working-directory: bridge
- run: zig build test
-
+ run: |
+ set -euo pipefail
+ zig build
+ zig build test
+ test -f zig-out/lib/liblith_bridge.a
spec-validation:
name: Validate Specifications
runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4.1.1
-
- - name: Check EBNF grammar syntax
- run: |
- echo "Validating EBNF grammar..."
- if ! grep -E '::=' spec/GQLdt-Grammar.ebnf > /dev/null; then
- echo "β No production rules found in grammar"
- exit 1
- fi
- echo "β
Grammar file appears valid"
-
- # Filenames corrected: these are GQL-DT-*, not GQLdt-*. The old list made
- # this job fail on a spelling mismatch and report it as a MISSING SPEC.
- - name: Verify specification files
- run: |
- missing=0
- for file in spec/GQL_Dependent_Types_Complete_Specification.md \
- spec/normalization-types.md \
- spec/GQLdt-Grammar.ebnf \
- spec/GQL-DT-Lexical.md \
- spec/GQL-DT-Railroad-Diagrams.md; do
- if [ ! -f "$file" ]; then
- echo "β Missing required spec file: $file"
- missing=1
- fi
- done
- [ "$missing" -eq 0 ] || exit 1
- echo "β
All specification files present"
-
- # REMOVED: a "naming consistency" step that ran
- # grep -i "gql-dt" STATE.scm ECOSYSTEM.scm 2>/dev/null
- # -> echo "Found old naming (gql-dt instead of gql-dt)"
- # It compared a string to itself, over two files that do not exist in this
- # repo (2>/dev/null swallowed the error), so it could only ever pass.
- # Deleted rather than repaired: there is no naming rule for it to enforce.
-
- documentation:
- name: Build Documentation
- runs-on: ubuntu-latest
-
+ timeout-minutes: 5
steps:
- - name: Checkout repository
- uses: actions/checkout@v4.1.1
-
- - name: Check markdown links
- uses: gaurav-nelson/github-action-markdown-link-check@1.0.15
+ - uses: actions/checkout@v4.1.1
with:
- use-quiet-mode: 'yes'
- config-file: '.github/markdown-link-check-config.json'
- continue-on-error: true
-
- - name: Generate spec index
+ persist-credentials: false
+ - name: Check implemented contract and private specification inventory
run: |
- echo "Specification files:" > spec-index.txt
- find spec/ -name "*.md" -o -name "*.ebnf" >> spec-index.txt
- cat spec-index.txt
-
- - name: Upload spec index
- uses: actions/upload-artifact@v4.3.0
- with:
- name: spec-index
- path: spec-index.txt
- retention-days: 30
+ set -euo pipefail
+ for file in docs/narration-slice.adoc test/NarrationTest.lean test/NarrationProofAudit.lean spec/GQLdt-Grammar.ebnf spec/GQL-DT-Lexical.adoc; do
+ test -s "$file"
+ done
+ # Presence is an inventory check; executable conformance is tested above.
+ grep -q '::=' spec/GQLdt-Grammar.ebnf
diff --git a/.github/workflows/push-email-notify.yml b/.github/workflows/push-email-notify.yml
index 9e133d7..579479c 100644
--- a/.github/workflows/push-email-notify.yml
+++ b/.github/workflows/push-email-notify.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# Dormant push-email notification. ARMED by setting the repo variable
@@ -40,7 +41,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Send push notification email
- uses: hyperpolymath/smtp-notify-action@v0.2.0 # NOSONAR β pin authority is actions.lock (sha1-ede1191ef6ff3ac02c4f4d9efdf837ee517e11d7)
+ uses: hyperpolymath/smtp-notify-action@v0.2.0
with:
server_address: ${{ secrets.SMTP_HOST }}
server_port: ${{ secrets.SMTP_PORT }}
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index d766450..c8805c6 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml
index aa4ad81..66890b6 100644
--- a/.github/workflows/secret-scanner.yml
+++ b/.github/workflows/secret-scanner.yml
@@ -1,3 +1,4 @@
+# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
@@ -19,5 +20,5 @@ permissions:
contents: read
jobs:
secret-scan:
- uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@571cc734cd69fb846032ec77a662aa8ee4fc32cd
+ uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@fcb566cfb8a86cea2d3666bf65a4f177a49b1313
secrets: inherit
diff --git a/.machine_readable/6a2/ECOSYSTEM.a2ml b/.machine_readable/6a2/ECOSYSTEM.a2ml
deleted file mode 100644
index 617f0e6..0000000
--- a/.machine_readable/6a2/ECOSYSTEM.a2ml
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-License-Identifier: MPL-2.0
-# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
-#
-# ECOSYSTEM.a2ml β Gql Dt ecosystem position
-[metadata]
-version = "1.0.0"
-last-updated = "2026-04-11"
-
-[project]
-name = "Gql Dt"
-purpose = "Add dependent types to Lithoglyph Query Language for compile-time verification"
-role = "language-extension"
-
-[position-in-ecosystem]
-category = ""
-
-[related-projects]
-projects = [
- # No related projects recorded
-]
diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/6a2/STATE.a2ml
deleted file mode 100644
index 38e7c9a..0000000
--- a/.machine_readable/6a2/STATE.a2ml
+++ /dev/null
@@ -1,116 +0,0 @@
-# SPDX-License-Identifier: MPL-2.0
-# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
-#
-# STATE.a2ml β hyperpolymath/gnpl project state
-#
-# Rewritten 2026-07-28. The previous revision was stale and partly corrupt: it named the
-# project "gql-dt", was dated 2026-02-01, listed already-completed milestones as critical
-# next actions, and its `purpose` field held a fragment of a build error rather than a
-# purpose. Every figure below is measured, not estimated; see [evidence].
-
-[metadata]
-project = "gnpl"
-version = "0.3.0"
-last-updated = "2026-07-28"
-status = "active"
-session = "proof-debt foundation; PRs #6 #7 #8 merged"
-
-[project-context]
-name = "GNPL"
-purpose = """
-GNPL is Lithoglyph's narration/projection language: it turns an evidence base into an
-account β for forensic histories, counterfactual paths, plural meanings, and
-synchronic/diachronic evidence interpretation. Where a query language answers "what is
-true in the store?", GNPL answers "what account does this evidence support, told from
-whose stance, with what warrant, and what rival accounts does the same evidence also
-support?".
-
-It is built as a layer ON TOP OF GQLdt in this repository and lowers to it:
-GNPL (what account) -> GQLdt (what is) -> Zig FFI -> Lithoglyph (the store).
-This is why sources are namespaced GqlDt in a repository named gnpl.
-"""
-completion-percentage = 40
-
-[position]
-phase = "partial-implementation" # design | implementation | testing | maintenance | archived
-maturity = "experimental" # experimental | alpha | beta | production | lts
-
-[layers]
-# Two layers, one repo. Nothing is being extracted or discarded.
-gqldt = "built and tested β the extensional query core, src/GqlDt/"
-gnpl = "design only β docs/THEORY.adoc + docs/LITHOGLYPH.adoc; no src/Gnpl/ yet"
-
-[verification]
-# What is actually established, and by what. A gate that has never gone red is not
-# evidence; both gates below were canary-tested in both directions.
-lean-build = "pass" # lake build, 34/35 targets
-lean-tests = "pass" # lake test, 163 checks, 3 suites
-lean-test-count = 163
-lean-test-suites = ["lexer_test", "parser_test", "type_safety_test"]
-zig-bridge-build = "pass" # cd bridge && zig build && zig build test
-incomplete-proofs = 0 # Lean reports no `sorry`
-trusted-base-axioms = 16 # `axiom` does NOT trigger Lean's sorry warning
-trusted-base-doc = "docs/proof-debt.md"
-gates-canary-tested = true
-
-[caveat]
-# The single most important thing for a machine reading this file to carry forward.
-note = """
-A green proof gate here means "nothing is admitted mid-proof". It does NOT mean "nothing
-is assumed". Lean 4 emits `declaration uses 'sorry'` for sorry/sorryAx only β `axiom`
-produces no warning at all. This repository declares 16 axioms, all stubs, none necessary
-in the trusted-base-policy sense. FIVE are in EXECUTABLE position (parseToIR,
-deserializeIR, many, many1, sepBy) and therefore have no implementation: code calling them
-typechecks and cannot run. So "34/35 targets build" is a claim about TYPECHECKING, not
-about a working parser. Read docs/proof-debt.md before relying on any verification claim.
-"""
-
-[route-to-mvp]
-milestones = [
- "DONE 2026-07-21 β identity: repo established as GNPL-over-GQLdt; licence restored to MPL-2.0",
- "DONE 2026-07-21 β design: docs/THEORY.adoc (the general case) + docs/LITHOGLYPH.adoc (the tethered case)",
- "DONE 2026-07-27 β dead code: two pre-0.15-API Zig trees removed; bridge/ is the only one",
- "DONE 2026-07-28 β foundation: lake test wired, 163 checks, suites can fail",
- "DONE 2026-07-28 β lexer conformance: 19 spec defects fixed (peek off-by-one)",
- "NEXT β proof debt D1: delete or prove executePreservesTypes (currently vacuous)",
- "NEXT β proof debt D3: construct the six asserted PromptScores examples (gated on averaging decision)",
- "THEN β proof debt D2: implement many/many1/sepBy, unblocking four parse* axioms",
- "THEN β src/Gnpl/ skeleton: Fabula, Projection, Focalization, Account, Warrant",
-]
-
-[blockers-and-issues]
-issues = [
- "DECISION NEEDED β averaging rule for PROMPT scores. PromptScores carries a proof field, overall_correct : overall.val = (sum)/6, so the arithmetic mean is welded into the TYPE. Changing it is a proof-obligation change on every value, in Lean and Zig simultaneously. Gates proof-debt D3.",
- "DECISION NEEDED β flake.nix vs guix.scm. Estate policy: Guix primary, Nix fallback, satisfying NEITHER is the violation. This repo has no guix.scm, so flake.nix is the only artefact satisfying it; removing it without a verified guix.scm turns Governance red.",
- "UPSTREAM hyperpolymath/standards#516 β Hypatia setup-beam pin cannot map ImageOS=ubuntu24; scanner never runs for any caller. Only red on gnpl main.",
- "UPSTREAM hyperpolymath/standards#486 β governance/Allowlist Preflight cannot resolve allowed-actions.json (the file EXISTS; path resolution after sparse-checkout). standards' own main is red on it too.",
- "UPSTREAM hyperpolymath/standards#520 β scorecard.yml template violates the estate SARIF policy as distributed.",
- "NO test coverage for the FFI boundary β ffi_test is excluded from lake test because it links liblith_bridge.a; it is covered only by the zig-ffi CI job.",
-]
-
-[critical-next-actions]
-actions = [
- "Discharge proof-debt D1: executePreservesTypes reduces to `... -> True` with body commented `-- Placeholder`. It reads as a soundness theorem and discharges nothing. Deleting it is strictly better than keeping a vacuous placeholder.",
- "Settle the averaging rule, then discharge D3 once against the final definition.",
- "Add a test driver entry for the FFI boundary once liblith_bridge.a can be assumed present.",
-]
-
-[history-landmines]
-notes = [
- "The gnpl extract from nextgen-databases was a SQUASH; granular history survives only in the _split_gnpl branch there. Never prune it.",
- "Local branches backup/sweeps-mistral-vibe and fix-ci-estate hold three superseded agent-generated sweep commits. Do not replay them: sweep2 is boilerplate mise.toml, sweep3 is an AGPL clobber into an MPL-2.0 repo.",
- "Callers pin standards reusables at @main, not a SHA, so upstream permission/interface changes reach this repo instantly and unannounced. This caused two separate estate-wide outages in July 2026.",
-]
-
-[evidence]
-# Commands a machine or human can run to reproduce every claim above.
-build = "lake build"
-test = "lake test"
-bridge = "cd bridge && zig build && zig build test"
-proof-gate = "lake build 2>&1 | tee lake-build.log && ./scripts/check-lean-proofs.sh --build-log lake-build.log"
-trusted-base = "bash /scripts/check-trusted-base.sh ."
-
-[maintenance-status]
-last-run-utc = "2026-07-28T18:45:00Z"
-last-result = "pass" # unknown | pass | warn | fail
-last-result-detail = "lake build exit 0; lake test exit 0 with 163 checks across 3 suites; verified from a clean checkout of merged main (9de0713)."
diff --git a/.machine_readable/ROADMAP.a2ml b/.machine_readable/ROADMAP.a2ml
index 1bd8c0f..224ddd3 100644
--- a/.machine_readable/ROADMAP.a2ml
+++ b/.machine_readable/ROADMAP.a2ml
@@ -1,210 +1,25 @@
; SPDX-License-Identifier: MPL-2.0
-; Lithoglyph Ecosystem - Unified Roadmap to MVP 1.0.0
-; Media-Type: application/vnd.roadmap+scm
-;
-; This file is distributed to all Lithoglyph ecosystem repos:
-; - lithoglyph (core database)
-; - gql-dt (dependently-typed query language)
-; - lithoglyph-studio (GUI)
-; - lithoglyph-debugger (recovery tool)
-
-(unified-roadmap
- (metadata
- (version "1.0.0")
- (created "2026-01-12")
- (updated "2026-01-12")
- (author "hyperpolymath")
- (target "MVP 1.0.0"))
-
- ;; ============================================================================
- ;; ECOSYSTEM OVERVIEW
- ;; ============================================================================
- (ecosystem-summary
- (components
- (lithoglyph
- (version "0.0.4")
- (completion 70)
- (role "Core database engine")
- (tech "Forth + Factor + Zig"))
- (gql-dt
- (version "0.2.0")
- (completion 85)
- (role "Dependently-typed query language")
- (tech "Lean 4 + Zig"))
- (lithoglyph-studio
- (version "0.1.0")
- (completion 45)
- (role "Zero-friction GUI")
- (tech "ReScript + Tauri 2.0 + Rust"))
- (lithoglyph-debugger
- (version "0.1.0")
- (completion 55)
- (role "Proof-carrying recovery tool")
- (tech "Lean 4 + Idris 2 + Rust")))
-
- (architecture
- "βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"
- "β Lithoglyph Studio (GUI) β"
- "β β generates FQLdt code β"
- "βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€"
- "β FQLdt (Lean 4) β"
- "β β compiles to proof blobs β"
- "βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€"
- "β Form.Bridge (Zig ABI) β"
- "β β calls β"
- "βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€"
- "β Lithoglyph Core (Forth + Factor) β"
- "β Form.Runtime β Form.Normalizer β Form.Model β Form.Blocksβ"
- "βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€"
- "β Lithoglyph Debugger (alongside) β"
- "β β proves recovery safe β"
- "β Lithoglyph + FQLdt β"
- "βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"))
-
- ;; ============================================================================
- ;; CRITICAL PATH TO MVP 1.0.0
- ;; ============================================================================
- (critical-path
- (phase (id "P1") (name "Core Integration")
- (duration "weeks 1-6")
- (focus "Lithoglyph + FQLdt integration")
-
- (lithoglyph-tasks
- (task "Complete M11: HTTP API Server" priority: critical status: in-progress)
- (task "Expose Form.Bridge FFI for proof verification" priority: high status: pending)
- (task "Add CBOR proof blob acceptance in query path" priority: high status: pending))
-
- (gql-dt-tasks
- (task "M5: Zig FFI bridge to Form.Bridge" priority: critical status: not-started)
- (task "M6: GQL parser (integrate with Lithoglyph's EBNF)" priority: high status: not-started)
- (task "Proof blob serialization (CBOR RFC 8949)" priority: high status: pending))
-
- (checkpoint "FQLdt can compile a query β proof blob β Lithoglyph accepts and executes"))
-
- (phase (id "P2") (name "User-Facing Tools")
- (duration "weeks 7-10")
- (focus "Studio and Debugger completion")
-
- (studio-tasks
- (task "Verify ReScript/Tauri build pipeline" priority: critical status: pending)
- (task "Wire ReScript UI to FQLdt code generation" priority: high status: pending)
- (task "Connect to Lithoglyph HTTP API" priority: high status: blocked)
- (task "Test schema creation β query β results flow" priority: medium status: pending))
-
- (debugger-tasks
- (task "Wire Idris REPL to PostgreSQL adapter" priority: high status: pending)
- (task "Lithoglyph adapter: parse real journal files" priority: high status: partial)
- (task "Complete Ratatui TUI interface" priority: medium status: in-progress)
- (task "Integration: proof verification before recovery" priority: medium status: pending))
-
- (checkpoint "Users can create schemas in Studio, debug with Debugger"))
-
- (phase (id "P3") (name "Production Hardening")
- (duration "weeks 11-12")
- (focus "Stability and polish")
-
- (all-repos
- (task "Crash recovery tests" priority: high)
- (task "Error handling improvements" priority: high)
- (task "Cross-platform testing" priority: medium)
- (task "Documentation completion" priority: medium)
- (task "Performance optimization" priority: low))
-
- (checkpoint "MVP 1.0.0 release ready")))
-
- ;; ============================================================================
- ;; DEPENDENCY GRAPH
- ;; ============================================================================
- (dependencies
- (lithoglyph-m11
- (name "Lithoglyph HTTP API Server")
- (blocks "Studio M2" "Debugger Lithoglyph adapter")
- (priority critical))
-
- (gql-dt-m5
- (name "FQLdt Zig FFI Bridge")
- (blocks "Studio M3" "Real type checking")
- (depends-on "Lithoglyph Form.Bridge")
- (priority critical))
-
- (gql-dt-m6
- (name "FQLdt GQL Parser")
- (blocks "Full FQLdt compilation")
- (depends-on "gql-dt-m5")
- (priority high))
-
- (studio-m1
- (name "Studio Build Pipeline")
- (blocks "All Studio features")
- (priority critical))
-
- (debugger-repl-db
- (name "Debugger REPL Database Connection")
- (blocks "Real debugging")
- (priority high)))
-
- ;; ============================================================================
- ;; UNRESOLVED DECISIONS
- ;; ============================================================================
- (decisions-needed
- (decision (id "DECISION-002")
- (title "FQLdt parser approach")
- (repo "gql-dt")
- (options
- "Hand-rolled parser (simple, no deps)"
- "Lean 4 Parsec (built-in)"
- "Integrate with Lithoglyph's Factor-based GQL parser")
- (recommendation "Integrate - reuse Lithoglyph's EBNF grammar via FFI")
- (impact "Affects M6 implementation"))
-
- (decision (id "DECISION-003")
- (title "Lithoglyph integration strategy for FQLdt")
- (repo "gql-dt")
- (options
- "Mock Forth core for MVP"
- "Real Form.Bridge integration")
- (recommendation "Real integration - M11 HTTP API makes this feasible")
- (impact "Determines MVP scope")))
-
- ;; ============================================================================
- ;; POST-MVP ROADMAP
- ;; ============================================================================
- (post-mvp
- (release (version "1.1.0") (name "Normalization & Migration")
- (features
- "Form.Normalizer full integration (FD discovery β decomposition)"
- "Three-phase migration workflow (Announce/Shadow/Commit)"
- "Studio: visual normalization wizard"
- "Debugger: migration rollback proofs"))
-
- (release (version "1.2.0") (name "Multi-Database Support")
- (features
- "Debugger: SQLite adapter completion"
- "Lithoglyph: clustering/replication (Form.ControlPlane begins)"
- "Studio: connection manager for multiple DBs"))
-
- (release (version "2.0.0") (name "Agentic Ecosystem")
- (features
- "Form.ControlPlane (Elixir/OTP) for distributed coordination"
- "Agent handover protocols"
- "Long-term archive format standardization"
- "Multi-user collaboration in Studio")))
-
- ;; ============================================================================
- ;; SUCCESS METRICS
- ;; ============================================================================
- (success-metrics
- (mvp-criteria
- "User can create a schema in Studio with visual builder"
- "Schema generates valid FQLdt with type checking"
- "User can insert data with provenance tracking"
- "User can query data and see results"
- "Debugger can analyze schema and propose fixes"
- "All operations have proof-carrying verification")
-
- (quality-gates
- "All ReScript code compiles without warnings"
- "All Rust code passes Clippy lints"
- "All Lean 4 code builds with lake"
- "Cross-platform builds succeed (Mac/Windows/Linux)"
- "Integration tests pass end-to-end")))
+; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+; GNPL roadmap; replaces the obsolete January ecosystem-wide schedule.
+(roadmap
+ (project "gnpl")
+ (updated "2026-09-07")
+ (human-readable "ROADMAP.adoc")
+ (state ".machine_readable/descriptiles/STATE.a2ml")
+ (implemented
+ "Direct-evidence narration, focalization, typed warrants and ordered accounts"
+ "Limited rival relation and hypothetical withdrawal"
+ "Projection surface, versioned evidence import and CLI"
+ "Five Lean suites and scoped narration axiom audit")
+ (next
+ "Read-only Lithoglyph adapter with consistent revision and withdrawal tests"
+ "Checked warrant derivation rules"
+ "Explicit partial-order and temporal semantics")
+ (open-design
+ "Confidence composition and interpretation"
+ "General account relations and argumentation semantics")
+ (later
+ "Durable account storage and Glyphbase rendering")
+ (boundary
+ "Selection and storage are private machinery; no additional public language"
+ "Local tests do not establish live journal integration, remote CI or deployment"))
diff --git a/.machine_readable/6a2/AGENTIC.a2ml b/.machine_readable/descriptiles/AGENTIC.a2ml
similarity index 100%
rename from .machine_readable/6a2/AGENTIC.a2ml
rename to .machine_readable/descriptiles/AGENTIC.a2ml
diff --git a/.machine_readable/descriptiles/ECOSYSTEM.a2ml b/.machine_readable/descriptiles/ECOSYSTEM.a2ml
new file mode 100644
index 0000000..c8a67f1
--- /dev/null
+++ b/.machine_readable/descriptiles/ECOSYSTEM.a2ml
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: MPL-2.0
+# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
+#
+# ECOSYSTEM.a2ml β GNPL ecosystem position
+[metadata]
+version = "1.0.0"
+last-updated = "2026-09-07"
+
+[project]
+name = "GNPL"
+purpose = "Construct warranted accounts under declared focalization and retain rival interpretations over evidence"
+role = "narration-and-projection-language"
+
+[position-in-ecosystem]
+category = "database-languages"
+
+[related-projects]
+projects = [
+ "lithoglyph: intended durable evidence source; live snapshot adapter remains work",
+ "glyphbase: intended account rendering surface; integration remains work",
+ "nextgen-databases: portfolio coordination only"
+]
diff --git a/.machine_readable/6a2/META.a2ml b/.machine_readable/descriptiles/META.a2ml
similarity index 57%
rename from .machine_readable/6a2/META.a2ml
rename to .machine_readable/descriptiles/META.a2ml
index f7354a5..43c653d 100644
--- a/.machine_readable/6a2/META.a2ml
+++ b/.machine_readable/descriptiles/META.a2ml
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
#
-# META.a2ml β Gql Dt meta-level information
+# META.a2ml β GNPL meta-level information
[metadata]
version = "1.0.0"
-last-updated = "2026-04-11"
+last-updated = "2026-09-07"
[project-info]
license = "MPL-2.0"
@@ -12,13 +12,15 @@ author = "Jonathan D.A. Jewell (hyperpolymath)"
[architecture-decisions]
decisions = [
- # No ADRs recorded
+ "Narration semantics are public; selection and storage machinery is private, with no fixed lowering target.",
+ "The initial narration kernel imports Lean/Std independently of the legacy substrate.",
+ "Direct-evidence support checks declared inputs; it does not establish external truth."
]
[development-practices]
versioning = "SemVer"
documentation = "AsciiDoc"
-build-tool = "just"
+build-tool = "lake"
[maintenance-axes]
scoping-first = true
diff --git a/.machine_readable/6a2/NEUROSYM.a2ml b/.machine_readable/descriptiles/NEUROSYM.a2ml
similarity index 100%
rename from .machine_readable/6a2/NEUROSYM.a2ml
rename to .machine_readable/descriptiles/NEUROSYM.a2ml
diff --git a/.machine_readable/6a2/PLAYBOOK.a2ml b/.machine_readable/descriptiles/PLAYBOOK.a2ml
similarity index 66%
rename from .machine_readable/6a2/PLAYBOOK.a2ml
rename to .machine_readable/descriptiles/PLAYBOOK.a2ml
index 5003fd0..c35e24c 100644
--- a/.machine_readable/6a2/PLAYBOOK.a2ml
+++ b/.machine_readable/descriptiles/PLAYBOOK.a2ml
@@ -11,16 +11,22 @@ last-updated = "2026-04-11"
# target = "container" # container | binary | library | wasm
[incident-response]
-# 1. Check .machine_readable/STATE.a2ml for current status
+# 1. Check .machine_readable/descriptiles/STATE.a2ml for current status
# 2. Review recent commits and CI results
# 3. Run `just validate` to check compliance
# 4. Run `just security` to audit for vulnerabilities
[release-process]
-# 1. Update version in STATE.a2ml, META.a2ml
+# 1. Update version in .machine_readable/descriptiles/STATE.a2ml and .machine_readable/descriptiles/META.a2ml
# 2. Run `just release-preflight` (validate + quality + security + maint-hard-pass)
# 3. Tag and push
[maintenance-operations]
# Baseline audit: just maint-audit
# Hard release gate: just maint-hard-pass
+
+[narration-validation]
+build = "lake build"
+tests = "lake test"
+guide = "docs/narration-slice.adoc"
+scope = "Imported-snapshot narration; no live journal, deployment or release guarantee"
diff --git a/.machine_readable/descriptiles/STATE.a2ml b/.machine_readable/descriptiles/STATE.a2ml
new file mode 100644
index 0000000..0ce8600
--- /dev/null
+++ b/.machine_readable/descriptiles/STATE.a2ml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: MPL-2.0
+# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+# Current local checkpoint; historical checkpoints remain in Git history.
+
+[metadata]
+project = "gnpl"
+version = "0.3.0"
+last-updated = "2026-09-07"
+status = "active"
+
+[project-context]
+name = "GNPL"
+purpose = "Warranted accounts, focalization and rival interpretations over evidence."
+phase = "implemented direct-evidence narration fragment; live journal integration next"
+maturity = "experimental"
+
+[implemented]
+narration = "src/Gnpl/: typed direct-evidence warrants and accounts, focalization, telling order, limited rival relation and hypothetical withdrawal"
+cli = "src/GnplMain.lean: narrate and counterfactual over versioned imported snapshots"
+private-substrate = "Complete-statement parsing and schema-validated in-memory insertion/retrieval fragment; historical namespace is not a public language or fixed lowering target"
+
+[verification]
+horizon = "Local working tree on 2026-09-07, Lean 4.15.0; remote CI and deployment not established"
+build = "lake build: exit 0"
+test = "lake test: exit 0, five suites"
+suites = ["lexer_test", "parser_test", "type_safety_test", "substrate_test", "narration_test"]
+private-substrate-checks = 26
+narration-checks = 35
+narration-cli = "Warranted accounts, focalization refusal, cited-withdrawal invalidation, unrelated-withdrawal preservation, input failure and byte-for-byte evidence preservation"
+proof-gate = "Successful build log passes scripts/check-lean-proofs.sh --build-log"
+narration-properties = ["withdrawn_cannot_support", "narration_preserves_projection"]
+narration-axiom-footprint = "Lean reports [propext] for narrate and both properties; default-build NarrationProofAudit checks this exact diagnostic"
+ffi = "Separate boundary; not covered by lake test and not reverified in this checkpoint"
+
+[trust-boundary]
+inputs = "Imported source attribution, audience and integer scores are trusted declarations; no source authentication or external truth claim"
+warrant = "Exact claim match, present active evidence, audience membership, nonblank provenance fields and explicit threshold"
+confidence = "Declared integer in 0β100; no composition, probability, source ranking or entrenchment semantics"
+proof-scope = "New narration kernel is independent of private storage assumptions; private modules retain proof debt, including floating-point equality"
+wire = "Readable JSON warrant trail; erased Lean proofs are not portable proof certificates"
+
+[known-limits]
+narration = ["Live Lithoglyph journal adapter", "General derivation chains", "Partial-order and temporal event semantics", "General account relations and search", "Confidence composition", "Durable account storage and Glyphbase rendering"]
+private-pipeline-refuses = ["Unverified attached-proof mode", "Persistent execution", "Complete IR interchange", "Unchecked update/delete lowering"]
+initialisation = "REQUIRES_INITIALISATION.adoc lists unresolved conduct/security facts in the current AsciiDoc sources; no values invented"
+
+[critical-next-actions]
+actions = ["Connect a consistent real Lithoglyph snapshot and test cited versus unrelated withdrawal across revisions", "Define and prove additional warrant derivation rules", "Keep broader confidence and temporal semantics explicit before implementation"]
+
+[history-landmines]
+notes = ["The extract from nextgen-databases was a squash; granular history survives in its _split_gnpl branch. Never prune it.", "Do not replay superseded sweep branches that reintroduce boilerplate or an incompatible licence.", "July proof-debt totals and external CI issue statuses are historical; this checkpoint does not revalidate them."]
+
+[evidence]
+build = "lake build"
+test = "lake test"
+guide = "docs/narration-slice.adoc"
+boundary = "docs/executable-boundary.adoc"
+next-integration = "docs/LITHOGLYPH.adoc"
diff --git a/0-AI-MANIFEST.a2ml b/0-AI-MANIFEST.a2ml
index 5fd7451..d5e982a 100644
--- a/0-AI-MANIFEST.a2ml
+++ b/0-AI-MANIFEST.a2ml
@@ -1,7 +1,7 @@
; SPDX-License-Identifier: MPL-2.0
; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath)
;
-; 0-AI-MANIFEST.a2ml β Universal AI entry point for GQL-DT
+; 0-AI-MANIFEST.a2ml β Universal AI entry point for GNPL
; Media-Type: application/a2ml
(manifest
@@ -13,7 +13,7 @@
(license "MPL-2.0")
(author "Jonathan D.A. Jewell ")
(parent-project "lithoglyph")
- (monorepo-parent "nextgen-databases"))
+ (coordination-repository "nextgen-databases"))
(purpose
"Lithoglyph's narration/projection language. Where a query language answers
@@ -22,41 +22,38 @@
does the same evidence also support?' β for forensic histories, counterfactual
paths, plural meanings, and synchronic/diachronic evidence interpretation.
- TWO LAYERS, ONE REPO. GNPL is built on top of GQLdt here and lowers to it:
- GNPL (what account) -> GQLdt (what is) -> Zig FFI -> Lithoglyph (the store).
- This is why every source file is namespaced GqlDt in a repo named gnpl; that
- is expected, not a mistake. GQLdt is the dependently-typed query core β Lean 4
- with Mathlib, compile-time verification of database constraints, provenance
- tracking and normalization proofs β and it is GNPL's compilation target.
+ IMPLEMENTED: a direct-evidence narration fragment in src/Gnpl/, with a
+ projection parser, versioned evidence import, CLI, focalization, checked
+ warrants, ordered accounts, a limited rival relation and hypothetical
+ withdrawal. The snapshot importer is not a live Lithoglyph adapter.
- STATUS: GQLdt builds and is tested (163 checks). GNPL itself is DESIGN ONLY β
- docs/THEORY.adoc and docs/LITHOGLYPH.adoc; there is no src/Gnpl/ yet.")
+ Private selection, type validation and storage code remains under its
+ historical source namespace. It is not a second public language or a
+ prescribed lowering target. See docs/narration-slice.adoc and
+ docs/executable-boundary.adoc for the executable contracts.")
(caveat-for-agents
- "A green proof gate here means 'nothing is admitted mid-proof'. It does NOT mean
- 'nothing is assumed'. Lean's sorry warning does not fire on `axiom`, and this
- repo declares 16 axioms β five in EXECUTABLE position (parseToIR, deserializeIR,
- many, many1, sepBy), which therefore have no implementation at all. Code calling
- them typechecks and cannot run. Do not report this repository as 'verified' on the
- strength of a green build. See docs/proof-debt.md.")
+ "A green incomplete-proof gate does not establish an axiom-free repository.
+ The new narration kernel depends only on Lean/Std. Its default-build audit
+ requires Lean to report only propext for narrate and the two scoped theorems.
+ Private substrate modules retain separate assumptions, including floating-
+ point equality. Historical proof-debt totals are not a current inventory.
+ Imported attribution, audience and scores are trusted inputs; checked
+ support is not proof of external truth or authenticated source provenance.")
- ;; Corrected 2026-07-28: all six of the previous entries pointed at files that do not
- ;; exist. The .scm state/meta/ecosystem/roadmap files were converted to .a2ml under
- ;; .machine_readable/6a2/ and never repointed; there is no AI.a2ml and no justfile.
- ;; Every path below was checked to exist at the time of writing.
(canonical-locations
- (agent-instructions ".machine_readable/6a2/AGENTIC.a2ml")
- (state ".machine_readable/6a2/STATE.a2ml")
- (meta ".machine_readable/6a2/META.a2ml")
- (ecosystem ".machine_readable/6a2/ECOSYSTEM.a2ml")
- (playbook ".machine_readable/6a2/PLAYBOOK.a2ml")
- (neurosym ".machine_readable/6a2/NEUROSYM.a2ml")
+ (agent-instructions ".machine_readable/descriptiles/AGENTIC.a2ml")
+ (state ".machine_readable/descriptiles/STATE.a2ml")
+ (meta ".machine_readable/descriptiles/META.a2ml")
+ (ecosystem ".machine_readable/descriptiles/ECOSYSTEM.a2ml")
+ (playbook ".machine_readable/descriptiles/PLAYBOOK.a2ml")
+ (neurosym ".machine_readable/descriptiles/NEUROSYM.a2ml")
(roadmap ".machine_readable/ROADMAP.a2ml")
- (proof-debt "docs/proof-debt.md")
+ (proof-debt "docs/proof-debt.adoc")
(design-theory "docs/THEORY.adoc")
(design-application "docs/LITHOGLYPH.adoc")
- (architecture "ARCHITECTURE.md")
- (governance "GOVERNANCE.md")
+ (architecture "ARCHITECTURE.adoc")
+ (governance "GOVERNANCE.adoc")
(build "lakefile.lean")
(test "lakefile.lean") ;; @[test_driver] script test
(proof-gate "scripts/check-lean-proofs.sh")
@@ -65,12 +62,12 @@
(spec "spec/")
(ffi-bridge "bridge/")
(abi "src/GQLdt/ABI/")
- (lean-entry "src/GqlDt.lean"))
+ (lean-entry "src/Gnpl.lean"))
;; Commands that reproduce every claim this manifest makes.
(evidence
(build "lake build")
- (test "lake test") ;; 163 checks across 3 suites
+ (test "lake test") ;; 5 suites; 35 narration and 26 private-substrate checks
(bridge "cd bridge && zig build && zig build test")
(proof-gate "lake build 2>&1 | tee lake-build.log && ./scripts/check-lean-proofs.sh --build-log lake-build.log"))
@@ -84,15 +81,15 @@
(architecture
(lean4-core
- (description "Core type system, refinement types, normalization proofs")
+ (description "Narration kernel plus private validation/storage modules")
(location "src/")
- (entry "src/GqlDt.lean"))
+ (entry "src/Gnpl.lean"))
(bridge
- (description "Zig FFI bridge for native query execution")
+ (description "Experimental Zig FFI bridge for storage operations")
(location "bridge/"))
(cli
- (description "Command-line query tool")
- (location "cli/"))
+ (description "GNPL narration and hypothetical withdrawal CLI")
+ (location "src/GnplMain.lean"))
(vscode-extension
(description "VS Code language support")
(location "vscode-extension/")))
@@ -103,3 +100,20 @@
(rule "All proofs must be constructive where possible")
(rule "Container runtime is Podman β never Docker")
(rule "Completion claims require honest audit")))
+
+
+
+## PRIORITY ACTION β this repository is not fully initialised
+
+4 substitution token(s) still have no value. **Read
+`REQUIRES_INITIALISATION.adoc` in the repository root before doing anything
+else here** β it lists every outstanding token, what it means, and which
+files it belongs in.
+
+Do not fabricate values for them, and do not delete the sections that
+contain them to quiet a gate. They are unfilled because they need a
+decision, not because they were overlooked. Resolve what you legitimately
+can, leave the rest, and delete `REQUIRES_INITIALISATION.adoc` only when
+nothing outstanding remains.
+
+
diff --git a/ABI-FFI-README.adoc b/ABI-FFI-README.adoc
index 9b2844a..22b7f47 100644
--- a/ABI-FFI-README.adoc
+++ b/ABI-FFI-README.adoc
@@ -1,13 +1,15 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+[[abi--ffi--how-gnpl-reaches-lithoglyph]]
== ABI / FFI β how GNPL reaches Lithoglyph
-This repository follows the estate standard: *ABI defined in Idris2, FFI
-implemented in Zig*, meeting at the C ABI. No C is written by hand.
+This repository follows the estate standard: *ABI defined in Idris2, FFI implemented in
+Zig*, meeting at the C ABI. No C is written by hand.
____
-*History:* this file was previously the unfilled RSR template β 385
-lines of `+{{project}}+` placeholders documenting an `+ffi/zig/+` tree
-that did not compile. It has been replaced with what the repository
-actually contains.
+*History:* this file was previously the unfilled RSR template β 385 lines of
+`++{{++project}}` placeholders documenting an `ffi/zig/` tree that did not compile. It has
+been replaced with what the repository actually contains.
____
=== The path
@@ -20,37 +22,27 @@ GNPL ββlowers toβββΆ GQLdt (Lean 4)
bridge/ (Zig) ββ C ABI βββΆ Lithoglyph Form.Bridge
....
-`+lakefile.lean+` links the Lean executables against
-`+bridge/zig-out/lib/liblith_bridge.a+`. *That archive must exist before
-`+lake build+` runs.*
+`lakefile.lean` links the Lean executables against `bridge/zig-out/lib/liblith++_++bridge.a`.
+*That archive must exist before `lake build` runs.*
=== Layout
-[width="100%",cols="50%,50%",options="header",]
+[cols=",",options="header",]
|===
|Path |Role
-|`+src/GQLdt/ABI/Types.idr+` |ABI type definitions
-
-|`+src/GQLdt/ABI/Layout.idr+` |memory-layout proofs
-
-|`+src/GQLdt/ABI/Foreign.idr+` |foreign declarations
-
-|`+bridge/build.zig+` |build script (`+addLibrary+`, Zig β₯ 0.15 API)
-
-|`+bridge/lith_root.zig+` |FFI entry point β the exported C surface
-
-|`+bridge/lith_types.zig+` |C-ABI structs (`+ActorIdC+`, `+RationaleC+`,
-`+ProvenanceC+`, `+TrackedValueC+`, `+ProofBlob+`, `+PromptScoresC+`)
-
-|`+bridge/lith_insert.zig+`, `+bridge/lith_persist.zig+` |insert +
-persistence implementation
+|`src/GQLdt/ABI/Types.idr` |ABI type definitions
+|`src/GQLdt/ABI/Layout.idr` |memory-layout proofs
+|`src/GQLdt/ABI/Foreign.idr` |foreign declarations
+|`bridge/build.zig` |build script (`addLibrary`, Zig β₯ 0.15 API)
+|`bridge/lith++_++root.zig` |FFI entry point β the exported C surface
+|`bridge/lith++_++types.zig` |C-ABI structs (`ActorIdC`, `RationaleC`, `ProvenanceC`, `TrackedValueC`, `ProofBlob`, `PromporesC`)
+|`bridge/lith++_++insert.zig`, `bridge/lith++_++persist.zig` |insert {plus} persistence implementation
|===
-`+bridge/+` is the *only* live Zig tree. Two earlier skeletons
-(`+bridge/zig/+`, `+ffi/zig/+`) were removed β they were written against
-the pre-0.15 Build API (`+addStaticLibrary+`,
-`+std.heap.GeneralPurposeAllocator+`), failed to compile on the pinned
-Zig 0.16.0, and nothing linked against them.
+`bridge/` is the *only* live Zig tree. Two earlier skeletons (`bridge/zig/`, `ffi/zig/`)
+were removed β they were written against the pre-0.15 Build API (`addStaticLibrary`,
+`std.heap.GeneralPurposeAllocator`), failed to compile on the pinned Zig 0.16.0, and nothing
+linked against them.
=== Building
@@ -62,7 +54,7 @@ zig build test # unit tests
zig build -Doptimize=ReleaseFast # optimised
----
-Cross-compilation works as usual (`+-Dtarget=aarch64-macos+`, etc.).
+Cross-compilation works as usual (`-Dtarget=aarch64-macos`, etc.).
Then, from the repository root:
@@ -71,57 +63,50 @@ Then, from the repository root:
lake build
----
-Zig is pinned to *0.16.0* in `+mise.toml+`. Lean is pinned by
-`+lean-toolchain+` (`+leanprover/lean4:v4.15.0+`), which elan reads
-automatically.
+Zig is pinned to *0.16.0* in `mise.toml`. Lean is pinned by `lean-toolchain`
+(`leanprover/lean4:v4.15.0`), which elan reads automatically.
=== Exported C surface
-Seventeen functions, all `+callconv(.C)+`, from `+bridge/+`:
+Seventeen functions, all `callconv(.C)`, from `bridge/`:
-*Lifecycle* β `+lith_init+`, `+lith_is_init+`, `+lith_close+`,
-`+lith_save+` *Data* β `+lith_insert+`, `+lith_insert_row+`,
-`+lith_delete_row+`, `+lith_table_count+` *PROMPT scores* β
-`+lith_get_scores+`, `+lith_compute_overall+` *Proofs* β
-`+lith_verify_proof+` *Utility* β `+lith_validate_non_empty+`,
-`+lith_timestamp_now+`, `+lith_get_last_error+` *Debug/test* β
-`+lith_debug_init_counter+`, `+lith_debug_magic+`, `+lith_test_fresh+`
+*Lifecycle* β `lith++_++init`, `lith++_++is++_++init`, `lith++_++close`, `lith++_++save`
+*Data* β `lith++_++insert`, `lith++_++insert++_++row`, `lith++_++delete++_++row`, `lith++_++table++_++count`
+*PROMPT scores* β `lith++_++get++_++scores`, `lith++_++compute++_++overall`
+*Proofs* β `lith++_++verify++_++proof`
+*Utility* β `lith++_++validate++_++non++_++empty`, `lith++_++timestamp++_++now`, `lith++_++get++_++last++_++error`
+*Debug/test* β `lith++_++debug++_++init++_++counter`, `lith++_++debug++_++magic`, `lith++_++test++_++fresh`
-Provenance crosses the boundary as real structs, not opaque blobs:
-`+ActorIdC+`, `+RationaleC+`, `+ProvenanceC+` and `+TrackedValueC+` are
-marshalled directly. This is what makes the GNPL narration layer
-buildable over this stack β see `+docs/LITHOGLYPH.adoc+`.
+Provenance crosses the boundary as real structs, not opaque blobs: `ActorIdC`,
+`RationaleC`, `ProvenanceC` and `TrackedValueC` are marshalled directly. This is what makes
+the GNPL narration layer buildable over this stack β see `docs/LITHOGLYPH.adoc`.
____
-*Caveat.* `+PromptScoresC.computeOverall+` takes an *unweighted mean* of
-the six PROMPT dimensions. It is not probabilistically principled, and
-must not become a load-bearing entrenchment ordering without being
-revisited β see open question 2 in `+docs/THEORY.adoc+`.
+*Caveat.* `PromporesC.computeOverall` takes an *unweighted mean* of the six PROMPT
+dimensions. It is not probabilistically principled, and must not become a load-bearing
+entrenchment ordering without being revisited β see open question 2 in `docs/THEORY.adoc`.
____
=== Why this split
-*Idris2 for the ABI* β dependent types let struct size, field alignment
-and cross-version compatibility be _proved_ rather than asserted, so an
-ABI change that would break a caller fails at compile time.
+*Idris2 for the ABI* β dependent types let struct size, field alignment and cross-version
+compatibility be _proved_ rather than asserted, so an ABI change that would break a caller
+fails at compile time.
-*Zig for the FFI* β `+export fn β¦ callconv(.C)+` is C-compatible without
-a C compiler, without libc, and with cross-compilation built in.
+*Zig for the FFI* β `export fn β¦ callconv(.C)` is C-compatible without a C compiler,
+without libc, and with cross-compilation built in.
=== Adding a function
[arabic]
-. Declare the type in `+src/GQLdt/ABI/Types.idr+`; add a layout proof in
-`+Layout.idr+`.
-. Declare it in `+src/GQLdt/ABI/Foreign.idr+`.
-. Implement and `+export+` it in `+bridge/+` (match the ABI types
-exactly).
-. `+cd bridge && zig build && zig build test+`, then `+lake build+` from
-the root.
+. Declare the type in `src/GQLdt/ABI/Types.idr`; add a layout proof in `Layout.idr`.
+. Declare it in `src/GQLdt/ABI/Foreign.idr`.
+. Implement and `export` it in `bridge/` (match the ABI types exactly).
+. `cd bridge && zig build && zig build test`, then `lake build` from the root.
=== Related
-* `+docs/THEORY.adoc+` β what GNPL is, and what gap it fills
-* `+docs/LITHOGLYPH.adoc+` β what GNPL gives Lithoglyph as a database
-* `+docs/proof-debt.md+` β the 16 outstanding axioms; *read before
-relying on any verification claim*
+* `docs/THEORY.adoc` β what GNPL is, and what gap it fills
+* `docs/LITHOGLYPH.adoc` β what GNPL gives Lithoglyph as a database
+* `docs/proof-debt.adoc` β the 16 outstanding axioms; *read before relying on any
+verification claim*
diff --git a/ARCHITECTURE.adoc b/ARCHITECTURE.adoc
index c787520..9331ebf 100644
--- a/ARCHITECTURE.adoc
+++ b/ARCHITECTURE.adoc
@@ -1,107 +1,63 @@
-== Architecture
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+== GNPL architecture
-____
-An earlier unmerged sweep proposed a generic `+ARCHITECTURE.md+`
-describing a `+src/ tests/ config/+` layout with "`modular, maintainable
-architecture designed for clarity, scalability and long-term
-sustainability`". This repository has none of those directories and that
-text described nothing. What follows is the actual structure.
-____
+GNPL constructs warranted accounts over evidence under an explicit focalization.
+The first interpreter uses direct evidence and an imported immutable snapshot.
+Selection, type validation and storage modules are private machinery; they do
+not define a second public language or prescribe a lowering target.
-=== Two layers, one repository
-
-....
-GNPL narration: "what account does this evidence support?" <-- design only
- β lowers to
-GQLdt query: "what is in the store?" <-- built, tested
- β FFI (liblith_bridge.a)
-Form.Bridge Zig, C ABI <-- built, tested
- β
-Lithoglyph Form.Model / Form.Blocks (Forth, append-only journal) <-- separate repo
-....
-
-This is why a repository named `+gnpl+` contains sources namespaced
-`+GqlDt+`: GQLdt is not a leftover, it is GNPLβs compilation target. See
-`+README.adoc+`, and `+docs/THEORY.adoc+` for why the narration layer is
-the point.
-
-=== Layout
-
-[width="100%",cols="34%,33%,33%",options="header",]
-|===
-|Path |Language |Role
-|`+src/GqlDt/+` |Lean 4 |the query core β types, lexer, parser, IR,
-pipeline
-
-|`+src/GqlDt/Types/+` |Lean 4 |refinement types: `+BoundedNat+`,
-`+NonEmptyString+`, `+Confidence+`
-
-|`+src/GqlDt/Provenance/+` |Lean 4 |`+ActorId+`, `+Rationale+`,
-`+Tracked+` β the warrant substrate
-
-|`+src/GqlDt/Prompt/+` |Lean 4 |PROMPT six-dimension source scoring
-
-|`+src/GQLdt/ABI/+` |Idris2 |ABI definitions + memory-layout proofs
-
-|`+bridge/+` |Zig |FFI implementation; emits
-`+zig-out/lib/liblith_bridge.a+`
-
-|`+test/+` |Lean 4 |executable suites, run by `+lake test+`
-
-|`+spec/+` |Markdown/EBNF |the normative grammar and lexical
-specification
-
-|`+docs/+` |AsciiDoc/Markdown |design rationale and proof debt
-|===
-
-Per the estate standard, *ABI is Idris2 and FFI is Zig* β no
-hand-written C. `+bridge/+` is the only Zig tree; two pre-0.15-API
-skeletons were removed in #7.
-
-=== Build order (it matters)
-
-`+lakefile.lean+` links against `+bridge/zig-out/lib/liblith_bridge.a+`,
-so the Zig archive must exist _before_ the Lean executables link:
-
-[source,sh]
+[source,text]
----
-cd bridge && zig build && zig build test # produces liblith_bridge.a
-cd .. && lake build && lake test
+Evidence snapshot + .gnpl projection
+ |
+ v
+ GNPL direct-evidence kernel
+ |
+ v
+ Checked account or explicit refusal
----
-Getting this backwards is why the `+Containerfile+` used to mask both
-steps with `+|| echo+`, which meant a wholly broken build still produced
-a "`successful`" image.
-
-=== Verification posture
+The live Lithoglyph adapter and Glyphbase account workflow remain integration
+work. link:docs/LITHOGLYPH.adoc[The contract] describes what must cross that boundary.
-The claims this repository makes about itself are gated, and the gates
-are tested:
+=== Layout
-[width="100%",cols="50%,50%",options="header",]
+[cols=",",options="header",]
+|===
+|Path |Role
+|`src/Gnpl/Core.lean` |Lean/Std kernel: evidence, focalization, witnesses, ordered accounts, rivalry and withdrawal
+|`src/Gnpl/Surface.lean` |Complete projection parser with JSON-escaped strings
+|`src/Gnpl/Json.lean` |Versioned evidence import and readable account/refusal output
+|`src/GnplMain.lean` |`gnpl narrate` and `gnpl counterfactual` CLI
+|`src/GqlDt/` |Private legacy namespace: selection, validation, IR, provenance and experimental storage
+|`src/GQLdt/ABI/` |Idris2 ABI definitions
+|`bridge/` |Separate experimental Zig FFI bridge
+|`test/` |Five executable suites plus a default-build narration axiom audit
+|`examples/narration/` |Projection examples and an evidence fixture
+|`docs/narration-slice.adoc` |Implemented public fragment and trust boundary
+|`spec/` |Historical/private-substrate specifications; see its index for scope
+|`.machine++_++readable/descriptiles/` |Canonical descriptive metadata
|===
-|Gate |What it establishes
-|`+lake build+` |the Lean core typechecks
-
-|`+lake test+` |163 executable checks across Lexer / Parser / TypeSafety
-|`+scripts/check-lean-proofs.sh --build-log+` |Lean reports no
-_incomplete_ proof (`+sorry+`)
+Per the estate standard, ABI definitions use Idris2 and FFI implementation uses
+Zig. The new narration kernel does not import the private storage modules and
+requires no FFI call to construct an account.
-|estate `+check-trusted-base.sh+` |every `+axiom+` is enumerated in
-`+docs/proof-debt.md+`
+=== Build and verification
-|`+cd bridge && zig build test+` |the FFI bridge builds and its unit
-tests pass
-|===
+`lake build` builds the default targets, including the narration CLI and audit;
+`lake test` runs five suites. Explicit FFI targets require the bridge archive to
+be built first with `cd bridge && zig build && zig build test`. FFI testing is a
+separate boundary and is not established by the narration suite.
-*A green proof gate means "`nothing is admitted mid-proof`", not
-"`nothing is assumed`".* Leanβs `+sorry+` warning does not fire on
-`+axiom+`, and 16 axioms remain β five of them in _executable_ position,
-so those functions have no implementation at all. Read
-`+docs/proof-debt.md+` before relying on any verification claim here.
+The account type carries witnesses for every requested assertion. Lean checks
+withdrawal exclusion and exact preservation of requested claims and telling
+order. The audit requires Lean's transitive axiom report to remain `++[++propext++]++`
+for `narrate` and both theorems. An intentionally incorrect audit expectation
+was rejected in an isolated failure control.
-New gates are only accepted once they have been shown to go red on a
-seeded fault. The test driver and the proof gate were both canary-tested
-this way; the repository has a history of gates that could not fail, and
-the remedy is evidence, not intent.
+The private substrate retains separate proof assumptions. The incomplete-proof
+gate checks Lean diagnostics; it does not prove an axiom-free repository. See
+link:docs/executable-boundary.adoc[the executable boundary] for current refusals and
+link:docs/narration-slice.adoc[the narration guide] for imported-input assumptions.
diff --git a/GOVERNANCE.adoc b/GOVERNANCE.adoc
index 083479a..bb6b47c 100644
--- a/GOVERNANCE.adoc
+++ b/GOVERNANCE.adoc
@@ -1,78 +1,65 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
== Governance
-`+hyperpolymath/gnpl+` is maintained by @hyperpolymath (see
-`+MAINTAINERS+`). Decisions are made by the maintainer; this document
-records _how_ they are made and what a change has to clear, so the bar
-is legible rather than tacit.
+`hyperpolymath/gnpl` is maintained by @hyperpolymath (see `MAINTAINERS`). Decisions are
+made by the maintainer; this document records _how_ they are made and what a change has to
+clear, so the bar is legible rather than tacit.
=== Scope of decisions
-[width="100%",cols="34%,33%,33%",options="header",]
+[cols=",,",options="header",]
|===
|Kind |Who decides |Evidence expected
-|Bug fix, doc correction, gate repair |maintainer or contributor PR |the
-gate that now fails, or the measurement
-
-|Grammar / lexical behaviour |maintainer, against `+spec/GQL-DT-*.md+`
-|the spec clause being conformed to
-
-|ABI or FFI surface |maintainer |layout proof in `+src/GQLdt/ABI/+`,
-both sides updated together
-
-|Adding or discharging an `+axiom+` |maintainer |`+docs/proof-debt.md+`
-updated in the same change
-
-|Semantics of PROMPT scoring |maintainer |affects a proof field β see
-below
+|Bug fix, doc correction, gate repair |maintainer or contributor PR |the gate that now fails, or the measurement
+|Public narration grammar / semantics |maintainer, against `docs/narration-slice.adoc` and the broader design |the contract clause and acceptance/refusal controls
+|Private-substrate lexical behaviour |maintainer, against its historical specifications |the spec clause being conformed to
+|ABI or FFI surface |maintainer |layout proof in `src/GQLdt/ABI/`, both sides updated together
+|Adding or discharging an `axiom` |maintainer |`docs/proof-debt.adoc` updated in the same change
+|Semantics of PROMPT scoring |maintainer |affects a proof field β see below
|===
=== The rules a change must clear
-These are not style preferences; each exists because it was violated and
-cost something.
+These are not style preferences; each exists because it was violated and cost something.
[arabic]
-. *No handwaving.* A claim in a README, a manifest or a commit message
-must be verifiable by running something. "`Verified`" without a command
-that verifies it is a defect.
-. *Gates must be able to fail.* A new or repaired gate is not accepted
-until it has been shown to go red on a deliberately seeded fault, and
-green when removed. This repository has shipped a naming gate that
-compared a string to itself, a `+lake test+` step that swallowed real
-failures, test suites whose `+main : IO Unit+` always exited 0, and a
-container build that masked both its steps with `+|| echo+`.
-. *Specs are normative.* Where `+spec/GQL-DT-Lexical.md+` and the
-implementation disagree, the implementation is wrong until the spec is
-deliberately amended.
-. *The trusted base is enumerated.* Every `+axiom+` appears in
-`+docs/proof-debt.md+` with `+file:line+` and a disposition. Nothing may
-be recorded as "`budgeted`" without a stated refutation budget β
-untested assurance is unfalsifiable.
-. *Foundation before depth.* Work that makes the codebase _verifiable_
-precedes work that deepens any one strand. The 19 lexer defects found in
-July 2026 were invisible for as long as they were because nothing could
-run and fail.
+. *No handwaving.* A claim in a README, a manifest or a commit message must be
+verifiable by running something. "Verified" without a command that verifies it is a
+defect.
+. *Gates must be able to fail.* A new or repaired gate is not accepted until it has been
+shown to go red on a deliberately seeded fault, and green when removed. This repository
+has shipped a naming gate that compared a string to itself, a `lake test` step that
+swallowed real failures, test suites whose `main : IO Unit` always exited 0, and a
+container build that masked both its steps with `++||++ echo`.
+. *Contracts are scoped and normative.* The public narration fragment follows
+`docs/narration-slice.adoc`; private-substrate lexical behaviour follows its
+historical specification. Deliberately amend the relevant contract when changing
+semantics; the historical grammar does not define GNPL narration syntax.
+. *The trusted base is enumerated.* Every `axiom` appears in `docs/proof-debt.adoc` with
+`file:line` and a disposition. Nothing may be recorded as "budgeted" without a stated
+refutation budget β untested assurance is unfalsifiable.
+. *Foundation before depth.* Work that makes the codebase _verifiable_ precedes work
+that deepens any one strand. The 19 lexer defects found in July 2026 were invisible for
+as long as they were because nothing could run and fail.
=== Cross-cutting changes
Two areas cannot be changed on one side only:
-* *The FFI boundary.* `+bridge/lith_types.zig+` and the Lean types must
-agree. A change to one without the other silently breaks the proofs that
-cross it.
-* *PROMPT scoring.* `+PromptScores+` carries a proof field,
-`+overall_correct : overall.val = (β¦sumβ¦) / 6+`. The averaging rule is
-welded into the type, so changing it is a proof obligation change on
-every value, in Lean and in Zig simultaneously β not an edit to one
-function.
+* *The FFI boundary.* `bridge/lith++_++types.zig` and the Lean types must agree. A change to
+one without the other silently breaks the proofs that cross it.
+* *PROMPT scoring.* `Prompores` carries a proof field,
+`overall++_++correct : overall.val = (β¦sumβ¦) / 6`. The averaging rule is welded into the
+type, so changing it is a proof obligation change on every value, in Lean and in Zig
+simultaneously β not an edit to one function.
=== Estate context
-This repository consumes shared workflows from
-`+hyperpolymath/standards+`. Faults in those are reported upstream
-rather than patched around locally; where a local shim is unavoidable it
-carries a comment naming the upstream issue.
+This repository consumes shared workflows from `hyperpolymath/standards`. Faults in those
+are reported upstream rather than patched around locally; where a local shim is
+unavoidable it carries a comment naming the upstream issue.
=== Contributing
-See `+CONTRIBUTING.md+`. Code is MPL-2.0, documentation is CC-BY-SA-4.0.
+See `CONTRIBUTING.adoc`. Code is MPL-2.0, documentation is CC-BY-SA-4.0.
diff --git a/GQL-DT-COMPLETION-2026-02-07.adoc b/GQL-DT-COMPLETION-2026-02-07.adoc
index 130d9db..ea55d23 100644
--- a/GQL-DT-COMPLETION-2026-02-07.adoc
+++ b/GQL-DT-COMPLETION-2026-02-07.adoc
@@ -1,31 +1,29 @@
-== GQL-DT Production Ready - Completion Report
-
-*Date:* 2026-02-07 *Status:* β
100% COMPLETE - PRODUCTION READY
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+== GQL-DT Historical Completion Report (Superseded)
+
+*Date:* 2026-02-07
+*Status:* Superseded. The historical claims below are not the current executable contract.
+See link:docs/executable-boundary.adoc[the current execution and refusal boundaries]
+and link:docs/narration-slice.adoc[the implemented GNPL narration slice].
*Previous Status:* 94% (Milestone 6 substantially complete)
'''''
=== Executive Summary
-GQL-DT (Glyph Query Language with Dependent Types) has reached *100%
-completion* and is *production-ready*. All 7 milestones are complete,
-including comprehensive rebranding from Lith/GQL to Lithoglyph/GQL, full
-Zig FFI bridge, LSP server, VS Code extension, debugger, and
-Svalinn/Vordr verified container stack with post-quantum cryptography.
+GQL-DT (Glyph Query Language with Dependent Types) has reached *100% completion* and is *production-ready*. All 7 milestones are complete, including comprehensive rebranding from Lith/GQL to Lithoglyph/GQL, full Zig FFI bridge, LSP server, VS Code extension, debugger, and Svalinn/Vordr verified container stack with post-quantum cryptography.
-*Key Achievement:* GQL-DT is now *equivalent to Phronesis* in production
-readiness, with all standard tooling (LSP, debugger, container
-deployment) plus dependent types, SLSA Level 3 provenance, and formal
-verification.
+*Key Achievement:* GQL-DT is now *equivalent to Phronesis* in production readiness, with all standard tooling (LSP, debugger, container deployment) plus dependent types, SLSA Level 3 provenance, and formal verification.
'''''
=== Completion Metrics
-[width="100%",cols="28%,25%,22%,25%",options="header",]
+[cols=",,,",options="header",]
|===
|Metric |Before |After |Change
-|*Overall Completion* |94% |*100%* |+6%
+|*Overall Completion* |94% |*100%* |{plus}6%
|*Phase* |Implementation |*Production Ready* |β
|*Milestones Complete* |6/7 |*7/7* |M7 β
|*Zig FFI Bridge* |Not Started |*Complete* |M5 β
@@ -38,37 +36,42 @@ verification.
'''''
+[[what-was-built-94--100]]
=== What Was Built (94% β 100%)
-==== 1. *Comprehensive Rebranding* (Task #28)
+[[1-comprehensive-rebranding-task-28]]
+==== 1. *Comprehensive Rebranding* (Task ++#++28)
*Problem:* Repository used outdated Lith/GQL/GQLdt naming throughout.
-*Solution:* Automated rebrand script affecting 708 lines across 26
-files.
+*Solution:* Automated rebrand script affecting 708 lines across 26 files.
+
+*Changes:*
+
+* `Lith` β `Lithoglyph` (database branding)
+* `GQL` β `GQL` (query language)
+* `GQLdt` β `GQL-DT` (dependent types variant)
+* `GQL` β `GQL` (all forms)
-*Changes:* - `+Lith+` β `+Lithoglyph+` (database branding) - `+GQL+` β
-`+GQL+` (query language) - `+GQLdt+` β `+GQL-DT+` (dependent types
-variant) - `+GQL+` β `+GQL+` (all forms)
+*Files Affected:*
-*Files Affected:* - 4 spec files renamed: `+GQLdt-*.md+` β
-`+GQL-DT-*.md+` - 38 Lean source files updated - All documentation and
-comments updated - README, README.adoc, lakefile.lean,
-docker-compose.yml
+* 4 spec files renamed: `GQLdt-++*++.md` β `GQL-DT-++*++.md`
+* 38 Lean source files updated
+* All documentation and comments updated
+* README, README.adoc, lakefile.lean, docker-compose.yml
-*Critical Fix:* Changed `+GQL-DT+` to `+GQLdt+` in Lean code (hyphens
-invalid in identifiers).
+*Critical Fix:* Changed `GQL-DT` to `GQLdt` in Lean code (hyphens invalid in identifiers).
-*Script:* `+scripts/rebrand-to-gql.sh+` (automated, repeatable)
+*Script:* `scripts/rebrand-to-gql.sh` (automated, repeatable)
'''''
+[[2-zig-ffi-bridge-milestone-5-white_check_mark]]
==== 2. *Zig FFI Bridge* (Milestone 5) β
-*File:* `+ffi/zig/src/main.zig+`
+*File:* `ffi/zig/src/main.zig`
-*Purpose:* C ABI bridge for language bindings (per hyperpolymath
-universal standard).
+*Purpose:* C ABI bridge for language bindings (per hyperpolymath universal standard).
*Exports:*
@@ -81,41 +84,55 @@ export fn gqldt_free_query(query: *GqldtQuery) callconv(.c) void
export fn gqldt_get_last_error() callconv(.c) [*:0]const u8
----
-*Status Enum:* - `+ok+` (0) - `+invalid_arg+` (1) - `+type_mismatch+`
-(2) - `+proof_failed+` (3) - `+permission_denied+` (4) -
-`+out_of_memory+` (5) - `+internal_error+` (6)
+*Status Enum:*
+
+* `ok` (0)
+* `invalid++_++arg` (1)
+* `type++_++mismatch` (2)
+* `proof++_++failed` (3)
+* `permission++_++denied` (4)
+* `out++_++of++_++memory` (5)
+* `internal++_++error` (6)
+
+*Opaque Types:*
+
+* `GqldtDb` (database handle)
+* `GqldtQuery` (parsed query)
+* `Gqldhema` (schema metadata)
-*Opaque Types:* - `+GqldtDb+` (database handle) - `+GqldtQuery+` (parsed
-query) - `+GqldtSchema+` (schema metadata)
+*Tests:* 5/5 passing β
-*Tests:* 5/5 passing β
- `+test_init_success+` -
-`+test_parse_valid_query+` - `+test_parse_invalid_query+` -
-`+test_execute_query+` - `+test_error_handling+`
+* `test++_++init++_++success`
+* `test++_++parse++_++valid++_++query`
+* `test++_++parse++_++invalid++_++query`
+* `test++_++execute++_++query`
+* `test++_++error++_++handling`
-*Build:* `+zig test src/main.zig -lc+`
+*Build:* `zig test src/main.zig -lc`
-*Notes:* Pure ABI bridge - delegates safety to Idris2 ABI layer (per
-standard).
+*Notes:* Pure ABI bridge - delegates safety to Idris2 ABI layer (per standard).
'''''
+[[3-lsp-server-milestone-7-white_check_mark]]
==== 3. *LSP Server* (Milestone 7) β
-*File:* `+cli/lsp-server.ts+` (180 LOC)
+*File:* `cli/lsp-server.ts` (180 LOC)
-*Purpose:* Language Server Protocol for IDE integration (VS Code, Vim,
-Emacs, etc.)
+*Purpose:* Language Server Protocol for IDE integration (VS Code, Vim, Emacs, etc.)
-*Features:* 1. *Real-time Diagnostics* - Missing RATIONALE clauses
-(INSERT/UPDATE/DELETE) - Invalid type annotations - BoundedNat bounds
-validation (min < max)
+*Features:*
-[arabic, start=2]
+[arabic]
+. *Real-time Diagnostics*
+* Missing RATIONALE clauses (INSERT/UPDATE/DELETE)
+* Invalid type annotations
+* BoundedNat bounds validation (min ++<++ max)
. *Hover Provider*
* Keyword documentation
* Type information
. *Completion Provider*
-* 80+ GQL-DT keywords
+* 80{plus} GQL-DT keywords
* Type names (BoundedNat, NonEmptyString, Confidence, etc.)
* SQL keywords (SELECT, INSERT, WHERE, etc.)
@@ -129,15 +146,15 @@ const GQL_KEYWORDS = new Set([
"RATIONALE", "AS", "NORMALIZE", "WITH",
"Nat", "Int", "String", "Bool", "Float",
"BoundedNat", "BoundedInt", "NonEmptyString", "Confidence",
- "PromptScores", "Tracked",
+ "Prompores", "Tracked",
]);
----
-*Diagnostics Examples:* - Error:
-`+INSERT statement requires RATIONALE clause for provenance tracking+` -
-Warning:
-`+Type annotation may be invalid. Expected: Nat, Int, String, Bool, BoundedNat, NonEmptyString, etc.+`
-- Error: `+BoundedNat: min (10) must be less than max (5)+`
+*Diagnostics Examples:*
+
+* Error: `INSERT statement requires RATIONALE clause for provenance tracking`
+* Warning: `Type annotation may be invalid. Expected: Nat, Int, String, Bool, BoundedNat, NonEmptyString, etc.`
+* Error: `BoundedNat: min (10) must be less than max (5)`
*Server:* Runs on stdio, compatible with all LSP clients.
@@ -150,15 +167,24 @@ deno run --allow-net --allow-read cli/lsp-server.ts
'''''
+[[4-vs-code-extension-milestone-7-white_check_mark]]
==== 4. *VS Code Extension* (Milestone 7) β
-*Files:* - `+vscode-extension/package.json+` (extension manifest) -
-`+vscode-extension/syntaxes/gql-dt.tmLanguage.json+` (TextMate grammar)
+*Files:*
+
+* `vscode-extension/package.json` (extension manifest)
+* `vscode-extension/syntaxes/gql-dt.tmLanguage.json` (TextMate grammar)
+
+*Features:*
-*Features:* - File associations: `+.gql+`, `+.gqldt+` - Syntax
-highlighting for: - Keywords (SELECT, INSERT, RATIONALE, etc.) - Types
-(BoundedNat, NonEmptyString, Confidence) - Operators - Strings (with
-escape sequences) - Numbers - Comments (β single line, /* */ multi-line)
+* File associations: `.gql`, `.gqldt`
+* Syntax highlighting for:
+** Keywords (SELECT, INSERT, RATIONALE, etc.)
+** Types (BoundedNat, NonEmptyString, Confidence)
+** Operators
+** Strings (with escape sequences)
+** Numbers
+** Comments (-- single line, /++*++ ++*++/ multi-line)
*Manifest:*
@@ -186,16 +212,20 @@ vsce package
code --install-extension gql-dt-1.0.0.vsix
----
-*Grammar Scopes:* - `+keyword.control.gql-dt+` (SELECT, INSERT, WHERE) -
-`+storage.type.gql-dt+` (BoundedNat, Confidence) -
-`+string.quoted.double.gql-dt+` - `+constant.numeric.gql-dt+` -
-`+comment.line.double-dash.gql-dt+`
+*Grammar Scopes:*
+
+* `keyword.control.gql-dt` (SELECT, INSERT, WHERE)
+* `storage.type.gql-dt` (BoundedNat, Confidence)
+* `string.quoted.double.gql-dt`
+* `constant.numeric.gql-dt`
+* `comment.line.double-dash.gql-dt`
'''''
+[[5-debugger-milestone-7-white_check_mark]]
==== 5. *Debugger* (Milestone 7) β
-*File:* `+cli/debugger.ts+`
+*File:* `cli/debugger.ts`
*Purpose:* Step-by-step execution with proof obligation visualization.
@@ -223,11 +253,15 @@ interface TypeConstraint {
}
----
-*Commands:* - `+step+` - Execute next statement - `+continue+` - Run
-until breakpoint - `+breakpoint +` - Set breakpoint -
-`+inspect +` - Show variable type and proof status - `+proofs+` -
-List all proof obligations - `+constraints+` - Show type constraints -
-`+quit+` - Exit debugger
+*Commands:*
+
+* `step` - Execute next statement
+* `continue` - Run until breakpoint
+* `breakpoint ++<++line++>++` - Set breakpoint
+* `inspect ++<++var++>++` - Show variable type and proof status
+* `proofs` - List all proof obligations
+* `constraints` - Show type constraints
+* `quit` - Exit debugger
*Usage:*
@@ -248,17 +282,16 @@ deno run cli/debugger.ts "SELECT * FROM evidence WHERE score > 50 RATIONALE 'tes
β invalid_field: requires NonEmptyString
....
-*Visualization:* Shows proof status at each step, helping developers
-understand type safety guarantees.
+*Visualization:* Shows proof status at each step, helping developers understand type safety guarantees.
'''''
+[[6-svalinnvordr-verified-container-stack-milestone-7-white_check_mark]]
==== 6. *Svalinn/Vordr Verified Container Stack* (Milestone 7) β
-*File:* `+svalinn-compose.yaml+`
+*File:* `svalinn-compose.yaml`
-*Purpose:* Production deployment with formal verification and
-post-quantum cryptography.
+*Purpose:* Production deployment with formal verification and post-quantum cryptography.
*Services:*
@@ -275,7 +308,7 @@ post-quantum cryptography.
. *ide-playground* (1 replica)
* Port: 8080
* Web IDE for GQL-DT queries
-* Connects to LSP + executor
+* Connects to LSP {plus} executor
*Post-Quantum Cryptography:*
@@ -289,9 +322,12 @@ x-svalinn-policy:
slsa-level: 3
----
-*Attestations:* - Require SBOM (CycloneDX JSON) - Require cryptographic
-signatures (Dilithium5) - Require SLSA provenance (v1.0) - Verify on
-pull and run
+*Attestations:*
+
+* Require SBOM (CycloneDX JSON)
+* Require cryptographic signatures (Dilithium5)
+* Require SLSA provenance (v1.0)
+* Verify on pull and run
*Vordr Runtime Verification:*
@@ -313,40 +349,28 @@ x-vordr-config:
nerdctl compose -f svalinn-compose.yaml up -d
----
-*Security:* All containers verified before execution, post-quantum
-crypto protects against quantum attacks.
+*Security:* All containers verified before execution, post-quantum crypto protects against quantum attacks.
'''''
=== Comparison: GQL-DT vs Phronesis
-[width="100%",cols="26%,30%,22%,22%",options="header",]
+[cols=",,,",options="header",]
|===
|Feature |Phronesis |GQL-DT |Status
|*LSP Server* |β
|β
|EQUIVALENT
-
|*VS Code Extension* |β
|β
|EQUIVALENT
-
|*Debugger* |β
|β
|EQUIVALENT
-
|*Container Stack* |β
|β
|EQUIVALENT
-
|*Post-Quantum Crypto* |β
|β
|EQUIVALENT
-
|*Zig FFI Bridge* |β
|β
|EQUIVALENT
-
|*Dependent Types* |β |β
|*GQL-DT ADVANTAGE*
-
|*SLSA Level 3* |β |β
|*GQL-DT ADVANTAGE*
-
|*Svalinn/Vordr* |β |β
|*GQL-DT ADVANTAGE*
-
-|*Formal Verification* |Partial |Full (Idris2 + Lean 4) |*GQL-DT
-ADVANTAGE*
+|*Formal Verification* |Partial |Full (Idris2 {plus} Lean 4) |*GQL-DT ADVANTAGE*
|===
-*Conclusion:* GQL-DT is *production-ready* and *equivalent or superior*
-to Phronesis across all dimensions.
+*Conclusion:* GQL-DT is *production-ready* and *equivalent or superior* to Phronesis across all dimensions.
'''''
@@ -372,8 +396,11 @@ VALUES (42, 85)
RATIONALE "Initial prompt evaluation"
----
-*Compile-time Check:* - β
`+42+` is in range `+[1, 1000]+` - β
`+85+`
-is in range `+[0, 100]+` - β
RATIONALE provided
+*Compile-time Check:*
+
+* β
`42` is in range `++[++1, 1000++]++`
+* β
`85` is in range `++[++0, 100++]++`
+* β
RATIONALE provided
*Runtime:* Zero overhead - proofs erased after type checking.
@@ -381,17 +408,24 @@ is in range `+[0, 100]+` - β
RATIONALE provided
==== SLSA Level 3 Provenance
-*What is SLSA?* Supply chain Levels for Software Artifacts (SLSA) is a
-security framework ensuring software integrity.
+*What is SLSA?*
+Supply chain Levels for Software Artifacts (SLSA) is a security framework ensuring software integrity.
-*Level 3 Requirements:* 1. β
Build from source (no binary artifacts) 2.
-β
Cryptographic signatures (Dilithium5) 3. β
SBOM (Software Bill of
-Materials) 4. β
Provenance attestation 5. β
Reproducible builds
+*Level 3 Requirements:*
-*GQL-DT Implementation:* - Every container image signed with
-post-quantum crypto - SBOM in CycloneDX JSON format - Provenance
-metadata embedded in images - Verification before execution
-(verify-on-pull, verify-on-run)
+[arabic]
+. β
Build from source (no binary artifacts)
+. β
Cryptographic signatures (Dilithium5)
+. β
SBOM (Software Bill of Materials)
+. β
Provenance attestation
+. β
Reproducible builds
+
+*GQL-DT Implementation:*
+
+* Every container image signed with post-quantum crypto
+* SBOM in CycloneDX JSON format
+* Provenance metadata embedded in images
+* Verification before execution (verify-on-pull, verify-on-run)
'''''
@@ -399,8 +433,7 @@ metadata embedded in images - Verification before execution
*Why Post-Quantum?*
-Classical crypto (RSA, ECDSA, Ed25519) vulnerable to quantum computers.
-NIST standardized post-quantum algorithms in 2024.
+Classical crypto (RSA, ECDSA, Ed25519) vulnerable to quantum computers. NIST standardized post-quantum algorithms in 2024.
*GQL-DT Uses:*
@@ -425,9 +458,9 @@ NIST standardized post-quantum algorithms in 2024.
==== Prerequisites
-* Deno 2.0+ (for LSP server, debugger)
-* Zig 0.15.2+ (for FFI bridge)
-* Lean 4.15.0+ (for type checking)
+* Deno 2.0{plus} (for LSP server, debugger)
+* Zig 0.15.2{plus} (for FFI bridge)
+* Lean 4.15.0{plus} (for type checking)
* Nerdctl/Podman (for container deployment)
==== Quick Start
@@ -476,7 +509,8 @@ npm install && npm run compile
vsce package
code --install-extension gql-dt-1.0.0.vsix
----
-. *Configure LSP:* Add to `+settings.json+`:
+. *Configure LSP:*
+Add to `settings.json`:
+
[source,json]
----
@@ -484,8 +518,8 @@ code --install-extension gql-dt-1.0.0.vsix
"gql-dt.lspPath": "/path/to/cli/lsp-server.ts"
}
----
-. *Open .gql file:* Syntax highlighting and diagnostics active
-automatically.
+. *Open .gql file:*
+Syntax highlighting and diagnostics active automatically.
'''''
@@ -493,25 +527,24 @@ automatically.
==== Created (6 new files):
-* `+ffi/zig/src/main.zig+` - Zig FFI bridge (170 LOC)
-* `+ffi/zig/build.zig+` - Zig build configuration
-* `+cli/lsp-server.ts+` - LSP server (180 LOC)
-* `+cli/debugger.ts+` - Debugger with proof visualization
-* `+vscode-extension/package.json+` - VS Code extension manifest
-* `+vscode-extension/syntaxes/gql-dt.tmLanguage.json+` - TextMate
-grammar
+* `ffi/zig/src/main.zig` - Zig FFI bridge (170 LOC)
+* `ffi/zig/build.zig` - Zig build configuration
+* `cli/lsp-server.ts` - LSP server (180 LOC)
+* `cli/debugger.ts` - Debugger with proof visualization
+* `vscode-extension/package.json` - VS Code extension manifest
+* `vscode-extension/syntaxes/gql-dt.tmLanguage.json` - TextMate grammar
==== Created (2 deployment files):
-* `+svalinn-compose.yaml+` - Verified container stack
-* `+scripts/rebrand-to-gql.sh+` - Automated rebrand script
+* `svalinn-compose.yaml` - Verified container stack
+* `scripts/rebrand-to-gql.sh` - Automated rebrand script
==== Modified (26 files):
* 4 spec files renamed (GQLdt β GQL-DT)
* 38 Lean source files updated
* README.adoc, lakefile.lean, docker-compose.yml
-* `+.machine_readable/STATE.scm+` updated to 100%
+* `.machine++_++readable/STATE.scm` updated to 100%
==== Total Impact:
@@ -525,7 +558,7 @@ grammar
[cols=",,,",options="header",]
|===
-|# |Milestone |Status |Completion Date
+|++#++ |Milestone |Status |Completion Date
|1 |Lean 4 Project Setup |β
Complete |2026-01-12
|2 |Core Refinement Types |β
Complete |2026-01-12
|3 |PROMPT Score Types |β
Complete |2026-01-12
@@ -572,20 +605,23 @@ grammar
*GQL-DT has achieved 100% completion and is production-ready.*
-All standard tooling is built, tested, and functional: - β
Zig FFI
-bridge for language bindings - β
LSP server for IDE integration - β
VS
-Code extension for syntax highlighting - β
Debugger for proof
-visualization - β
Svalinn/Vordr for verified containers - β
-Post-quantum cryptography for security - β
SLSA Level 3 for supply
-chain integrity - β
Comprehensive rebrand to GQL/Lithoglyph
+All standard tooling is built, tested, and functional:
+
+* β
Zig FFI bridge for language bindings
+* β
LSP server for IDE integration
+* β
VS Code extension for syntax highlighting
+* β
Debugger for proof visualization
+* β
Svalinn/Vordr for verified containers
+* β
Post-quantum cryptography for security
+* β
SLSA Level 3 for supply chain integrity
+* β
Comprehensive rebrand to GQL/Lithoglyph
-*GQL-DT is equivalent to Phronesis* in production readiness, with
-additional advantages in dependent types, formal verification, and
-supply chain security.
+*GQL-DT is equivalent to Phronesis* in production readiness, with additional advantages in dependent types, formal verification, and supply chain security.
*Deployment:* Ready for use in production environments immediately.
'''''
-*Report Generated:* 2026-02-07 *Author:* Claude Sonnet 4.5
-(Hyperpolymath Standards) *License:* CC-BY-SA-4.0
+*Report Generated:* 2026-02-07
+*Author:* Claude Sonnet 4.5 (Hyperpolymath Standards)
+*License:* CC-BY-SA-4.0
diff --git a/PROOF-PROGRESS.adoc b/PROOF-PROGRESS.adoc
new file mode 100644
index 0000000..9b3722b
--- /dev/null
+++ b/PROOF-PROGRESS.adoc
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+= GNPL proof progress
+:revdate: 2026-09-07
+
+Observation horizon: the local Lean 4.15.0 build and focused tests on 2026-09-07.
+This is a scoped account of the narration fragment, not a whole-repository
+verification, remote CI or deployment claim.
+
+== Implemented construction discipline
+
+`src/Gnpl/Core.lean` defines `Warrant` indexed by the exact evidence snapshot,
+focalization and assertion request. `Narration` is indexed by the requested
+assertion list, and `Account` also carries snapshot/projection validity proofs.
+The checker constructs these witnesses from a decidable direct-evidence rule.
+It does not accept an unconditional witness or a descriptive proof blob.
+
+== Checked properties
+
+[cols="1,3",options=header]
+|===
+| Declaration | Property
+| `withdrawn_cannot_support`
+| Evidence marked withdrawn cannot satisfy the direct-evidence support rule.
+| `narration_preserves_projection`
+| The checked narration's claims equal the requested claims in their telling order.
+|===
+
+Lean's transitive axiom report for `narrate` and both theorems is `[propext]`.
+`test/NarrationProofAudit.lean` checks that exact diagnostic during the default
+build. A deliberately wrong expectation in an isolated scratch file was rejected
+with exit 1; the real audit builds successfully.
+
+The narration kernel imports Lean/Std independently of the private substrate's
+floating-point equality assumption. The substrate retains other proof debt;
+historical totals in link:docs/proof-debt.adoc[] are not a current axiom inventory.
+
+== Executable evidence
+
+`lake build` succeeds and `lake test` passes five suites, including 35 narration
+checks and 26 private-substrate checks alongside the existing suites. Narration
+checks cover actual CLI runs, acceptance, access and citation refusals, rivalry,
+threshold boundaries and dependent versus unrelated withdrawal. The original
+evidence file remains byte-for-byte unchanged by counterfactual evaluation.
+
+The successful build log passes `scripts/check-lean-proofs.sh --build-log`.
+That gate detects incomplete-proof diagnostics, not every assumption.
+
+== Remaining obligations
+
+* Live Lithoglyph import must preserve source attribution, visibility, consistent
+ revision identity and withdrawal semantics.
+* Additional warrant derivations need explicit rules and soundness properties.
+* Temporal/partial-order semantics and richer account relations need definition.
+* Confidence composition remains open; integer threshold checks do not settle it.
+* Durable account storage and Glyphbase rendering need integration tests.
+
+The current rule proves traceability and declared admission, not external truth,
+source authenticity, persuasive rationale or probabilistic confidence. Output
+JSON carries a readable warrant trail, not independently checkable proof terms.
+See link:docs/narration-slice.adoc[the implemented contract].
diff --git a/README.adoc b/README.adoc
index 4362479..8e97f78 100644
--- a/README.adoc
+++ b/README.adoc
@@ -1,225 +1,135 @@
-== GQLdt β the query layer
-
-https://www.mozilla.org/en-US/MPL/2.0/[image:https://img.shields.io/badge/License-MPL--2.0-blue.svg[License:
-MPL-2.0]] // SPDX-License-Identifier: CC-BY-SA-4.0 //
-SPDX-FileCopyrightText: 2025 hyperpolymath
-
-____
-*This is not the repository README.* It documents *one of two layers*.
-
-This repo is *GNPL*, a _narration/projection_ language β see
-*README.adoc*, which is what GitHub renders on the landing page. GNPL
-answers _"`what account does this evidence support, from whose stance,
-with what warrant`"_. It is being built *on top of* GQLdt and *lowers
-to* it:
-
-....
-GNPL ββlowers toβββΆ GQLdt ββFFIβββΆ Lithoglyph
-(what account) (what is) (the data store)
-....
-
-The document below describes *GQLdt only* β the extensional query core
-under `+src/GqlDt/+`, which is why the sources are namespaced `+GqlDt+`
-in a repo named `+gnpl+`. Nothing here is being discarded; GQLdt becomes
-GNPLβs compilation target. Design rationale: docs/THEORY.adoc and
-docs/LITHOGLYPH.adoc.
-____
-
-GQLdt extends
-https://github.com/hyperpolymath/nextgen-databases/tree/main/lithoglyph[Lithoglyph]βs
-query language with *dependent types*, enabling compile-time
-verification of database constraints, provenance tracking, and
-reversibility proofs.
-
-____
-*Note*: GQL stands for "`Lithoglyph Query Language`"βthe native query
-interface for Lithoglyph. It is not related to HTML forms or form
-builders.
-____
-
-=== Relationship to Lithoglyph
-
-....
-βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-β GQL (Factor) β GQLdt (Lean 4) β
-β - Runtime constraint checks β - Compile-time proofs β
-β - Dynamic, practical β - Static, verified β
-β - "Just run it" β - "Prove it first" β
-βββββββββββββββββ¬βββββββββββββββββ΄βββββββββββββββββ¬ββββββββββββ
- β β
- βΌ βΌ
-βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-β Form.Bridge (Zig) - Bidirectional ABI β
-β - No C dependency β
-β - callconv(.C) for FFI compatibility β
-βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
-β Form.Model + Form.Blocks (Forth) β
-β - Single source of truth β
-βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-....
-
-*Same database, different guarantees:*
-
-[width="100%",cols="20%,39%,41%",options="header",]
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+= GNPL β a narration/projection language for Lithoglyph
+:toc: macro
+:toclevels: 2
+
+image:https://img.shields.io/badge/License-MPL--2.0-blue.svg[License: MPL-2.0,link="https://www.mozilla.org/en-US/MPL/2.0/"]
+image:https://img.shields.io/badge/docs-CC--BY--SA--4.0-lightgrey.svg[Docs: CC-BY-SA-4.0,link="https://creativecommons.org/licenses/by-sa/4.0/"]
+
+**GNPL** is Lithoglyph's narration/projection language: it turns an evidence base into an
+*account* β for forensic histories, counterfactual paths, plural meanings, and
+synchronic/diachronic evidence interpretation.
+
+For proof progress summary, see link:PROOF-PROGRESS.adoc[`PROOF-PROGRESS.adoc`].
+
+GNPL asks: *what account does this evidence support, from whose stance, with
+what warrant, and what rival accounts does the same evidence support?*
+
+toc::[]
+
+== Implementation boundary
+
+GNPL owns the public semantics. Existing type validation, selection and storage
+machinery is a private substrate. The historical `src/GqlDt/` namespace is a
+compatibility detail, not a second public language or a fixed lowering contract.
+The first narration interpreter is implemented in `src/Gnpl/`: it checks direct
+evidence, constructs an ordered account under a declared focalization, and
+re-evaluates that account after a hypothetical source withdrawal.
+
+Start with link:docs/narration-slice.adoc[the runnable narration slice]. It uses
+an imported evidence snapshot; the live Lithoglyph journal adapter, general
+derivation chains and Glyphbase rendering remain integration work.
+
+See link:docs/executable-boundary.adoc[the executable boundary] for the actual
+source-to-IR path, rejection behaviour and remaining proof assumptions.
+
+== Design documents
+
+[cols="1,3",options=header]
|===
-|Aspect |GQL (practical) |GQLdt (verified)
-|When constraints checked |Runtime |Compile-time
+| Document | Question it answers
-|Invalid insert |Runtime error |Wonβt compile
+| link:docs/THEORY.adoc[`docs/THEORY.adoc`]
+| What is a narration/projection language, and what gap does it fill? Positions GNPL
+ against query languages, bitemporal stores, provenance semirings, argumentation
+ frameworks, belief revision and narratology.
-|Reversibility |Runtime inverse stored |Proof that inverse exists
+| link:docs/LITHOGLYPH.adoc[`docs/LITHOGLYPH.adoc`]
+| What does GNPL concretely give *Lithoglyph*, as a database?
-|PROMPT scores |`+CHECK (score BETWEEN 0 AND 100)+`
-|`+BoundedNat 0 100+` in type
+| link:docs/STATE-OF-PLAY.adoc[`docs/STATE-OF-PLAY.adoc`]
+| Where the project actually stands, what is verified and by which command, what is known
+ missing, and which decisions are open. Descriptive anchors belong under
+ `.machine_readable/descriptiles/`; historical checkpoints may lag.
-|Provenance |Application enforces |Type system enforces
+| link:docs/proof-debt.adoc[`docs/proof-debt.adoc`]
+| Historical proof-debt inventory; its totals predate the executable-boundary fixes.
+ Check the current source and boundary document before relying on a proof claim.
|===
-=== Features
-
-* *Refinement Types*: `+BoundedNat 0 100+`, `+NonEmptyString+`,
-`+Confidence+`
-* *Dependent Types*: Length-indexed vectors, provenance-tracked values
-* *Proof Obligations*: Compile-time verification of constraints
-* *Reversibility Proofs*: Prove operations have inverses before
-execution
-* *Normalization Types*: Type-encoded functional dependencies, normal
-form predicates (1NF-BCNF), proof-carrying schema evolution
-* *Backward Compatible*: Standard GQL is valid in dependent-type mode
-
-=== Current Status
-
-*Build Status*: 34/35 modules compiling (97% success) - Updated
-2026-02-01
-
-*Completed Milestones*: - β
M1: Lean 4 project setup (v4.15.0 +
-Mathlib) - β
M2: Core refinement types (BoundedNat, BoundedInt,
-NonEmptyString, Confidence) - β
M3: PROMPT score types
-(PromptDimension, PromptScores with auto-computed overall) - β
M4:
-Provenance tracking (ActorId, Rationale, Tracked with proofs) - β
M5:
-Specifications (EBNF grammar, lexical spec, railroad diagrams) - π‘ M6:
-GQL-DT/GQL Parser (substantially complete - see below)
-
-*M6 Parser Status* (Substantially Complete): - β
Lexer: Hand-rolled
-540-line implementation (80+ keywords, operators, literals, comments) β
-verified by 163 executable checks (`+lake test+`), not asserted.
-Two-character lookahead was off by one until 2026-07-27, so
-`+<=+`/`+>=+`/`+!=+`/`+<>+` never lexed as single tokens, `+:+` lexed as
-`+::+`, and block comments were skipped entirely; fixed and covered. -
-β
Parser: Combinator-based parser for INSERT/SELECT/UPDATE/DELETE - β
-Type System: Refinement types, PROMPT scores, provenance tracking - β
-Pipeline: 6-stage compilation (tokenize β parse β type check β IR β
-validate β serialize) - β
Serialization: CBOR encoding/decoding (RFC
-8949), JSON support - β
Documentation: 8 comprehensive docs (seam
-analysis, integration, language bindings, etc.) - β
Infrastructure:
-Containerfile, Dockerfile, CI/CD workflow - β οΈ AST.lean: 1 nested
-inductive type issue (requires restructuring)
-
-*Recent Updates* (2026-02-01): - Seam analysis: Fixed 76 issues,
-resolved 33 compilation blockers - Namespace consistency: Global GqlDt β
-GqlDt renaming across 24 files - Circular dependency: Created
-Serialization/Types.lean to break IR β Serialization cycle - CBOR tags:
-Updated to vendor-specific range (55800-55804) to avoid IANA collisions
-- Lexer rewrite: Complete hand-rolled implementation (Parsec unavailable
-in Lean 4.15.0)
-
-*Next Steps*: - Fix AST.lean nested inductive issue (TypedValue/Tracked
-relationship) - Achieve 35/35 modules compiling (100% build success) -
-Start M7 (Idris2 ABI) + M8 (Zig FFI) in parallel - M9: ReScript bindings
-(HIGHEST PRIORITY after M7+M8)
-
-For detailed progress tracking, see .machine_readable/STATE.scm.
-
-=== Zig FFI (Bidirectional)
-
-GQLdt compiles to operations on Form.Bridge, which uses Zigβs stable
-ABI:
-
-[source,zig]
+== Status
+
+* `lake build` succeeds. `lake test` runs five suites, including 35 narration
+ checks and 26 private-substrate checks alongside the existing suites.
+* The narration kernel constructs witnesses for direct-evidence support. It
+ refuses inaccessible, withdrawn, missing or mismatched citations. A limited
+ rival relation preserves conflicting accounts without choosing a winner.
+* Lean proves that withdrawn evidence cannot support an assertion and that
+ checked narration preserves the requested claims and their telling order.
+ A default-build audit checks that these proofs and `narrate` depend only on
+ Lean's `propext` axiom, with no project-specific axiom dependency.
+* The substrate parses one complete statement, validates inserts against a supplied
+ schema and supports in-memory insertion/retrieval. It rejects unverified proof mode,
+ unchecked mutations, incomplete wire interchange and persistent-execution requests.
+* Existing ABI/FFI code is separate from a verified, durable narration pipeline.
+* The direct-evidence rule checks traceability and declared admission policy.
+ It does not establish external truth, authenticate source declarations, or
+ settle confidence composition and general narrative inference.
+
+== Build
+
+[source,console]
----
-/// Bidirectional FFI: Lean 4 β Zig β Forth core
-/// and Forth core β Zig β Lean 4 callbacks
-
-pub const LithStatus = struct {
- code: i32,
- error_blob: ?[*]const u8,
- error_len: usize,
-};
-
-/// Forward: GQLdt β Form.Bridge
-pub export fn lith_insert(
- db: *LithDb,
- collection: [*:0]const u8,
- document: [*]const u8,
- doc_len: usize,
- proof_blob: [*]const u8, // Serialised proof from Lean 4
- proof_len: usize,
-) callconv(.C) LithStatus;
-
-/// Reverse: Form.Bridge β GQLdt (for constraint checking)
-pub export fn lith_register_constraint_checker(
- db: *LithDb,
- checker: *const fn (doc: [*]const u8, len: usize) callconv(.C) bool,
-) callconv(.C) LithStatus;
+# Lean core (first build fetches mathlib β expect a long run)
+$ lake build
+
+$ lake test
+
+# Produce an account with its warrant trail
+$ .lake/build/bin/gnpl narrate --evidence examples/narration/evidence.json --projection examples/narration/inspection.gnpl
+
+# Zig FFI bridge β must exist before the Lean FFI executables link
+$ cd bridge && zig build && zig build test
+----
+
+Toolchains: Lean is pinned by `lean-toolchain` (`v4.15.0`, read automatically by elan);
+Zig and Idris2 are pinned in `mise.toml`. Per the estate ABI/FFI standard, ABI definitions
+are Idris2 (`src/GQLdt/ABI/*.idr`) and the FFI implementation is Zig (`bridge/`).
+
+=== Proof gate
+
+`scripts/check-lean-proofs.sh` enforces the manifest invariant *"No sorry in Lean 4 proofs"*.
+Its authoritative mode reads Lean's own diagnostics:
+
+[source,console]
----
+$ lake build 2>&1 | tee lake-build.log
+$ ./scripts/check-lean-proofs.sh --build-log lake-build.log
+----
+
+It deliberately does *not* use a bare `grep -r "sorry\|admit"`: this repo legitimately
+contains an `admit` constructor, a `.admit` reference, a `"sorry"` lexer keyword and a
+commented-out `sorry`, none of which are incomplete proofs.
+
+[IMPORTANT]
+====
+A green proof gate means no incomplete proof was reported by that gate. It does
+not establish an axiom-free trusted base. Parser implementations and insert
+validation no longer rely on their former executable/typing axioms, but the
+existing floating-point equality assumption and other module assumptions remain
+in the private substrate. The independent narration kernel has the narrower
+audited footprint described above.
+See link:docs/executable-boundary.adoc[the current boundary] before interpreting
+older proof-debt totals or completion percentages.
+====
+
+== Licence
+
+Code is **MPL-2.0**; documentation (`.md`, `.adoc`) is **CC-BY-SA-4.0**. See `LICENSE` and
+`LICENSES/`.
+
+== ABI/FFI standard
-No C headers or libc required. Zig provides C-compatible calling
-convention for interop.
-
-=== Specification
-
-See spec/GQL_Dependent_Types_Complete_Specification.md for the full
-specification covering:
-
-[arabic]
-. Type System (universes, primitives, constructors)
-. Refinement Types (bounded values, non-empty strings)
-. Dependent Types (provenance tracking, reversibility)
-. DDL/DML with proofs
-. Proof obligations and tactics
-. Complete examples (BoFIG journalism use case)
-
-See spec/normalization-types.md for normalization types covering:
-
-[arabic]
-. Functional dependency encoding (FunDep, Armstrongβs Axioms)
-. Normal form predicates (1NF, 2NF, 3NF, BCNF, 4NF)
-. Proof-carrying schema evolution (NormalizationStep)
-. Integration with Form.Normalizer
-. GQL syntax extensions for normalization commands
-
-=== Setup
-
-[arabic]
-. Ensure `+just+` and `+podman+` are installed
-. Run `+just check+` to verify Lean 4 proofs
-. For non-bash shells, see `+scripts/bootstrap_all.sh+`
-
-=== Implementation Timeline
-
-* *Phase 1* (Month 1-6): Refinement types
-* *Phase 2* (Month 7-12): Simple dependent types
-* *Phase 3* (Month 13-18): Full verification
-* *Phase 4* (Month 19-24): Normalization types (FunDep, normal forms,
-proof-carrying evolution)
-
-=== See Also
-
-* https://github.com/hyperpolymath/nextgen-databases/tree/main/lithoglyph[Lithoglyph]
-- The narrative-first database
-* https://github.com/hyperpolymath/nextgen-databases/tree/main/lithoglyph/spec/self-normalizing.adoc[Lithoglyph
-Self-Normalizing Spec] - Self-normalizing database specification
-* https://github.com/hyperpolymath/glyphbase[Glyphbase] - Lithoglyph web
-UI (Airtable-mode delivery)
-* https://github.com/hyperpolymath/lithoglyphdb[lithoglyphdb] - Reserved
-future home of the database (extraction pending)
-* https://github.com/hyperpolymath/bofig[BoFIG] - Evidence graph for
-investigative journalism
-* https://github.com/hyperpolymath/zotero-lithoglyph[Zotero-Lithoglyph]
-- Production pilot: reference manager with PROMPT scores
-* Lithoglyph Studio - Zero-friction GUI for GQLdt _(planned; not yet
-published)_
-* Lithoglyph Debugger - Proof-carrying database debugger, Lean 4 + Idris
-2 _(planned; not yet published)_
-* https://github.com/hyperpolymath/formbase[FormBase] - Open-source
-Airtable alternative with provenance
+See link:ABI-FFI-README.adoc[`ABI-FFI-README.adoc`] for the estate-wide ABI (Idris2) / FFI (Zig)
+standard this repository follows.
diff --git a/REQUIRES_INITIALISATION.adoc b/REQUIRES_INITIALISATION.adoc
new file mode 100644
index 0000000..8212f86
--- /dev/null
+++ b/REQUIRES_INITIALISATION.adoc
@@ -0,0 +1,18 @@
+= Outstanding Repository Initialisation
+
+The current policy documents still contain four distinct substitution tokens.
+Their values require the repository owner's decision; the language and CI work
+does not establish them.
+
+[cols="1,1,2",options="header"]
+|===
+|Token |Document |Required fact
+|CONDUCT_EMAIL |CODE_OF_CONDUCT.adoc |The contact address for conduct reports and appeals.
+|RESPONSE_TIME |CODE_OF_CONDUCT.adoc |The acknowledgment time that the maintainers commit to.
+|CONDUCT_TEAM |CODE_OF_CONDUCT.adoc |The people or body responsible for reviewing conduct reports.
+|PGP_KEY_URL |SECURITY.adoc |The authoritative download URL for the vulnerability-reporting public key.
+|===
+
+Do not infer these values from unrelated repositories or suppress the unresolved
+sections to satisfy a check. Remove this marker once all four values have been
+supplied and the policy documents have been checked.
diff --git a/ROADMAP.adoc b/ROADMAP.adoc
index 37e9eeb..f4f9220 100644
--- a/ROADMAP.adoc
+++ b/ROADMAP.adoc
@@ -1,22 +1,39 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
-= Gql Dt Roadmap
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+= GNPL engineering roadmap
+:revdate: 2026-09-07
-== Current Status
+== Implemented foundation
-Initial development phase.
+* Executable private parser and schema validation, with explicit refusals where
+ persistence, proof checking and interchange remain incomplete.
+* Direct-evidence narration: typed accounts and warrants, focalization, declared
+ telling order, a limited rival relation and hypothetical withdrawal.
+* A `.gnpl` projection surface, versioned evidence import and executable CLI.
+* Five passing Lean suites, including acceptance and rejection controls.
+* Two checked narration properties and a default-build transitive axiom audit.
-== Milestones
+== Next: connect the evidence source
-=== v0.1.0 - Foundation
-* [ ] Core functionality
-* [ ] Basic documentation
-* [ ] CI/CD pipeline
+Implement a read-only Lithoglyph adapter for the snapshot contract. Demonstrate
+an account over real stored evidence, invalidate it after a cited withdrawal,
+and preserve it after an unrelated withdrawal. Preserve revision identity and
+historical accounts. See link:docs/LITHOGLYPH.adoc[the integration contract].
-=== v1.0.0 - Stable Release
-* [ ] Full feature set
-* [ ] Comprehensive tests
-* [ ] Production ready
+== Extend the semantics deliberately
-== Future Directions
+* Checked derivation chains with named inference rules and compositional warrant.
+* Event identity and partial-order/temporal semantics, separate from telling order.
+* Richer account relations, with the intended argumentation semantics explicit.
+* A justified confidence-composition policy; declared integer thresholds do not
+ settle PROMPT averaging, probability or epistemic entrenchment.
-_To be determined based on community feedback._
+Each extension needs an acceptance case, a meaningful refusal case and a precise
+proof obligation. Keep useful selection and storage operations as private
+machinery; no additional public language or fixed lowering target is assumed.
+
+== Complete the application path
+
+Add durable account storage and Glyphbase rendering only with an end-to-end
+warrant/withdrawal test. Report configured CI separately from remote results,
+and local proofs separately from source authenticity or deployed guarantees.
diff --git a/docs/EXECUTION-STRATEGY.adoc b/docs/EXECUTION-STRATEGY.adoc
index 0750ad0..ceb2b7c 100644
--- a/docs/EXECUTION-STRATEGY.adoc
+++ b/docs/EXECUTION-STRATEGY.adoc
@@ -1,25 +1,21 @@
== GQL-DT Execution Strategy: SQL vs IR vs Native
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Date:* 2026-02-01 *Status:* Architectural Decision *Priority:* CRITICAL
-- Affects Milestone 6 Parser Design
+*Date:* 2026-02-01
+*Status:* Architectural Decision
+*Priority:* CRITICAL - Affects Milestone 6 Parser Design
'''''
=== The Question
-*"`Does it make sense to compile GQL-DT to SQL or a lower-level IR for
-execution?`"*
+*"Does it make sense to compile GQL-DT to SQL or a lower-level IR for execution?"*
-*Your intuition:* Compiling to SQL feels like "`being a purist`" but
-might sacrifice compatibility.
+*Your intuition:* Compiling to SQL feels like "being a purist" but might sacrifice compatibility.
-*TL;DR Answer:* Your intuition is *100% correct*. Compiling to SQL
-*destroys the type safety guarantees* that make GQL-DT valuable.
-*Recommendation: Compile to typed IR, execute natively on Lithoglyph,
-with optional SQL backend for compatibility.*
+*TL;DR Answer:* Your intuition is *100% correct*. Compiling to SQL *destroys the type safety guarantees* that make GQL-DT valuable. *Recommendation: Compile to typed IR, execute natively on Lithoglyph, with optional SQL backend for compatibility.*
'''''
@@ -52,29 +48,16 @@ VALUES ('ONS Data', 95);
==== Problems with SQL Compilation
-[width="100%",cols="53%,47%",options="header",]
+[cols=",",options="header",]
|===
|Problem |Impact
-|*Proof Erasure* |All proofs removed - canβt verify correctness at
-execution
-
-|*Type Information Loss* |`+BoundedNat 0 100+` becomes `+INTEGER+` -
-bounds lost
-
-|*Refinement Types Gone* |`+NonEmptyString+` becomes `+TEXT+` -
-non-emptiness not enforced
-
-|*No Dependent Types* |`+PromptScores+` flattened to 7 separate columns
-- overall auto-computation lost
-
-|*Provenance Tracking Weakened* |`+Tracked Ξ±+` becomes regular columns -
-no type-level guarantees
-
-|*Runtime-Only Checks* |SQL CHECK constraints run at INSERT, not at
-query construction
-
-|*Error Messages Poor* |SQL errors like "`CHECK constraint violated`"
-instead of helpful GQL-DT messages
+|*Proof Erasure* |All proofs removed - can't verify correctness at execution
+|*Type Information Loss* |`BoundedNat 0 100` becomes `INTEGER` - bounds lost
+|*Refinement Types Gone* |`NonEmptyString` becomes `TEXT` - non-emptiness not enforced
+|*No Dependent Types* |`Prompores` flattened to 7 separate columns - overall auto-computation lost
+|*Provenance Tracking Weakened* |`Tracked Ξ±` becomes regular columns - no type-level guarantees
+|*Runtime-Only Checks* |SQL CHECK constraints run at INSERT, not at query construction
+|*Error Messages Poor* |SQL errors like "CHECK constraint violated" instead of helpful GQL-DT messages
|===
==== Example: Information Loss
@@ -98,18 +81,22 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
-- DETAIL: Failing row contains (150)
----
-*Loss:* User finds out about error when running query, not when writing
-it. Defeats the entire purpose of GQL-DT.
+*Loss:* User finds out about error when running query, not when writing it. Defeats the entire purpose of GQL-DT.
==== When SQL Compilation Makes Sense
-*Compatibility Layer Only:* - GQL (user tier) β SQL for broad tool
-compatibility - GQL-DT proofs already verified β SQL as "`dumb
-transport`" - Read-only queries where type safety less critical -
-Integration with existing SQL tools (BI dashboards, reporting)
+*Compatibility Layer Only:*
+
+* GQL (user tier) β SQL for broad tool compatibility
+* GQL-DT proofs already verified β SQL as "dumb transport"
+* Read-only queries where type safety less critical
+* Integration with existing SQL tools (BI dashboards, reporting)
+
+*NOT for:*
-*NOT for:* - Primary execution path - Security-critical operations -
-When type safety guarantees needed
+* Primary execution path
+* Security-critical operations
+* When type safety guarantees needed
'''''
@@ -176,22 +163,15 @@ structure IR.InsertStmt (schema : Schema) where
==== Benefits of IR Approach
-[width="100%",cols="53%,47%",options="header",]
+[cols=",",options="header",]
|===
|Benefit |Impact
|*Type Preservation* |All dependent type information preserved
-
|*Proof Transport* |Proofs serialized (CBOR) and verified on server
-
-|*Multiple Backends* |IR β Lithoglyph (native), IR β SQL (compat), IR β
-Debug
-
+|*Multiple Backends* |IR β Lithoglyph (native), IR β SQL (compat), IR β Debug
|*Optimization* |IR can be optimized before execution
-
|*Security* |Type-safe IR prevents SQL injection entirely
-
|*Error Messages* |IR execution can reference original GQL-DT source
-
|*Proof Caching* |Verified proofs cached in IR, no re-verification
|===
@@ -244,23 +224,36 @@ Lithoglyph Server (Rust/Zig)
==== Why Native Execution Wins
-*1. Type Safety Preserved End-to-End* - Dependent types from parser to
-database - Proofs verified once, trusted throughout - No information
-loss at any layer
+*1. Type Safety Preserved End-to-End*
+
+* Dependent types from parser to database
+* Proofs verified once, trusted throughout
+* No information loss at any layer
-*2. Performance* - No SQL parsing/planning overhead - Direct execution
-on Lithoglyph storage - Proof verification at parse time, not runtime -
-Zero-copy deserialization (CBOR β Rust/Zig)
+*2. Performance*
-*3. Security* - Type-safe IR eliminates SQL injection - Proof blobs
-cryptographically verified - No string concatenation vulnerabilities
+* No SQL parsing/planning overhead
+* Direct execution on Lithoglyph storage
+* Proof verification at parse time, not runtime
+* Zero-copy deserialization (CBOR β Rust/Zig)
-*4. Error Quality* - Errors reference original GQL-DT source - Type
-mismatch errors show expected vs actual types - Proof failure errors
-show which tactic failed
+*3. Security*
-*5. Future-Proof* - Not constrained by SQL semantics - Can add features
-SQL doesnβt support - Normalization operations require custom IR anyway
+* Type-safe IR eliminates SQL injection
+* Proof blobs cryptographically verified
+* No string concatenation vulnerabilities
+
+*4. Error Quality*
+
+* Errors reference original GQL-DT source
+* Type mismatch errors show expected vs actual types
+* Proof failure errors show which tactic failed
+
+*5. Future-Proof*
+
+* Not constrained by SQL semantics
+* Can add features SQL doesn't support
+* Normalization operations require custom IR anyway
==== Lithoglyph Native Storage Integration
@@ -293,9 +286,11 @@ const Collection = struct {
};
----
-*No SQL Translation Needed:* - Lithoglyph storage layer speaks
-"`dependent types`" natively - IR maps directly to storage operations -
-Proofs already verified, storage just executes
+*No SQL Translation Needed:*
+
+* Lithoglyph storage layer speaks "dependent types" natively
+* IR maps directly to storage operations
+* Proofs already verified, storage just executes
'''''
@@ -358,7 +353,7 @@ def executeIR (ir : IR) (backend : Backend) : IO Result :=
*Benchmark: 10,000 INSERTs with dependent types*
-[width="100%",cols="19%,12%,20%,15%,12%,22%",options="header",]
+[cols=",,,,,",options="header",]
|===
|Approach |Parse |Type Check |Execute |Total |Type Safety
|*GQL-DT β IR β Lithoglyph* |50ms |20ms |100ms |*170ms* |β
Full
@@ -367,10 +362,12 @@ def executeIR (ir : IR) (backend : Backend) : IO Result :=
|*Raw SQL β DB* |10ms |0ms |200ms |*210ms* |β None
|===
-*Key Insight:* Native IR execution is *faster* than SQL compilation
-because: 1. No SQL parsing overhead on server 2. Proof verification at
-parse time (one-time cost) 3. Direct storage operations (no query
-planner)
+*Key Insight:* Native IR execution is *faster* than SQL compilation because:
+
+[arabic]
+. No SQL parsing overhead on server
+. Proof verification at parse time (one-time cost)
+. Direct storage operations (no query planner)
==== Proof Erasure Performance
@@ -384,9 +381,11 @@ def insert (score : BoundedNat 0 100) : IO Unit :=
storageWrite score.val
----
-*Runtime overhead of dependent types: ZERO* - Proofs erased after type
-checking - Only data values remain - Same runtime representation as
-untyped
+*Runtime overhead of dependent types: ZERO*
+
+* Proofs erased after type checking
+* Only data values remain
+* Same runtime representation as untyped
'''''
@@ -394,7 +393,7 @@ untyped
[cols=",,,",options="header",]
|===
-|Criterion |SQL Compilation |IR + Native |Hybrid (IR primary)
+|Criterion |SQL Compilation |IR {plus} Native |Hybrid (IR primary)
|*Type Safety* |β Lost |β
Full |β
Full (native)
|*Performance* |β οΈ Slower |β
Faster |β
Faster (native)
|*Compatibility* |β
Broad |β οΈ Lithoglyph only |β
Both
@@ -417,7 +416,7 @@ untyped
. Performance: Excellent
. Compatibility: Lithoglyph only
-==== Phase 2: Add SQL Compatibility (M8+)
+==== Phase 2: Add SQL Compatibility (M8{plus})
[arabic]
. IR β SQL lowering for read-only queries
@@ -426,28 +425,26 @@ untyped
. Performance: Good for reads
. Compatibility: Broad
-==== Phase 3: Optimize IR (M9+)
+==== Phase 3: Optimize IR (M9{plus})
[arabic]
. IR optimizations (constant folding, proof caching)
. Query plan optimization
. Parallel execution
-. Performance: Excellent++
+. Performance: Excellent{plus}{plus}
'''''
=== Your Intuition is Correct
-*You said:* "`I think this might have bearing on [permissions] but if
-not, treat this as the next step.`"
+*You said:* "I think this might have bearing on ++[++permissions++]++ but if not, treat this as the next step."
-*Youβre right on both counts:*
+*You're right on both counts:*
[arabic]
-. *Permissions Bearing:* YES - permission enforcement happens in IR, not
-SQL
+. *Permissions Bearing:* YES - permission enforcement happens in IR, not SQL
* TypeWhitelist filters in IR generation
-* SQL canβt represent "`user allowed types [Nat, String, Date]`"
+* SQL can't represent "user allowed types ++[++Nat, String, Date++]++"
* IR preserves permission metadata through execution
. *Next Step:* YES - this is the critical decision before M6 Parser
* Parser must generate IR, not SQL
@@ -458,6 +455,7 @@ SQL
=== Implementation Plan (M6)
+[[m6a-gql-dt-parser--typed-ir]]
==== M6a: GQL-DT Parser β Typed IR
[source,lean]
@@ -484,6 +482,7 @@ def generateIR (ast : TypedAST) : IO IR :=
}
----
+[[m6b-gql-parser--typed-ir-via-inference]]
==== M6b: GQL Parser β Typed IR (via inference)
[source,lean]
@@ -498,6 +497,7 @@ def parseGQL (source : String) : IO (Except ParseError IR) := do
return ir
----
+[[m6c-ir--lithoglyph-native-execution]]
==== M6c: IR β Lithoglyph Native Execution
[source,zig]
@@ -531,39 +531,54 @@ fn insert(db: *Database, stmt: IR.InsertStmt) !void {
=== Conclusion
-*Donβt compile to SQL. Your instinct is right.*
+*Don't compile to SQL. Your instinct is right.*
+
+*SQL compilation:*
+
+* β Destroys type safety
+* β Loses proofs
+* β Worse error messages
+* β Slower (SQL parsing overhead)
+* β
Broad compatibility (only upside)
+
+*Native IR execution:*
-*SQL compilation:* - β Destroys type safety - β Loses proofs - β
-Worse error messages - β Slower (SQL parsing overhead) - β
Broad
-compatibility (only upside)
+* β
Preserves type safety
+* β
Keeps proofs
+* β
Better error messages
+* β
Faster (direct execution)
+* β
SQL injection immune
+* β οΈ Requires Lithoglyph (solvable with hybrid)
-*Native IR execution:* - β
Preserves type safety - β
Keeps proofs - β
-Better error messages - β
Faster (direct execution) - β
SQL injection
-immune - β οΈ Requires Lithoglyph (solvable with hybrid)
+*Hybrid approach (RECOMMENDED):*
-*Hybrid approach (RECOMMENDED):* - β
All benefits of native IR - β
SQL
-compatibility layer for BI tools - β
Best of both worlds - β οΈ Slightly
-more complex (manageable)
+* β
All benefits of native IR
+* β
SQL compatibility layer for BI tools
+* β
Best of both worlds
+* β οΈ Slightly more complex (manageable)
-*Decision:* Implement IR-first with native Lithoglyph execution. Add SQL
-compatibility layer later if needed for BI tool integration.
+*Historical design decision:* Proposed IR-first native Lithoglyph execution, with optional SQL compatibility. Native persistent execution is not implemented by the current pipeline; see link:executable-boundary.adoc[the executable boundary].
'''''
-*Next Steps:* 1. Design IR data structures (src/GqlDt/IR.lean) 2.
-Implement AST β IR generation 3. Design CBOR proof blob format 4.
-Coordinate with Lithoglyph team on native IR execution 5. Update M6
-Parser milestone with IR targets
+*Next Steps:*
-*This is NOT "`being a purist`" - itβs being correct.* Dependent types
-with proofs require a type-preserving execution model. SQL canβt
-represent that.
+[arabic]
+. Design IR data structures (src/GqlDt/IR.lean)
+. Implement AST β IR generation
+. Design CBOR proof blob format
+. Coordinate with Lithoglyph team on native IR execution
+. Update M6 Parser milestone with IR targets
+
+*This is NOT "being a purist" - it's being correct.* Dependent types with proofs require a type-preserving execution model. SQL can't represent that.
'''''
*Document Status:* Complete architectural decision on execution strategy
-*See Also:* - `+docs/PARSER-DECISION.md+` - Why Lean 4 for parsing -
-`+docs/TWO-TIER-DESIGN.md+` - GQL-DT vs GQL architecture -
-`+docs/TYPE-SAFETY-ENFORCEMENT.md+` - How type safety works - Lithoglyph
-Zig FFI: `+bridge/zig/src/main.zig+`
+*See Also:*
+
+* `docs/PARSER-DECISION.adoc` - Why Lean 4 for parsing
+* `docs/TWO-TIER-DESIGN.adoc` - GQL-DT vs GQL architecture
+* `docs/TYPE-SAFETY-ENFORCEMENT.adoc` - How type safety works
+* Lithoglyph Zig FFI: `bridge/zig/src/main.zig`
diff --git a/docs/INTEGRATION.adoc b/docs/INTEGRATION.adoc
index 26fecff..3df4c3c 100644
--- a/docs/INTEGRATION.adoc
+++ b/docs/INTEGRATION.adoc
@@ -1,19 +1,20 @@
== GQL-DT Integration: ReScript, WASM, ABI, FFI
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Date:* 2026-02-01 *Status:* Integration Requirements *Priority:* HIGH -
-Required for M7+ (Post-Parser)
+*Date:* 2026-02-01
+*Status:* Integration Requirements
+*Priority:* HIGH - Required for M7{plus} (Post-Parser)
'''''
=== Integration Requirements
+[[1-rescript-bindings]]
==== 1. ReScript Bindings
-*Purpose:* Seamless integration with existing hyperpolymath projects
-(TypeScript/JavaScript replacement)
+*Purpose:* Seamless integration with existing hyperpolymath projects (TypeScript/JavaScript replacement)
*Architecture:*
@@ -73,7 +74,7 @@ module TypedValue = {
| Nat(int)
| BoundedNat({min: int, max: int, value: int})
| NonEmptyString(string)
- | PromptScores(PromptScores.t)
+ | Prompores(Prompores.t)
// Convert to C-compatible representation
@module("@gqldt/core") @scope("TypedValue")
@@ -101,10 +102,10 @@ let insertEvidence = async () => {
'''''
+[[2-wasm-compatibility]]
==== 2. WASM Compatibility
-*Purpose:* Public-facing deployments, browser-based Lithoglyph Studio,
-edge computing
+*Purpose:* Public-facing deployments, browser-based Lithoglyph Studio, edge computing
*WASM Compilation Strategy:*
@@ -164,10 +165,13 @@ pub fn build(b: *std.Build) void {
}
----
-*WASM Features:* - β
Type checking in browser - β
Query validation
-before server round-trip - β
Proof verification client-side (for GQL-DT
-tier) - β
Offline Lithoglyph Studio (IndexedDB storage) - β
Edge
-computing (Cloudflare Workers, Deno Deploy)
+*WASM Features:*
+
+* β
Type checking in browser
+* β
Query validation before server round-trip
+* β
Proof verification client-side (for GQL-DT tier)
+* β
Offline Lithoglyph Studio (IndexedDB storage)
+* β
Edge computing (Cloudflare Workers, Deno Deploy)
*Example WASM Usage:*
@@ -204,20 +208,23 @@ let validateQuery = async (queryString: string) => {
'''''
+[[3-abi-in-idris2]]
==== 3. ABI in Idris2
-*Purpose:* Formally verified Application Binary Interface with dependent
-type proofs
+*Purpose:* Formally verified Application Binary Interface with dependent type proofs
+
+*Why Idris2 for ABI:*
-*Why Idris2 for ABI:* - β
Dependent types prove interface correctness -
-β
Verify memory layout (alignment, padding, size) - β
-Platform-specific ABIs with compile-time selection - β
Backward
-compatibility proofs - β
Type-level guarantees impossible in C/Zig/Rust
+* β
Dependent types prove interface correctness
+* β
Verify memory layout (alignment, padding, size)
+* β
Platform-specific ABIs with compile-time selection
+* β
Backward compatibility proofs
+* β
Type-level guarantees impossible in C/Zig/Rust
*ABI Architecture:*
....
-src/abi/ # Idris2 ABI definitions
+src/GQLdt/ABI/ # Idris2 ABI definitions
βββ Types.idr # Type definitions with proofs
βββ Layout.idr # Memory layout verification
βββ Foreign.idr # FFI declarations
@@ -237,7 +244,7 @@ generated/abi/ # Auto-generated from Idris2
[source,idris]
----
--- src/abi/Types.idr
+-- src/GQLdt/ABI/Types.idr
module GqlDt.ABI.Types
import Data.So
@@ -289,7 +296,7 @@ backwardCompatible = ?proof_backward_compat
[source,c]
----
// generated/abi/gqldt.h
-// Auto-generated from src/abi/Types.idr - DO NOT EDIT
+// Auto-generated from src/GQLdt/ABI/Types.idr - DO NOT EDIT
#ifndef GQLDT_ABI_H
#define GQLDT_ABI_H
@@ -327,24 +334,29 @@ _Static_assert(_Alignof(GqlDt_InsertStmt) == 8, "InsertStmt alignment");
#endif // GQLDT_ABI_H
----
-*Benefits of Idris2 ABI:* - β
*Compile-time verification* - Memory
-layout proven correct - β
*Platform portability* - Same ABI works
-Linux/macOS/Windows - β
*Backward compatibility* - Proven
-mathematically, not tested - β
*No undefined behavior* - Type system
-prevents null pointers, alignment issues - β
*Self-documenting* -
-Proofs explain why layout is correct
+*Benefits of Idris2 ABI:*
+
+* β
*Compile-time verification* - Memory layout proven correct
+* β
*Platform portability* - Same ABI works Linux/macOS/Windows
+* β
*Backward compatibility* - Proven mathematically, not tested
+* β
*No undefined behavior* - Type system prevents null pointers, alignment issues
+* β
*Self-documenting* - Proofs explain why layout is correct
'''''
+[[4-ffi-in-zig]]
==== 4. FFI in Zig
-*Purpose:* C-compatible foreign function interface, cross-platform,
-memory-safe
+*Purpose:* C-compatible foreign function interface, cross-platform, memory-safe
-*Why Zig for FFI:* - β
Native C ABI compatibility without overhead - β
-Memory safety by default - β
Cross-compilation built-in (any platform,
-any architecture) - β
No runtime dependencies - β
Simpler than Rust
-FFI, safer than C - β
Works with WASM (wasm32-wasi)
+*Why Zig for FFI:*
+
+* β
Native C ABI compatibility without overhead
+* β
Memory safety by default
+* β
Cross-compilation built-in (any platform, any architecture)
+* β
No runtime dependencies
+* β
Simpler than Rust FFI, safer than C
+* β
Works with WASM (wasm32-wasi)
*FFI Architecture:*
@@ -462,7 +474,7 @@ extern fn lean_gqldt_typecheck(
};
----
-*Cross-Compilation (Zigβs Superpower):*
+*Cross-Compilation (Zig's Superpower):*
[source,bash]
----
@@ -502,7 +514,7 @@ zig build -Dtarget=wasm32-wasi
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-β Idris2 ABI (src/abi/) β
+β Idris2 ABI (src/GQLdt/ABI/) β
β - Formal interface specification with proofs β
β - Generates C headers for FFI β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
@@ -531,7 +543,7 @@ zig build -Dtarget=wasm32-wasi
==== M7: Idris2 ABI (Post-Parser)
-* [ ] Create `+src/abi/+` directory structure
+* [ ] Create `src/GQLdt/ABI/` directory structure
* [ ] Define core types with dependent type proofs
* [ ] Verify memory layouts (size, alignment)
* [ ] Platform-specific ABI selection
@@ -551,7 +563,7 @@ zig build -Dtarget=wasm32-wasi
==== M9: ReScript Bindings
-* [ ] Create `+bindings/rescript/+` directory
+* [ ] Create `bindings/rescript/` directory
* [ ] Define type-safe ReScript API
* [ ] External bindings to Zig FFI
* [ ] Promise-based async API
@@ -572,41 +584,42 @@ zig build -Dtarget=wasm32-wasi
=== Benefits of This Architecture
-[width="100%",cols="25%,41%,34%",options="header",]
+[cols=",,",options="header",]
|===
|Layer |Technology |Benefits
-|*Parser* |Lean 4 |Dependent types, theorem proving, compile-time
-verification
-
-|*ABI* |Idris2 |Formal interface proofs, memory layout verification,
-platform portability
-
-|*FFI* |Zig |C ABI compat, memory safety, cross-compilation, WASM
-support
-
+|*Parser* |Lean 4 |Dependent types, theorem proving, compile-time verification
+|*ABI* |Idris2 |Formal interface proofs, memory layout verification, platform portability
+|*FFI* |Zig |C ABI compat, memory safety, cross-compilation, WASM support
|*Bindings* |ReScript |Type-safe JS, seamless integration, modern syntax
-
|*Deployment* |WASM |Browser, edge, serverless, offline-first
|===
-*Result:* - β
Type safety from source to execution - β
Mathematically
-proven interface correctness - β
Memory safety without garbage
-collection - β
Cross-platform (Linux/macOS/Windows/Web) - β
Seamless
-ReScript integration - β
WASM for public deployments - β
Zero-cost
-abstractions (proof erasure)
+*Result:*
+
+* β
Type safety from source to execution
+* β
Mathematically proven interface correctness
+* β
Memory safety without garbage collection
+* β
Cross-platform (Linux/macOS/Windows/Web)
+* β
Seamless ReScript integration
+* β
WASM for public deployments
+* β
Zero-cost abstractions (proof erasure)
'''''
*Document Status:* Complete integration architecture
-*Next Steps:* 1. Complete M6 Parser (generate typed IR) 2. Start M7:
-Idris2 ABI implementation 3. Start M8: Zig FFI bridge (parallel with M7)
-4. Create ReScript bindings after FFI stable 5. WASM compilation after
-ReScript bindings work
-
-*See Also:* - `+docs/EXECUTION-STRATEGY.md+` - Why native IR execution -
-`+docs/TWO-TIER-DESIGN.md+` - GQL-DT vs GQL architecture -
-`+~/abi-migration-guide.md+` - ABI/FFI universal standard (per
-CLAUDE.md) -
-`+~/Documents/hyperpolymath-repos/rsr-template-repo/ABI-FFI-README.md+`
-- Template
+*Next Steps:*
+
+[arabic]
+. Complete M6 Parser (generate typed IR)
+. Start M7: Idris2 ABI implementation
+. Start M8: Zig FFI bridge (parallel with M7)
+. Create ReScript bindings after FFI stable
+. WASM compilation after ReScript bindings work
+
+*See Also:*
+
+* `docs/EXECUTION-STRATEGY.adoc` - Why native IR execution
+* `docs/TWO-TIER-DESIGN.adoc` - GQL-DT vs GQL architecture
+* `~/abi-migration-guide.md` - ABI/FFI universal standard (per CLAUDE.md)
+* `~/Documents/hyperpolymath-repos/rsr-template-repo/ABI-FFI-README.md` - Template
diff --git a/docs/LANGUAGE-BINDINGS.adoc b/docs/LANGUAGE-BINDINGS.adoc
index 713854e..51da234 100644
--- a/docs/LANGUAGE-BINDINGS.adoc
+++ b/docs/LANGUAGE-BINDINGS.adoc
@@ -1,17 +1,17 @@
== GQL-DT Language Bindings: Multi-Language Support
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Date:* 2026-02-01 *Status:* Language Binding Specifications *Priority:*
-MEDIUM - Post-Core Implementation
+*Date:* 2026-02-01
+*Status:* Language Binding Specifications
+*Priority:* MEDIUM - Post-Core Implementation
'''''
=== Overview
-GQL-DT provides language bindings for all *allowed languages* in the
-hyperpolymath ecosystem (per `+CLAUDE.md+` language policy).
+GQL-DT provides language bindings for all *allowed languages* in the hyperpolymath ecosystem (per `CLAUDE.md` language policy).
==== Binding Architecture
@@ -36,28 +36,32 @@ Zig FFI (C-compatible bridge)
'''''
+[[1-rescript-bindings-primary]]
=== 1. ReScript Bindings (PRIMARY)
-*Status:* β
Specified in `+docs/INTEGRATION.md+`
+*Status:* β
Specified in `docs/INTEGRATION.adoc`
*Priority:* CRITICAL - Primary language for application development
-*Location:* `+bindings/rescript/+`
+*Location:* `bindings/rescript/`
-*Use Cases:* - Lithoglyph Studio (web UI) - Client-side query validation
-- Browser-based type checking - Deno backend services
+*Use Cases:*
-*See:* `+docs/INTEGRATION.md+` for complete ReScript binding
-specification
+* Lithoglyph Studio (web UI)
+* Client-side query validation
+* Browser-based type checking
+* Deno backend services
+
+*See:* `docs/INTEGRATION.adoc` for complete ReScript binding specification
'''''
+[[2-rust-bindings]]
=== 2. Rust Bindings
-*Priority:* HIGH - Systems programming, CLI tools, performance-critical
-code
+*Priority:* HIGH - Systems programming, CLI tools, performance-critical code
-*Location:* `+bindings/rust/+`
+*Location:* `bindings/rust/`
*Directory Structure:*
@@ -93,7 +97,7 @@ pub enum TypedValue {
Nat(u64),
BoundedNat { min: u64, max: u64, value: u64 },
NonEmptyString(String),
- PromptScores(PromptScores),
+ Prompores(Prompores),
}
/// INSERT statement builder (Rust-idiomatic API)
@@ -245,11 +249,12 @@ criterion = "0.5" # For benchmarks
'''''
+[[3-julia-bindings]]
=== 3. Julia Bindings
*Priority:* MEDIUM - Batch scripts, data processing (per RSR)
-*Location:* `+bindings/julia/+`
+*Location:* `bindings/julia/`
*Directory Structure:*
@@ -393,11 +398,12 @@ julia = "1.9"
'''''
+[[4-gleam-bindings]]
=== 4. Gleam Bindings
*Priority:* MEDIUM - Backend services on BEAM
-*Location:* `+bindings/gleam/+`
+*Location:* `bindings/gleam/`
*Directory Structure:*
@@ -424,11 +430,11 @@ pub type TypedValue {
Nat(Int)
BoundedNat(min: Int, max: Int, value: Int)
NonEmptyString(String)
- PromptScores(PromptScores)
+ Prompores(Prompores)
}
-pub type PromptScores {
- PromptScores(
+pub type Prompores {
+ Prompores(
provenance: Int,
replicability: Int,
objective: Int,
@@ -544,11 +550,12 @@ ERL_NIF_INIT(gqldt_nif, nif_funcs, NULL, NULL, NULL, NULL)
'''''
+[[5-elixir-bindings]]
=== 5. Elixir Bindings
*Priority:* MEDIUM - Distributed systems, Phoenix backend
-*Location:* `+bindings/elixir/+`
+*Location:* `bindings/elixir/`
*Directory Structure:*
@@ -669,11 +676,12 @@ end
'''''
+[[6-haskell-bindings]]
=== 6. Haskell Bindings
*Priority:* LOW-MEDIUM - Scaffoldia CLI, type-heavy tools
-*Location:* `+bindings/haskell/+`
+*Location:* `bindings/haskell/`
*Directory Structure:*
@@ -803,11 +811,12 @@ insertCreate table columns values rationale = do
'''''
+[[7-denojavascript-bindings]]
=== 7. Deno/JavaScript Bindings
*Priority:* MEDIUM - Runtime, glue code, MCP protocol
-*Location:* `+bindings/deno/+`
+*Location:* `bindings/deno/`
*Directory Structure:*
@@ -833,9 +842,9 @@ export type TypedValue =
| { type: "nat"; value: number }
| { type: "bounded_nat"; min: number; max: number; value: number }
| { type: "non_empty_string"; value: string }
- | { type: "prompt_scores"; value: PromptScores };
+ | { type: "prompt_scores"; value: Prompores };
-export interface PromptScores {
+export interface Prompores {
provenance: number;
replicability: number;
objective: number;
@@ -906,20 +915,20 @@ await new InsertBuilder("evidence")
'''''
+[[8-ada-bindings]]
=== 8. Ada Bindings
*Priority:* LOW - Safety-critical systems (where required per ecosystem)
-*Location:* `+bindings/ada/+`
+*Location:* `bindings/ada/`
-*Note:* Ada bindings follow same pattern as other languages but use
-Adaβs package system and GNAT FFI (Interfaces.C).
+*Note:* Ada bindings follow same pattern as other languages but use Ada's package system and GNAT FFI (Interfaces.C).
'''''
=== Language Priority Summary
-[width="100%",cols="27%,26%,26%,21%",options="header",]
+[cols=",,,",options="header",]
|===
|Language |Priority |Use Case |Status
|*ReScript* |β
CRITICAL |Web, apps, primary development |β
Specified
@@ -937,6 +946,7 @@ Adaβs package system and GNAT FFI (Interfaces.C).
=== Common Patterns Across All Bindings
+[[1-builder-pattern]]
==== 1. Builder Pattern
All languages use ergonomic builder APIs:
@@ -945,23 +955,36 @@ All languages use ergonomic builder APIs:
new(table) β column(name, value) β rationale(text) β execute()
....
+[[2-type-safety]]
==== 2. Type Safety
-Type systems leveraged where possible: - Rust: Enums + Result types -
-Haskell: GADTs + phantom types - ReScript: Variants + polymorphic
-variants - Gleam: Custom types + Result - Elixir: Type specs + structs
+Type systems leveraged where possible:
+
+* Rust: Enums {plus} Result types
+* Haskell: GADTs {plus} phantom types
+* ReScript: Variants {plus} polymorphic variants
+* Gleam: Custom types {plus} Result
+* Elixir: Type specs {plus} structs
+[[3-error-handling]]
==== 3. Error Handling
-All bindings return `+Result+`/`+Either+`/tuple types: - Rust:
-`+Result+` - ReScript: `+result<'a, 'e>+` - Gleam:
-`+Result(a, String)+` - Elixir: `+{:ok, value} | {:error, msg}+` -
-Haskell: `+Either String a+`
+All bindings return `Result`/`Either`/tuple types:
+
+* Rust: `Result++<++T, Error++>++`
+* ReScript: `result++<++'a, 'e++>++`
+* Gleam: `Result(a, String)`
+* Elixir: `++{++:ok, value} ++|++ ++{++:error, msg}`
+* Haskell: `Either String a`
+[[4-ffi-safety]]
==== 4. FFI Safety
-All bindings validate inputs before calling Zig FFI: - Non-null strings
-- Array bounds - Type tags
+All bindings validate inputs before calling Zig FFI:
+
+* Non-null strings
+* Array bounds
+* Type tags
'''''
@@ -969,7 +992,7 @@ All bindings validate inputs before calling Zig FFI: - Non-null strings
==== M9: ReScript Bindings (PRIORITY)
-* [ ] Create `+bindings/rescript/+` structure
+* [ ] Create `bindings/rescript/` structure
* [ ] Implement FFI bindings to Zig
* [ ] Builder API with type safety
* [ ] Examples and documentation
@@ -977,19 +1000,21 @@ All bindings validate inputs before calling Zig FFI: - Non-null strings
==== M10: Rust Bindings
-* [ ] Create `+bindings/rust/+` structure
-* [ ] Cargo.toml + build.rs
+* [ ] Create `bindings/rust/` structure
+* [ ] Cargo.toml {plus} build.rs
* [ ] FFI bindings via unsafe blocks
* [ ] Safe Rust API wrapper
* [ ] Examples and tests
-==== M11: Julia + Deno Bindings
+[[m11-julia--deno-bindings]]
+==== M11: Julia {plus} Deno Bindings
-* [ ] Julia: `+bindings/julia/+` with ccall
-* [ ] Deno: `+bindings/deno/+` with dlopen
+* [ ] Julia: `bindings/julia/` with ccall
+* [ ] Deno: `bindings/deno/` with dlopen
* [ ] Examples for both
-==== M12: BEAM Bindings (Gleam + Elixir)
+[[m12-beam-bindings-gleam--elixir]]
+==== M12: BEAM Bindings (Gleam {plus} Elixir)
* [ ] Erlang NIF (C bridge to Zig)
* [ ] Gleam bindings
@@ -1006,11 +1031,16 @@ All bindings validate inputs before calling Zig FFI: - Non-null strings
*Document Status:* Complete language binding specifications
-*Next Steps:* 1. Complete M6 Parser (typed IR generation) 2. Complete M7
-Idris2 ABI + M8 Zig FFI (foundation for all bindings) 3. Implement M9
-ReScript bindings (highest priority) 4. Implement remaining bindings
-based on ecosystem needs
+*Next Steps:*
+
+[arabic]
+. Complete M6 Parser (typed IR generation)
+. Complete M7 Idris2 ABI {plus} M8 Zig FFI (foundation for all bindings)
+. Implement M9 ReScript bindings (highest priority)
+. Implement remaining bindings based on ecosystem needs
+
+*See Also:*
-*See Also:* - `+docs/INTEGRATION.md+` - ReScript, WASM, ABI/FFI
-architecture - `+docs/EXECUTION-STRATEGY.md+` - Why native IR execution
-- `+~/abi-migration-guide.md+` - Idris2 ABI + Zig FFI universal standard
+* `docs/INTEGRATION.adoc` - ReScript, WASM, ABI/FFI architecture
+* `docs/EXECUTION-STRATEGY.adoc` - Why native IR execution
+* `~/abi-migration-guide.md` - Idris2 ABI {plus} Zig FFI universal standard
diff --git a/docs/LANGUAGE-DESIGN-STATUS.adoc b/docs/LANGUAGE-DESIGN-STATUS.adoc
index 69de847..faad971 100644
--- a/docs/LANGUAGE-DESIGN-STATUS.adoc
+++ b/docs/LANGUAGE-DESIGN-STATUS.adoc
@@ -1,98 +1,113 @@
== GQL-DT Language Design - Complete Status
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Date:* 2026-02-01 *Status:* β
ALL REQUIREMENTS MET
+*Date:* 2026-02-01
+*Status:* β
ALL REQUIREMENTS MET
'''''
=== Language Design Checklist
+[[white_check_mark-1-type-system-definition-and-implementation-of-custom-data-types]]
==== β
1. Type System: Definition and Implementation of Custom Data Types
*Status:* β
COMPLETE
-*Files:* - `+src/GqlDt/Types.lean+` - Core type definitions -
-`+src/GqlDt/Types/BoundedNat.lean+` - Bounded natural numbers with
-proofs - `+src/GqlDt/Types/BoundedInt.lean+` - Bounded integers with
-proofs - `+src/GqlDt/Types/NonEmptyString.lean+` - Non-empty strings
-with proofs - `+src/GqlDt/Types/Confidence.lean+` - Confidence scores
-[0, 100] - `+src/GqlDt/Prompt.lean+` - PROMPT score types -
-`+src/GqlDt/Prompt/PromptScores.lean+` - Auto-computed overall scores -
-`+src/GqlDt/Provenance.lean+` - Provenance tracking types
+*Files:*
+
+* `src/GqlDt/Types.lean` - Core type definitions
+* `src/GqlDt/Types/BoundedNat.lean` - Bounded natural numbers with proofs
+* `src/GqlDt/Types/BoundedInt.lean` - Bounded integers with proofs
+* `src/GqlDt/Types/NonEmptyString.lean` - Non-empty strings with proofs
+* `src/GqlDt/Types/Confidence.lean` - Confidence scores ++[++0, 100++]++
+* `src/GqlDt/Prompt.lean` - PROMPT score types
+* `src/GqlDt/Prompt/Prompores.lean` - Auto-computed overall scores
+* `src/GqlDt/Provenance.lean` - Provenance tracking types
*Custom Types Implemented:*
-[width="100%",cols="16%,25%,41%,18%",options="header",]
+[cols=",,,",options="header",]
|===
|Type |Refinement |Proof Obligation |Status
-|`+Nat+` |None |None |β
Built-in
+|`Nat` |None |None |β
Built-in
+|`BoundedNat min max` |`min β€ value β€ max` |`by omega` |β
Complete
+|`BoundedInt min max` |`min β€ value β€ max` |`by omega` |β
Complete
+|`NonEmptyString` |`length ++>++ 0` |`by decide` |β
Complete
+|`Confidence` |`0 β€ value β€ 100` |`by omega` |β
Complete
+|`Prompores` |6 dimensions {plus} overall |Auto-computed |β
Complete
+|`Tracked Ξ±` |Provenance metadata |Type-level |β
Complete
+|`ActorId` |Non-empty identifier |`by decide` |β
Complete
+|`Rationale` |Non-empty justification |`by decide` |β
Complete
+|===
-|`+BoundedNat min max+` |`+min β€ value β€ max+` |`+by omega+` |β
-Complete
+*Advanced Features:*
-|`+BoundedInt min max+` |`+min β€ value β€ max+` |`+by omega+` |β
-Complete
+* β
Dependent types (types depend on values)
+* β
Refinement types (subset types with predicates)
+* β
Type-indexed values (`TypedValue : TypeExpr β Type`)
+* β
Proof-carrying types (proofs attached to values)
+* β
Auto-computation (Prompores overall calculated automatically)
+* β
Provenance tracking (all data has actor/timestamp/rationale)
-|`+NonEmptyString+` |`+length > 0+` |`+by decide+` |β
Complete
+'''''
-|`+Confidence+` |`+0 β€ value β€ 100+` |`+by omega+` |β
Complete
+[[white_check_mark-2-grammar--syntax-formal-specification]]
+==== β
2. Grammar & Syntax: Formal Specification
-|`+PromptScores+` |6 dimensions + overall |Auto-computed |β
Complete
+*Status:* β
COMPLETE
-|`+Tracked Ξ±+` |Provenance metadata |Type-level |β
Complete
+*Files:*
-|`+ActorId+` |Non-empty identifier |`+by decide+` |β
Complete
+* `spec/GQL-DT-Grammar.ebnf` - Complete EBNF grammar (800{plus} lines)
+* `spec/GQL-DT-Lexical.adoc` - Lexical specification (700{plus} lines)
+* `spec/GQL-DT-Railroad-Diagrams.adoc` - Visual syntax (600{plus} lines)
+* `spec/README.adoc` - Specification index
-|`+Rationale+` |Non-empty justification |`+by decide+` |β
Complete
-|===
+*Formal Specifications:*
-*Advanced Features:* - β
Dependent types (types depend on values) - β
-Refinement types (subset types with predicates) - β
Type-indexed values
-(`+TypedValue : TypeExpr β Type+`) - β
Proof-carrying types (proofs
-attached to values) - β
Auto-computation (PromptScores overall
-calculated automatically) - β
Provenance tracking (all data has
-actor/timestamp/rationale)
+===== EBNF Grammar (ISO/IEC 14977)
-'''''
+β
DDL (Data Definition Language)
-==== β
2. Grammar & Syntax: Formal Specification
+* CREATE COLLECTION with type constraints
+* Target normal form specifications
+* Permission annotations
-*Status:* β
COMPLETE
+β
DML (Data Manipulation Language)
-*Files:* - `+spec/GQL-DT-Grammar.ebnf+` - Complete EBNF grammar (800+
-lines) - `+spec/GQL-DT-Lexical.md+` - Lexical specification (700+ lines)
-- `+spec/GQL-DT-Railroad-Diagrams.md+` - Visual syntax (600+ lines) -
-`+spec/README.md+` - Specification index
+* INSERT with type annotations and proofs
+* SELECT with type refinements
+* UPDATE with proof obligations
+* DELETE with mandatory rationale
-*Formal Specifications:*
+β
Normalization Commands
-===== EBNF Grammar (ISO/IEC 14977)
+* NORMALIZE to target normal form
+* Decomposition strategies
+* Preservation proofs
-β
DDL (Data Definition Language) - CREATE COLLECTION with type
-constraints - Target normal form specifications - Permission annotations
+β
Type Expressions
-β
DML (Data Manipulation Language) - INSERT with type annotations and
-proofs - SELECT with type refinements - UPDATE with proof obligations -
-DELETE with mandatory rationale
+* Primitive types (Nat, Int, String, Bool)
+* Refined types (BoundedNat, NonEmptyString)
+* Dependent types (Prompores, custom)
+* Function types (for constraints)
-β
Normalization Commands - NORMALIZE to target normal form -
-Decomposition strategies - Preservation proofs
+β
Proof Syntax
-β
Type Expressions - Primitive types (Nat, Int, String, Bool) - Refined
-types (BoundedNat, NonEmptyString) - Dependent types (PromptScores,
-custom) - Function types (for constraints)
-
-β
Proof Syntax - WITH_PROOF blocks - Tactic invocations (omega, decide,
-simp) - Custom proof terms
+* WITH++_++PROOF blocks
+* Tactic invocations (omega, decide, simp)
+* Custom proof terms
===== Lexical Specification
-β
Reserved Keywords (80+) - SQL keywords (case-insensitive): SELECT,
-INSERT, UPDATE, DELETE, etc. - Type keywords (case-sensitive):
-BoundedNat, NonEmptyString, etc. - Proof keywords: WITH_PROOF,
-RATIONALE, THEOREM, etc.
+β
Reserved Keywords (80{plus})
+
+* SQL keywords (case-insensitive): SELECT, INSERT, UPDATE, DELETE, etc.
+* Type keywords (case-sensitive): BoundedNat, NonEmptyString, etc.
+* Proof keywords: WITH++_++PROOF, RATIONALE, THEOREM, etc.
β
Operators & Precedence (11 levels)
@@ -110,33 +125,45 @@ Level 10: [] (array access)
Level 11: () (function call, grouping)
....
-β
Identifiers - Unicode support (XID_Start, XID_Continue) -
-Backtick-quoted identifiers for reserved words - Schema-qualified names
-(schema.table.column)
+β
Identifiers
-β
Literals - Natural numbers: `+0+`, `+42+`, `+1_000_000+` - Integers:
-`+-1+`, `++42+` - Floats: `+3.14+`, `+1.0e-5+` - Strings:
-`+'single quotes'+`, `+"double quotes"+` - Escape sequences: `+\n+`,
-`+\t+`, `+\x2A+`, `+\u{1F4A9}+`
+* Unicode support (XID++_++Start, XID++_++Continue)
+* Backtick-quoted identifiers for reserved words
+* Schema-qualified names (schema.table.column)
+
+β
Literals
+
+* Natural numbers: `0`, `42`, `1++_++000++_++000`
+* Integers: `-1`, `{plus}42`
+* Floats: `3.14`, `1.0e-5`
+* Strings: `'single quotes'`, `"double quotes"`
+* Escape sequences: `++\++n`, `++\++t`, `++\++x2A`, `++\++u++{++1F4A9}`
===== Railroad Diagrams
-β
CREATE COLLECTION syntax β
INSERT statement with types β
SELECT
-with refinements β
Type expressions β
Proof clauses β
UPDATE
-statements β
Normalization commands
+β
CREATE COLLECTION syntax
+β
INSERT statement with types
+β
SELECT with refinements
+β
Type expressions
+β
Proof clauses
+β
UPDATE statements
+β
Normalization commands
'''''
+[[white_check_mark-3-type-safety-rules-for-ensuring-type-safety]]
==== β
3. Type Safety: Rules for Ensuring Type Safety
*Status:* β
COMPLETE
-*Files:* - `+docs/TYPE-SAFETY-ENFORCEMENT.md+` - Complete guide (500+
-lines) - `+src/GqlDt/AST.lean+` - Type-safe AST -
-`+src/GqlDt/TypeSafe.lean+` - Smart constructors -
-`+src/GqlDt/TypeChecker.lean+` - Type checker with validation -
-`+src/GqlDt/TypeSafeQueries.lean+` - Type safety examples -
-`+test/TypeSafetyTests.lean+` - Test demonstrations
+*Files:*
+
+* `docs/TYPE-SAFETY-ENFORCEMENT.adoc` - Complete guide (500{plus} lines)
+* `src/GqlDt/AST.lean` - Type-safe AST
+* `src/GqlDt/TypeSafe.lean` - Smart constructors
+* `src/GqlDt/TypeChecker.lean` - Type checker with validation
+* `src/GqlDt/TypeSafeQueries.lean` - Type safety examples
+* `test/TypeSafetyTests.lean` - Test demonstrations
*Type Safety Enforcement:*
@@ -167,7 +194,7 @@ structure InsertStmt (schema : Schema) where
* Construction requires proofs of correctness
* Auto-proved with tactics (omega, decide, simp)
-* If proof fails β query doesnβt compile
+* If proof fails β query doesn't compile
β
*Smart Constructors*
@@ -182,18 +209,25 @@ def mkInsert (schema : Schema) ... (h : ) : InsertStmt schema
===== Runtime (GQL Tier)
-β
*Type Inference* - Infer dependent types from SQL-like syntax -
-Auto-generate proof attempts - Fall back to runtime validation if proofs
-fail
+β
*Type Inference*
+
+* Infer dependent types from SQL-like syntax
+* Auto-generate proof attempts
+* Fall back to runtime validation if proofs fail
-β
*Transaction Validation* - Invalid queries rejected BEFORE commit -
-No bad data reaches database - User sees helpful error messages with
-suggestions
+β
*Transaction Validation*
-β
*Four-Layer Defense* 1. UI validation (Lithoglyph Studio
-forms/dropdowns) 2. Type inference + runtime checks (GQL parser) 3.
-Compile-time proofs (GQL-DT parser) 4. Database constraints (final
-safety net)
+* Invalid queries rejected BEFORE commit
+* No bad data reaches database
+* User sees helpful error messages with suggestions
+
+β
*Four-Layer Defense*
+
+[arabic]
+. UI validation (Lithoglyph Studio forms/dropdowns)
+. Type inference {plus} runtime checks (GQL parser)
+. Compile-time proofs (GQL-DT parser)
+. Database constraints (final safety net)
*Theorem:*
@@ -209,13 +243,15 @@ Well-typed queries cannot produce runtime type errors.
'''''
-==== β
4. Serialization/Deserialization: Converting Between Types and Storage Formats
+[[white_check_mark-4-serializationdeserialization-converting-between-types-and-storage-formats]]
+==== 4. Serialization/Deserialization: Partial Private Substrate
-*Status:* β
COMPLETE
+*Status:* Partial. Selected typed-value codecs exist. The pipeline refuses complete IR interchange when it would lose clauses or require unchecked proof reconstruction. The supported public snapshot format is documented in link:narration-slice.adoc[the narration guide]; link:executable-boundary.adoc[the executable boundary] supersedes the historical codec claims below.
-*Files:* - `+src/GqlDt/Serialization.lean+` - *NEW* Complete
-serialization (600+ lines) - `+src/GqlDt/IR.lean+` - IR with CBOR
-support
+*Files:*
+
+* `src/GqlDt/Serialization.lean` - *NEW* Complete serialization (600{plus} lines)
+* `src/GqlDt/IR.lean` - IR with CBOR support
*Supported Formats:*
@@ -234,8 +270,11 @@ support
}
----
-β
*Deserialize JSON β TypedValue* - Type tag preserved - Proof blobs
-included - Round-trip identity
+β
*Deserialize JSON β TypedValue*
+
+* Type tag preserved
+* Proof blobs included
+* Round-trip identity
===== CBOR (RFC 8949) - Proof Blobs, IR Transport
@@ -245,12 +284,13 @@ included - Round-trip identity
Tag 1000: BoundedNat
Tag 1001: NonEmptyString
Tag 1002: Confidence
-Tag 1003: PromptScores
+Tag 1003: Prompores
Tag 1004: ProofBlob
....
-β
*Deterministic encoding* β
*Compact representation* β
*Schema
-evolution support*
+β
*Deterministic encoding*
+β
*Compact representation*
+β
*Schema evolution support*
===== Binary (Lithoglyph Native Storage)
@@ -260,8 +300,9 @@ evolution support*
[Tag: 1 byte][Value data: N bytes][Proof blob: M bytes]
....
-β
*Little-endian encoding* β
*Fixed-width for primitive types* β
-*Length-prefixed for strings*
+β
*Little-endian encoding*
+β
*Fixed-width for primitive types*
+β
*Length-prefixed for strings*
===== Database-Native (SQL Compatibility)
@@ -273,24 +314,31 @@ def toSQLValue (tv : TypedValue t) : String
def fromSQLValue (sql : String) (hint : TypeExpr) : TypedValue t
----
-β οΈ *WARNING: Type information lost!* - BoundedNat β INTEGER (bounds
-lost) - NonEmptyString β TEXT (proof lost) - Only for compatibility
-layer
+β οΈ *WARNING: Type information lost!*
-*Features:* - β
Preserve type information in serialized form - β
-Include proofs in representation - β
Round-trip identity (serialize β
-deserialize = id) - β
Versioned formats for schema evolution - β
-Format selection at runtime
+* BoundedNat β INTEGER (bounds lost)
+* NonEmptyString β TEXT (proof lost)
+* Only for compatibility layer
+
+*Features:*
+
+* β
Preserve type information in serialized form
+* β
Include proofs in representation
+* β
Round-trip identity (serialize β deserialize = id)
+* β
Versioned formats for schema evolution
+* β
Format selection at runtime
'''''
+[[white_check_mark-5-integration-with-rescript-bindings-type-definitions-utilities]]
==== β
5. Integration with ReScript: Bindings, Type Definitions, Utilities
*Status:* β
COMPLETE
-*Files:* - `+docs/INTEGRATION.md+` - ReScript bindings architecture
-(1200+ lines) - `+docs/LANGUAGE-BINDINGS.md+` - Multi-language bindings
-(2000+ lines)
+*Files:*
+
+* `docs/INTEGRATION.adoc` - ReScript bindings architecture (1200{plus} lines)
+* `docs/LANGUAGE-BINDINGS.adoc` - Multi-language bindings (2000{plus} lines)
*ReScript Integration:*
@@ -326,7 +374,7 @@ module TypedValue = {
| Nat(int)
| BoundedNat({min: int, max: int, value: int})
| NonEmptyString(string)
- | PromptScores(PromptScores.t)
+ | Prompores(Prompores.t)
}
----
@@ -343,9 +391,10 @@ external fromCBOR: Js.TypedArray2.Uint8Array.t => result =
===== WASM Support
-β
*Browser-compatible WASM module* β
*Client-side type checking* β
-*Offline Lithoglyph Studio (IndexedDB)* β
*Edge computing (Cloudflare
-Workers, Deno Deploy)*
+β
*Browser-compatible WASM module*
+β
*Client-side type checking*
+β
*Offline Lithoglyph Studio (IndexedDB)*
+β
*Edge computing (Cloudflare Workers, Deno Deploy)*
===== Builder API
@@ -373,14 +422,17 @@ let insertEvidence = async () => {
===== Utilities
-β
*JSON serialization helpers* β
*CBOR encoding/decoding* β
*Type
-validation* β
*Error handling with Result types* β
*Promise-based
-async API*
+β
*JSON serialization helpers*
+β
*CBOR encoding/decoding*
+β
*Type validation*
+β
*Error handling with Result types*
+β
*Promise-based async API*
'''''
=== Additional Language Bindings (Bonus)
+[[white_check_mark-rust-bindings]]
==== β
Rust Bindings
* Cargo integration
@@ -388,24 +440,28 @@ async API*
* Result error handling
* FFI via unsafe blocks
+[[white_check_mark-julia-bindings]]
==== β
Julia Bindings
* ccall to Zig FFI
* Type-safe API
* Batch script support
+[[white_check_mark-gleamelixir-bindings]]
==== β
Gleam/Elixir Bindings
* Erlang NIF bridge
* BEAM integration
* Phoenix support
+[[white_check_mark-haskell-bindings]]
==== β
Haskell Bindings
* GADTs for type safety
* Phantom types
* Scaffoldia integration
+[[white_check_mark-denojavascript-bindings]]
==== β
Deno/JavaScript Bindings
* dlopen FFI
@@ -418,8 +474,10 @@ async API*
*Status:* β
DECIDED - Native IR Execution
-*Files:* - `+docs/EXECUTION-STRATEGY.md+` - Complete analysis (1500+
-lines) - `+src/GqlDt/IR.lean+` - Typed intermediate representation
+*Files:*
+
+* `docs/EXECUTION-STRATEGY.adoc` - Complete analysis (1500{plus} lines)
+* `src/GqlDt/IR.lean` - Typed intermediate representation
*Architecture:*
@@ -437,11 +495,12 @@ Lithoglyph Native Execution (Zig/Rust)
Direct storage operations (no SQL)
....
-*Performance:* - Native IR: 170ms (10k inserts) β
- SQL compilation:
-270ms (10k inserts) β
+*Performance:*
+
+* Native IR: 170ms (10k inserts) β
+* SQL compilation: 270ms (10k inserts) β
-*Decision:* Native IR execution is *faster* and preserves type safety.
-SQL compilation only for optional compatibility layer.
+*Decision:* Native IR execution is *faster* and preserves type safety. SQL compilation only for optional compatibility layer.
'''''
@@ -449,8 +508,9 @@ SQL compilation only for optional compatibility layer.
*Status:* β
DESIGNED
-*Files:* - `+docs/TWO-TIER-DESIGN.md+` - Complete architecture (1000+
-lines)
+*Files:*
+
+* `docs/TWO-TIER-DESIGN.adoc` - Complete architecture (1000{plus} lines)
*Tiers:*
@@ -464,9 +524,11 @@ lines)
|Users |Admins, developers |Everyone else
|===
-*Permission System:* β
Granular type whitelists β
Per-role validation
-levels β
Workplace-specific restrictions (e.g., "`only Nat, String,
-Date`") β
Form-based UI (no SQL exposure)
+*Permission System:*
+β
Granular type whitelists
+β
Per-role validation levels
+β
Workplace-specific restrictions (e.g., "only Nat, String, Date")
+β
Form-based UI (no SQL exposure)
'''''
@@ -474,7 +536,9 @@ Date`") β
Form-based UI (no SQL exposure)
*Status:* β
DESIGNED (Implementation in M7-M8)
-*Files:* - `+docs/INTEGRATION.md+` - Idris2 ABI + Zig FFI architecture
+*Files:*
+
+* `docs/INTEGRATION.adoc` - Idris2 ABI {plus} Zig FFI architecture
*Stack:*
@@ -490,37 +554,36 @@ Zig FFI (C-compatible bridge)
ReScript/Rust/Julia/Gleam/etc.
....
-*Benefits:* - β
Formally verified ABI (Idris2 dependent types) - β
-Memory-safe FFI (Zig) - β
Cross-platform (Linux/macOS/Windows/WASM) -
-β
C ABI compatible (all languages)
+*Benefits:*
+
+* β
Formally verified ABI (Idris2 dependent types)
+* β
Memory-safe FFI (Zig)
+* β
Cross-platform (Linux/macOS/Windows/WASM)
+* β
C ABI compatible (all languages)
'''''
=== Summary: Language Design Completeness
-[width="100%",cols="38%,22%,20%,20%",options="header",]
+[cols=",,,",options="header",]
|===
|Requirement |Status |Files |Notes
-|*1. Type System* |β
COMPLETE |9 files |All custom types implemented
-with proofs
-
-|*2. Grammar & Syntax* |β
COMPLETE |4 files |EBNF, lexical, railroad
-diagrams
-
-|*3. Type Safety* |β
COMPLETE |5 files |Compile-time + runtime
-enforcement
-
-|*4. Serialization* |β
COMPLETE |1 file |JSON, CBOR, Binary, SQL
-formats
-
-|*5. ReScript Integration* |β
COMPLETE |2 files |Bindings, WASM,
-utilities
+|*1. Type System* |β
COMPLETE |9 files |All custom types implemented with proofs
+|*2. Grammar & Syntax* |β
COMPLETE |4 files |EBNF, lexical, railroad diagrams
+|*3. Type Safety* |β
COMPLETE |5 files |Compile-time {plus} runtime enforcement
+|*4. Serialization* |β
COMPLETE |1 file |JSON, CBOR, Binary, SQL formats
+|*5. ReScript Integration* |β
COMPLETE |2 files |Bindings, WASM, utilities
|===
-*Bonus:* - β
IR design (native execution) - β
Type inference (GQL
-tier) - β
Permission system (granular controls) - β
Multi-language
-bindings (8 languages) - β
Execution strategy (native vs SQL) - β
-Two-tier architecture (GQL-DT + GQL) - β
ABI/FFI design (Idris2 + Zig)
+*Bonus:*
+
+* β
IR design (native execution)
+* β
Type inference (GQL tier)
+* β
Permission system (granular controls)
+* β
Multi-language bindings (8 languages)
+* β
Execution strategy (native vs SQL)
+* β
Two-tier architecture (GQL-DT {plus} GQL)
+* β
ABI/FFI design (Idris2 {plus} Zig)
'''''
@@ -528,12 +591,15 @@ Two-tier architecture (GQL-DT + GQL) - β
ABI/FFI design (Idris2 + Zig)
*Current:* Type system, grammar, type safety, serialization all complete
-*Ready to implement:* 1. β
IR data structures β *DONE*
-(src/GqlDt/IR.lean) 2. β
Type inference β *DONE*
-(src/GqlDt/TypeInference.lean) 3. β
Serialization β *DONE*
-(src/GqlDt/Serialization.lean) 4. β³ Actual parser (text β AST) - NEXT
-5. β³ AST β IR generation - NEXT 6. β³ CBOR encoding implementation -
-NEXT
+*Ready to implement:*
+
+[arabic]
+. β
IR data structures β *DONE* (src/GqlDt/IR.lean)
+. β
Type inference β *DONE* (src/GqlDt/TypeInference.lean)
+. β
Serialization β *DONE* (src/GqlDt/Serialization.lean)
+. β³ Actual parser (text β AST) - NEXT
+. β³ AST β IR generation - NEXT
+. β³ CBOR encoding implementation - NEXT
*All language design requirements: β
COMPLETE*
@@ -541,5 +607,4 @@ NEXT
*Document Status:* Complete language design verification
-*Recommendation:* All requirements met. Ready for parser implementation
-(M6).
+*Recommendation:* All requirements met. Ready for parser implementation (M6).
diff --git a/docs/LITHOGLYPH.adoc b/docs/LITHOGLYPH.adoc
index 49f2c8b..6a58ef1 100644
--- a/docs/LITHOGLYPH.adoc
+++ b/docs/LITHOGLYPH.adoc
@@ -1,204 +1,97 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
-= GNPL for Lithoglyph β the tethered case
-:toc: macro
-:toclevels: 3
+= GNPL for Lithoglyph: the integration contract
+:revdate: 2026-09-07
-*Status:* design document. Companion to link:THEORY.adoc[`THEORY.adoc`], which argues the
-general case. This document argues the specific one: **what GNPL buys Lithoglyph**, and why
-Lithoglyph is an unusually good host for it.
+GNPL expresses warranted accounts over evidence. Lithoglyph is the intended
+source of durable evidence and provenance; Glyphbase is the intended application
+surface. Their owning repositories are `hyperpolymath/lithoglyph` and
+`hyperpolymath/glyphbase`. The umbrella repository coordinates this relationship.
-toc::[]
+== What runs today
-== Summary
+The direct-evidence kernel, `.gnpl` projection parser and `gnpl` executable run
+against an imported `gnpl-evidence-v1` snapshot. They construct ordered accounts,
+apply focalization and a declared threshold, retain rival accounts, and
+re-evaluate a projection after a hypothetical source withdrawal.
-Lithoglyph already pays, at write time, the cost that a narration language needs someone to
-have paid. Three facts, all verifiable in the code rather than asserted:
-
-. **Every mutation is journalled.** `Form.Blocks` maintains an append-only journal of all
- mutations, with the invariant that *journal entries are written before block mutations*
- (`nextgen-databases/lithoglyph/ARCHITECTURE.adoc`).
-. **Every modification carries a reason.** `src/GqlDt/Provenance/Rationale.lean`:
- *"Every data modification in GQLdt must include a rationale. This is enforced at the type
- level β you cannot construct a `Tracked` value without providing a non-empty rationale."*
-. **Provenance crosses the ABI.** `bridge/lith_types.zig` already marshals `ActorIdC`,
- `RationaleC`, `ProvenanceC` and `TrackedValueC` as C-ABI structs, alongside proof blobs
- and six-dimension source-quality scores.
-
-In most databases, building narration means first retrofitting provenance β the hard,
-invasive part. Here it is already done and already mandatory. **GNPL is the layer that
-makes that investment pay.**
-
-== The argument from sunk cost
-
-Right now, mandatory rationale is a *tax*. Writers must supply a non-empty justification for
-every modification. Nothing in the system consumes it. It is stored, marshalled across the
-FFI boundary, and β absent a reader β mostly never read.
-
-This is a familiar failure mode: a governance feature that imposes cost at write time and
-delivers value nowhere, until it is quietly disabled or filled with boilerplate
-("Initial data entry", "User request" β both are literally the pre-baked constants in
-`Rationale.lean`).
-
-GNPL changes the economics. Once accounts are generated *from* warrant, rationale quality
-becomes directly observable: a lazy rationale produces a visibly weak account. The feature
-starts defending itself.
-
-== Mapping: GNPL constructs to what Lithoglyph already has
-
-[cols="1,2,2",options=header]
-|===
-| GNPL construct | Lithoglyph/GQLdt substrate | Status
-
-| `Fabula`
-| The `Form.Blocks` append-only mutation journal
-| **Exists.** Needs a typed view, not new storage.
-
-| `Warrant`
-| `Provenance/Rationale` + `Types/Confidence`
-| **Exists**, enforced at construction.
-
-| `Focalization`
-| `Provenance/ActorId`
-| **Exists** as an identifier; the *access restriction* is new.
-
-| Entrenchment (for retraction)
-| PROMPT scores β provenance, replicability, objective, methodology, publication,
- transparency (`bridge/lith_types.zig`)
-| **Exists** as data; not yet used as an ordering.
-
-| `Account`, `Projection`, `Plurality`
-| β
-| **New.** This is the work.
-|===
-
-The right-hand column is the point: three of the six are already built, and the two hardest
-to retrofit (journal, mandatory warrant) are the ones already present.
-
-=== Where GNPL sits in the stack
-
-Lithoglyph's layering (Elixir control plane β Factor runtime β Zig bridge β Forth model β
-Forth blocks) is unchanged. GNPL adds one layer at the top and reuses the existing descent:
+See link:narration-slice.adoc[the runnable slice] for commands, examples, tests
+and the exact warrant rule. The example JSON is a fixture. It is not a journal
+export produced by a live Lithoglyph adapter.
----
- GNPL (narration: "what account") <-- new
- β lowers to
- GQLdt (query: "what is") <-- exists, builds
- β FFI (liblith_bridge.a)
- Form.Bridge (Zig ABI) <-- exists
- β
- Form.Model / Form.Blocks (Forth) <-- exists, journalled
+Lithoglyph evidence/journal
+ | read-only snapshot adapter: next integration
+ v
+GNPL evidence snapshot + declared projection
+ | implemented direct-evidence narration kernel
+ v
+Account with warrant trail, or explicit refusal
+ | durable account storage and rendering: later integration
+ v
+Glyphbase
----
-No new descent path, no second storage engine, and no change to the write path. GNPL is
-read-side only β which is also what makes it safe to build incrementally.
+Selection and storage validation remain private machinery. GNPL has no fixed
+public intermediate language or promised compilation route through the existing
+storage modules.
-== Five concrete capabilities
-
-=== 1. Forensic history as a query, not a report
-
-Today, "reconstruct what happened to record R" is a human task: read the audit trail,
-interpret it, write it up. It is slow, unrepeatable, and its quality varies by analyst.
-
-With GNPL it is a projection:
-
-----
-account of R
- focalized by actor A
- as at 2026-03-01
-----
+== What the adapter must establish
-Repeatable, diffable, and β critically β *attributable*: the account states its own warrant,
-so a reader can audit the reasoning rather than trusting the writer.
-
-=== 2. Contradiction as a result, not a defect
-
-Two sources disagree about a field's value. Conventional handling: last-write-wins, or a
-constraint violation, or an application-level "conflict" flag that every consumer
-re-interprets.
-
-GNPL returns *both* accounts, marked **rival**, each with its warrant. The disagreement
-becomes a first-class answer. For an evidence database β which is what "narrative-first"
-means in practice β this is the difference between recording the evidence and destroying it.
-
-=== 3. Impact analysis: "if this source falls, what falls with it?"
-
-This is the counterfactual operation from `THEORY.adoc`, and it is the capability with the
-clearest external demand. A source is retracted, a witness is discredited, a dataset is
-found to be fabricated. The question is immediate and currently very hard: **which of our
-conclusions rested on it?**
-
-Because every assertion in an account carries its warrant chain, this is a retraction and
-re-projection, and the answer is a diff. The estate's misinformation-defence work wants
-exactly this; so does any newsroom or audit function.
-
-Note the honest limit: this answers *which narrated claims lose their warrant*. It does not
-answer whether they are false β an unwarranted claim may still be true.
-
-=== 4. Entrenchment from PROMPT, not from stipulation
-
-`THEORY.adoc` flags an open question in belief revision: AGM says retraction should respect
-an entrenchment ordering, but is silent on where that ordering comes from. Lithoglyph
-already scores sources on six dimensions.
-
-That gives a *defensible*, data-derived entrenchment ordering rather than a stipulated one β
-which is unusual, and worth exploiting.
-
-[WARNING]
-====
-`PromptScoresC.computeOverall` currently takes an **unweighted mean** of the six dimensions,
-and `Confidence.avg` likewise averages. Neither is probabilistically principled, and both
-would be load-bearing if used as an entrenchment ordering. This must be resolved before any
-retraction result is shown to a user β see open question 2 in `THEORY.adoc`.
-====
-
-=== 5. Glyphbase gets a rendering target
-
-`glyphbase` (the Lithoglyph web UI, already extracted to its own repo) currently renders
-records. An `Account` is a *document* β ordered, warranted, attributable. It is a far more
-natural thing to render than a result grid, and it gives the UI a reason to display
-provenance inline rather than in a hidden audit tab.
-
-== What this does not do
-
-Stating the limits plainly, because a narration layer invites over-claiming:
-
-* **It does not adjudicate.** GNPL never says which rival account is true.
-* **It does not improve the data.** Weak rationales yield weak accounts. GNPL makes that
- visible; it does not fix it.
-* **It does not replace the audit log.** The journal remains the record of fact; an account
- is an interpretation *of* it, and must never be mistaken for it.
-* **It adds no write-path guarantees.** Everything here is read-side.
-
-== Sequencing
-
-A build order that keeps each step independently useful:
-
-. **Typed view over the journal** β `Fabula` as a read-only projection of `Form.Blocks`.
- Useful alone: a principled history API.
-. **`Warrant` + `Account`** with the no-narration-without-warrant constructor. Useful alone:
- generated, attributable audit narratives.
-. **`Focalization`** as access restriction. Useful alone: per-actor views.
-. **`Plurality`** β rival/compatible/entailing relations. The first genuinely novel step.
-. **Counterfactual retraction + stability proofs.** The capability with the most external
- pull, and the one that most needs open question 2 settled first.
-
-Steps 1β3 are largely engineering over existing substrate. Steps 4β5 are research.
-
-== Prerequisites
+[cols="1,3",options=header]
+|===
+| Snapshot field | Required mapping and check
+| Snapshot identity and revision
+| Read a consistent evidence state and identify it reproducibly. A historical
+ account refers to that state; later withdrawal requires a new evaluation.
+| Evidence identifier and structured claim
+| Preserve distinct source assertions, including disagreements. Each identifier
+ is unique within the imported snapshot. Subject/slot/value matching in the
+ first fragment assumes a single-valued slot within each account.
+| Source and rationale
+| Preserve attribution and a readable rationale. Journal membership, a nonempty
+ reason or an ABI proof blob alone does not establish semantic warrant.
+| Audience
+| Derive visibility from an explicit policy. The current local importer trusts
+ supplied audience lists; it provides no actor authentication or access service.
+| Declared confidence
+| Provide an integer in 0β100 with its interpretation documented. The kernel
+ compares it to a threshold; it does not average PROMPT dimensions or derive a
+ probability, entrenchment ordering or winner.
+| Withdrawal
+| Map retractions to evidence status without rewriting historical snapshots.
+ Test a cited withdrawal, an unrelated withdrawal and revision consistency.
+|===
-* `lake build` green β **partially satisfied**: it builds, 34/35 targets, and Lean reports
- no incomplete proofs. But Lean's `sorry` warning does not fire on `axiom`, and GQLdt
- declares **16 axioms**, all stubs β five of them in *executable* position, so those
- functions have no implementation at all. See `docs/proof-debt.md`. Steps 1β3 of the
- sequencing above depend on the *types*, which are sound; step 5's stability proofs
- depend on the axioms actually being discharged.
-* Zig bridge building β **satisfied**: `bridge/` produces `liblith_bridge.a` and its tests
- pass.
-* A decision on `Confidence` representation. `Types/Confidence.lean` notes it uses runtime
- validation over `Float` "since Float proofs are complex in Lean 4". A narration layer that
- proves stability properties will feel this; an exact rational or interval type may be
- required.
-* Lithoglyph's own extraction to `hyperpolymath/lithoglyphdb` is still pending; until then
- `nextgen-databases/lithoglyph` is canonical. GNPL should depend on the *interface*
- (the Zig ABI), not the location.
+The existing ABI/FFI structures are potential integration components. Their
+presence does not establish that these mappings, durable writes or read paths
+are wired. In particular, the proof registry's refusal of unimplemented
+verifiers must remain visible to any adapter that asks for certificate checking.
+
+== Why this serves Lithoglyph
+
+* A forensic account can show the source, rationale, stance and declared score
+ alongside each assertion, making its dependency on recorded evidence inspectable.
+* Conflicting source assertions can support separate rival accounts. The first
+ fragment detects rival values for a subject/slot and does not adjudicate truth.
+* A hypothetical withdrawal can identify when this particular account loses its
+ warrant. An invalidated account is not a finding that its claims are false.
+* Glyphbase can eventually render an ordered account and its warrant trail,
+ including revision and withdrawal results, once the durable path is implemented.
+
+The current slice does not implement causal reconstruction, event-time queries,
+general argumentation, automatic account search, derivation chains or confidence
+composition. Those require further semantics; they are not implied by the
+source's rationale text or by passing storage tests.
+
+== Next acceptance boundary
+
+Create evidence through a real Lithoglyph interface, import a consistent snapshot,
+and narrate an account using that imported evidence. Then withdraw one cited
+item through the same store and show that a fresh projection refuses it while
+the historical account remains tied to its earlier snapshot. A parallel control
+must withdraw an uncited item and preserve the account.
+
+Only after that path passes should Glyphbase claim a durable account workflow.
+The local counterfactual command already exercises the corresponding kernel
+behaviour without changing the input file.
diff --git a/docs/M6-PARSER-STATUS.adoc b/docs/M6-PARSER-STATUS.adoc
index 4dab784..0a52706 100644
--- a/docs/M6-PARSER-STATUS.adoc
+++ b/docs/M6-PARSER-STATUS.adoc
@@ -1,30 +1,30 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
== M6 Parser Implementation - Status Report
-*Date:* 2026-02-01 *Status:* β
*Substantially Complete* (85%) *Next
-Milestone:* M7 (Idris2 ABI) + M8 (Zig FFI)
+*Date:* 2026-02-01
+*Status:* β
*Substantially Complete* (85%)
+*Next Milestone:* M7 (Idris2 ABI) {plus} M8 (Zig FFI)
'''''
=== Overview
-Milestone 6 (GQL-DT/GQL Parser) has been substantially completed. The
-parser infrastructure is feature-complete for basic queries (INSERT,
-SELECT, UPDATE, DELETE), with full CBOR encoding/decoding, type
-inference, and IR generation.
+Milestone 6 (GQL-DT/GQL Parser) has been substantially completed. The parser infrastructure is feature-complete for basic queries (INSERT, SELECT, UPDATE, DELETE), with full CBOR encoding/decoding, type inference, and IR generation.
=== Completed Components
-==== 1. Lexer (`+src/GqlDt/Lexer.lean+`) β
+[[1-lexer-srcgqldtlexerlean-white_check_mark]]
+==== 1. Lexer (`src/GqlDt/Lexer.lean`) β
*Status:* 100% Complete
-* *Token Types:* 80+ keywords (SQL, type, proof, Lithoglyph)
+* *Token Types:* 80{plus} keywords (SQL, type, proof, Lithoglyph)
* *Operators:* 11 precedence levels
* *Literals:* Nat, Int, Float, String, Bool
-* *Identifiers:* Unicode support (XID_Start, XID_Continue)
-* *Case Sensitivity:* SQL keywords case-insensitive, type keywords
-case-sensitive
-* *Comments:* Single-line (`+--+`) and multi-line (`+/* */+`)
+* *Identifiers:* Unicode support (XID++_++Start, XID++_++Continue)
+* *Case Sensitivity:* SQL keywords case-insensitive, type keywords case-sensitive
+* *Comments:* Single-line (`--`) and multi-line (`/++*++ ++*++/`)
* *Whitespace Handling:* Complete
*Key Functions:*
@@ -38,50 +38,61 @@ def lookupKeyword (s : String) : Option TokenType
'''''
-==== 2. Parser Combinators (`+src/GqlDt/Parser.lean+`) β
+[[2-parser-combinators-srcgqldtparserlean-white_check_mark]]
+==== 2. Parser Combinators (`src/GqlDt/Parser.lean`) β
*Status:* 95% Complete
-*Basic Combinators:* β
- `+peek+`, `+advance+`, `+next+` - Token
-navigation - `+expect+`, `+expectIdentifier+` - Specific token matching
-- `+optional+`, `+many+`, `+many1+`, `+sepBy+` - Standard combinators
+*Basic Combinators:* β
-*Expression Parsing:* β
- `+parseLiteral+` - All literal types -
-`+parseTypeExpr+` - Type expressions including `+BoundedNat min max+`
+* `peek`, `advance`, `next` - Token navigation
+* `expect`, `expectIdentifier` - Specific token matching
+* `optional`, `many`, `many1`, `sepBy` - Standard combinators
+
+*Expression Parsing:* β
+
+* `parseLiteral` - All literal types
+* `parseTypeExpr` - Type expressions including `BoundedNat min max`
*Statement Parsing:* β
-[width="100%",cols="39%,27%,34%",options="header",]
+[cols=",,",options="header",]
|===
|Statement |Status |Features
|*INSERT* |β
Complete |Both GQL (inferred) and GQL-DT (explicit types)
-
|*SELECT* |β
Complete |SELECT list, FROM clause, WHERE, ORDER BY, LIMIT
-
-|*UPDATE* |β
Complete |SET assignments, optional WHERE, mandatory
-RATIONALE
-
+|*UPDATE* |β
Complete |SET assignments, optional WHERE, mandatory RATIONALE
|*DELETE* |β
Complete |Mandatory WHERE (safety), mandatory RATIONALE
|===
-*WHERE Clause:* β
- Column comparison predicates (`+column op value+`)
-- All comparison operators: `+=+`, `+<+`, `+>+`, `+<=+`, `+>=+`, `+!=+`
-- *TODO:* Complex expressions (AND, OR, NOT, nested predicates)
+*WHERE Clause:* β
-*ORDER BY Clause:* β
- Multiple columns - ASC/DESC direction (partially
-implemented)
+* Column comparison predicates (`column op value`)
+* All comparison operators: `=`, `++<++`, `++>++`, `++<++=`, `++>++=`, `!=`
+* *TODO:* Complex expressions (AND, OR, NOT, nested predicates)
-*LIMIT Clause:* β
- Natural number literals
+*ORDER BY Clause:* β
+
+* Multiple columns
+* ASC/DESC direction (partially implemented)
+
+*LIMIT Clause:* β
+
+* Natural number literals
'''''
-==== 3. Type Inference (`+src/GqlDt/TypeInference.lean+`) β
+[[3-type-inference-srcgqldttypeinferencelean-white_check_mark]]
+==== 3. Type Inference (`src/GqlDt/TypeInference.lean`) β
*Status:* 100% Complete
-*Features:* - Infer types from literals - Schema-guided type inference -
-Auto-proof generation (decide, omega, simp tactics) - Runtime validation
-fallback
+*Features:*
+
+* Infer types from literals
+* Schema-guided type inference
+* Auto-proof generation (decide, omega, simp tactics)
+* Runtime validation fallback
*Key Functions:*
@@ -93,97 +104,138 @@ def inferInsert (schema : Schema) (table : String) (columns : List String) (valu
'''''
-==== 4. Serialization (`+src/GqlDt/Serialization.lean+`) β
+[[4-serialization-srcgqldtserializationlean-white_check_mark]]
+==== 4. Serialization (`src/GqlDt/Serialization.lean`) β
*Status:* 95% Complete
-*CBOR Encoding (RFC 8949):* β
Complete - All 8 major types: unsigned,
-negative, byteString, textString, array, map, tag, simple/float -
-Multi-byte encoding: 1-byte, 2-byte, 4-byte, 8-byte - Semantic tags: -
-`+1000+` - BoundedNat - `+1001+` - NonEmptyString - `+1002+` -
-Confidence - `+1003+` - PromptScores - `+1004+` - ProofBlob
+*CBOR Encoding (RFC 8949):* β
Complete
+
+* All 8 major types: unsigned, negative, byteString, textString, array, map, tag, simple/float
+* Multi-byte encoding: 1-byte, 2-byte, 4-byte, 8-byte
+* Semantic tags:
+** `1000` - BoundedNat
+** `1001` - NonEmptyString
+** `1002` - Confidence
+** `1003` - Prompores
+** `1004` - ProofBlob
-*CBOR Decoding:* β
Complete - Recursive decoder with state monad -
-`+CBORDecoder+` with `+readByte+`, `+readBytes+`, `+decodeUnsignedCBOR+`
-- `+decodeCBORValue+` handles all major types
+*CBOR Decoding:* β
Complete
-*JSON Serialization:* β
- `+serializeTypedValueJSON+` - TypedValue β
-JSON - `+jsonToBytes+` - JSON β UTF-8 bytes -
-`+deserializeTypedValueJSON+` - JSON β TypedValue
+* Recursive decoder with state monad
+* `CBORDecoder` with `readByte`, `readBytes`, `decodeUnsignedCBOR`
+* `decodeCBORValue` handles all major types
-*JSON Parsing:* β οΈ Stub (10% remaining) - `+bytesToJson+` - Currently
-returns error - *TODO:* Full JSON parser
+*JSON Serialization:* β
-*Binary Format:* β
- High-performance Lithoglyph native storage - Type
-tags with little-endian encoding - Proof blob support
+* `serializeTypedValueJSON` - TypedValue β JSON
+* `jsonToBytes` - JSON β UTF-8 bytes
+* `deserializeTypedValueJSON` - JSON β TypedValue
-*SQL Compatibility:* β
- `+toSQLValue+`, `+fromSQLValue+` - *WARNING:*
-Type information lost (compatibility layer only)
+*JSON Parsing:* β οΈ Stub (10% remaining)
+
+* `bytesToJson` - Currently returns error
+* *TODO:* Full JSON parser
+
+*Binary Format:* β
+
+* High-performance Lithoglyph native storage
+* Type tags with little-endian encoding
+* Proof blob support
+
+*SQL Compatibility:* β
+
+* `toSQLValue`, `fromSQLValue`
+* *WARNING:* Type information lost (compatibility layer only)
'''''
-==== 5. Intermediate Representation (`+src/GqlDt/IR.lean+`) β
+[[5-intermediate-representation-srcgqldtirlean-white_check_mark]]
+==== 5. Intermediate Representation (`src/GqlDt/IR.lean`) β
*Status:* 90% Complete
-*IR Data Structures:* β
- `+IR.Insert+`, `+IR.Select+`, `+IR.Update+`,
-`+IR.Delete+`, `+IR.Normalize+` - `+ProofBlob+` - CBOR-serialized proof
-terms - `+PermissionMetadata+` - userId, roleId, validationLevel,
-allowedTypes, timestamp - `+ValidationLevel+` - none, runtime, compile,
-paranoid
+*IR Data Structures:* β
+
+* `IR.Insert`, `IR.Select`, `IR.Update`, `IR.Delete`, `IR.Normalize`
+* `ProofBlob` - CBOR-serialized proof terms
+* `PermissionMetadata` - userId, roleId, validationLevel, allowedTypes, timestamp
+* `ValidationLevel` - none, runtime, compile, paranoid
+
+*IR Serialization:* β
+
+* `serializeInsert`, `serializeSelect`, `serializeUpdate`, `serializeDelete`, `serializeNormalize`
+* CBOR maps with type tags
+* `serializePermissions` - Permission metadata
+* `serializeProof` - Proof metadata for audit
+
+*IR Deserialization:* β οΈ Stub (10% remaining)
-*IR Serialization:* β
- `+serializeInsert+`, `+serializeSelect+`,
-`+serializeUpdate+`, `+serializeDelete+`, `+serializeNormalize+` - CBOR
-maps with type tags - `+serializePermissions+` - Permission metadata -
-`+serializeProof+` - Proof metadata for audit
+* `deserializeIR` - Stub, needs schema reconstruction
+* *TODO:* Reconstruct typed IR from CBOR
-*IR Deserialization:* β οΈ Stub (10% remaining) - `+deserializeIR+` -
-Stub, needs schema reconstruction - *TODO:* Reconstruct typed IR from
-CBOR
+*SQL Lowering:* β
-*SQL Lowering:* β
- `+lowerToSQL+` - IR β SQL (compatibility layer) -
-`+lowerInsertToSQL+`, `+lowerSelectToSQL+`, `+lowerUpdateToSQL+`,
-`+lowerDeleteToSQL+` - *WARNING:* Type information erased
+* `lowerToSQL` - IR β SQL (compatibility layer)
+* `lowerInsertToSQL`, `lowerSelectToSQL`, `lowerUpdateToSQL`, `lowerDeleteToSQL`
+* *WARNING:* Type information erased
-*Permission Validation:* β
- `+isTypeAllowed+` - Check type against
-whitelist - `+validatePermissions+` - Validate IR against permission
-profile
+*Permission Validation:* β
-*Proof Serialization:* β
- `+serializeProof+` - Extract proof metadata
-- `+generateIR_Insert+` - Proof blobs for BoundedNat, NonEmptyString,
-Confidence, PromptScores
+* `isTypeAllowed` - Check type against whitelist
+* `validatePermissions` - Validate IR against permission profile
+
+*Proof Serialization:* β
+
+* `serializeProof` - Extract proof metadata
+* `generateIR++_++Insert` - Proof blobs for BoundedNat, NonEmptyString, Confidence, Prompores
'''''
-==== 6. Pipeline (`+src/GqlDt/Pipeline.lean+`) β
+[[6-pipeline-srcgqldtpipelinelean-white_check_mark]]
+==== 6. Pipeline (`src/GqlDt/Pipeline.lean`) β
*Status:* 85% Complete
-*6-Stage Pipeline:* β
1. *Tokenize* - Source β Tokens 2. *Parse* -
-Tokens β AST 3. *Type Check* - Validate AST (GQL-DT mode) 4. *Generate
-IR* - AST β Typed IR 5. *Validate Permissions* - Check type whitelists
-6. *Serialize* - IR β CBOR/JSON/Binary
+*6-Stage Pipeline:* β
+
+[arabic]
+. *Tokenize* - Source β Tokens
+. *Parse* - Tokens β AST
+. *Type Check* - Validate AST (GQL-DT mode)
+. *Generate IR* - AST β Typed IR
+. *Validate Permissions* - Check type whitelists
+. *Serialize* - IR β CBOR/JSON/Binary
+
+*Pipeline Configuration:* β
-*Pipeline Configuration:* β
- `+ParsingMode+` - gqld (explicit types),
-gql (inferred types) - `+ValidationLevel+` - none, runtime, compile,
-paranoid - `+SerializationFormat+` - json, cbor, binary, sql
+* `ParsingMode` - gqld (explicit types), gql (inferred types)
+* `ValidationLevel` - none, runtime, compile, paranoid
+* `SerializationFormat` - json, cbor, binary, sql
-*Convenience Functions:* β
- `+parseGQL+` - User tier (type inference)
-- `+parseGQL-DT+` - Admin tier (explicit types) - `+parseAndExecute+` -
-Parse + execute on Lithoglyph
+*Convenience Functions:* β
-*Error Reporting:* β
- `+PipelineError+` with line, column, source
-context - `+formatError+` - Human-readable error messages
+* `parseGQL` - User tier (type inference)
+* `parseGQL-DT` - Admin tier (explicit types)
+* `parseAndExecute` - Parse {plus} execute on Lithoglyph
-*Examples & Tests:* β
- `+exampleParseGQL+` - INSERT with type
-inference - `+exampleParseGQL-DT+` - INSERT with explicit types -
-`+exampleParseSelect+` - SELECT query - `+testValidGQL+`,
-`+testInvalidQuery+` - Validation tests
+*Error Reporting:* β
-*AST β IR Conversion:* β οΈ Partial (15% remaining) -
-`+generateIRFromAST+` - Handles SELECT, stubs for INSERT/UPDATE/DELETE -
-*TODO:* Complete InferredInsert β IR.Insert (needs schema registry) -
-*TODO:* Complete UPDATE/DELETE β IR (needs schema lookup)
+* `PipelineError` with line, column, source context
+* `formatError` - Human-readable error messages
+
+*Examples & Tests:* β
+
+* `exampleParseGQL` - INSERT with type inference
+* `exampleParseGQL-DT` - INSERT with explicit types
+* `exampleParseSelect` - SELECT query
+* `testValidGQL`, `testInvalidQuery` - Validation tests
+
+*AST β IR Conversion:* β οΈ Partial (15% remaining)
+
+* `generateIRFromAST` - Handles SELECT, stubs for INSERT/UPDATE/DELETE
+* *TODO:* Complete InferredInsert β IR.Insert (needs schema registry)
+* *TODO:* Complete UPDATE/DELETE β IR (needs schema lookup)
'''''
@@ -197,14 +249,14 @@ inference - `+exampleParseGQL-DT+` - INSERT with explicit types -
* Required for AST β IR conversion
* Coordinate with Lithoglyph team
. *AST β IR Conversion* (5%)
-* `+InferredInsert β IR.Insert+` (needs schema)
-* `+UpdateStmt β IR.Update+` (needs schema)
-* `+DeleteStmt β IR.Delete+` (needs schema)
+* `InferredInsert β IR.Insert` (needs schema)
+* `UpdateStmt β IR.Update` (needs schema)
+* `DeleteStmt β IR.Delete` (needs schema)
. *JSON Parsing* (3%)
-* `+bytesToJson+` - UTF-8 β JsonValue
+* `bytesToJson` - UTF-8 β JsonValue
* Required for JSON deserialization roundtrip
. *IR Deserialization* (2%)
-* `+deserializeIR+` - CBOR β IR with schema reconstruction
+* `deserializeIR` - CBOR β IR with schema reconstruction
* Required for network transport
==== Nice-to-Have (Not Blocking)
@@ -218,28 +270,18 @@ inference - `+exampleParseGQL-DT+` - INSERT with explicit types -
=== Architecture Decisions Made
+[[white_check_mark-decisions-implemented]]
==== β
Decisions Implemented
-[width="100%",cols="34%,30%,36%",options="header",]
+[cols=",,",options="header",]
|===
|Decision |Outcome |Rationale
-|*Parser Technology* |Lean 4 parser combinators |Dependent types require
-proof execution
-
-|*Execution Strategy* |Native IR execution |Preserves type safety,
-faster than SQL (170ms vs 270ms)
-
-|*Serialization* |CBOR primary, JSON/Binary/SQL secondary |RFC 8949
-deterministic, proof blob transport
-
-|*Two-Tier Architecture* |One language, two syntaxes + permissions
-|GQL-DT (advanced) + GQL (users) + granular permissions
-
-|*ABI/FFI Standard* |Idris2 ABI + Zig FFI |Per hyperpolymath universal
-standard
-
-|*Integration Priority* |ReScript β Rust β Julia/Deno β Others |Aligned
-with existing ecosystem
+|*Parser Technology* |Lean 4 parser combinators |Dependent types require proof execution
+|*Execution Strategy* |Native IR execution |Preserves type safety, faster than SQL (170ms vs 270ms)
+|*Serialization* |CBOR primary, JSON/Binary/SQL secondary |RFC 8949 deterministic, proof blob transport
+|*Two-Tier Architecture* |One language, two syntaxes {plus} permissions |GQL-DT (advanced) {plus} GQL (users) {plus} granular permissions
+|*ABI/FFI Standard* |Idris2 ABI {plus} Zig FFI |Per hyperpolymath universal standard
+|*Integration Priority* |ReScript β Rust β Julia/Deno β Others |Aligned with existing ecosystem
|===
'''''
@@ -248,29 +290,22 @@ with existing ecosystem
==== Source Files (6 new files)
-[width="100%",cols="21%,23%,26%,30%",options="header",]
+[cols=",,,",options="header",]
|===
|File |Lines |Status |Purpose
-|`+src/GqlDt/Lexer.lean+` |407 |β
Complete |Tokenization
-
-|`+src/GqlDt/Parser.lean+` |550+ |β
Complete |Parser combinators,
-statements
-
-|`+src/GqlDt/TypeInference.lean+` |~200 |β
Complete |Type inference for
-GQL
-
-|`+src/GqlDt/IR.lean+` |410 |π‘ 90% |Typed IR, serialization
-
-|`+src/GqlDt/Serialization.lean+` |530+ |π‘ 95% |CBOR, JSON, Binary, SQL
-
-|`+src/GqlDt/Pipeline.lean+` |290 |π‘ 85% |End-to-end orchestration
+|`src/GqlDt/Lexer.lean` |407 |β
Complete |Tokenization
+|`src/GqlDt/Parser.lean` |550{plus} |β
Complete |Parser combinators, statements
+|`src/GqlDt/TypeInference.lean` |~200 |β
Complete |Type inference for GQL
+|`src/GqlDt/IR.lean` |410 |π‘ 90% |Typed IR, serialization
+|`src/GqlDt/Serialization.lean` |530{plus} |π‘ 95% |CBOR, JSON, Binary, SQL
+|`src/GqlDt/Pipeline.lean` |290 |π‘ 85% |End-to-end orchestration
|===
==== Updated Files
-* `+src/GqlDt.lean+` - Import all M6 modules
-* `+STATE.scm+` - Updated completion (65% β 75%), added M6 snapshot
-* `+docs/M6-PARSER-STATUS.md+` - This file
+* `src/GqlDt.lean` - Import all M6 modules
+* `STATE.scm` - Updated completion (65% β 75%), added M6 snapshot
+* `docs/M6-PARSER-STATUS.adoc` - This file
'''''
@@ -282,11 +317,11 @@ GQL
. *Schema Registry*
* Lithoglyph must expose schema lookup API
* GQL-DT parser needs runtime schema access
-* Format: `+getSchema (tableName : String) : IO (Option Schema)+`
+* Format: `gehema (tableName : String) : IO (Option Schema)`
. *Native IR Execution*
* Lithoglyph must implement IR executor
* Input: CBOR-serialized IR
-* Output: Query results + proof verification status
+* Output: Query results {plus} proof verification status
. *Permission Enforcement*
* Lithoglyph must store user permission profiles
* PermissionMetadata validated on IR submission
@@ -304,18 +339,18 @@ GQL
* Complete AST β IR conversion
* Add JSON parsing
. *Start M7: Idris2 ABI* (parallel with M8)
-* `+src/abi/Types.idr+` - ABI type definitions
-* `+src/abi/Layout.idr+` - Memory layout proofs
-* `+src/abi/Foreign.idr+` - FFI declarations
+* `src/GQLdt/ABI/Types.idr` - ABI type definitions
+* `src/GQLdt/ABI/Layout.idr` - Memory layout proofs
+* `src/GQLdt/ABI/Foreign.idr` - FFI declarations
. *Start M8: Zig FFI* (parallel with M7)
-* `+ffi/zig/src/main.zig+` - C-compatible implementation
-* `+ffi/zig/build.zig+` - Build configuration
-* `+ffi/zig/test/integration_test.zig+` - FFI tests
+* `ffi/zig/src/main.zig` - C-compatible implementation
+* `ffi/zig/build.zig` - Build configuration
+* `ffi/zig/test/integration++_++test.zig` - FFI tests
==== Short-Term (This Month)
[arabic, start=4]
-. *Complete M7+M8*
+. *Complete M7{plus}M8*
* Idris2 ABI β Zig FFI integration
* C header generation
* Proof verification across FFI boundary
@@ -342,7 +377,7 @@ GQL
=== Success Metrics
-[width="100%",cols="25%,24%,27%,24%",options="header",]
+[cols=",,,",options="header",]
|===
|Metric |Target |Current |Status
|*Lexer Coverage* |100% tokens |100% |β
@@ -358,17 +393,12 @@ GQL
=== Conclusion
-*M6 Parser is substantially complete (85%).* The core parsing
-infrastructure is feature-complete, with full CBOR encoding/decoding,
-type inference, and IR generation. The remaining 15% consists of schema
-registry integration and ASTβIR conversion stubs, which require
-coordination with the Lithoglyph team.
+*M6 Parser is substantially complete (85%).* The core parsing infrastructure is feature-complete, with full CBOR encoding/decoding, type inference, and IR generation. The remaining 15% consists of schema registry integration and ASTβIR conversion stubs, which require coordination with the Lithoglyph team.
-*Recommended Next Action:* Proceed with M7 (Idris2 ABI) + M8 (Zig FFI)
-in parallel while coordinating with Lithoglyph team on schema registry
-requirements.
+*Recommended Next Action:* Proceed with M7 (Idris2 ABI) {plus} M8 (Zig FFI) in parallel while coordinating with Lithoglyph team on schema registry requirements.
'''''
-*Document Version:* 1.0 *Author:* Jonathan D.A. Jewell (@hyperpolymath)
+*Document Version:* 1.0
+*Author:* Jonathan D.A. Jewell (@hyperpolymath)
*License:* CC-BY-SA-4.0
diff --git a/docs/SEAM-ANALYSIS-2026-02-01.adoc b/docs/SEAM-ANALYSIS-2026-02-01.adoc
index 69dc82e..767fb1b 100644
--- a/docs/SEAM-ANALYSIS-2026-02-01.adoc
+++ b/docs/SEAM-ANALYSIS-2026-02-01.adoc
@@ -1,59 +1,65 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+[[gql-dt-m6-parser---seam-analysis--fixes]]
== GQL-DT M6 Parser - Seam Analysis & Fixes
-*Date:* 2026-02-01 *Analyst:* Seam Analysis Agent *Engineer:* Jonathan
-D.A. Jewell (@hyperpolymath)
+*Date:* 2026-02-01
+*Analyst:* Seam Analysis Agent
+*Engineer:* Jonathan D.A. Jewell (@hyperpolymath)
'''''
=== Executive Summary
-Comprehensive seam analysis identified *76 critical issues* across M6
-Parser implementation. *Phase 1 critical fixes (33 compilation-blocking
-issues) now COMPLETE*.
+Comprehensive seam analysis identified *76 critical issues* across M6 Parser implementation. *Phase 1 critical fixes (33 compilation-blocking issues) now COMPLETE*.
-*Status:* β
All compilation blockers resolved *Build Status:* Ready for
-`+lake build+` test *Next Phase:* Phase 2 functionality fixes
+*Status:* β
All compilation blockers resolved
+*Build Status:* Ready for `lake build` test
+*Next Phase:* Phase 2 functionality fixes
'''''
+[[phase-1-critical-fixes-white_check_mark-complete]]
=== Phase 1: Critical Fixes β
COMPLETE
+[[11-circular-import-dependency-white_check_mark-fixed]]
==== 1.1 Circular Import Dependency β
FIXED
-*Problem:* `+IR.lean+` β `+Serialization.lean+` circular import causing
-compilation failure.
+*Problem:* `IR.lean` β `Serialization.lean` circular import causing compilation failure.
-*Solution:* Created new module `+src/GqlDt/Serialization/Types.lean+`
-with shared types: - `+JsonValue+` - JSON in-memory representation -
-`+CBORValue+`, `+CBORMajorType+` - CBOR types (RFC 8949) -
-`+SerializationFormat+` - Format selection enum - CBOR semantic tags
-(55800-55804)
+*Solution:*
+Created new module `src/GqlDt/Serialization/Types.lean` with shared types:
-*Changed Tags:* Updated from 1000-1004 β 55800-55804 (vendor-specific
-range)
+* `JsonValue` - JSON in-memory representation
+* `CBORValue`, `CBORMajorType` - CBOR types (RFC 8949)
+* `SerializationFormat` - Format selection enum
+* CBOR semantic tags (55800-55804)
-*Files Modified:* - β
`+src/GqlDt/Serialization/Types.lean+` - CREATED
-- β
`+src/GqlDt/Serialization.lean+` - Import from Types, removed
-duplicates - β
`+src/GqlDt/IR.lean+` - Import Serialization.Types
-instead of Serialization - β
`+src/GqlDt.lean+` - Export
-Serialization.Types
+*Changed Tags:* Updated from 1000-1004 β 55800-55804 (vendor-specific range)
+
+*Files Modified:*
+
+* β
`src/GqlDt/Serialization/Types.lean` - CREATED
+* β
`src/GqlDt/Serialization.lean` - Import from Types, removed duplicates
+* β
`src/GqlDt/IR.lean` - Import Serialization.Types instead of Serialization
+* β
`src/GqlDt.lean` - Export Serialization.Types
*Impact:* Circular dependency broken, clean module separation.
'''''
+[[12-inconsistent-import-paths-white_check_mark-fixed]]
==== 1.2 Inconsistent Import Paths β
FIXED
-*Problem:* 17 files used `+import GqlDt.*+` instead of
-`+import GqlDt.*+`.
+*Historical record:* This report attributed an import-namespace repair to the 17 files below. Later renaming made its recorded before/after namespaces identical, so this text no longer establishes the original spelling. Current Lean imports use `GqlDt`; the build checks their resolution.
-*Solution:* Global find-and-replace across all `+.lean+` files.
+*Solution:* Global find-and-replace across all `.lean` files.
*Files Fixed (17 total):*
....
src/GqlDt/Prompt/PromptDimension.lean
-src/GqlDt/Prompt/PromptScores.lean
+src/GqlDt/Prompt/Prompores.lean
src/GqlDt/Provenance/ActorId.lean
src/GqlDt/Provenance/Rationale.lean
src/GqlDt/Provenance/Tracked.lean
@@ -71,17 +77,13 @@ src/GqlDt/Query.lean
src/Main.lean
....
-*Command Used:*
-
-[source,bash]
-----
-sed -i 's/import GqlDt\./import GqlDt./g'
-----
+*Reproduction note:* The former command replaced a namespace with itself and has been removed. Consult the original revision history before attempting to reproduce that historical rename.
*Impact:* All imports now use correct namespace prefix.
'''''
+[[13-missing-type-definitions-white_check_mark-fixed]]
==== 1.3 Missing Type Definitions β
FIXED
*Problem:* Parser.lean used types not defined in imported modules.
@@ -118,18 +120,21 @@ structure OrderByClause where
columns : List (String Γ String) -- (column, direction)
----
-*Rationale:* - `+InferredType+` moved to avoid circular dependency
-(TypeInference β AST β TypeInference) - `+WhereClause+`,
-`+OrderByClause+` are shared AST types needed by Parser
+*Rationale:*
+
+* `InferredType` moved to avoid circular dependency (TypeInference β AST β TypeInference)
+* `WhereClause`, `OrderByClause` are shared AST types needed by Parser
-*Files Modified:* - β
`+src/GqlDt/AST.lean+` - Added 3 type definitions
-- β
`+src/GqlDt/TypeInference.lean+` - Removed InferredType (now
-imported from AST)
+*Files Modified:*
+
+* β
`src/GqlDt/AST.lean` - Added 3 type definitions
+* β
`src/GqlDt/TypeInference.lean` - Removed InferredType (now imported from AST)
*Impact:* All types properly defined before use, no forward references.
'''''
+[[14-missing-imports-white_check_mark-fixed]]
==== 1.4 Missing Imports β
FIXED
*Problem:* Parser.lean referenced types without importing their modules.
@@ -154,18 +159,20 @@ import GqlDt.Provenance
open Lexer AST TypeInference IR Types
----
-*Impact:* All referenced types now available, no "`unknown identifier`"
-errors.
+*Impact:* All referenced types now available, no "unknown identifier" errors.
'''''
+[[15-parser-monad-error-handling-white_check_mark-fixed]]
==== 1.5 Parser Monad Error Handling β
FIXED
-*Problem:* Parser used `+throw+` without implementing `+MonadExcept+`
-typeclass.
+*Problem:* Parser used `throw` without implementing `MonadExcept` typeclass.
+
+*Solution:*
-*Solution:* 1. Added `+fail+` helper function to Parser monad 2.
-Replaced all 6 instances of `+throw+` with `+fail+`
+[arabic]
+. Added `fail` helper function to Parser monad
+. Replaced all 6 instances of `throw` with `fail`
*Helper Function:*
@@ -176,74 +183,70 @@ def fail {Ξ± : Type} (msg : String) : Parser Ξ± :=
fun s => .error msg s
----
-*Replacements Made:* | Line | Original | Fixed | |ββ|βββ-|ββ-| | 244 |
-`+throw "Expected string for RATIONALE"+` |
-`+fail "Expected string for RATIONALE"+` | | 245 |
-`+throw "Expected RATIONALE value"+` |
-`+fail "Expected RATIONALE value"+` | | 298 |
-`+throw "Expected SELECT list"+` | `+fail "Expected SELECT list"+` | |
-361 | `+throw "Expected number for LIMIT"+` |
-`+fail "Expected number for LIMIT"+` | | 362 |
-`+throw "Expected LIMIT value"+` | `+fail "Expected LIMIT value"+` | |
-475 | `+throw s!"Unexpected token: {tok.type}"+` |
-`+fail s!"Unexpected token: {tok.type}"+` | | 476 |
-`+throw "Unexpected EOF"+` | `+fail "Unexpected EOF"+` |
+*Replacements Made:*
+++|++ Line ++|++ Original ++|++ Fixed ++|++
+++|++------++|++----------++|++-------++|++
+++|++ 244 ++|++ `throw "Expected string for RATIONALE"` ++|++ `fail "Expected string for RATIONALE"` ++|++
+++|++ 245 ++|++ `throw "Expected RATIONALE value"` ++|++ `fail "Expected RATIONALE value"` ++|++
+++|++ 298 ++|++ `throw "Expected SELECT list"` ++|++ `fail "Expected SELECT list"` ++|++
+++|++ 361 ++|++ `throw "Expected number for LIMIT"` ++|++ `fail "Expected number for LIMIT"` ++|++
+++|++ 362 ++|++ `throw "Expected LIMIT value"` ++|++ `fail "Expected LIMIT value"` ++|++
+++|++ 475 ++|++ `throw s!"Unexpected token: ++{++tok.type}"` ++|++ `fail s!"Unexpected token: ++{++tok.type}"` ++|++
+++|++ 476 ++|++ `throw "Unexpected EOF"` ++|++ `fail "Unexpected EOF"` ++|++
*Impact:* Parser error handling now compiles correctly.
'''''
+[[16-duplicate-type-definitions-white_check_mark-fixed]]
==== 1.6 Duplicate Type Definitions β
FIXED
*Problem:* Parser.lean duplicated types already in AST.lean.
*Solution:* Removed duplicates, kept only distinct parsing-level types.
-*Removed from Parser.lean:* - `+Assignment+` - Identical to
-AST.Assignment - `+OrderByClause+` - Identical to AST.OrderByClause
+*Removed from Parser.lean:*
+
+* `Assignment` - Identical to AST.Assignment
+* `OrderByClause` - Identical to AST.OrderByClause
+
+*Kept in Parser.lean:*
+
+* `UpdateStmt` - Simplified version (no schema proofs)
+* `DeleteStmt` - Simplified version (uses WhereClause instead of Condition)
-*Kept in Parser.lean:* - `+UpdateStmt+` - Simplified version (no schema
-proofs) - `+DeleteStmt+` - Simplified version (uses WhereClause instead
-of Condition)
+*Rationale:*
-*Rationale:* - Parser produces simplified AST for parsing - Type checker
-converts to fully type-safe AST - Two-tier approach prevents premature
-type constraints
+* Parser produces simplified AST for parsing
+* Type checker converts to fully type-safe AST
+* Two-tier approach prevents premature type constraints
*Impact:* No duplicate definitions, clear separation of concerns.
'''''
+[[cbor-tag-registry-update-white_check_mark-improved]]
=== CBOR Tag Registry Update β
IMPROVED
-*Problem:* Original tags (1000-1004) in unassigned IANA range, no
-documentation.
+*Problem:* Original tags (1000-1004) in unassigned IANA range, no documentation.
*Solution:* Moved to vendor-specific range with full documentation.
*Tag Assignments:*
-[width="100%",cols="23%,27%,50%",options="header",]
+[cols=",,",options="header",]
|===
|Tag |Type |Structure
-|55800 |BoundedNat
-|`+map { "min": unsigned, "max": unsigned, "value": unsigned, "proof": map }+`
-
-|55801 |NonEmptyString |`+map { "value": textString, "proof": map }+`
-
-|55802 |Confidence |`+map { "value": unsigned, "proof": map }+`
-
-|55803 |PromptScores
-|`+map { "provenance": unsigned, ..., "proof": map }+`
-
-|55804 |ProofBlob
-|`+map { "type": textString, "data": textString, "verified": bool }+`
+|55800 |BoundedNat |`map ++{++ "min": unsigned, "max": unsigned, "value": unsigned, "proof": map }`
+|55801 |NonEmptyString |`map ++{++ "value": textString, "proof": map }`
+|55802 |Confidence |`map ++{++ "value": unsigned, "proof": map }`
+|55803 |Prompores |`map ++{++ "provenance": unsigned, ..., "proof": map }`
+|55804 |ProofBlob |`map ++{++ "type": textString, "data": textString, "verified": bool }`
|===
*Vendor Range:* 55799-55899 (100 tags reserved for GQL-DT extensions)
-*Documentation:* Added comprehensive docstrings in
-Serialization/Types.lean
+*Documentation:* Added comprehensive docstrings in Serialization/Types.lean
*Future:* Submit to IANA for official registration
@@ -254,89 +257,80 @@ Serialization/Types.lean
=== Files Created
[arabic]
-. `+src/GqlDt/Serialization/Types.lean+` - Shared serialization types
-(118 lines)
-. `+docs/SEAM-ANALYSIS-2026-02-01.md+` - This document
+. `src/GqlDt/Serialization/Types.lean` - Shared serialization types (118 lines)
+. `docs/SEAM-ANALYSIS-2026-02-01.adoc` - This document
'''''
=== Files Modified
-[width="100%",cols="29%,40%,31%",options="header",]
+[cols=",,",options="header",]
|===
|File |Changes |Lines
-|`+src/GqlDt/Serialization.lean+` |Import Types, remove duplicates |-50
-
-|`+src/GqlDt/IR.lean+` |Import Serialization.Types |+1, -1
-
-|`+src/GqlDt/AST.lean+` |Add InferredType, WhereClause, OrderByClause
-|+35
-
-|`+src/GqlDt/TypeInference.lean+` |Remove InferredType |-8
-
-|`+src/GqlDt/Parser.lean+` |Add imports, fix error handling, remove
-duplicates |+9, -15
-
-|`+src/GqlDt.lean+` |Export Serialization.Types |+1
-
-|*17 Query/Prompt/Provenance files* |Fix GqlDt β GqlDt imports |~17
-changes
+|`src/GqlDt/Serialization.lean` |Import Types, remove duplicates |-50
+|`src/GqlDt/IR.lean` |Import Serialization.Types |{plus}1, -1
+|`src/GqlDt/AST.lean` |Add InferredType, WhereClause, OrderByClause |{plus}35
+|`src/GqlDt/TypeInference.lean` |Remove InferredType |-8
+|`src/GqlDt/Parser.lean` |Add imports, fix error handling, remove duplicates |{plus}9, -15
+|`src/GqlDt.lean` |Export Serialization.Types |{plus}1
+|*17 Query/Prompt/Provenance files* |Fix GqlDt β GqlDt imports |~17 changes
|===
-*Total Files Modified:* 24 *Total Lines Changed:* ~100
+*Total Files Modified:* 24
+*Total Lines Changed:* ~100
'''''
-=== Remaining Issues (Phase 2+)
+=== Remaining Issues (Phase 2{plus})
==== Phase 2: High-Priority Functionality (15% of M6)
[arabic]
. *AST β IR Conversion* β οΈ Not Implemented
-* `+InferredInsert β IR.Insert+` (needs schema lookup)
-* `+UpdateStmt β IR.Update+` (needs schema lookup)
-* `+DeleteStmt β IR.Delete+` (needs schema lookup)
+* `InferredInsert β IR.Insert` (needs schema lookup)
+* `UpdateStmt β IR.Update` (needs schema lookup)
+* `DeleteStmt β IR.Delete` (needs schema lookup)
. *Permission Metadata Threading* β οΈ Incomplete
-* Parser doesnβt pass permissions to IR generation
+* Parser doesn't pass permissions to IR generation
* Type whitelist not enforced during parsing
. *Schema Registry* β οΈ Missing
* No runtime schema lookup mechanism
-* Hardcoded `+evidenceSchema+` used everywhere
+* Hardcoded `evidenceSchema` used everywhere
* Coordinate with Lithoglyph team
==== Phase 3: Medium-Priority Correctness
[arabic, start=4]
. *Runtime Validation in Deserialization* β οΈ Stubs
-* `+deserializeTypedValueJSON+`: Uses `+sorry+` for proofs
-* `+deserializeTypedValueFromCBOR+`: Uses `+sorry+` for proofs
-* `+deserializeTypedValueBinary+`: Uses `+sorry+` for proofs
+* `deserializeTypedValueJSON`: Uses `sorry` for proofs
+* `deserializeTypedValueFromCBOR`: Uses `sorry` for proofs
+* `deserializeTypedValueBinary`: Uses `sorry` for proofs
* *Security Risk:* Untrusted data bypasses type constraints
. *JSON Parsing* β οΈ Stub
-* `+bytesToJson+` returns error
+* `bytesToJson` returns error
* Needed for full JSON roundtrip
. *IR Deserialization* β οΈ Stub
-* `+deserializeIR+` only dispatches by type tag
+* `deserializeIR` only dispatches by type tag
* Schema reconstruction not implemented
==== Phase 4: Low-Priority Improvements
[arabic, start=7]
. *Documentation Gaps*
-* 20+ functions missing docstrings
+* 20{plus} functions missing docstrings
* Module-level docs incomplete
. *Example Coverage*
* No UPDATE/DELETE examples
* No error case examples
. *Error Message Standardization*
-* Mix of "`Expected X, got Y`" and "`Expected X, found Y`"
-* Recommend: "`Expected , found \{actual}`"
+* Mix of "Expected X, got Y" and "Expected X, found Y"
+* Recommend: "Expected ++<++what++>++, found ++{++actual}"
'''''
=== Compilation Test Plan
-*Next Step:* Run `+lake build+` to verify Phase 1 fixes.
+*Next Step:* Run `lake build` to verify Phase 1 fixes.
*Expected Outcome:* Clean build with no errors.
@@ -349,9 +343,13 @@ lake clean
lake build
----
-*If Build Fails:* 1. Check error message for module import issues 2.
-Verify all GqlDt β GqlDt replacements 3. Check for remaining `+throw+`
-statements 4. Verify Serialization.Types is exported
+*If Build Fails:*
+
+[arabic]
+. Check error message for module import issues
+. Verify all GqlDt β GqlDt replacements
+. Check for remaining `throw` statements
+. Verify Serialization.Types is exported
'''''
@@ -378,7 +376,7 @@ statements 4. Verify Serialization.Types is exported
* *Module Cohesion:* Improved (shared types extracted)
* *Dependency Graph:* Cleaned (no cycles)
* *Type Safety:* Maintained (all types properly defined)
-* *Error Handling:* Improved (consistent `+fail+` usage)
+* *Error Handling:* Improved (consistent `fail` usage)
* *CBOR Compliance:* Enhanced (documented vendor tags)
'''''
@@ -386,8 +384,7 @@ statements 4. Verify Serialization.Types is exported
=== Lessons Learned
[arabic]
-. *Early Seam Analysis:* Critical issues caught before integration
-testing
+. *Early Seam Analysis:* Critical issues caught before integration testing
. *Circular Dependencies:* Easily missed during incremental development
. *Type Sharing:* Common types need dedicated modules
. *Import Consistency:* Namespace refactors require comprehensive search
@@ -397,15 +394,15 @@ testing
=== Recommendations
-==== Immediate (Before M7+M8)
+==== Immediate (Before M7{plus}M8)
[arabic]
-. β
Run `+lake build+` to verify Phase 1 fixes
+. β
Run `lake build` to verify Phase 1 fixes
. β οΈ Implement schema registry (coordinate with Lithoglyph)
. β οΈ Complete AST β IR conversions
. β οΈ Add runtime validation in deserialization
-==== Short-Term (During M7+M8)
+==== Short-Term (During M7{plus}M8)
[arabic, start=5]
. Add comprehensive examples (UPDATE, DELETE, error cases)
@@ -413,7 +410,7 @@ testing
. Add missing docstrings
. Write integration tests
-==== Long-Term (M9+)
+==== Long-Term (M9{plus})
[arabic, start=9]
. Submit CBOR tags to IANA for registration
@@ -425,15 +422,12 @@ testing
=== Conclusion
-*Phase 1 seam analysis successfully identified and fixed all
-compilation-blocking issues.* The M6 Parser implementation is now
-structurally sound with clean module boundaries, no circular
-dependencies, and consistent type definitions.
+*Phase 1 seam analysis successfully identified and fixed all compilation-blocking issues.* The M6 Parser implementation is now structurally sound with clean module boundaries, no circular dependencies, and consistent type definitions.
-*Next milestone:* Run `+lake build+` to verify, then proceed to Phase 2
-functionality fixes (ASTβIR conversion, schema registry).
+*Next milestone:* Run `lake build` to verify, then proceed to Phase 2 functionality fixes (ASTβIR conversion, schema registry).
'''''
-*Document Version:* 1.0 *Author:* Jonathan D.A. Jewell (@hyperpolymath)
+*Document Version:* 1.0
+*Author:* Jonathan D.A. Jewell (@hyperpolymath)
*License:* CC-BY-SA-4.0
diff --git a/docs/STATE-OF-PLAY.adoc b/docs/STATE-OF-PLAY.adoc
index 80eaa8c..920edf2 100644
--- a/docs/STATE-OF-PLAY.adoc
+++ b/docs/STATE-OF-PLAY.adoc
@@ -1,155 +1,80 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
-= GNPL β state of play
-:toc: macro
-:toclevels: 2
-
-*As at 2026-07-28, `main` = `9de0713`.* The machine-readable counterpart is
-`.machine_readable/6a2/STATE.a2ml`; both are regenerated together and should agree.
-
-This document exists because the repository's own claims about itself were, for a period,
-false β a README describing a template, a lexer advertised as supporting operators it could
-not lex, and a manifest pointing at six files that did not exist. What follows is written
-to be *checkable*: every claim names the command that establishes it.
-
-toc::[]
-
-== What this is, in one paragraph
-
-GNPL is Lithoglyph's *narration/projection* language. A query language answers
-"what is true in the store?"; GNPL answers "what account does this evidence support, told
-from whose stance, with what warrant β and what rival accounts does the same evidence also
-support?". It is built as a layer on top of GQLdt *in this repository* and lowers to it.
-That is why every source file is namespaced `GqlDt` in a repo called `gnpl`: GQLdt is not
-a leftover, it is the compilation target.
-
-----
-GNPL ββlowers toβββΆ GQLdt ββFFIβββΆ Lithoglyph
-(what account) (what is) (the data store)
-----
-
-== Where things actually stand
-
-[cols="2,1,3",options=header]
-|===
-| Component | State | Established by
-
-| GQLdt core (Lean 4)
-| *typechecks*
-| `lake build` β 34/35 targets, exit 0
-
-| Test suites
-| *163 checks, green*
-| `lake test` β Lexer, Parser, TypeSafety; exit 0
-
-| Zig FFI bridge (`bridge/`)
-| *builds, tests pass*
-| `cd bridge && zig build && zig build test` β emits `liblith_bridge.a`
-
-| Incomplete proofs (`sorry`)
-| *none*
-| `scripts/check-lean-proofs.sh --build-log`
-
-| Trusted base
-| *16 axioms outstanding*
-| estate `check-trusted-base.sh`; enumerated in `docs/proof-debt.md`
-
-| GNPL narration layer
-| *design only*
-| `docs/THEORY.adoc`, `docs/LITHOGLYPH.adoc`; no `src/Gnpl/` yet
-|===
-
-=== The caveat that matters most
-
-[IMPORTANT]
-====
-*A green proof gate means "nothing is admitted mid-proof". It does not mean "nothing is
-assumed."*
-
-Lean 4 emits `declaration uses 'sorry'` for `sorry`/`sorryAx` only β **`axiom` produces no
-warning at all**. This repository declares *16 axioms*, all stubs, none necessary in the
-policy sense. **Five sit in executable position** (`parseToIR`, `deserializeIR`, `many`,
-`many1`, `sepBy`) and therefore have *no implementation*: code calling them typechecks and
-cannot run.
-
-So "34/35 targets build" is a statement about **typechecking**, not about a working parser.
-Read `docs/proof-debt.md` before relying on any verification claim made here.
-====
-
-== How to check any of this yourself
+= GNPL: state of play
+:revdate: 2026-09-07
+
+Observation horizon: the local working tree, Lean 4.15.0, `lake build` and
+`lake test` on 2026-09-07. These results do not establish remote CI, deployment,
+a live Lithoglyph integration or whole-repository proof completeness. The current
+machine-readable checkpoint is `.machine_readable/descriptiles/STATE.a2ml`.
+
+== Implemented and tested
+
+* `src/Gnpl/` contains an independent direct-evidence narration kernel, projection
+ parser and versioned evidence importer; `src/GnplMain.lean` provides the CLI.
+* Accounts carry witnesses indexed by the exact evidence snapshot, focalization
+ and requested assertions. Requested telling order is preserved.
+* Focalization checks supplied audience declarations. Evidence must be active,
+ match the requested claim and meet the projection's declared integer threshold.
+* A limited rival relation detects conflicting single-valued subject/slot values
+ across two checked accounts. It neither searches for accounts nor picks a winner.
+* Hypothetical withdrawal re-evaluates the projection on a changed in-memory
+ snapshot. The CLI preserves the original evidence file byte for byte.
+* The private substrate parses complete statements, validates inserts against a
+ supplied schema, and supports its tested in-memory insertion/retrieval fragment.
+ Its historical namespace is a compatibility detail, not a public language.
+
+`lake build` passes. `lake test` passes five suites: the existing lexer, parser
+and type-safety suites, 26 private-substrate checks and 35 narration checks.
+The narration suite includes real CLI invocations, success and refusal paths,
+rival accounts and both dependent and unrelated withdrawals.
+
+== Formal scope
+
+Lean checks that withdrawn evidence cannot satisfy the direct-evidence support
+rule and that a checked narration contains exactly the requested claims in their
+order. `test/NarrationProofAudit.lean` is a default build target: Lean's transitive
+axiom report must remain `[propext]` for `narrate` and both theorems.
+
+This establishes properties of the encoded rule. It does not establish external
+truth, authenticated provenance, persuasive reasoning or a portable proof
+certificate in the emitted JSON. The new kernel imports Lean/Std independently
+of the private substrate's floating-point equality assumption.
+
+The saved successful build log also passes `scripts/check-lean-proofs.sh
+--build-log`. That diagnostic gate checks for incomplete proofs reported by Lean;
+it does not establish an axiom-free repository. Historical totals in
+`docs/proof-debt.adoc` predate the executable parser and insert-witness fixes.
+
+== Known limits and next work
+
+. Build the read-only Lithoglyph journal adapter and test withdrawal against a
+ real store revision. See link:LITHOGLYPH.adoc[the integration contract].
+. Define additional warrant derivation rules before allowing inferred claims.
+. Add explicit event identity and partial-order/temporal semantics; current
+ assertion order describes telling only.
+. Resolve confidence composition and account relations as language design
+ questions. The current threshold does not settle PROMPT averaging or
+ probabilistic interpretation.
+. Connect durable account storage and Glyphbase rendering with visible refusals.
+
+The private pipeline still refuses attached-proof mode, persistent execution,
+complete IR wire interchange and unchecked update/delete lowering. `lake test`
+does not cover the separate FFI boundary. No FFI or remote CI result is asserted
+by this checkpoint.
+
+Repository initialisation also retains unresolved governance/security tokens in
+`REQUIRES_INITIALISATION.adoc`. This implementation does not invent those values.
+
+== Reproduce
[source,console]
----
-$ lake build # the Lean core typechecks
-$ lake test # 163 checks, 3 suites
-$ cd bridge && zig build && zig build test # the FFI bridge
-$ cd .. && lake build 2>&1 | tee lake-build.log
-$ ./scripts/check-lean-proofs.sh --build-log lake-build.log
+lake build
+lake test
+.lake/build/bin/gnpl narrate --evidence examples/narration/evidence.json --projection examples/narration/inspection.gnpl
+.lake/build/bin/gnpl counterfactual --evidence examples/narration/evidence.json --projection examples/narration/inspection.gnpl --withdraw inspection-17
----
-Build *order* matters: `lakefile.lean` links `bridge/zig-out/lib/liblith_bridge.a`, so the
-Zig archive must exist before the Lean FFI executables link.
-
-== Gates, and why they are trusted
-
-Every gate here has been shown to go *red* on a seeded fault and green when it is removed.
-That is the standard, because this repository has shipped, and since removed, four gates
-that could not fail:
-
-* a naming check that compared a string to itself, over files that did not exist;
-* a `lake test` step whose `|| echo` swallowed genuine failures;
-* test suites whose `main : IO Unit` always exited 0 while printing "All tests passed!";
-* a `Containerfile` masking both its build steps with `|| echo`.
-
-A gate that has never gone red is not evidence of anything.
-
-== What is known to be missing
-
-* **No FFI-boundary coverage in `lake test`.** `ffi_test` links `liblith_bridge.a`, so it
- is excluded from the driver and covered only by the `zig-ffi` CI job.
-* **No property tests.** Nothing in `docs/proof-debt.md` Β§(b) can cite a refutation budget
- yet, so nothing has been promoted there.
-* **`src/Gnpl/` does not exist.** The narration layer is specified, not built.
-
-== Open decisions
-
-Two questions are recorded here because work is genuinely blocked on them, and guessing
-would be worse than waiting.
-
-*1. The averaging rule for PROMPT scores.* `PromptScores` carries a proof field β
-`overall_correct : overall.val = (β¦sumβ¦) / 6` β so the arithmetic mean is welded into the
-*type*. Changing it is a proof-obligation change on every value, in Lean and in Zig
-simultaneously, not an edit to one function. An unweighted arithmetic mean also lets a
-source with *zero provenance* score 83/100, which is hard to defend for an evidence
-database. This gates proof-debt item D3.
-
-*2. `flake.nix` versus `guix.scm`.* Estate policy is Guix primary, Nix fallback, and
-satisfying *neither* is the violation. This repo has no `guix.scm`, so `flake.nix` is the
-only artefact satisfying the policy; removing it without a verified replacement turns
-Governance red.
-
-== Sequencing
-
-Foundation first, breadth before depth β the base layer is whatever makes everything else
-*verifiable*.
-
-. *Done.* Suites can fail; `lake test` runs; gates canary-tested.
-. *Next, unblocked:* proof-debt **D1** β `executePreservesTypes` reduces to `β¦ β True`
- with its body commented `-- Placeholder`. It reads as a soundness theorem and discharges
- nothing. Deleting it is strictly better than keeping it.
-. *Next, gated on decision 1:* **D3** β construct the six asserted `PromptScores` examples.
- They are the demonstrations of the repo's central claim, and are currently axioms, so
- they demonstrate the opposite of what their comments say.
-. *Then:* **D2** β implement `many`/`many1`/`sepBy`; the four `parse*` axioms exist only
- because these three do.
-. *Then:* `src/Gnpl/` β `Fabula`, `Projection`, `Focalization`, `Account`, `Warrant`,
- carrying the no-narration-without-warrant constructor discipline.
-
-== Related
-
-* `README.adoc` β start here; the two-layer story
-* `ARCHITECTURE.md` β layout, build order, verification posture
-* `GOVERNANCE.md` β the rules a change must clear, and why each exists
-* `docs/proof-debt.md` β all 16 axioms with `file:line` and disposition
-* `docs/THEORY.adoc` β what a narration language is, and what gap it fills
-* `docs/LITHOGLYPH.adoc` β what GNPL gives Lithoglyph specifically
+The counterfactual command intentionally exits 1 with `invalidated`. Full surface,
+JSON trust boundary and exit-code documentation: link:narration-slice.adoc[].
diff --git a/docs/THEORY.adoc b/docs/THEORY.adoc
index 73e6794..bb6c530 100644
--- a/docs/THEORY.adoc
+++ b/docs/THEORY.adoc
@@ -4,7 +4,9 @@
:toc: macro
:toclevels: 3
-*Status:* design document. No implementation yet; see `README.adoc` for what does exist.
+*Status:* broader design, with a restricted direct-evidence fragment implemented.
+See link:narration-slice.adoc[the executable slice] for its exact semantics and
+proof scope. Constructs below that exceed that fragment remain design work.
toc::[]
@@ -42,29 +44,31 @@ different account to hold instead?**
That is a narration problem, and it has structure worth typing.
-=== Four properties conventional query languages have
+=== Four commitments GNPL makes explicit
-SQL, Cypher, SPARQL and GraphQL share four assumptions. Each is reasonable; together they
-make narration inexpressible.
+Retrieval languages and database schemas can encode accounts, temporal records,
+conflicts and access rules. GNPL's case does not depend on those things being
+inexpressible elsewhere. Its purpose is to give the following objects shared
+language semantics and constructor obligations, so applications can rely on the
+same rules rather than recreate them independently.
[cols="1,3",options=header]
|===
-| Property | Consequence
+| Commitment | Language obligation
-| *Extensional*
-| A query denotes a set of tuples/nodes. There is no object denoting *an account*, so
- accounts cannot be compared, diffed, or reasoned about.
+| *Accounts as values*
+| Preserve the declared telling order and carry warrant for every assertion.
-| *Presentist*
-| The current state is privileged. History is an add-on (audit tables, triggers), and the
- *history of the interpretation* is not represented at all.
+| *Explicit evidence state*
+| Index an account by its evidence snapshot; future temporal semantics must also
+ distinguish event time, recording time and interpretation history.
-| *Univocal*
-| One query, one answer. Plurality is an error condition, not a result.
+| *Plurality*
+| Retain warranted rival accounts and express their relation without silently
+ choosing a winner.
-| *Stance-free*
-| No notion of who is telling, to whom, with what access or what interest. Every answer is
- narrated from nowhere.
+| *Declared stance*
+| State whose access and admission policy constrain the projection.
|===
== Prior art, and what each already does
@@ -212,9 +216,11 @@ whether the synthesis is usable, not on novelty of parts.
=== The governing invariant
-GQLdt already enforces an analogous rule at the data layer: `Provenance/Rationale.lean`
-states that *"you cannot construct a `Tracked` value without providing a non-empty
-rationale"*. GNPL's rule is the narrative counterpart:
+The private provenance types require a nonempty rationale, which is a useful
+data constraint. GNPL needs a stronger constructor obligation: the cited evidence
+must actually license the requested assertion under the declared stance. In the
+first fragment, licensing means exact claim match, visibility, active evidence
+and an explicit threshold; a nonempty rationale alone is insufficient.
[IMPORTANT]
====
@@ -260,7 +266,8 @@ with entrenchment read from recorded `Confidence` rather than stipulated.
* **Not a summariser.** Selection is declared by a `Projection`, not inferred by a model.
* **Not a truth oracle.** It never adjudicates which rival account is correct; it
characterises the accounts the evidence supports and their relations.
-* **Not a replacement for GQLdt.** It lowers to it.
+* **No prescribed private lowering target.** Storage selection and validation are
+ supporting implementation choices, not additional public language identities.
That third point is a design commitment, not a limitation: a system that silently picked a
winner would reintroduce exactly the reconciliation loss described at the top.
@@ -272,7 +279,9 @@ winner would reintroduce exactly the reconciliation loss described at the top.
the choice a language parameter?
. **Where does `Confidence` composition come from?** The current `Confidence.avg` and
`.mul` are placeholders and are not probabilistically principled. DempsterβShafer? A
- provenance semiring? This must be decided before any number is shown to a user.
+ provenance semiring? This must be decided before computed confidence is claimed.
+ The first slice exposes only declared integer scores and a chosen threshold;
+ it does not combine scores or give them probabilistic meaning.
. **Is `Focalization` a restriction, or a full epistemic modality?** Restriction is simpler;
a modality is needed for "A believes that B knows X", which forensic work does want.
. **How much of narratological *duration* and *frequency* is worth mechanising?** Order and
@@ -281,9 +290,10 @@ winner would reintroduce exactly the reconciliation loss described at the top.
if discharging it is not so painful that users route around it.
. **Does the partial order need to be a lattice** for projection to be well-behaved, or is
a DAG enough?
-. **Confidence is currently `Float`** with runtime-only validation (see the note in
- `Types/Confidence.lean`). Proof-level guarantees over floats are hard in Lean 4; does the
- narration layer need an exact rational or interval representation instead?
+. **The private substrate's confidence type uses `Float`** with runtime-only
+ validation. The initial narration kernel uses a bounded integer admission
+ score independently of it. Future composition still needs a justified
+ representation and semantics, potentially exact rationals or intervals.
== References
diff --git a/docs/TWO-TIER-DESIGN.adoc b/docs/TWO-TIER-DESIGN.adoc
index 77ad8e4..ec44b16 100644
--- a/docs/TWO-TIER-DESIGN.adoc
+++ b/docs/TWO-TIER-DESIGN.adoc
@@ -1,29 +1,29 @@
== GQL-DT Two-Tier Language Design
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Date:* 2026-02-01 *Status:* Architectural Decision
+*Date:* 2026-02-01
+*Status:* Architectural Decision
'''''
=== The Problem: Two User Populations
+[[population-1-developers--advanced-admins-gql-dt]]
==== Population 1: Developers & Advanced Admins (GQL-DT)
-* *Who:* Formal methods experts, security auditors, senior database
-admins
-* *Needs:* Full type safety, proof obligations, compile-time
-verification
-* *Willing to:* Write proofs, understand dependent types, debug type
-errors
+* *Who:* Formal methods experts, security auditors, senior database admins
+* *Needs:* Full type safety, proof obligations, compile-time verification
+* *Willing to:* Write proofs, understand dependent types, debug type errors
* *Use case:* Extreme secure audit projects, critical data entry
+[[population-2-regular-users--junior-admins-gql]]
==== Population 2: Regular Users & Junior Admins (GQL)
* *Who:* Journalists, researchers, junior staff
* *Needs:* Simple syntax, runtime checks, helpful error messages
-* *Canβt:* Write Lean 4 proofs, understand type theory
+* *Can't:* Write Lean 4 proofs, understand type theory
* *Use case:* Day-to-day database operations, routine queries
'''''
@@ -63,6 +63,7 @@ errors
=== Tier 1: GQL-DT (Developer/Admin)
+[[syntax-explicit-types--proofs]]
==== Syntax: Explicit Types & Proofs
[source,lean]
@@ -83,15 +84,20 @@ WITH_PROOF {
};
----
-*Characteristics:* - β
*Compile-time verification* - Invalid queries
-donβt compile - β
*Proof obligations* - Must provide proofs or use
-auto-tactics - β
*Type safety guaranteed* - No runtime type errors
-possible - β οΈ *Steep learning curve* - Requires Lean 4 knowledge - β οΈ
-*Verbose* - Explicit types and proofs
+*Characteristics:*
-*Who uses it:* - Security auditors entering sensitive data - Database
-administrators setting up schemas - Developers creating normalization
-proofs - Formal verification team
+* β
*Compile-time verification* - Invalid queries don't compile
+* β
*Proof obligations* - Must provide proofs or use auto-tactics
+* β
*Type safety guaranteed* - No runtime type errors possible
+* β οΈ *Steep learning curve* - Requires Lean 4 knowledge
+* β οΈ *Verbose* - Explicit types and proofs
+
+*Who uses it:*
+
+* Security auditors entering sensitive data
+* Database administrators setting up schemas
+* Developers creating normalization proofs
+* Formal verification team
'''''
@@ -112,20 +118,26 @@ RATIONALE 'Official statistics';
-- 3. Rationale check: 'Official statistics' non-empty β validated
----
-*Characteristics:* - β
*Familiar syntax* - Looks like standard SQL - β
-*Type inference* - Types automatically inferred - β
*Helpful errors* -
-Runtime errors with fix suggestions - β
*No proofs needed* -
-Constraints checked at runtime - β οΈ *Runtime overhead* - Validation
-happens at execution
+*Characteristics:*
+
+* β
*Familiar syntax* - Looks like standard SQL
+* β
*Type inference* - Types automatically inferred
+* β
*Helpful errors* - Runtime errors with fix suggestions
+* β
*No proofs needed* - Constraints checked at runtime
+* β οΈ *Runtime overhead* - Validation happens at execution
+
+*Who uses it:*
-*Who uses it:* - Journalists entering evidence - Researchers adding
-claims - Junior admins performing routine operations - General users
-querying data
+* Journalists entering evidence
+* Researchers adding claims
+* Junior admins performing routine operations
+* General users querying data
'''''
=== How They Interact: Compilation Strategy
+[[gql--gql-dt--lithoglyph]]
==== GQL β GQL-DT β Lithoglyph
....
@@ -145,6 +157,7 @@ Type Checking (validate proofs)
Execute Error (with fix suggestion)
....
+[[example-gql--gql-dt-translation]]
==== Example: GQL β GQL-DT Translation
*Input (GQL):*
@@ -183,7 +196,7 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
=== Preventing User Mistakes: Safety Mechanisms
-==== Problem: "`Annoying users mess up, admins spend time fixing`"
+==== Problem: "Annoying users mess up, admins spend time fixing"
==== Solution 1: Transaction-Based Validation
@@ -231,9 +244,11 @@ CREATE COLLECTION evidence (
);
----
-*Access levels:* - `+runtime+`: GQL with type inference + runtime checks
-- `+compile_time+`: GQL-DT with proofs auto-generated where possible -
-`+proof_required+`: GQL-DT with manual proofs required (no auto-admit)
+*Access levels:*
+
+* `runtime`: GQL with type inference {plus} runtime checks
+* `compile++_++time`: GQL-DT with proofs auto-generated where possible
+* `proof++_++required`: GQL-DT with manual proofs required (no auto-admit)
==== Solution 3: Admin Review Queue
@@ -290,9 +305,12 @@ function submitEvidence(form: EvidenceForm) {
}
----
-*Benefits:* - β
Users never write raw SQL - β
UI enforces constraints
-(dropdowns, sliders, validation) - β
Type-safe generation of GQL - β
-Admins donβt see malformed queries
+*Benefits:*
+
+* β
Users never write raw SQL
+* β
UI enforces constraints (dropdowns, sliders, validation)
+* β
Type-safe generation of GQL
+* β
Admins don't see malformed queries
==== Solution 5: Gradual Validation Levels
@@ -343,7 +361,7 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
==== Phase 1: GQL-DT Only (Current)
* β
Milestone 1-4: Core types implemented
-* π§ Milestone 5-6: Parser + type checker
+* π§ Milestone 5-6: Parser {plus} type checker
*Status:* Advanced users can use GQL-DT now
@@ -356,6 +374,7 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
*Estimated:* 2-3 months after M6 complete
+[[phase-3-validation-levels--permissions-later]]
==== Phase 3: Validation Levels & Permissions (Later)
* [ ] Permission system
@@ -378,6 +397,7 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
=== Recommended Approach: NOW vs LATER
+[[white_check_mark-deal-with-now-during-parser-implementation]]
==== β
Deal with NOW (During Parser Implementation)
[arabic]
@@ -386,14 +406,15 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
* Proof annotations optional
* Same AST, different parsing paths
. *Add type inference hooks*
-* Placeholder for "`infer type from value`"
+* Placeholder for "infer type from value"
* Auto-proof generation infrastructure
-* Graceful degradation (admit if canβt prove)
+* Explicit rejection when an obligation cannot be proved
. *Define validation levels*
* Schema metadata: which tier is allowed
* User roles: which validation level they get
* Default: GQL for users, GQL-DT for admins
+[[hourglass_flowing_sand-deal-with-later-after-m6]]
==== β³ Deal with LATER (After M6)
[arabic]
@@ -422,7 +443,7 @@ CREATE COLLECTION evidence (
id : UUID PRIMARY KEY,
title : NonEmptyString,
prompt_provenance : BoundedNat 0 100,
- prompt_scores : PromptScores
+ prompt_scores : Prompores
) WITH DEPENDENT_TYPES
TARGET_NORMAL_FORM BCNF
PERMISSIONS (
@@ -462,11 +483,11 @@ RATIONALE 'Official statistics';
-- Admin writes full type annotations
INSERT INTO evidence (
title : NonEmptyString,
- prompt_scores : PromptScores
+ prompt_scores : Prompores
)
VALUES (
NonEmptyString.mk "ONS CPI Data" (by decide),
- PromptScores.create
+ Prompores.create
(BoundedNat.mk 0 100 100 (by omega) (by omega))
(BoundedNat.mk 0 100 100 (by omega) (by omega))
(BoundedNat.mk 0 100 95 (by omega) (by omega))
@@ -489,9 +510,13 @@ WITH_PROOF {
*Recommendation:* Add two-tier support *during Milestone 6 (Parser)*
-*Why NOW:* 1. Parser architecture affects both tiers 2. AST design must
-support type inference 3. Easier to build both parsers together 4. Type
-inference shares infrastructure with type checker
+*Why NOW:*
+
+[arabic]
+. Parser architecture affects both tiers
+. AST design must support type inference
+. Easier to build both parsers together
+. Type inference shares infrastructure with type checker
*What to implement:*
@@ -506,7 +531,7 @@ inference shares infrastructure with type checker
* Parse SQL-like syntax
* Infer types from values
* Auto-generate proofs where possible
-* Graceful degradation (admit if canβt prove)
+* Explicit rejection when an obligation cannot be proved
==== M6c: Unified Type Checker
@@ -534,7 +559,7 @@ inference shares infrastructure with type checker
==== Preventing User Mistakes
[arabic]
-. *Transaction validation* - Invalid queries donβt commit
+. *Transaction validation* - Invalid queries don't commit
. *Permission levels* - Users get runtime validation
. *Admin review queue* - Optional approval workflow
. *Template-based UI* - Lithoglyph Studio (no raw SQL)
@@ -550,7 +575,7 @@ inference shares infrastructure with type checker
=== Granular Permission System: Workplace-Specific Type Restrictions
-==== The Question: "`Can we restrict users to ONLY numbers, strings, dates?`"
+==== The Question: "Can we restrict users to ONLY numbers, strings, dates?"
*Answer: YES - Fine-grained type-level permissions*
@@ -563,7 +588,7 @@ structure TypeWhitelist where
allowedTypes : List TypeExpr
allowBuiltinTypes : Bool -- Nat, String, Bool
allowRefinedTypes : Bool -- BoundedNat, NonEmptyString
- allowDependentTypes : Bool -- PromptScores, custom types
+ allowDependentTypes : Bool -- Prompores, custom types
allowProofTypes : Bool -- Types requiring manual proofs
-- Permission profile for a user or role
@@ -587,7 +612,7 @@ def journalistPermissions : PermissionProfile := {
allowedTypes := [.nat, .string, .date], -- ONLY these types
allowBuiltinTypes := true,
allowRefinedTypes := false, -- No BoundedNat
- allowDependentTypes := false, -- No PromptScores
+ allowDependentTypes := false, -- No Prompores
allowProofTypes := false -- No custom proofs
},
validationLevel := .runtime, -- GQL only
@@ -691,9 +716,11 @@ CREATE COLLECTION simple_data (
(operations all)))))
----
-*Result:* - Journalists: Simple GQL, basic types only, canβt mess up
-type system - Editors: GQL with some refined types, still
-runtime-checked - Tech admins: Full GQL-DT, compile-time verification
+*Result:*
+
+* Journalists: Simple GQL, basic types only, can't mess up type system
+* Editors: GQL with some refined types, still runtime-checked
+* Tech admins: Full GQL-DT, compile-time verification
===== Example 2: Security Audit Firm
@@ -721,9 +748,11 @@ runtime-checked - Tech admins: Full GQL-DT, compile-time verification
(require-review false)))))
----
-*Result:* - Junior auditors: Limited types, all queries reviewed -
-Senior auditors: All standard types, compile-time checks - Principals:
-Full dependent types, manual proof obligations
+*Result:*
+
+* Junior auditors: Limited types, all queries reviewed
+* Senior auditors: All standard types, compile-time checks
+* Principals: Full dependent types, manual proof obligations
==== Implementation: Type Filter in AST
@@ -743,7 +772,7 @@ def isTypeAllowed (t : TypeExpr) (whitelist : TypeWhitelist) : Bool :=
whitelist.allowBuiltinTypes
| .boundedNat _ _ | .boundedFloat _ _ | .nonEmptyString | .confidence =>
whitelist.allowRefinedTypes
- | .promptScores | .custom _ =>
+ | .prompores | .custom _ =>
whitelist.allowDependentTypes
| .proof _ =>
whitelist.allowProofTypes
@@ -795,7 +824,7 @@ Executing INSERT...
----
// Lithoglyph Studio auto-hides fields based on permissions
function renderEvidenceForm(user: User, profile: PermissionProfile) {
- const schema = getSchema("evidence");
+ const schema = gehema("evidence");
const allowedColumns = filterSchemaForUser(schema, profile);
return (
@@ -827,7 +856,7 @@ function renderEvidenceForm(user: User, profile: PermissionProfile) {
==== Layer 2: Type Permissions (Organizational Policy)
* *Whitelist-based*: Only allow specific types per role
-* *Granular*: Can restrict to `+[Nat, String, Date]+` only
+* *Granular*: Can restrict to `++[++Nat, String, Date++]++` only
* *Schema-level*: Column access based on type requirements
* *Enforced in parser*: Type checks happen before execution
@@ -842,12 +871,11 @@ function renderEvidenceForm(user: User, profile: PermissionProfile) {
* *No syntax exposure*: Users never write SQL/GQL-DT
* *Type-driven forms*: UI generates based on allowed types
-* *Impossible to bypass*: Restricted columns donβt appear
+* *Impossible to bypass*: Restricted columns don't appear
-==== Answer to "`Flexibility`" Question
+==== Answer to "Flexibility" Question
-*Q: Can a workplace say "`GQL with numbers, strings, dates BUT NOTHING
-ELSE`"?*
+*Q: Can a workplace say "GQL with numbers, strings, dates BUT NOTHING ELSE"?*
*A: YES, exactly this:*
@@ -859,7 +887,7 @@ def workplacePolicy : PermissionProfile := {
allowedTypes := [.nat, .string, .date],
allowBuiltinTypes := true, -- Nat, String allowed
allowRefinedTypes := false, -- No BoundedNat
- allowDependentTypes := false, -- No PromptScores
+ allowDependentTypes := false, -- No Prompores
allowProofTypes := false -- No proofs
},
validationLevel := .runtime, -- GQL only
@@ -869,21 +897,27 @@ def workplacePolicy : PermissionProfile := {
}
----
-*Result:* - β
Can use: Nat, String, Date - β Cannot use: BoundedNat,
-NonEmptyString, PromptScores, custom types - β
Syntax: Simple SQL (GQL)
-- β Cannot access: GQL-DT syntax, proof obligations, dependent types -
-β
Queries: Runtime-checked, helpful error messages - β Cannot break:
-Type system (restricted types canβt violate invariants)
+*Result:*
+
+* β
Can use: Nat, String, Date
+* β Cannot use: BoundedNat, NonEmptyString, Prompores, custom types
+* β
Syntax: Simple SQL (GQL)
+* β Cannot access: GQL-DT syntax, proof obligations, dependent types
+* β
Queries: Runtime-checked, helpful error messages
+* β Cannot break: Type system (restricted types can't violate invariants)
'''''
-*Document Status:* Complete architectural decision for two-tier language
-design with granular permission system
+*Document Status:* Complete architectural decision for two-tier language design with granular permission system
+
+*Recommendation:* Implement dual-tier support {plus} permission system in Milestone 6 (Parser)
-*Recommendation:* Implement dual-tier support + permission system in
-Milestone 6 (Parser)
+*Next Steps:*
-*Next Steps:* 1. Design AST to support both tiers 2. Implement GQL-DT
-parser (explicit types) 3. Implement GQL parser (type inference) 4.
-Implement TypeWhitelist and PermissionProfile 5. Unified type checker
-with permission enforcement 6. Schema-level permission annotations
+[arabic]
+. Design AST to support both tiers
+. Implement GQL-DT parser (explicit types)
+. Implement GQL parser (type inference)
+. Implement TypeWhitelist and PermissionProfile
+. Unified type checker with permission enforcement
+. Schema-level permission annotations
diff --git a/docs/WP06_Dependently_Typed_Lithoglyph.adoc b/docs/WP06_Dependently_Typed_Lithoglyph.adoc
index 8c90e68..ad1a728 100644
--- a/docs/WP06_Dependently_Typed_Lithoglyph.adoc
+++ b/docs/WP06_Dependently_Typed_Lithoglyph.adoc
@@ -1,29 +1,21 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
== White Paper 06: Dependently-Typed Lithoglyph
*Status*: Research Proposal +
*Version*: 0.1.0 +
*Date*: 2025-01-11 +
*Authors*: Jonathan D.A. Jewell, Claude (Anthropic) +
-*License*: MPL-2.0
+*License*: CC-BY-SA-4.0
=== Abstract
-Lithoglyphβs narrative-first architecture demands stronger correctness
-guarantees than traditional databases can provide. We propose extending
-Lithoglyph with dependent typesβtypes that depend on valuesβenabling
-compile-time verification of epistemic properties. This transforms
-Lithoglyph from a database that _records_ provenance to one that
-_proves_ provenance. We demonstrate how dependent types naturally
-express PROMPT score constraints, provenance tracking, reversibility
-proofs, and belief fusion in the My-Newsroom multi-agent system. Our
-approach is incremental: refinement types first (simple, high ROI), then
-full dependent types (research frontier). This positions Lithoglyph as
-the first database with *provable epistemology*, uniquely suited for
-journalism, scientific reproducibility, and AI agent collaboration where
-correctness is non-negotiable.
+Lithoglyph's narrative-first architecture demands stronger correctness guarantees than traditional databases can provide. We propose extending Lithoglyph with dependent typesβtypes that depend on valuesβenabling compile-time verification of epistemic properties. This transforms Lithoglyph from a database that _records_ provenance to one that _proves_ provenance. We demonstrate how dependent types naturally express PROMPT score constraints, provenance tracking, reversibility proofs, and belief fusion in the My-Newsroom multi-agent system. Our approach is incremental: refinement types first (simple, high ROI), then full dependent types (research frontier). This positions Lithoglyph as the first database with *provable epistemology*, uniquely suited for journalism, scientific reproducibility, and AI agent collaboration where correctness is non-negotiable.
+[[1-introduction]]
=== 1. Introduction
+[[11-the-problem-runtime-correctness-is-insufficient]]
==== 1.1 The Problem: Runtime Correctness Is Insufficient
Traditional databases enforce correctness at *runtime*:
@@ -40,12 +32,15 @@ INSERT INTO evidence (prompt_provenance) VALUES (150);
-- ERROR: Check constraint "prompt_provenance_range" violated
----
-*Problems*: 1. *Late detection*: Errors caught during execution, not
-development 2. *Incomplete coverage*: Canβt express "`every UPDATE must
-have REASON`" 3. *No proofs*: Canβt prove invariants hold across all
-operations 4. *Agent confusion*: LLM agents struggle with runtime-only
-validation
+*Problems*:
+[arabic]
+. *Late detection*: Errors caught during execution, not development
+. *Incomplete coverage*: Can't express "every UPDATE must have REASON"
+. *No proofs*: Can't prove invariants hold across all operations
+. *Agent confusion*: LLM agents struggle with runtime-only validation
+
+[[12-the-solution-dependent-types]]
==== 1.2 The Solution: Dependent Types
*Dependent types* are types that depend on values:
@@ -53,30 +48,33 @@ validation
[source,idris]
----
-- Idris: Compile-time proof
-data PromptScore : Type where
- MkPromptScore : (n : Nat) ->
+data Prompore : Type where
+ MkPrompore : (n : Nat) ->
{auto prf : LTE n 100} -> -- Proof obligation
- PromptScore
+ Prompore
-- Invalid score is a TYPE ERROR, caught immediately
-badScore : PromptScore
-badScore = MkPromptScore 150 -- TYPE ERROR: Can't prove LTE 150 100
+badScore : Prompore
+badScore = MkPrompore 150 -- TYPE ERROR: Can't prove LTE 150 100
----
-*Benefits*: 1. *Early detection*: Type errors at compile time (or
-before) 2. *Complete coverage*: Type system enforces ALL invariants 3.
-*Machine-checkable proofs*: Types ARE proofs (Curry-Howard
-correspondence) 4. *Agent-friendly*: LLM agents can check types before
-generating code
+*Benefits*:
+
+[arabic]
+. *Early detection*: Type errors at compile time (or before)
+. *Complete coverage*: Type system enforces ALL invariants
+. *Machine-checkable proofs*: Types ARE proofs (Curry-Howard correspondence)
+. *Agent-friendly*: LLM agents can check types before generating code
+[[13-why-lithoglyph-needs-this]]
==== 1.3 Why Lithoglyph Needs This
Lithoglyph has *unique epistemic requirements*:
-[width="100%",cols="26%,35%,39%",options="header",]
+[cols=",,",options="header",]
|===
|Requirement |Current (Runtime) |With Dependent Types
-|PROMPT scores in [0, 100] |Runtime CHECK |Compile-time proof
+|PROMPT scores in ++[++0, 100++]++ |Runtime CHECK |Compile-time proof
|Every INSERT needs RATIONALE |Parser check |Type system enforces
|Provenance tracked |Application code |Baked into types
|Operations reversible |Runtime verification |Proof of inverse exists
@@ -84,11 +82,12 @@ Lithoglyph has *unique epistemic requirements*:
|Navigation paths ordered |Runtime sort |Type proves ordering
|===
-*Thesis*: Dependent types transform Lithoglyph from a database that
-_records_ epistemology to one that _proves_ epistemology.
+*Thesis*: Dependent types transform Lithoglyph from a database that _records_ epistemology to one that _proves_ epistemology.
+[[2-background-dependent-types]]
=== 2. Background: Dependent Types
+[[21-what-are-dependent-types]]
==== 2.1 What Are Dependent Types?
*Simple types* (SQL, most PLs):
@@ -106,9 +105,9 @@ Bounded 0 100 Int -- Integer between 0 and 100
{x : Int | x > 0} -- Refinement: positive integers
....
-Key insight: *Types can mention values*, enabling precise
-specifications.
+Key insight: *Types can mention values*, enabling precise specifications.
+[[22-refinement-types-subset-of-dependent-types]]
==== 2.2 Refinement Types (Subset of Dependent Types)
*Refinement types* restrict existing types with predicates:
@@ -118,13 +117,16 @@ specifications.
-- Base type + predicate
type PositiveInt = {n : Int | n > 0}
type Email = {s : String | matches s emailRegex}
-type PromptScore = {n : Nat | 0 <= n && n <= 100}
+type Prompore = {n : Nat | 0 <= n && n <= 100}
----
-*Why start here?* - Easier to understand than full dependent types -
-High ROI: catches most errors - Libraries exist (Liquid Haskell, F*,
-Dafny)
+*Why start here?*
+* Easier to understand than full dependent types
+* High ROI: catches most errors
+* Libraries exist (Liquid Haskell, F++*++, Dafny)
+
+[[23-full-dependent-types]]
==== 2.3 Full Dependent Types
*Full dependent types* allow arbitrary value dependencies:
@@ -144,10 +146,13 @@ head (x :: xs) = x
(++) : Vect n a -> Vect m a -> Vect (n + m) a
----
-*Why eventually move here?* - Express complex invariants (navigation
-path ordering) - Prove operations correct (reversibility) - Enable
-advanced reasoning (belief fusion proofs)
+*Why eventually move here?*
+
+* Express complex invariants (navigation path ordering)
+* Prove operations correct (reversibility)
+* Enable advanced reasoning (belief fusion proofs)
+[[24-curry-howard-correspondence]]
==== 2.4 Curry-Howard Correspondence
*Key insight*: Types = Propositions, Programs = Proofs
@@ -175,11 +180,12 @@ plusZeroRightNeutral (S k) = -- Proof for successor
rewrite plusZeroRightNeutral k in Refl
----
-*For Lithoglyph*: Type-checking = Proof-checking. If it compiles, the
-proof is valid!
+*For Lithoglyph*: Type-checking = Proof-checking. If it compiles, the proof is valid!
-=== 3. Motivation: Lithoglyphβs Epistemic Requirements
+[[3-motivation-lithoglyphs-epistemic-requirements]]
+=== 3. Motivation: Lithoglyph's Epistemic Requirements
+[[31-prompt-score-invariants]]
==== 3.1 PROMPT Score Invariants
*Current* (runtime):
@@ -200,9 +206,13 @@ CREATE COLLECTION evidence (
);
----
-*Problems*: 1. Can construct invalid struct: `+{provenance: 150, ...}+`
-2. Runtime error only on INSERT 3. No proof that `+overall+` is in [0,
-100] 4. Agents might hallucinate invalid scores
+*Problems*:
+
+[arabic]
+. Can construct invalid struct: `++{++provenance: 150, ...}`
+. Runtime error only on INSERT
+. No proof that `overall` is in ++[++0, 100++]++
+. Agents might hallucinate invalid scores
*With Dependent Types*:
@@ -213,8 +223,8 @@ PromptDimension : Type
PromptDimension = BoundedNat 0 100
-- Struct with proof that overall is computed correctly
-data PromptScores : Type where
- MkPromptScores :
+data Prompores : Type where
+ MkPrompores :
(provenance : PromptDimension) ->
(replicability : PromptDimension) ->
(objective : PromptDimension) ->
@@ -222,24 +232,27 @@ data PromptScores : Type where
(publication : PromptDimension) ->
(transparency : PromptDimension) ->
(overall : PromptDimension) ->
- {auto prf : overall = computeOverall provenance replicability
- objective methodology
+ {auto prf : overall = computeOverall provenance replicability
+ objective methodology
publication transparency} ->
- PromptScores
+ Prompores
-- Proof that average of bounded values is bounded
computeOverall : PromptDimension -> PromptDimension -> PromptDimension ->
PromptDimension -> PromptDimension -> PromptDimension ->
PromptDimension
-computeOverall p r o m pub t =
+computeOverall p r o m pub t =
MkBounded ((p + r + o + m + pub + t) `div` 6)
{prf = averageInBounds p r o m pub t}
----
-*Benefits*: - Invalid scores are TYPE ERRORS (caught at compile time) -
-Proof that `+overall+` is always in range - Agents can type-check before
-execution
+*Benefits*:
+* Invalid scores are TYPE ERRORS (caught at compile time)
+* Proof that `overall` is always in range
+* Agents can type-check before execution
+
+[[32-mandatory-rationale]]
==== 3.2 Mandatory Rationale
*Current* (parser):
@@ -258,7 +271,7 @@ INSERT INTO claims (text) VALUES ('Some claim');
----
-- Operations MUST carry provenance
data ProvenanceTracked : Type -> Type where
- MkTracked :
+ MkTracked :
(value : a) ->
(added_by : String) ->
(added_at : Timestamp) ->
@@ -266,16 +279,19 @@ data ProvenanceTracked : Type -> Type where
ProvenanceTracked a
-- Type signature FORCES provenance
-insertClaim : (text : String) ->
+insertClaim : (text : String) ->
(rationale : NonEmptyString) -> -- Required argument!
(actor : String) ->
ProvenanceTracked Claim
----
-*Benefits*: - Impossible to forget RATIONALE (type error) - Type system
-enforces ALL insertions have provenance - LLM agents see type signature,
-know whatβs required
+*Benefits*:
+* Impossible to forget RATIONALE (type error)
+* Type system enforces ALL insertions have provenance
+* LLM agents see type signature, know what's required
+
+[[33-reversibility-proofs]]
==== 3.3 Reversibility Proofs
*Current* (runtime verification):
@@ -288,8 +304,11 @@ INSERT INTO claims (text) VALUES ('X') RATIONALE "...";
-- Tests at runtime that inverse works
----
-*Problem*: - Inverse might be wrong (subtle bugs) - Only tested on
-specific data - No guarantee for ALL possible inputs
+*Problem*:
+
+* Inverse might be wrong (subtle bugs)
+* Only tested on specific data
+* No guarantee for ALL possible inputs
*With Dependent Types*:
@@ -301,13 +320,13 @@ data Reversible : Type -> Type where
(inverse : Delete a) ->
{auto prf : roundTrip data inverse = data} -> -- Proof!
Reversible a
-
+
Update : (old : a) ->
(new : a) ->
(inverse : Update a) ->
{auto prf : roundTrip (old, new) inverse = (new, old)} ->
Reversible a
-
+
Irreversible : (data : a) ->
(reason : NonEmptyString) ->
(justification : Why reason) -> -- Proof of why!
@@ -315,14 +334,17 @@ data Reversible : Type -> Type where
-- Proof that round-trip preserves data
roundTrip : a -> (a -> a) -> a
-roundTripPreservesIdentity : (x : a) -> (f : a -> a) ->
+roundTripPreservesIdentity : (x : a) -> (f : a -> a) ->
roundTrip x f = x
----
-*Benefits*: - *Mathematical proof* that inverse is correct - Proof holds
-for ALL inputs, not just tested cases - Canβt mark something
-irreversible without proving why
+*Benefits*:
+* *Mathematical proof* that inverse is correct
+* Proof holds for ALL inputs, not just tested cases
+* Can't mark something irreversible without proving why
+
+[[34-confidence-levels]]
==== 3.4 Confidence Levels
*Current*:
@@ -348,15 +370,18 @@ data Claim : Confidence -> Type where
Claim c
-- Type system ensures confidence matches evidence
-combineClaims : Claim c1 -> Claim c2 ->
+combineClaims : Claim c1 -> Claim c2 ->
{auto prf : Compatible c1 c2} ->
Claim (fuseConfidence c1 c2)
----
-*Benefits*: - Confidence canβt exceed 1.0 (type error) - Type proves
-confidence matches evidence - Combining claims requires proof of
-compatibility
+*Benefits*:
+
+* Confidence can't exceed 1.0 (type error)
+* Type proves confidence matches evidence
+* Combining claims requires proof of compatibility
+[[35-navigation-path-ordering]]
==== 3.5 Navigation Path Ordering
*Current*:
@@ -386,31 +411,47 @@ data NavigationPath : (ordering : Evidence -> Evidence -> Bool) -> Type where
-- Type proves path is ordered
createSkepticPath : List Evidence -> NavigationPath (orderByObjective)
-createSkepticPath evs = MkPath (sort orderByObjective evs)
+createSkepticPath evs = MkPath (sort orderByObjective evs)
{prf = sortProducesSorted _ _}
----
-*Benefits*: - Type proves path satisfies ordering invariant - Canβt
-create invalid path (type error) - Different audiences get different
-ordering proofs
+*Benefits*:
+* Type proves path satisfies ordering invariant
+* Can't create invalid path (type error)
+* Different audiences get different ordering proofs
+
+[[4-type-system-design]]
=== 4. Type System Design
+[[41-three-tier-approach]]
==== 4.1 Three-Tier Approach
-*Tier 1: Refinement Types* (Month 1-6) - Bounded integers:
-`+BoundedNat 0 100+` - Non-null strings: `+NonEmptyString+` - Bounded
-floats: `+BoundedFloat 0.0 1.0+` - Pattern-matched enums
+*Tier 1: Refinement Types* (Month 1-6)
+
+* Bounded integers: `BoundedNat 0 100`
+* Non-null strings: `NonEmptyString`
+* Bounded floats: `BoundedFloat 0.0 1.0`
+* Pattern-matched enums
+
+*Tier 2: Simple Dependent Types* (Month 7-12)
+
+* Length-indexed arrays: `Vect n a`
+* Computed fields with proofs
+* Provenance-tracked values: `Tracked a`
+* Type-safe edges: `Edge from to`
-*Tier 2: Simple Dependent Types* (Month 7-12) - Length-indexed arrays:
-`+Vect n a+` - Computed fields with proofs - Provenance-tracked values:
-`+Tracked a+` - Type-safe edges: `+Edge from to+`
+*Tier 3: Full Dependent Types* (Month 13-18)
-*Tier 3: Full Dependent Types* (Month 13-18) - Reversibility proofs -
-Belief fusion proofs - Path ordering proofs - Complex invariants
+* Reversibility proofs
+* Belief fusion proofs
+* Path ordering proofs
+* Complex invariants
+[[42-core-type-definitions]]
==== 4.2 Core Type Definitions
+[[421-bounded-types]]
===== *4.2.1 Bounded Types*
[source,idris]
@@ -438,6 +479,7 @@ Percentage : Type
Percentage = BoundedFloat 0.0 100.0
----
+[[422-non-empty-strings]]
===== *4.2.2 Non-Empty Strings*
[source,idris]
@@ -456,6 +498,7 @@ ActorId : Type
ActorId = NonEmptyString
----
+[[423-provenance-tracked-values]]
===== *4.2.3 Provenance-Tracked Values*
[source,idris]
@@ -477,12 +520,13 @@ getProvenance : Tracked a -> (ActorId, Timestamp, Rationale)
getProvenance (MkTracked _ actor ts rat) = (actor, ts, rat)
----
+[[424-prompt-scores]]
===== *4.2.4 PROMPT Scores*
[source,idris]
----
-data PromptScores : Type where
- MkPromptScores :
+data Prompores : Type where
+ MkPrompores :
(provenance : PromptDimension) ->
(replicability : PromptDimension) ->
(objective : PromptDimension) ->
@@ -490,16 +534,16 @@ data PromptScores : Type where
(publication : PromptDimension) ->
(transparency : PromptDimension) ->
(overall : PromptDimension) ->
- {auto prf : overall = computeOverall provenance replicability
- objective methodology
+ {auto prf : overall = computeOverall provenance replicability
+ objective methodology
publication transparency} ->
- PromptScores
+ Prompores
-- Proof that average is in bounds
computeOverall : PromptDimension -> PromptDimension -> PromptDimension ->
PromptDimension -> PromptDimension -> PromptDimension ->
PromptDimension
-computeOverall (MkBounded p) (MkBounded r) (MkBounded o)
+computeOverall (MkBounded p) (MkBounded r) (MkBounded o)
(MkBounded m) (MkBounded pub) (MkBounded t) =
MkBounded ((p + r + o + m + pub + t) `div` 6)
{prf = averagePreservesBounds p r o m pub t}
@@ -511,6 +555,7 @@ averagePreservesBounds : (p, r, o, m, pub, t : Nat) ->
LTE ((p + r + o + m + pub + t) `div` 6) 100
----
+[[425-collections-tables]]
===== *4.2.5 Collections (Tables)*
[source,idris]
@@ -531,6 +576,7 @@ query : Collection a -> (a -> Bool) -> List (Tracked a)
query (MkCollection _ rows) predicate = filter (predicate . getValue) rows
----
+[[426-edge-collections]]
===== *4.2.6 Edge Collections*
[source,idris]
@@ -547,10 +593,11 @@ data Edge : Type -> Type -> Type where
-- Type-safe graph traversal
traverse : List (Edge a b) -> a -> List b
-traverse edges start =
+traverse edges start =
[getValue to | MkEdge from to _ _ _ <- edges, getValue from == start]
----
+[[427-reversible-operations]]
===== *4.2.7 Reversible Operations*
[source,idris]
@@ -561,19 +608,19 @@ data ReversibleOp : Type -> Type where
(inverse : Delete a) ->
{auto prf : composeInverses (insert data) (delete inverse) = id} ->
ReversibleOp a
-
+
Update : (old : Tracked a) ->
(new : Tracked a) ->
(inverse : Update a) ->
- {auto prf : composeInverses (update old new) inverse =
+ {auto prf : composeInverses (update old new) inverse =
update new old} ->
ReversibleOp a
-
+
Delete : (data : Tracked a) ->
(inverse : Insert a) ->
{auto prf : composeInverses (delete data) (insert inverse) = id} ->
ReversibleOp a
-
+
Irreversible : (data : Tracked a) ->
(reason : Rationale) ->
(justification : Why reason) -> -- Proof of necessity
@@ -587,8 +634,10 @@ data JournalEntry : Type where
JournalEntry
----
+[[43-gql-syntax-extensions]]
==== 4.3 GQL Syntax Extensions
+[[431-type-annotations]]
===== *4.3.1 Type Annotations*
[source,gql]
@@ -604,11 +653,12 @@ CREATE COLLECTION evidence (
CREATE COLLECTION evidence (
id : UUID,
title : NonEmptyString,
- prompt_scores : PromptScores, -- Type carries proofs!
+ prompt_scores : Prompores, -- Type carries proofs!
added : Tracked () -- Provenance automatically tracked
) WITH DEPENDENT_TYPES;
----
+[[432-insertion-with-proof-obligations]]
===== *4.3.2 Insertion with Proof Obligations*
[source,gql]
@@ -629,6 +679,7 @@ RATIONALE "Official UK statistics";
-- 4. Operation reversible β
----
+[[433-queries-with-refinements]]
===== *4.3.3 Queries with Refinements*
[source,gql]
@@ -641,6 +692,7 @@ RETURNING (e : Evidence | e.prompt_scores.overall > 90);
-- Return type PROVES all results satisfy predicate
----
+[[434-verified-updates]]
===== *4.3.4 Verified Updates*
[source,gql]
@@ -658,8 +710,10 @@ WITH_PROOF {
};
----
+[[5-implementation-strategy]]
=== 5. Implementation Strategy
+[[51-architecture]]
==== 5.1 Architecture
....
@@ -694,14 +748,26 @@ WITH_PROOF {
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
....
+[[52-phase-1-external-type-checker-month-1-6]]
==== 5.2 Phase 1: External Type Checker (Month 1-6)
*Goal*: Opt-in type checking without changing Lithoglyph runtime.
-*Implementation*: 1. *GQL Parser Extension*:
-`+elixir # Parse dependent type annotations defmodule GQL.Parser.DependentTypes do def parse_type_annotation(tokens) do # Parse: "x : BoundedNat 0 100" # Returns: {:bounded_nat, 0, 100} end end+`
+*Implementation*:
-[arabic, start=2]
+[arabic]
+. *GQL Parser Extension*:
++
+[source,elixir]
+----
+# Parse dependent type annotations
+defmodule GQL.Parser.DependentTypes do
+ def parse_type_annotation(tokens) do
+ # Parse: "x : BoundedNat 0 100"
+ # Returns: {:bounded_nat, 0, 100}
+ end
+end
+----
. *Type Checker (Idris 2)*:
+
[source,idris]
@@ -748,7 +814,7 @@ lithoglyph execute output.gql
cat > example.gql.idr
CREATE COLLECTION evidence (
id : UUID,
- prompt_scores : PromptScores
+ prompt_scores : Prompores
);
INSERT INTO evidence VALUES (...);
@@ -758,6 +824,7 @@ INSERT INTO evidence VALUES (...);
./check_gql.sh example.gql.idr
----
+[[53-phase-2-proof-carrying-code-month-7-12]]
==== 5.3 Phase 2: Proof-Carrying Code (Month 7-12)
*Goal*: Store proofs alongside data in journal.
@@ -802,6 +869,7 @@ WHERE prompt_scores.provenance = 100
-- Returns data + proof verification results
----
+[[54-phase-3-verified-runtime-month-13-24]]
==== 5.4 Phase 3: Verified Runtime (Month 13-24)
*Goal*: Replace critical paths with verified code.
@@ -830,8 +898,10 @@ method InsertWithProvenance(
*Compile to C* β Link with Forth/Zig β Verified bridge!
+[[55-tooling]]
==== 5.5 Tooling
+[[551-ide-support]]
===== *5.5.1 IDE Support*
*Lean 4 LSP* (best IDE support):
@@ -866,6 +936,7 @@ $ lean4 --server
}
----
+[[552-proof-tactics]]
===== *5.5.2 Proof Tactics*
*Auto-solving Simple Proofs*:
@@ -883,6 +954,7 @@ example : 95 β€ 100 := by lithoglyph_bounds
-- Proven automatically!
----
+[[553-error-messages]]
===== *5.5.3 Error Messages*
*Current*:
@@ -899,7 +971,7 @@ TYPE ERROR at line 5, column 12:
INSERT INTO evidence (prompt_scores) VALUES ({provenance: 150, ...})
^^^
-Cannot construct PromptScores with provenance = 150
+Cannot construct Prompores with provenance = 150
Expected: BoundedNat 0 100
Got: 150 (out of bounds)
@@ -912,8 +984,10 @@ Suggestion: Use a value between 0 and 100
Much clearer!
+[[6-synergy-with-my-newsroom]]
=== 6. Synergy with My-Newsroom
+[[61-me-dialect-already-has-epistemic-types]]
==== 6.1 Me Dialect Already Has Epistemic Types
*From My-Newsroom*:
@@ -944,6 +1018,7 @@ getConfidence : Belief c a -> BoundedFloat 0.0 1.0
getConfidence (MkBelief _ c) = c
----
+[[62-type-safe-dempster-shafer-fusion]]
==== 6.2 Type-Safe Dempster-Shafer Fusion
*Current* (Julia, runtime):
@@ -971,9 +1046,13 @@ fusionPreservesBounds : (c1, c2 : BoundedFloat 0.0 1.0) ->
BoundedFloat 0.0 1.0 (dempsterFusion c1 c2)
----
-*Benefits*: - Type system ensures fusion is valid - Proof that result
-confidence is in [0.0, 1.0] - Agent can check types before executing
+*Benefits*:
+
+* Type system ensures fusion is valid
+* Proof that result confidence is in ++[++0.0, 1.0++]++
+* Agent can check types before executing
+[[63-agent-introspection-with-proofs]]
==== 6.3 Agent Introspection with Proofs
*Current*:
@@ -1010,8 +1089,9 @@ RETURN (reasoning, proof)
-- ]
----
-*Agent Beta* can now *verify Agent Alphaβs proofs* before trusting them!
+*Agent Beta* can now *verify Agent Alpha's proofs* before trusting them!
+[[64-byzantine-fault-tolerance-with-proofs]]
==== 6.4 Byzantine Fault Tolerance with Proofs
*Current*: 33% malicious agents tolerated (voting)
@@ -1030,7 +1110,7 @@ data VerifiedClaim : Type where
VerifiedClaim
-- Orchestrator verifies all proofs
-verifyAgentClaims : List (Agent, VerifiedClaim) ->
+verifyAgentClaims : List (Agent, VerifiedClaim) ->
Either ProofError (List VerifiedClaim)
verifyAgentClaims claims = do
-- Check each proof
@@ -1039,176 +1119,235 @@ verifyAgentClaims claims = do
pure (map snd claims)
----
-*Benefits*: - Malicious agents canβt fake proofs (type system enforces)
-- Honest agentsβ proofs always verify - Higher fault tolerance (50%+
-malicious if proofs required)
+*Benefits*:
+* Malicious agents can't fake proofs (type system enforces)
+* Honest agents' proofs always verify
+* Higher fault tolerance (50%{plus} malicious if proofs required)
+
+[[7-research-contributions]]
=== 7. Research Contributions
+[[71-novel-contributions]]
==== 7.1 Novel Contributions
[arabic]
. *First dependently-typed database*
* Databases: None have dependent types (to our knowledge)
-* Programming languages: Many (Idris, Agda, Lean, Coq, F*)
-* *Gap*: Database + dependent types = novel!
+* Programming languages: Many (Idris, Agda, Lean, Coq, F++*++)
+* *Gap*: Database {plus} dependent types = novel!
. *Provable epistemology*
-* Traditional: "`This claim has confidence 0.9`" (no proof)
-* Lithoglyph: "`This claim has confidence 0.9 AND hereβs a proof itβs
-justified`"
+* Traditional: "This claim has confidence 0.9" (no proof)
+* Lithoglyph: "This claim has confidence 0.9 AND here's a proof it's justified"
* *Impact*: Trust is verifiable, not just asserted
. *Type-safe multi-agent systems*
* Traditional: Agents share unverified beliefs
-* Lithoglyph: Agents share beliefs + proofs
+* Lithoglyph: Agents share beliefs {plus} proofs
* *Impact*: Byzantine resilience via proof verification
. *Proof-carrying provenance*
* Traditional: Provenance is metadata (can be forged)
-* Lithoglyph: Provenance is part of type (canβt be forged)
+* Lithoglyph: Provenance is part of type (can't be forged)
* *Impact*: Cryptographic-strength audit trails
+[[72-publications]]
==== 7.2 Publications
===== *Paper 1: POPL 2027 (Programming Languages)*
-*Title*: "`Lithoglyph: A Dependently-Typed Database for Verified
-Epistemology`" - Core type system - Proof-erasure semantics - Idris/Lean
-integration - *Venue*: Symposium on Principles of Programming Languages
-(top-tier PL)
+*Title*: "Lithoglyph: A Dependently-Typed Database for Verified Epistemology"
+
+* Core type system
+* Proof-erasure semantics
+* Idris/Lean integration
+* *Venue*: Symposium on Principles of Programming Languages (top-tier PL)
===== *Paper 2: VLDB 2027 (Databases)*
-*Title*: "`Dependent Types for Database Constraints: A Case Study in
-Journalism`" - BoFIG case study (UK Inflation 2023 dataset) - PROMPT
-score verification - Performance evaluation (type-checking overhead) -
-*Venue*: Very Large Data Bases (top-tier DB)
+*Title*: "Dependent Types for Database Constraints: A Case Study in Journalism"
+
+* BoFIG case study (UK Inflation 2023 dataset)
+* PROMPT score verification
+* Performance evaluation (type-checking overhead)
+* *Venue*: Very Large Data Bases (top-tier DB)
===== *Paper 3: ICFP 2027 (Functional Programming)*
-*Title*: "`Proof-Carrying Provenance: Dependent Types for Audit Trails`"
-- Reversibility proofs - Journal encoding with proof objects -
-Verification strategies - *Venue*: International Conference on
-Functional Programming
+*Title*: "Proof-Carrying Provenance: Dependent Types for Audit Trails"
+
+* Reversibility proofs
+* Journal encoding with proof objects
+* Verification strategies
+* *Venue*: International Conference on Functional Programming
===== *Paper 4: AAMAS 2027 (Multi-Agent Systems)*
-*Title*: "`Verified Belief Fusion: Dependent Types for Multi-Agent
-Epistemology`" - My-Newsroom integration - Type-safe Dempster-Shafer
-fusion - Byzantine resilience with proofs - *Venue*: Autonomous Agents
-and Multiagent Systems
+*Title*: "Verified Belief Fusion: Dependent Types for Multi-Agent Epistemology"
+
+* My-Newsroom integration
+* Type-safe Dempster-Shafer fusion
+* Byzantine resilience with proofs
+* *Venue*: Autonomous Agents and Multiagent Systems
+[[73-comparison-to-related-work]]
==== 7.3 Comparison to Related Work
-[width="100%",cols="21%,16%,18%,27%,18%",options="header",]
+[cols=",,,,",options="header",]
|===
|System |Types |Proofs |Provenance |Domain
-|Lithoglyph (ours) |β Dependent |β Machine-checkable |β Type-level
-|Journalism/i-docs
-
+|Lithoglyph (ours) |β Dependent |β Machine-checkable |β Type-level |Journalism/i-docs
|Datomic |Simple |β |β Time-based |General
-
|XTDB |Simple |β |β Bitemporal |General
-
|Prisma |Simple |β |β |General
-
|Liquid Haskell |β Refinement |β SMT-based |β |Programming
-
-|F* |β Dependent |β SMT + Tactics |β |Programming
-
+|F++*++ |β Dependent |β SMT {plus} Tactics |β |Programming
|Agda |β Dependent |β Interactive |β |Mathematics
|===
-*Key Insight*: Lithoglyph combines database + dependent types +
-provenance = *unique position*.
+*Key Insight*: Lithoglyph combines database {plus} dependent types {plus} provenance = *unique position*.
+[[8-evaluation]]
=== 8. Evaluation
+[[81-type-checking-performance]]
==== 8.1 Type-Checking Performance
-*Benchmark*: UK Inflation 2023 dataset (BoFIG) - 7 claims - 10 evidence
-items - 10 relationships - 3 navigation paths
+*Benchmark*: UK Inflation 2023 dataset (BoFIG)
+
+* 7 claims
+* 10 evidence items
+* 10 relationships
+* 3 navigation paths
+
+*Metrics*:
+
+* Type-checking time per operation
+* Proof generation time
+* Memory overhead
+* Journal size increase (with proofs)
-*Metrics*: - Type-checking time per operation - Proof generation time -
-Memory overhead - Journal size increase (with proofs)
+*Expected Results*:
-*Expected Results*: - Type-checking: <100ms per operation (acceptable
-for development) - Proof generation: <500ms (one-time cost) - Memory:
-+10-20% (proof objects) - Journal size: +5-10% (serialized proofs)
+* Type-checking: ++<++100ms per operation (acceptable for development)
+* Proof generation: ++<++500ms (one-time cost)
+* Memory: {plus}10-20% (proof objects)
+* Journal size: {plus}5-10% (serialized proofs)
+[[82-error-detection]]
==== 8.2 Error Detection
-*Compare*: - Runtime errors caught with traditional GQL - Type errors
-caught with dependent types
+*Compare*:
-*Hypothesis*: Dependent types catch 80%+ of errors at compile time.
+* Runtime errors caught with traditional GQL
+* Type errors caught with dependent types
-*Methodology*: - Seed dataset with 100 intentional errors: - Invalid
-PROMPT scores (20) - Missing rationale (20) - Invalid confidence levels
-(20) - Incorrect computed fields (20) - Invalid reversibility claims
-(20) - Measure: How many caught at type-check vs.Β runtime?
+*Hypothesis*: Dependent types catch 80%{plus} of errors at compile time.
+*Methodology*:
+
+* Seed dataset with 100 intentional errors:
+** Invalid PROMPT scores (20)
+** Missing rationale (20)
+** Invalid confidence levels (20)
+** Incorrect computed fields (20)
+** Invalid reversibility claims (20)
+* Measure: How many caught at type-check vs. runtime?
+
+[[83-developer-experience]]
==== 8.3 Developer Experience
-*User Study*: - 20 developers (10 Lithoglyph users, 10 control) - Task:
-Implement evidence import from Zotero - Measure: - Time to completion -
-Number of bugs - User satisfaction (Likert scale)
+*User Study*:
-*Hypothesis*: Dependent types reduce bugs by 50%, with 20% time
-overhead.
+* 20 developers (10 Lithoglyph users, 10 control)
+* Task: Implement evidence import from Zotero
+* Measure:
+** Time to completion
+** Number of bugs
+** User satisfaction (Likert scale)
+*Hypothesis*: Dependent types reduce bugs by 50%, with 20% time overhead.
+
+[[84-agent-integration]]
==== 8.4 Agent Integration
-*Experiment*: - 10-agent My-Newsroom system - Task: Verify 50 claims
-from UK Inflation investigation - Compare: - Without proofs: Agents vote
-(Byzantine voting) - With proofs: Agents verify proofs (proof-checking)
+*Experiment*:
+
+* 10-agent My-Newsroom system
+* Task: Verify 50 claims from UK Inflation investigation
+* Compare:
+** Without proofs: Agents vote (Byzantine voting)
+** With proofs: Agents verify proofs (proof-checking)
-*Metrics*: - Consensus time - Accuracy (vs.Β ground truth) - Byzantine
-resilience (% malicious agents tolerated)
+*Metrics*:
-*Hypothesis*: Proof-checking enables 50% malicious tolerance (vs.Β 33%
-with voting).
+* Consensus time
+* Accuracy (vs. ground truth)
+* Byzantine resilience (% malicious agents tolerated)
+*Hypothesis*: Proof-checking enables 50% malicious tolerance (vs. 33% with voting).
+
+[[9-challenges-and-mitigations]]
=== 9. Challenges and Mitigations
+[[91-challenge-learning-curve]]
==== 9.1 Challenge: Learning Curve
*Problem*: Dependent types are hard for most developers.
-*Mitigations*: 1. *Gradual adoption*: Start with refinement types
-(easier) 2. *IDE support*: Lean 4 LSP provides excellent autocomplete 3.
-*Proof tactics*: Automate 80% of proofs 4. *Documentation*: Extensive
-examples, tutorials 5. *Opt-in*: Can use simple types if needed
+*Mitigations*:
+
+[arabic]
+. *Gradual adoption*: Start with refinement types (easier)
+. *IDE support*: Lean 4 LSP provides excellent autocomplete
+. *Proof tactics*: Automate 80% of proofs
+. *Documentation*: Extensive examples, tutorials
+. *Opt-in*: Can use simple types if needed
+[[92-challenge-compilation-time]]
==== 9.2 Challenge: Compilation Time
*Problem*: Proof checking is slow (can be minutes for complex proofs).
-*Mitigations*: 1. *Caching*: Store proofs, donβt recheck 2. *Incremental
-checking*: Only check changed proofs 3. *Proof parallelization*: Check
-proofs in parallel 4. *Development mode*: Skip proofs during dev, check
-on commit 5. *Proof complexity budgets*: Warn if proof too complex
+*Mitigations*:
+
+[arabic]
+. *Caching*: Store proofs, don't recheck
+. *Incremental checking*: Only check changed proofs
+. *Proof parallelization*: Check proofs in parallel
+. *Development mode*: Skip proofs during dev, check on commit
+. *Proof complexity budgets*: Warn if proof too complex
+[[93-challenge-proof-obligation-failures]]
==== 9.3 Challenge: Proof Obligation Failures
*Problem*: Users write code, type checker demands proof, user stuck.
-*Mitigations*: 1. *Proof search*: Auto-generate simple proofs (e.g.,
-`+omega+` tactic) 2. *Partial proofs*: Allow `+admit+` during
-development 3. *Proof assistants*: Provide tactics for common patterns
-4. *Error messages*: Suggest fixes (e.g., "`Try reducing value from 150
-to 100`") 5. *Proof libraries*: Pre-proved theorems for common cases
+*Mitigations*:
+
+[arabic]
+. *Proof search*: Auto-generate simple proofs (e.g., `omega` tactic)
+. *Partial proofs*: Allow `admit` during development
+. *Proof assistants*: Provide tactics for common patterns
+. *Error messages*: Suggest fixes (e.g., "Try reducing value from 150 to 100")
+. *Proof libraries*: Pre-proved theorems for common cases
+[[94-challenge-runtime-performance]]
==== 9.4 Challenge: Runtime Performance
*Problem*: Proof objects increase journal size.
-*Mitigations*: 1. *Proof erasure*: Erase proofs at runtime (Idris/Lean
-support this) 2. *Optional proofs*: Only store proofs for critical
-operations 3. *Proof compression*: Serialize proofs efficiently 4.
-*Proof summaries*: Store hash instead of full proof 5. *Proof generation
-on demand*: Regenerate proofs from code if needed
+*Mitigations*:
+[arabic]
+. *Proof erasure*: Erase proofs at runtime (Idris/Lean support this)
+. *Optional proofs*: Only store proofs for critical operations
+. *Proof compression*: Serialize proofs efficiently
+. *Proof summaries*: Store hash instead of full proof
+. *Proof generation on demand*: Regenerate proofs from code if needed
+
+[[10-future-work]]
=== 10. Future Work
+[[101-full-verification-stack]]
==== 10.1 Full Verification Stack
*Goal*: End-to-end verified database.
@@ -1237,24 +1376,31 @@ on demand*: Regenerate proofs from code if needed
*Impact*: *Fully verified database* from top to bottom!
+[[102-proof-checked-journalism]]
==== 10.2 Proof-Checked Journalism
*Vision*: Journalists publish *proofs* alongside articles.
-*Example*: > *Claim*: "`UK rent inflation exceeded overall inflation by
-4.7 percentage points in 2023`" > > *Evidence*: ONS CPI data
-(provenance: 100, replicability: 100) > > *Proof*: [Download
-machine-checkable proof] > > Readers can verify the proof in Lean 4 or
-Idris 2. The claim is *mathematically guaranteed* to follow from the
-evidence.
+*Example*:
+
+____
+*Claim*: "UK rent inflation exceeded overall inflation by 4.7 percentage points in 2023"
+
+*Evidence*: ONS CPI data (provenance: 100, replicability: 100)
+
+*Proof*: ++[++Download machine-checkable proof++]++
+
+Readers can verify the proof in Lean 4 or Idris 2. The claim is *mathematically guaranteed* to follow from the evidence.
+____
*Impact*: *Verifiable journalism* - trust is provable, not asserted!
+[[103-llm-agents-with-proof-obligations]]
==== 10.3 LLM Agents with Proof Obligations
*Current*: LLM agents hallucinate, make mistakes.
-*With Dependent Types*: LLM generates code + proofs.
+*With Dependent Types*: LLM generates code {plus} proofs.
....
User: "Add evidence with PROMPT score 95/100"
@@ -1288,9 +1434,10 @@ LLM: "Sorry, 150 is out of range. Let me fix that..."
*Impact*: *Hallucination-proof LLMs* via type checking!
+[[104-proof-carrying-smart-contracts]]
==== 10.4 Proof-Carrying Smart Contracts
-*Blockchain + Dependent Types*:
+*Blockchain {plus} Dependent Types*:
[source,idris]
----
@@ -1306,31 +1453,27 @@ contract TransferFunds : Contract where
*Impact*: *Mathematically verified smart contracts* - no exploits!
+[[11-conclusion]]
=== 11. Conclusion
-Dependent types transform Lithoglyph from a database that *records*
-epistemology to one that *proves* epistemology. This enables:
+Dependent types transform Lithoglyph from a database that *records* epistemology to one that *proves* epistemology. This enables:
[arabic]
-. *Compile-time correctness*: Invalid data is a type error, caught
-immediately
-. *Provable provenance*: Canβt forge provenance (itβs in the type)
-. *Verified multi-agent systems*: Agents provide proofs, not just
-assertions
+. *Compile-time correctness*: Invalid data is a type error, caught immediately
+. *Provable provenance*: Can't forge provenance (it's in the type)
+. *Verified multi-agent systems*: Agents provide proofs, not just assertions
. *Hallucination-proof LLMs*: Type checker catches LLM mistakes
. *Verifiable journalism*: Readers can verify claims mathematically
-Our approach is incremental (refinement types β full dependent types β
-verified stack), making it practical for real-world adoption.
+Our approach is incremental (refinement types β full dependent types β verified stack), making it practical for real-world adoption.
-Lithoglyph becomes the *first dependently-typed database*, uniquely
-positioned for journalism, scientific reproducibility, and AI agent
-collaboration where *correctness is non-negotiable*.
+Lithoglyph becomes the *first dependently-typed database*, uniquely positioned for journalism, scientific reproducibility, and AI agent collaboration where *correctness is non-negotiable*.
'''''
=== Appendix A: Idris 2 Primer
+[[a1-basic-syntax]]
==== A.1 Basic Syntax
[source,idris]
@@ -1356,6 +1499,7 @@ plusZeroRightNeutral Z = Refl
plusZeroRightNeutral (S k) = cong S (plusZeroRightNeutral k)
----
+[[a2-tactics]]
==== A.2 Tactics
[source,idris]
@@ -1368,6 +1512,7 @@ example x y = ?proof
?proof = rewrite plusCommutative x y in Refl
----
+[[a3-auto-implicit-arguments]]
==== A.3 Auto-Implicit Arguments
[source,idris]
@@ -1385,6 +1530,7 @@ x = MkBounded 50 -- {prf = ...} filled in by compiler
=== Appendix B: Lean 4 Primer
+[[b1-basic-syntax]]
==== B.1 Basic Syntax
[source,lean]
@@ -1412,6 +1558,7 @@ theorem plus_zero : β n : Nat, n + 0 = n := by
| succ k ih => simp [plus]; exact ih
----
+[[b2-tactics]]
==== B.2 Tactics
[source,lean]
@@ -1422,6 +1569,7 @@ theorem example : β x y : Nat, x + y = y + x := by
rw [Nat.add_comm]
----
+[[b3-type-classes]]
==== B.3 Type Classes
[source,lean]
@@ -1454,14 +1602,14 @@ instance : Bounded Nat where
|Proof libraries |Medium |Large |Large |Very Large
|===
-*Recommendation*: *Lean 4* for best IDE support and automation. *Idris
-2* for simplicity. *Dafny* for C interop.
+*Recommendation*: *Lean 4* for best IDE support and automation. *Idris 2* for simplicity. *Dafny* for C interop.
'''''
-*Document Status*: Research proposal. Implementation timeline: 18-24
-months.
+*Document Status*: Research proposal. Implementation timeline: 18-24 months.
+
+*See Also*:
-*See Also*: - GQL Dependent Types Specification (companion document) -
-Lithoglyph arXiv paper (Section 14: Future Work) - My-Newsroom Me
-dialect specification
+* GQL Dependent Types Specification (companion document)
+* Lithoglyph arXiv paper (Section 14: Future Work)
+* My-Newsroom Me dialect specification
diff --git a/docs/executable-boundary.adoc b/docs/executable-boundary.adoc
new file mode 100644
index 0000000..1d65242
--- /dev/null
+++ b/docs/executable-boundary.adoc
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+= GNPL: executable boundary
+
+GNPL is a narration/projection language. Its public semantic objects are accounts,
+stances, warrants and rival accounts. Existing selection, type validation and
+storage code is private implementation machinery; it does not define a second
+public language or commit GNPL to a relational compilation target.
+
+The historical `GqlDt` source namespace remains a compatibility identifier.
+Renaming every import is separate from implementing the narration semantics.
+
+== What narration executes
+
+`src/Gnpl/` implements direct-evidence warrants, focalization, ordered accounts,
+a limited rival relation and hypothetical withdrawal. The `gnpl` executable
+parses a complete projection and imports a versioned evidence snapshot. It
+returns a warranted account or an explicit refusal, with no partial account on
+failure. See link:narration-slice.adoc[the surface, commands and trust boundary].
+
+`test/NarrationTest.lean` supplies 35 checks, including actual CLI invocations.
+The interpretation is independent of the private storage modules; it is not yet
+connected to a live Lithoglyph journal or Glyphbase.
+
+== What the executable substrate does
+
+`lake build` builds `substrate_test`; `lake test` runs it alongside the existing
+lexer, parser and type-safety suites. `test/SubstrateTest.lean` exercises source
+text through parsing, schema validation, IR construction, in-memory insertion
+and filtered retrieval. A second row is excluded by the predicate, so merely
+returning all stored rows cannot satisfy the positive control.
+
+Negative controls reject out-of-range evidence, empty refined strings and
+rationales, unknown tables and columns, mismatched annotations, arity errors,
+malformed optional clauses, trailing input and multiple statements. Repetition
+is executable and bounded by input consumption; a parser that consumes nothing
+is rejected. Insert typing witnesses are built by the validator against the
+caller's schema, instead of being supplied by an unconditional axiom.
+
+The private substrate's `Confidence` type preserves its distinct type tag and
+an integer admission score in `[0, 100]` through insertion, display storage and
+the typed-value JSON, CBOR and binary codecs. These bounded scores do not
+establish a probability or the truth of the supplied evidence. Empty insert
+column lists and fractional or out-of-range confidence inputs are rejected.
+
+The in-memory evaluator stores display strings. The pipeline therefore permits
+ordered predicates and sorting only for natural-number columns; string/Boolean
+predicates support equality and inequality. Other comparisons are refused until
+the evaluator can preserve their typed semantics.
+
+== Explicitly unavailable
+
+* Attached-proof checking: the corresponding mode refuses input.
+* Persistent execution through this pipeline: refuses success.
+* Complete IR wire encoding/decoding: the public pipeline refuses serialization
+ and decoding refuses reconstruction. Low-level experimental encoders remain;
+ some omit clauses and must not be used as a complete interchange protocol.
+* Checked update/delete lowering in this pipeline: refused until schema
+ validation is implemented.
+* General warrant derivations, temporal/causal event semantics, confidence
+ composition, live journal import and durable account storage remain outside
+ the implemented narration fragment.
+
+== Proof scope
+
+Dependent values establish their stated local constraints. Serialized descriptive
+proof blobs are not independently checkable certificates, and a nonempty rationale
+does not establish the truth, sufficiency or provenance of an account.
+
+The narration kernel constructs support witnesses and proves withdrawal
+exclusion and preservation of the requested claim order. Lean's transitive audit
+reports only `propext` for `narrate` and those two theorems. The default build
+checks the expected footprint in `test/NarrationProofAudit.lean`. This scope does
+not extend to the private substrate or to claims of external truth.
+
+The private parser and pipeline no longer require executable parser axioms or the
+unconditional inferred-insert typing axiom. This is not an axiom-free library:
+the validator still depends on its existing floating-point equality assumption,
+and other modules retain assumptions. A successful build or test suite is not a
+proof of the whole language. Historical total counts in older status documents
+must not be treated as a current trusted-base inventory.
diff --git a/docs/narration-slice.adoc b/docs/narration-slice.adoc
new file mode 100644
index 0000000..fff373c
--- /dev/null
+++ b/docs/narration-slice.adoc
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+= Direct-evidence narration: executable slice
+
+This slice implements accounts, focalization, direct-evidence warrants, a limited
+rival relation and hypothetical withdrawal. It runs over an imported immutable
+evidence snapshot. It is independent of the experimental storage substrate.
+
+== Run it
+
+[source,console]
+----
+lake build
+.lake/build/bin/gnpl narrate --evidence examples/narration/evidence.json --projection examples/narration/inspection.gnpl
+.lake/build/bin/gnpl narrate --evidence examples/narration/evidence.json --projection examples/narration/witness.gnpl
+.lake/build/bin/gnpl counterfactual --evidence examples/narration/evidence.json --projection examples/narration/inspection.gnpl --withdraw inspection-17
+.lake/build/bin/gnpl counterfactual --evidence examples/narration/evidence.json --projection examples/narration/inspection.gnpl --withdraw witness-22
+lake test
+----
+
+Both accounts are warranted under their explicit stance, although their bridge
+status assertions conflict. Withdrawing the inspection invalidates the inspection
+account; withdrawing the uncited witness preserves it. Neither counterfactual
+changes the evidence file. Exit 0 means warranted/preserved, 1 means refused or
+invalidated, and 2 means a usage, parsing or file-input error. JSON output includes
+the status; a refusal contains no partially constructed account.
+
+== Surface
+
+[source]
+----
+account "inspection account"
+focalized by "analyst"
+threshold 70
+assert "bridge" "status" "closed" citing "inspection-17"
+assert "site" "weather" "rain" citing "weather-3"
+----
+
+Each declaration occupies one line. Strings use JSON quoting and escapes.
+Blank lines and whole-line `--` comments are accepted. Header order is fixed;
+at least one assertion is required. Unknown declarations and trailing clauses
+are errors. An assertion assigns a value to a *single-valued subject/slot*.
+It is a structured recorded assertion, not a natural-language entailment claim.
+
+The projection declares telling order. This slice infers no temporal order,
+causality, granularity or narrative emphasis. In particular, the initial `Fabula`
+is an evidence snapshot without the planned partial-order event structure.
+
+== Warrant rule and trust boundary
+
+For each assertion, the selected evidence must be present, unwithdrawn, visible to
+the actor and an exact match for the requested subject/slot/value. Its source and
+rationale must be nonblank. Its declared confidence must be in 0β100 and meet the
+projection's threshold. Duplicate evidence identifiers, duplicate assertions and
+conflicting values within a single account are refused.
+
+Confidence here is an integer admission score declared in the input. No
+probabilistic meaning, averaging, confidence combination, entrenchment ordering or
+automatic choice between sources is implemented. The threshold is an explicit
+policy in the projection. This does not settle the broader confidence semantics.
+
+The importer trusts the snapshot's attribution, audience and scores. It does not
+authenticate the actor, verify a source signature, establish the truth of an
+assertion, or judge whether a rationale is persuasive. Focalization is evaluated
+against supplied audience data; it is not a network authorization service.
+
+`gnpl-evidence-v1` has an explicit version and required fields; unknown fields
+are refused. Output `gnpl-account-v1` contains a readable warrant trail. It is
+not a portable proof certificate: the Lean proofs are checked in the kernel,
+erased during execution and not encoded as independently checkable JSON proofs.
+
+== Types and proofs
+
+`Warrant` is indexed by the exact snapshot, focalization and assertion request.
+`Account` contains a narration indexed by the entire requested assertion list.
+It cannot silently drop an unwarranted assertion or reorder the telling.
+A warrant for an old snapshot is not a warrant for a changed snapshot.
+Historical accounts remain accounts of their original snapshots.
+
+Lean checks two general properties in `src/Gnpl/Core.lean`:
+
+* Withdrawn evidence cannot satisfy the direct-evidence support rule.
+* Every checked narration contains exactly the requested claims in their order.
+
+These properties are about the encoded rule and projection, not external truth
+or arbitrary narrative inference. Lean's transitive axiom audit reports only
+`propext` (propositional extensionality) for `narrate` and both theorems.
+`test/NarrationProofAudit.lean` checks this diagnostic during every default build.
+The kernel imports Lean/Std and does not depend on the storage substrate's
+floating-point equality assumption.
+
+The `rival` library operation detects different values for the same subject/slot
+across two checked accounts of the same snapshot. It retains both accounts. It
+does not implement general argumentation, entailment or automatic account search.
+
+== Validation and next integration
+
+`test/NarrationTest.lean` is built by `lake build` and run by `lake test`, including
+real executable invocations and their JSON/exit-code checks. It covers warranted
+accounts, inaccessible/mismatched/missing evidence, thresholds, malformed input,
+rival accounts, source withdrawal and preservation under an unrelated withdrawal.
+
+Next: a read-only Lithoglyph journal adapter supplying this snapshot contract,
+then checked derivation chains and explicit temporal/partial-order semantics.
+Durable account storage and Glyphbase rendering remain separate integration work.
diff --git a/docs/proof-debt.adoc b/docs/proof-debt.adoc
index 0c59eb5..b069953 100644
--- a/docs/proof-debt.adoc
+++ b/docs/proof-debt.adoc
@@ -1,225 +1,180 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
== Proof debt
-Per
-https://github.com/hyperpolymath/standards/blob/main/docs/TRUSTED-BASE-REDUCTION-POLICY.adoc[`+hyperpolymath/standards+`
-β Trusted-Base Reduction Policy].
+Per https://github.com/hyperpolymath/standards/blob/main/docs/TRUSTED-BASE-REDUCTION-POLICY.adoc[`hyperpolymath/standards` β Trusted-Base Reduction Policy].
-Enumerated 2026-07-21 by running the estate checker
-(`+standards/scripts/check-trusted-base.sh+`) against this repository:
-*19 soundness-relevant escape hatches detected*, of which *16 are real
-Lean `+axiom+` declarations* and 3 are detector false positives (Β§(e)).
+Enumerated 2026-07-21 by running the estate checker (`standards/scripts/check-trusted-base.sh`)
+against this repository: *19 soundness-relevant escape hatches detected*, of which
+*16 are real Lean `axiom` declarations* and 3 are detector false positives (Β§(e)).
=== Read this first
-`+lake build+` is green and Lean reports *no incomplete proofs* β no
-`+sorry+` is reached in any proof position. That is true, and it is
-*not* the same as "`the proofs are done`".
+`lake build` is green and Lean reports *no incomplete proofs* β no `sorry` is reached in
+any proof position. That is true, and it is *not* the same as "the proofs are done".
-Leanβs `+sorry+` warning does not fire on `+axiom+`. This repository
-declares 16 axioms, and *none of them is a necessary axiom* in the
-policyβs Β§(c) sense (function extensionality, classical choice, an
-extraction boundary). Every one is a *stub* β a declaration written to
-make the file compile while the implementation or proof was deferred.
-Two consequences that must not be understated:
+Lean's `sorry` warning does not fire on `axiom`. This repository declares 16 axioms, and
+*none of them is a necessary axiom* in the policy's Β§(c) sense (function extensionality,
+classical choice, an extraction boundary). Every one is a *stub* β a declaration written
+to make the file compile while the implementation or proof was deferred. Two consequences
+that must not be understated:
[arabic]
-. *Five axioms occupy executable positions.* `+parseToIR+`,
-`+deserializeIR+`, `+many+`, `+many1+` and `+sepBy+` are declared as
-`+axiom+`, so they have _no implementation at all_. Code that calls them
-typechecks and cannot run. "`34/35 targets build`" is therefore a
+. *Five axioms occupy executable positions.* `parseToIR`, `deserializeIR`, `many`,
+`many1` and `sepBy` are declared as `axiom`, so they have _no implementation at all_.
+Code that calls them typechecks and cannot run. "34/35 targets build" is therefore a
statement about typechecking, not about a working parser.
-. *`+executePreservesTypes+` proves nothing.* Its statement reduces to
-`+β¦ β True+`, with the body commented `+-- Placeholder+`. It reads like
-a type-safety soundness theorem and discharges no obligation whatsoever.
-It is the most misleading item in this list.
-
-Similarly, the worked examples in `+TypeSafeQueries.lean+` β the ones
-whose comments claim `+β Type-safe INSERT with valid score+` and
-demonstrate that an out-of-range score
-`+-- Type error: failed to prove 150 β€ 100+` β are themselves axioms.
-They assert the existence of the well-typed value rather than
-constructing it, so they demonstrate the opposite of what the
-surrounding 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.
+. *`executePreservesTypes` proves nothing.* Its statement reduces to `β¦ β True`, with
+the body commented `-- Placeholder`. It reads like a type-safety soundness theorem and
+discharges no obligation whatsoever. It is the most misleading item in this list.
+
+Similarly, the worked examples in `TypeSafeQueries.lean` β the ones whose comments claim
+`β Type-safe INSERT with valid score` and demonstrate that an out-of-range score
+`-- Type error: failed to prove 150 β€ 100` β are themselves axioms. They assert the
+existence of the well-typed value rather than constructing it, so they demonstrate the
+opposite of what the surrounding 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.
=== (a) Discharged in this repo
-* (none yet β entries are removed from Β§(d) and _not_ listed here once a
-proof lands)
+* (none yet β entries are removed from Β§(d) and _not_ listed here once a proof lands)
+[[b-budgeted--tested-with-refutation-budget]]
=== (b) Budgeted β tested with refutation budget
* (none yet β but the prerequisite is now met.)
-*Updated 2026-07-28.* This section previously read _"`this repo has no
-executable test coverage: `+lake test+` reports
-`+no test driver configured+` β¦ adding a `+@[test_driver]+` is a
-prerequisite for moving any item into this section.`"_ That prerequisite
-has been satisfied: `+lake test+` now runs three suites and *163
-checks*, and the gate is canary-tested in both directions (a seeded
-false check turns it red; removing it returns green).
-
-So items _can_ now be moved here β but none has been yet, and none
-should be moved without a *stated refutation budget*. Coverage existing
-is not the same as a given axiom being covered. The policyβs requirement
-is a citable budget ("`property-tested at N inputs by `++`,
-last green on `++``"), because without one "`covered by tests`" is
+*Updated 2026-07-28.* This section previously read _"this repo has no executable test
+coverage: `lake test` reports `no test driver configured` β¦ adding a `@++[++test++_++driver++]++` is a
+prerequisite for moving any item into this section."_ That prerequisite has been satisfied:
+`lake test` now runs three suites and *163 checks*, and the gate is canary-tested in both
+directions (a seeded false check turns it red; removing it returns green).
+
+So items _can_ now be moved here β but none has been yet, and none should be moved without
+a *stated refutation budget*. Coverage existing is not the same as a given axiom being
+covered. The policy's requirement is a citable budget ("property-tested at N inputs by
+`++<++command++>++`, last green on `++<++date++>++`"), because without one "covered by tests" is
unfalsifiable β which is the whole reason this section exists.
-The nearest candidate is *D4* (`+inferredInsertTypesMatch+`); see its
-entry.
+The nearest candidate is *D4* (`inferredInsertTypesMatch`); see its entry.
=== (c) Necessary axiom
* (none. No axiom in this repository is load-bearing in the Β§(c) sense.)
+[[d-debt--actively-to-be-closed]]
=== (d) DEBT β actively to be closed
-*Owner:* @hyperpolymath Β· *Deadline:* INDEFINITE β sequenced behind the
-GNPL narration layer (see `+docs/THEORY.adoc+`), except D1 which is
-called out as urgent below.
+*Owner:* @hyperpolymath Β· *Deadline:* INDEFINITE β sequenced behind the GNPL narration
+layer (see `docs/THEORY.adoc`), except D1 which is called out as urgent below.
+[[d1--fake-soundness-theorem-close-first]]
==== D1 β Fake soundness theorem (close first)
-* `+src/GqlDt/TypeSafe.lean:194+` β `+axiom executePreservesTypes+`
-** *Kind*: asserted soundness theorem whose statement is vacuous
-(`+β¦ β True+`).
-** *Why urgent*: it is the only item here that actively misinforms. A
-reader encountering `+executePreservesTypes+` reasonably concludes
-execution is proved type-preserving. Nothing of the sort has been
-established.
-** *Plan*: either state and prove the real property (execution preserves
-the schema typing of `+stmt.values+`), or *delete the axiom* and record
-the obligation as an open goal. Deleting is strictly better than keeping
-a vacuous placeholder.
-** *Blocked on*: the `+satisfiesConstraints+` signature issue noted in
-the source comment.
-
+* `src/GqlDt/TypeSafe.lean:194` β `axiom executePreservesTypes`
+** *Kind*: asserted soundness theorem whose statement is vacuous (`β¦ β True`).
+** *Why urgent*: it is the only item here that actively misinforms. A reader
+encountering `executePreservesTypes` reasonably concludes execution is proved
+type-preserving. Nothing of the sort has been established.
+** *Plan*: either state and prove the real property (execution preserves the schema
+typing of `stmt.values`), or *delete the axiom* and record the obligation as an
+open goal. Deleting is strictly better than keeping a vacuous placeholder.
+** *Blocked on*: the `satisfiesConstraints` signature issue noted in the source comment.
+
+[[d2--unimplemented-parser-combinators-and-entry-points]]
==== D2 β Unimplemented parser combinators and entry points
-Declared `+axiom+`, therefore *unimplemented*, not merely unproven:
+Declared `axiom`, therefore *unimplemented*, not merely unproven:
-[width="100%",cols="34%,33%,33%",options="header",]
+[cols=",,",options="header",]
|===
|Location |Axiom |Note
-|`+src/GqlDt/Parser.lean:130+` |`+many+` |commented-out `+partial def+`
-below it; `+-- TODO: Fix infinite loop in type checker+`
-
-|`+src/GqlDt/Parser.lean:141+` |`+many1+` |as above
-
-|`+src/GqlDt/Parser.lean:149+` |`+sepBy+` |as above
-
-|`+src/GqlDt/Parser.lean:347+` |`+parseSelectList+` |
-
-|`+src/GqlDt/Parser.lean:417+` |`+parseSelect+` |
-
-|`+src/GqlDt/Parser.lean:504+` |`+parseStatement+` |
-
-|`+src/GqlDt/Parser.lean:549+` |`+parseToIR+` |pipeline entry point;
-DELETEβIR conversion commented out as not implemented
-
-|`+src/GqlDt/IR.lean:348+` |`+deserializeIR+`
-|`+-- TODO: Implement full CBOR deserialization with schema reconstruction+`
+|`src/GqlDt/Parser.lean:130` |`many` |commented-out `partial def` below it; `-- TODO: Fix infinite loop in type checker`
+|`src/GqlDt/Parser.lean:141` |`many1` |as above
+|`src/GqlDt/Parser.lean:149` |`sepBy` |as above
+|`src/GqlDt/Parser.lean:347` |`parseSelectList` |
+|`src/GqlDt/Parser.lean:417` |`parseSelect` |
+|`src/GqlDt/Parser.lean:504` |`parseStatement` |
+|`src/GqlDt/Parser.lean:549` |`parseToIR` |pipeline entry point; DELETEβIR conversion commented out as not implemented
+|`src/GqlDt/IR.lean:348` |`deserializeIR` |`-- TODO: Implement full CBOR deserialization with schema reconstruction`
|===
-* *Plan*: implement as `+partial def+` (or with an explicit termination
-measure / fuel parameter, which is the standard Lean 4 remedy for the
-combinator non-termination the source comment describes).
-`+many+`/`+many1+`/`+sepBy+` are the root β the four `+parse*+` axioms
-above them exist because these three do.
-* *Consequence while open*: the M6 "`parser substantially complete`"
-status in `+README.md+` overstates what is executable. Corrected in
-`+README.adoc+`.
+* *Plan*: implement as `partial def` (or with an explicit termination measure /
+fuel parameter, which is the standard Lean 4 remedy for the combinator
+non-termination the source comment describes). `many`/`many1`/`sepBy` are the
+root β the four `parse++*++` axioms above them exist because these three do.
+* *Consequence while open*: the M6 "parser substantially complete" status in
+`README.adoc` overstates what is executable. Corrected in `README.adoc`.
+[[d3--examplefixture-values-asserted-rather-than-constructed]]
==== D3 β Example/fixture values asserted rather than constructed
-[width="100%",cols="50%,50%",options="header",]
+[cols=",",options="header",]
|===
|Location |Axiom
-|`+src/GqlDt/Parser.lean:268+` |`+evidenceSchema+` β
-`+/-- Dummy schema for type inference -/+`
-
-|`+src/GqlDt/IR.lean:721+` |`+exampleInsertIR+` β "`Simplified to use
-axioms to avoid complex PromptScores proof obligations`"
-
-|`+src/GqlDt/TypeSafeQueries.lean:44+` |`+insertWithValidScore+`
-
-|`+src/GqlDt/TypeSafeQueries.lean:73+` |`+validPromptScores+`
-
-|`+src/GqlDt/TypeSafeQueries.lean:99+` |`+insertWithProvenance+`
-
-|`+src/GqlDt/TypeSafeQueries.lean:119+` |`+selectHighQuality+`
+|`src/GqlDt/Parser.lean:268` |`evidenceSchema` β `/-- Dummy schema for type inference -/`
+|`src/GqlDt/IR.lean:721` |`exampleInsertIR` β "Simplified to use axioms to avoid complex Prompores proof obligations"
+|`src/GqlDt/TypeSafeQueries.lean:44` |`insertWithValidScore`
+|`src/GqlDt/TypeSafeQueries.lean:73` |`validPrompores`
+|`src/GqlDt/TypeSafeQueries.lean:99` |`insertWithProvenance`
+|`src/GqlDt/TypeSafeQueries.lean:119` |`selectHighQuality`
|===
-* *Plan*: construct each concretely, discharging the
-`+BoundedNat 0 100+` / `+NonEmptyString+` / `+Confidence+` obligations
-with `+by decide+` or `+by norm_num+`. These are the _demonstrations_ of
-the repoβs central claim ("`invalid insert wonβt compile`"), so leaving
-them asserted defeats their purpose. Lowest difficulty, highest
-credibility-per-unit-effort of the three groups β *do these first after
-D1*.
+* *Plan*: construct each concretely, discharging the `BoundedNat 0 100` /
+`NonEmptyString` / `Confidence` obligations with `by decide` or `by norm++_++num`. These
+are the _demonstrations_ of the repo's central claim ("invalid insert won't compile"),
+so leaving them asserted defeats their purpose. Lowest difficulty, highest
+credibility-per-unit-effort of the three groups β *do these first after D1*.
+[[d4--dynamic-to-static-reflection-gap]]
==== D4 β Dynamic-to-static reflection gap
-* `+src/GqlDt/Pipeline.lean:147+` β `+axiom inferredInsertTypesMatch+`
-** *Kind*: the one item with a _reasoned_ justification in-source β the
-dynamic schema lookup in `+inferInsert+` already performs the check, and
-reconstructing that proof structurally would require reflecting the
-schema into the type system.
-** *Assessment*: plausible, and closest of the 16 to a genuine Β§(b)/Β§(c)
-entry. Not Β§(c), because it _is_ derivable in principle. Not yet Β§(b)
-either β but the reason has changed as of 2026-07-28: a test suite now
-exists (163 checks), so the blocker is no longer "`no coverage at all`",
-it is that *this specific path is not property-tested* and has no
-citable refutation budget.
-** *Plan*: property-test `+inferInsert+` over generated schema/value
-pairs, then promote to Β§(b) quoting the command and the input count; or
-discharge via schema reflection (the sourceβs own "`future work`"). The
-first is now genuinely reachable.
-
+* `src/GqlDt/Pipeline.lean:147` β `axiom inferredInsertTypesMatch`
+** *Kind*: the one item with a _reasoned_ justification in-source β the dynamic schema
+lookup in `inferInsert` already performs the check, and reconstructing that proof
+structurally would require reflecting the schema into the type system.
+** *Assessment*: plausible, and closest of the 16 to a genuine Β§(b)/Β§(c) entry. Not
+Β§(c), because it _is_ derivable in principle. Not yet Β§(b) either β but the reason has
+changed as of 2026-07-28: a test suite now exists (163 checks), so the blocker is no
+longer "no coverage at all", it is that *this specific path is not property-tested*
+and has no citable refutation budget.
+** *Plan*: property-test `inferInsert` over generated schema/value pairs, then promote
+to Β§(b) quoting the command and the input count; or discharge via schema reflection
+(the source's own "future work"). The first is now genuinely reachable.
+
+[[e-detector-false-positives--no-action]]
=== (e) Detector false positives β no action
-The estate checker matches `+\bsorry\b+` textually in `+.lean+` files.
-Three hits are not escape hatches, and are listed here so the count
-reconciles (19 = 16 + 3):
+The estate checker matches `++\++bsorry++\++b` textually in `.lean` files. Three hits are not
+escape hatches, and are listed here so the count reconciles (19 = 16 {plus} 3):
-[width="100%",cols="50%,50%",options="header",]
+[cols=",",options="header",]
|===
|Location |What it actually is
-|`+src/GqlDt/TypeInference.lean:179+` |`+\| .admit => "sorry"+` β a
-*string literal* returned by a pretty-printer
-
-|`+src/GqlDt/Lexer.lean:230+` |`+("sorry", .kwSorry)+` β a *keyword
-table entry*; GQL-dt has a `+sorry+` token
-
-|`+test/LexerTest.lean:147+`
-|`+runTest "sorry" (firstType "sorry" == some .kwSorry)+` β a *test
-input*
+|`src/GqlDt/TypeInference.lean:179` |`{vbar} .admit =++>++ "sorry"` β a *string literal* returned by a pretty-printer
+|`src/GqlDt/Lexer.lean:230` |`("sorry", .kwSorry)` β a *keyword table entry*; GQL-dt has a `sorry` token
+|`test/LexerTest.lean:147` |`runTest "sorry" (firstType "sorry" == some .kwSorry)` β a *test input*
|===
-A fourth textual hit, `+src/GqlDt/TypeSafeQueries.lean:90+`
-(`+-- overall_correct := by sorry }+`), is inside a comment and is
-already excluded by the checkerβs own comment filter.
+A fourth textual hit, `src/GqlDt/TypeSafeQueries.lean:90`
+(`-- overall++_++correct := by sorry }`), is inside a comment and is already excluded by
+the checker's own comment filter.
-`+scripts/check-lean-proofs.sh+` in this repo excludes all four by
-design. See its header.
+`scripts/check-lean-proofs.sh` in this repo excludes all four by design. See its header.
-=== Reconciliation with `+scripts/check-lean-proofs.sh+`
+[[reconciliation-with-scriptscheck-lean-proofssh]]
+=== Reconciliation with `scripts/check-lean-proofs.sh`
The two checks answer different questions and both are needed:
-[width="100%",cols="34%,33%,33%",options="header",]
+[cols=",,",options="header",]
|===
|Check |Question |Current answer
-|`+scripts/check-lean-proofs.sh --build-log+` |Does Lean report any
-incomplete proof (`+sorry+`/`+sorryAx+`)? |*No* β
-
-|`+standards/scripts/check-trusted-base.sh+` |How large is the unproven
-trusted base (`+axiom+`)? |*16 axioms, all stubs* β
+|`scripts/check-lean-proofs.sh --build-log` |Does Lean report any incomplete proof (`sorry`/`sorryAx`)? |*No* β
+|`standards/scripts/check-trusted-base.sh` |How large is the unproven trusted base (`axiom`)? |*16 axioms, all stubs* β
|===
-A green proof gate here means "`nothing is admitted mid-proof`". It does
-*not* mean "`nothing is assumed`". This document is the record of what
-is assumed.
+A green proof gate here means "nothing is admitted mid-proof". It does *not* mean
+"nothing is assumed". This document is the record of what is assumed.
diff --git a/examples/narration/evidence.json b/examples/narration/evidence.json
new file mode 100644
index 0000000..0c835e3
--- /dev/null
+++ b/examples/narration/evidence.json
@@ -0,0 +1,34 @@
+{
+ "format": "gnpl-evidence-v1",
+ "snapshot": "bridge-case",
+ "revision": 7,
+ "evidence": [
+ {
+ "id": "inspection-17",
+ "source": "inspector",
+ "claim": {"subject": "bridge", "slot": "status", "value": "closed"},
+ "rationale": "Recorded inspection reports a closure barrier.",
+ "confidence": 90,
+ "audience": ["analyst", "inspector"],
+ "withdrawn": false
+ },
+ {
+ "id": "witness-22",
+ "source": "witness",
+ "claim": {"subject": "bridge", "slot": "status", "value": "open"},
+ "rationale": "The witness reports crossing the bridge.",
+ "confidence": 80,
+ "audience": ["analyst", "witness"],
+ "withdrawn": false
+ },
+ {
+ "id": "weather-3",
+ "source": "weather-log",
+ "claim": {"subject": "site", "slot": "weather", "value": "rain"},
+ "rationale": "The site log records rain.",
+ "confidence": 95,
+ "audience": ["analyst"],
+ "withdrawn": false
+ }
+ ]
+}
diff --git a/examples/narration/inaccessible.gnpl b/examples/narration/inaccessible.gnpl
new file mode 100644
index 0000000..ba98d79
--- /dev/null
+++ b/examples/narration/inaccessible.gnpl
@@ -0,0 +1,6 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+account "public account"
+focalized by "public"
+threshold 70
+assert "bridge" "status" "closed" citing "inspection-17"
diff --git a/examples/narration/inspection.gnpl b/examples/narration/inspection.gnpl
new file mode 100644
index 0000000..b01888a
--- /dev/null
+++ b/examples/narration/inspection.gnpl
@@ -0,0 +1,8 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+-- Declared telling order; it does not assert a temporal ordering of events.
+account "inspection account"
+focalized by "analyst"
+threshold 70
+assert "bridge" "status" "closed" citing "inspection-17"
+assert "site" "weather" "rain" citing "weather-3"
diff --git a/examples/narration/witness.gnpl b/examples/narration/witness.gnpl
new file mode 100644
index 0000000..49f373b
--- /dev/null
+++ b/examples/narration/witness.gnpl
@@ -0,0 +1,6 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+account "witness account"
+focalized by "analyst"
+threshold 70
+assert "bridge" "status" "open" citing "witness-22"
diff --git a/lakefile.lean b/lakefile.lean
index bd649dd..6a40b7b 100644
--- a/lakefile.lean
+++ b/lakefile.lean
@@ -22,6 +22,27 @@ lean_lib GqlDt where
srcDir := "src"
roots := #[`GqlDt]
+-- Public narration kernel, independent of the experimental storage substrate.
+@[default_target]
+lean_lib Gnpl where
+ srcDir := "src"
+ roots := #[`Gnpl]
+
+@[default_target]
+lean_exe gnpl where
+ srcDir := "src"
+ root := `GnplMain
+
+@[default_target]
+lean_exe narration_test where
+ srcDir := "test"
+ root := `NarrationTest
+
+@[default_target]
+lean_lib NarrationProofAudit where
+ srcDir := "test"
+ roots := #[`NarrationProofAudit]
+
-- Shared test support (failure counter + exit-code summary).
-- Declared as a library so the individual test executables can `import TestHarness`;
-- a bare file under a target's srcDir is not otherwise resolvable as a module.
@@ -65,6 +86,12 @@ lean_exe type_safety_test where
srcDir := "test"
root := `TypeSafetyTests
+-- Exercises the executable private substrate, including rejection paths.
+@[default_target]
+lean_exe substrate_test where
+ srcDir := "test"
+ root := `SubstrateTest
+
-- Test driver: `lake test`.
--
-- Without this, `lake test` reported "no test driver configured" and exited non-zero,
@@ -77,7 +104,7 @@ lean_exe type_safety_test where
-- fail on a clean checkout for a reason unrelated to Lean.
@[test_driver]
script test do
- let suites := #["lexer_test", "parser_test", "type_safety_test"]
+ let suites := #["lexer_test", "parser_test", "type_safety_test", "substrate_test", "narration_test"]
let mut failed : Array String := #[]
for suite in suites do
let bin := System.mkFilePath [".lake", "build", "bin", suite]
diff --git a/spec/GQL-DT-Lexical.adoc b/spec/GQL-DT-Lexical.adoc
index c47096c..5bb99be 100644
--- a/spec/GQL-DT-Lexical.adoc
+++ b/spec/GQL-DT-Lexical.adoc
@@ -1,55 +1,64 @@
== GQL-DT Lexical Specification
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Version:* 1.0.0 *Date:* 2026-02-01
+*Version:* 1.0.0
+*Date:* 2026-02-01
=== Table of Contents
[arabic]
-. link:#character-set[Character Set]
-. link:#lexical-elements[Lexical Elements]
-. link:#keywords[Keywords]
-. link:#identifiers[Identifiers]
-. link:#literals[Literals]
-. link:#operators[Operators]
-. link:#punctuation[Punctuation]
-. link:#comments[Comments]
-. link:#whitespace[Whitespace]
-. link:#operator-precedence[Operator Precedence]
+. link:#1-character-set[Character Set]
+. link:#2-lexical-elements[Lexical Elements]
+. link:#3-keywords[Keywords]
+. link:#4-identifiers[Identifiers]
+. link:#5-literals[Literals]
+. link:#6-operators[Operators]
+. link:#7-punctuation[Punctuation]
+. link:#8-comments[Comments]
+. link:#9-whitespace[Whitespace]
+. link:#10-operator-precedence[Operator Precedence]
'''''
+[[1-character-set]]
=== 1. Character Set
GQL-DT source files are encoded in *UTF-8*.
-*Character Classes:* - *ASCII:* U+0000 to U+007F - *Unicode:* Full
-Unicode 15.0 support (U+0000 to U+10FFFF) - *Line terminators:* LF
-(U+000A), CR (U+000D), CRLF (U+000D U+000A)
+*Character Classes:*
+
+* *ASCII:* U{plus}0000 to U{plus}007F
+* *Unicode:* Full Unicode 15.0 support (U{plus}0000 to U{plus}10FFFF)
+* *Line terminators:* LF (U{plus}000A), CR (U{plus}000D), CRLF (U{plus}000D U{plus}000A)
'''''
+[[2-lexical-elements]]
=== 2. Lexical Elements
-GQL-DT source text is a sequence of *tokens* separated by *whitespace*
-and *comments*.
+GQL-DT source text is a sequence of *tokens* separated by *whitespace* and *comments*.
+
+*Token Types:*
-*Token Types:* 1. *Keywords* - Reserved words 2. *Identifiers* - Names
-(variables, tables, columns) 3. *Literals* - Constants (numbers,
-strings, booleans) 4. *Operators* - Symbols for operations 5.
-*Punctuation* - Delimiters and separators 6. *Comments* - Ignored by
-lexer
+[arabic]
+. *Keywords* - Reserved words
+. *Identifiers* - Names (variables, tables, columns)
+. *Literals* - Constants (numbers, strings, booleans)
+. *Operators* - Symbols for operations
+. *Punctuation* - Delimiters and separators
+. *Comments* - Ignored by lexer
'''''
+[[3-keywords]]
=== 3. Keywords
+[[31-sql-style-keywords]]
==== 3.1 SQL-Style Keywords
-Keywords are *case-insensitive* (accepted in any case, but
-conventionally UPPERCASE).
+Keywords are *case-insensitive* (accepted in any case, but conventionally UPPERCASE).
....
AND, APPLY, AS, ASC, AUDIENCE, BECAUSE, BETWEEN, BY
@@ -73,6 +82,7 @@ VALUES, VERIFY_PROOFS
WHERE, WITH, WITH_INVERSE, WITH_JUSTIFICATION, WITH_PROOF
....
+[[32-type-keywords]]
==== 3.2 Type Keywords
Type keywords are *case-sensitive* (must match exactly as shown).
@@ -94,7 +104,7 @@ Confidence, PromptDimension, Percentage, Rationale, ActorId
*Dependent Types:*
....
-Vector, Tracked, PromptScores, NavigationPath, Claim, Belief
+Vector, Tracked, Prompores, NavigationPath, Claim, Belief
Collection, Edge, ReversibleOp
....
@@ -104,18 +114,21 @@ Collection, Edge, ReversibleOp
Option, Either
....
+[[33-normal-form-keywords]]
==== 3.3 Normal Form Keywords
....
1NF, 2NF, 3NF, BCNF, 4NF, 5NF
....
+[[34-strategy-keywords]]
==== 3.4 Strategy Keywords
....
PreferPreserving, to3NF, toBCNF, toBCNFPreferPreserving
....
+[[35-proof-tactic-keywords]]
==== 3.5 Proof Tactic Keywords
....
@@ -126,8 +139,10 @@ fd_tactic, nf_tactic, lossless_tactic
'''''
+[[4-identifiers]]
=== 4. Identifiers
+[[41-syntax]]
==== 4.1 Syntax
*ASCII Identifiers:*
@@ -140,17 +155,16 @@ fd_tactic, nf_tactic, lossless_tactic
*Examples:*
....
-user_id, evidence, PromptScore, _internal, table123
+user_id, evidence, Prompore, _internal, table123
....
+[[42-unicode-identifiers]]
==== 4.2 Unicode Identifiers
-GQL-DT supports *Unicode identifiers* following Unicode Standard Annex
-#31:
+GQL-DT supports *Unicode identifiers* following Unicode Standard Annex ++#++31:
-* *First character:* `+XID_Start+` category (letters, ideographs, etc.)
-* *Subsequent characters:* `+XID_Continue+` category (letters, digits,
-underscore, etc.)
+* *First character:* `XID++_++Start` category (letters, ideographs, etc.)
+* *Subsequent characters:* `XID++_++Continue` category (letters, digits, underscore, etc.)
*Examples:*
@@ -158,26 +172,28 @@ underscore, etc.)
cafΓ©, η¨ζ·, donnΓ©es, Ξ£, Ξ±, Ξ»_expr
....
+[[43-reserved-identifiers]]
==== 4.3 Reserved Identifiers
-The following identifiers are *reserved* and cannot be used as user
-identifiers:
+The following identifiers are *reserved* and cannot be used as user identifiers:
* All keywords (see section 3)
-* Built-in function names: `+NOW+`, `+INTERVAL+`
-* Special identifiers: `+$GENERATED_ID+`
+* Built-in function names: `NOW`, `INTERVAL`
+* Special identifiers: `$GENERATED++_++ID`
+[[44-case-sensitivity]]
==== 4.4 Case Sensitivity
-* *SQL keywords:* Case-insensitive (`+SELECT+` = `+select+` =
-`+SeLeCt+`)
-* *Type keywords:* Case-sensitive (`+BoundedNat+` β `+boundednat+`)
-* *User identifiers:* Case-sensitive (`+userId+` β `+UserId+`)
+* *SQL keywords:* Case-insensitive (`SELECT` = `select` = `SeLeCt`)
+* *Type keywords:* Case-sensitive (`BoundedNat` β `boundednat`)
+* *User identifiers:* Case-sensitive (`userId` β `UserId`)
'''''
+[[5-literals]]
=== 5. Literals
+[[51-natural-number-literals]]
==== 5.1 Natural Number Literals
*Syntax:*
@@ -193,8 +209,9 @@ identifiers:
0, 42, 100, 9999
....
-*Type:* `+Nat+`
+*Type:* `Nat`
+[[52-integer-literals]]
==== 5.2 Integer Literals
*Syntax:*
@@ -210,8 +227,9 @@ identifiers:
-42, 0, 42, -9999
....
-*Type:* `+Int+`
+*Type:* `Int`
+[[53-float-literals]]
==== 5.3 Float Literals
*Syntax:*
@@ -227,8 +245,9 @@ identifiers:
0.0, 3.14, -2.718, 1.23e10, 6.022e-23
....
-*Type:* `+Float+`
+*Type:* `Float`
+[[54-string-literals]]
==== 5.4 String Literals
*Single-quoted:*
@@ -245,31 +264,40 @@ identifiers:
"She said \"hi\"" -- Escaped quote
....
-*Escape Sequences:* - `+\\+` - Backslash - `+\'+` - Single quote -
-`+\"+` - Double quote - `+\n+` - Newline - `+\r+` - Carriage return -
-`+\t+` - Tab - `+\uXXXX+` - Unicode code point (4 hex digits) -
-`+\UXXXXXXXX+` - Unicode code point (8 hex digits)
+*Escape Sequences:*
-*Type:* `+String+`
+* `++\\++` - Backslash
+* `++\++'` - Single quote
+* `++\++"` - Double quote
+* `++\++n` - Newline
+* `++\++r` - Carriage return
+* `++\++t` - Tab
+* `++\++uXXXX` - Unicode code point (4 hex digits)
+* `++\++UXXXXXXXX` - Unicode code point (8 hex digits)
+*Type:* `String`
+
+[[55-boolean-literals]]
==== 5.5 Boolean Literals
....
true, false
....
-*Type:* `+Bool+`
+*Type:* `Bool`
-*Note:* Case-insensitive (`+TRUE+` = `+true+`)
+*Note:* Case-insensitive (`TRUE` = `true`)
+[[56-unit-literal]]
==== 5.6 Unit Literal
....
()
....
-*Type:* `+Unit+`
+*Type:* `Unit`
+[[57-timestamp-literals]]
==== 5.7 Timestamp Literals
*Syntax:* ISO 8601 format as string literal
@@ -279,143 +307,157 @@ true, false
'2026-02-01T12:34:56.123+00:00'
....
-*Type:* `+Timestamp+`
+*Type:* `Timestamp`
'''''
+[[6-operators]]
=== 6. Operators
+[[61-arithmetic-operators]]
==== 6.1 Arithmetic Operators
[cols=",,,",options="header",]
|===
|Operator |Name |Precedence |Associativity
-|`+^+` |Exponentiation |9 |Right
-|`+*+` |Multiplication |8 |Left
-|`+/+` |Division |8 |Left
-|`+div+` |Integer division |8 |Left
-|`+mod+` |Modulo |8 |Left
-|`+++` |Addition |7 |Left
-|`+-+` |Subtraction (binary) |7 |Left
-|`+-+` |Negation (unary) |10 |Right
+|`^` |Exponentiation |9 |Right
+|`++*++` |Multiplication |8 |Left
+|`/` |Division |8 |Left
+|`div` |Integer division |8 |Left
+|`mod` |Modulo |8 |Left
+|`{plus}` |Addition |7 |Left
+|`-` |Subtraction (binary) |7 |Left
+|`-` |Negation (unary) |10 |Right
|===
+[[62-comparison-operators]]
==== 6.2 Comparison Operators
[cols=",,,",options="header",]
|===
|Operator |Name |Precedence |Associativity
-|`+=+` |Equality |5 |Non-assoc
-|`+<>+` |Inequality (SQL) |5 |Non-assoc
-|`+!=+` |Inequality |5 |Non-assoc
-|`+<+` |Less than |5 |Non-assoc
-|`+>+` |Greater than |5 |Non-assoc
-|`+<=+` |Less or equal |5 |Non-assoc
-|`+>=+` |Greater or equal |5 |Non-assoc
+|`=` |Equality |5 |Non-assoc
+|`++<>++` |Inequality (SQL) |5 |Non-assoc
+|`!=` |Inequality |5 |Non-assoc
+|`++<++` |Less than |5 |Non-assoc
+|`++>++` |Greater than |5 |Non-assoc
+|`++<++=` |Less or equal |5 |Non-assoc
+|`++>++=` |Greater or equal |5 |Non-assoc
|===
+[[63-set-operators]]
==== 6.3 Set Operators
[cols=",,,",options="header",]
|===
|Operator |Name |Precedence |Associativity
-|`+β+` |Element of |5 |Non-assoc
-|`+β+` |Not element of |5 |Non-assoc
-|`+β+` |Subset |5 |Non-assoc
-|`+β+` |Superset |5 |Non-assoc
+|`β` |Element of |5 |Non-assoc
+|`β` |Not element of |5 |Non-assoc
+|`β` |Subset |5 |Non-assoc
+|`β` |Superset |5 |Non-assoc
|===
+[[64-logical-operators]]
==== 6.4 Logical Operators
[cols=",,,,",options="header",]
|===
|Operator |ASCII Alt |Name |Precedence |Associativity
-|`+Β¬+` |`+NOT+` |Negation |4 |Right
-|`+β§+` |`+AND+`, `+&&+` |Conjunction |3 |Left
-|`+β¨+` |`+OR+`, `+\|\|+` |Disjunction |2 |Left
-|`+β+` |`+=>+` |Implication |1 |Right
-|`+β+` |`+==>+` |Implication |1 |Right
-|`+β+` |`+<=>+` |Biconditional |1 |Right
-|`+β+` |`+<==>+` |Biconditional |1 |Right
+|`Β¬` |`NOT` |Negation |4 |Right
+|`β§` |`AND`, `&&` |Conjunction |3 |Left
+|`β¨` |`OR`, `{vbar}{vbar}` |Disjunction |2 |Left
+|`β` |`=++>++` |Implication |1 |Right
+|`β` |`==++>++` |Implication |1 |Right
+|`β` |`++<++=++>++` |Biconditional |1 |Right
+|`β` |`++<++==++>++` |Biconditional |1 |Right
|===
+[[65-type-operators]]
==== 6.5 Type Operators
[cols=",,,",options="header",]
|===
|Operator |Name |Precedence |Associativity
-|`+->+` |Function type |1 |Right
-|`+Γ+` |Product type |6 |Left
-|`+β+` |Sum type |6 |Left
+|`-++>++` |Function type |1 |Right
+|`Γ` |Product type |6 |Left
+|`β` |Sum type |6 |Left
|===
+[[66-special-operators]]
==== 6.6 Special Operators
[cols=",,,",options="header",]
|===
|Operator |Name |Precedence |Associativity
-|`+.+` |Field access |11 |Left
-|`+::+` |Cons (list prepend) |6 |Right
-|`+,+` |Comma (tuple/list sep) |0 |Left
-|`+:+` |Type annotation |N/A |N/A
-|`+\|+` |Type refinement |N/A |N/A
+|`.` |Field access |11 |Left
+|`::` |Cons (list prepend) |6 |Right
+|`,` |Comma (tuple/list sep) |0 |Left
+|`:` |Type annotation |N/A |N/A
+|`{vbar}` |Type refinement |N/A |N/A
|===
+[[67-lambda-operators]]
==== 6.7 Lambda Operators
[cols=",,",options="header",]
|===
|Operator |ASCII Alt |Name
-|`+Ξ»+` |`+\+` |Lambda abstraction
+|`Ξ»` |`++\++` |Lambda abstraction
|===
'''''
+[[7-punctuation]]
=== 7. Punctuation
+[[71-delimiters]]
==== 7.1 Delimiters
[cols=",",options="header",]
|===
|Symbol |Name
-|`+(+` |Left parenthesis
-|`+)+` |Right parenthesis
-|`+[+` |Left bracket
-|`+]+` |Right bracket
-|`+{+` |Left brace
-|`+}+` |Right brace
-|`+β¨+` |Left angle (Lean proof)
-|`+β©+` |Right angle (Lean proof)
+|`(` |Left parenthesis
+|`)` |Right parenthesis
+|`++[++` |Left bracket
+|`++]++` |Right bracket
+|`++{++` |Left brace
+|`}` |Right brace
+|`β¨` |Left angle (Lean proof)
+|`β©` |Right angle (Lean proof)
|===
+[[72-separators]]
==== 7.2 Separators
[cols=",",options="header",]
|===
|Symbol |Name
-|`+,+` |Comma
-|`+;+` |Semicolon
-|`+.+` |Period/dot
-|`+:+` |Colon
-|`+\|+` |Pipe/bar
+|`,` |Comma
+|`;` |Semicolon
+|`.` |Period/dot
+|`:` |Colon
+|`{vbar}` |Pipe/bar
|===
+[[73-special]]
==== 7.3 Special
[cols=",",options="header",]
|===
|Symbol |Name
-|`+--+` |Line comment start
-|`+/*+` |Block comment start
-|`+*/+` |Block comment end
-|`+{-+` |Haskell-style comment start
-|`+-}+` |Haskell-style comment end
+|`--` |Line comment start
+|`/++*++` |Block comment start
+|`++*++/` |Block comment end
+|`++{++-` |Haskell-style comment start
+|`-}` |Haskell-style comment end
|===
'''''
+[[8-comments]]
=== 8. Comments
+[[81-line-comments]]
==== 8.1 Line Comments
*Syntax:*
@@ -424,7 +466,7 @@ true, false
-- This is a line comment
....
-* Start with `+--+`
+* Start with `--`
* Extend to end of line
* Can appear anywhere whitespace is allowed
@@ -436,6 +478,7 @@ SELECT * FROM evidence -- Get all evidence
WHERE prompt_overall > 90 -- High quality only
----
+[[82-block-comments]]
==== 8.2 Block Comments
*Syntax (C-style):*
@@ -464,8 +507,10 @@ WHERE prompt_overall > 90 -- High quality only
'''''
+[[9-whitespace]]
=== 9. Whitespace
+[[91-whitespace-characters]]
==== 9.1 Whitespace Characters
GQL-DT treats the following as *whitespace*:
@@ -473,14 +518,15 @@ GQL-DT treats the following as *whitespace*:
[cols=",,",options="header",]
|===
|Character |Unicode |Name
-|Space |U+0020 |SPACE
-|Tab |U+0009 |CHARACTER TABULATION
-|LF |U+000A |LINE FEED
-|CR |U+000D |CARRIAGE RETURN
-|VT |U+000B |LINE TABULATION
-|FF |U+000C |FORM FEED
+|Space |U{plus}0020 |SPACE
+|Tab |U{plus}0009 |CHARACTER TABULATION
+|LF |U{plus}000A |LINE FEED
+|CR |U{plus}000D |CARRIAGE RETURN
+|VT |U{plus}000B |LINE TABULATION
+|FF |U{plus}000C |FORM FEED
|===
+[[92-significance]]
==== 9.2 Significance
* *Required:* Between adjacent keywords/identifiers
@@ -501,13 +547,18 @@ SELECT*FROMevidence
SELECT * FROM evidence
----
+[[93-line-terminators]]
==== 9.3 Line Terminators
-Accepted line terminators: - *LF* (Unix/Linux/macOS): `+\n+` - *CRLF*
-(Windows): `+\r\n+` - *CR* (old Mac): `+\r+`
+Accepted line terminators:
+
+* *LF* (Unix/Linux/macOS): `++\++n`
+* *CRLF* (Windows): `++\++r++\++n`
+* *CR* (old Mac): `++\++r`
'''''
+[[10-operator-precedence]]
=== 10. Operator Precedence
*Complete precedence table (highest to lowest):*
@@ -515,34 +566,22 @@ Accepted line terminators: - *LF* (Unix/Linux/macOS): `+\n+` - *CRLF*
[cols=",,,",options="header",]
|===
|Level |Operators |Associativity |Description
-|11 |`+.+` |Left |Field access
-
-|10 |Function application |Left |`+f x+`
-
-|9 |`+^+` |Right |Exponentiation
-
-|8 |`+*+`, `+/+`, `+div+`, `+mod+` |Left |Multiplicative
-
-|7 |`+++`, `+-+` (binary) |Left |Additive
-
-|6 |`+::+`, `+Γ+`, `+β+` |Right/Left |List cons, type product/sum
-
-|5 |`+=+`, `+<>+`, `+!=+`, `+<+`, `+>+`, `+<=+`, `+>=+` |Non-assoc
-|Comparison
-
-|5 |`+β+`, `+β+`, `+β+`, `+β+` |Non-assoc |Set membership
-
-|4 |`+Β¬+`, `+NOT+` |Right |Logical negation
-
-|3 |`+β§+`, `+AND+`, `+&&+` |Left |Logical conjunction
-
-|2 |`+β¨+`, `+OR+`, `+\|\|+` |Left |Logical disjunction
-
-|1 |`+β+`, `+β+`, `+β+`, `+β+`, `+->+` |Right |Implication, type arrow
-
-|0 |`+,+` |Left |Comma (separator)
+|11 |`.` |Left |Field access
+|10 |Function application |Left |`f x`
+|9 |`^` |Right |Exponentiation
+|8 |`++*++`, `/`, `div`, `mod` |Left |Multiplicative
+|7 |`{plus}`, `-` (binary) |Left |Additive
+|6 |`::`, `Γ`, `β` |Right/Left |List cons, type product/sum
+|5 |`=`, `++<>++`, `!=`, `++<++`, `++>++`, `++<++=`, `++>++=` |Non-assoc |Comparison
+|5 |`β`, `β`, `β`, `β` |Non-assoc |Set membership
+|4 |`Β¬`, `NOT` |Right |Logical negation
+|3 |`β§`, `AND`, `&&` |Left |Logical conjunction
+|2 |`β¨`, `OR`, `{vbar}{vbar}` |Left |Logical disjunction
+|1 |`β`, `β`, `β`, `β`, `-++>++` |Right |Implication, type arrow
+|0 |`,` |Left |Comma (separator)
|===
+[[101-associativity-rules]]
==== 10.1 Associativity Rules
*Left-associative:*
@@ -565,6 +604,7 @@ a -> b -> c = a -> (b -> c)
a < b < c = (SYNTAX ERROR - use a < b AND b < c)
....
+[[102-parentheses]]
==== 10.2 Parentheses
Use parentheses to override precedence:
@@ -577,8 +617,10 @@ a + (b * c) -- Multiplication first (default)
'''''
+[[11-lexical-analysis-algorithm]]
=== 11. Lexical Analysis Algorithm
+[[111-maximal-munch-rule]]
==== 11.1 Maximal Munch Rule
The lexer uses *maximal munch* (longest match):
@@ -589,6 +631,7 @@ The lexer uses *maximal munch* (longest match):
123.45 β Token: 123.45 (float, not 123 . 45)
....
+[[112-token-recognition-priority]]
==== 11.2 Token Recognition Priority
[arabic]
@@ -596,22 +639,25 @@ The lexer uses *maximal munch* (longest match):
. *Keywords* - Matched before identifiers
. *Multi-character operators* - Matched before single-char
. *Literals* - Numbers, strings, booleans
-. *Identifiers* - Alphanumeric + underscore
+. *Identifiers* - Alphanumeric {plus} underscore
. *Single-character operators/punctuation*
+[[113-ambiguity-resolution]]
==== 11.3 Ambiguity Resolution
-*Example:* `+SELECT*FROM+`
+*Example:* `SELECT++*++FROM`
-* Greedy matching: `+SELECT+`, `+*+`, `+FROM+` (correct)
-* Not: `+SELECT*F+`, `+ROM+` (incorrect)
+* Greedy matching: `SELECT`, `++*++`, `FROM` (correct)
+* Not: `SELECT++*++F`, `ROM` (incorrect)
*Rule:* Always prefer keyword matches over identifiers.
'''''
+[[12-lexical-extensions]]
=== 12. Lexical Extensions
+[[121-unicode-mathematical-symbols]]
==== 12.1 Unicode Mathematical Symbols
GQL-DT accepts Unicode mathematical symbols with ASCII alternatives:
@@ -619,24 +665,25 @@ GQL-DT accepts Unicode mathematical symbols with ASCII alternatives:
[cols=",,",options="header",]
|===
|Unicode |ASCII |Meaning
-|`+Ξ»+` |`+\+` |Lambda
-|`+β+` |`+forall+` |Universal quantifier
-|`+β+` |`+exists+` |Existential quantifier
-|`+β§+` |`+AND+`, `+&&+` |Logical AND
-|`+β¨+` |`+OR+`, `+\|\|+` |Logical OR
-|`+Β¬+` |`+NOT+` |Logical NOT
-|`+β+` |`+->+`, `+=>+` |Implication, function arrow
-|`+β+` |`+==>+` |Double implication
-|`+β+` |`+<=>+` |Biconditional
-|`+β+` |`+<==>+` |Double biconditional
-|`+Γ+` |`+*+` (in type context) |Product type
-|`+β+` |`+++` (in type context) |Sum type
-|`+β+` |`+IN+` |Set membership
-|`+β+` |`+NOT IN+` |Not in set
-|`+β+` |`+SUBSET+` |Subset
-|`+β+` |`+SUPERSET+` |Superset
+|`Ξ»` |`++\++` |Lambda
+|`β` |`forall` |Universal quantifier
+|`β` |`exists` |Existential quantifier
+|`β§` |`AND`, `&&` |Logical AND
+|`β¨` |`OR`, `{vbar}{vbar}` |Logical OR
+|`Β¬` |`NOT` |Logical NOT
+|`β` |`-++>++`, `=++>++` |Implication, function arrow
+|`β` |`==++>++` |Double implication
+|`β` |`++<++=++>++` |Biconditional
+|`β` |`++<++==++>++` |Double biconditional
+|`Γ` |`++*++` (in type context) |Product type
+|`β` |`{plus}` (in type context) |Sum type
+|`β` |`IN` |Set membership
+|`β` |`NOT IN` |Not in set
+|`β` |`SUBSET` |Subset
+|`β` |`SUPERSET` |Superset
|===
+[[122-proof-literals]]
==== 12.2 Proof Literals
*Lean 4 proof terms:*
@@ -663,8 +710,10 @@ by simp [rule1, rule2]; omega
'''''
+[[13-compatibility-notes]]
=== 13. Compatibility Notes
+[[131-standard-gql-compatibility]]
==== 13.1 Standard GQL Compatibility
GQL-DT is a *superset* of standard Lithoglyph GQL:
@@ -673,26 +722,29 @@ GQL-DT is a *superset* of standard Lithoglyph GQL:
* *Type annotations* are optional (inferred if omitted)
* *Proof clauses* are optional (auto-generated or admitted)
+[[132-sql-compatibility]]
==== 13.2 SQL Compatibility
GQL-DT follows SQL conventions:
* *Keywords are case-insensitive* (SELECT = select)
-* *String literals* use single quotes (standard) or double quotes
-(PostgreSQL-style)
-* *Comments* use `+--+` (SQL standard) or `+/* */+` (C-style)
+* *String literals* use single quotes (standard) or double quotes (PostgreSQL-style)
+* *Comments* use `--` (SQL standard) or `/++*++ ++*++/` (C-style)
+[[133-lean-4--idris-2-compatibility]]
==== 13.3 Lean 4 / Idris 2 Compatibility
Type expressions and proof terms can embed:
* *Lean 4 syntax* - Full Lean 4 type expressions in type annotations
-* *Idris 2 syntax* - Full Idris 2 proof terms in WITH_PROOF clauses
+* *Idris 2 syntax* - Full Idris 2 proof terms in WITH++_++PROOF clauses
'''''
+[[14-error-recovery]]
=== 14. Error Recovery
+[[141-lexical-errors]]
==== 14.1 Lexical Errors
*Unterminated string:*
@@ -719,26 +771,33 @@ SELECT 1.2.3 FROM t
-- ERROR: Invalid float literal '1.2.3' at line 1, column 8
----
+[[142-recovery-strategy]]
==== 14.2 Recovery Strategy
-On lexical error: 1. *Report error* with line and column number 2. *Skip
-to next whitespace* or punctuation 3. *Continue tokenization* (collect
-all errors)
+On lexical error:
+
+[arabic]
+. *Report error* with line and column number
+. *Skip to next whitespace* or punctuation
+. *Continue tokenization* (collect all errors)
'''''
+[[15-implementation-notes]]
=== 15. Implementation Notes
+[[151-recommended-tools]]
==== 15.1 Recommended Tools
-* *Lexer generator:* Alex (Haskell), ocamllex (OCaml), Flex (C/C++)
+* *Lexer generator:* Alex (Haskell), ocamllex (OCaml), Flex (C/C{plus}{plus})
* *Hand-rolled:* Lean 4 Parsec, Rust nom, ReScript combinators
+[[152-performance-considerations]]
==== 15.2 Performance Considerations
* *Unicode normalization:* Normalize identifiers to NFC form
* *Keyword lookup:* Use hash table for O(1) keyword recognition
-* *Number parsing:* Use fast float parsing (e.g., `+from_str_radix+`)
+* *Number parsing:* Use fast float parsing (e.g., `from++_++str++_++radix`)
'''''
@@ -746,7 +805,7 @@ all errors)
[arabic]
. *ISO/IEC 14977* - EBNF Syntax Notation
-. *Unicode Standard Annex #31* - Unicode Identifier and Pattern Syntax
+. *Unicode Standard Annex ++#++31* - Unicode Identifier and Pattern Syntax
. *SQL:2023 Standard* - ISO/IEC 9075
. *Lean 4 Reference* - https://lean-lang.org/
. *Idris 2 Tutorial* - https://idris2.readthedocs.io/
@@ -755,6 +814,7 @@ all errors)
*Document Status:* Complete lexical specification for GQL-DT v1.0
-*See Also:* - `+GQL-DT-Grammar.ebnf+` - Formal EBNF grammar -
-`+GQL_Dependent_Types_Complete_Specification.md+` - Type system
-specification
+*See Also:*
+
+* `GQL-DT-Grammar.ebnf` - Formal EBNF grammar
+* `GQL_Dependent_Types_Complete_Specification.adoc` - Type system specification
diff --git a/spec/GQL-DT-Railroad-Diagrams.adoc b/spec/GQL-DT-Railroad-Diagrams.adoc
index 60407ca..262d52e 100644
--- a/spec/GQL-DT-Railroad-Diagrams.adoc
+++ b/spec/GQL-DT-Railroad-Diagrams.adoc
@@ -1,28 +1,31 @@
== GQL-DT Railroad Diagrams
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Version:* 1.0.0 *Date:* 2026-02-01
+*Version:* 1.0.0
+*Date:* 2026-02-01
-This document provides railroad diagram specifications for GQL-DT
-syntax. These can be used with: - *Online:*
-https://www.bottlecaps.de/rr/ui - *CLI:* `+rr+` (Railroad Diagram
-Generator) - *Graphviz:* Convert to DOT format
+This document provides railroad diagram specifications for GQL-DT syntax. These can be used with:
+
+* *Online:* https://www.bottlecaps.de/rr/ui
+* *CLI:* `rr` (Railroad Diagram Generator)
+* *Graphviz:* Convert to DOT format
=== Table of Contents
[arabic]
-. link:#create-collection[CREATE COLLECTION]
-. link:#insert-statement[INSERT Statement]
-. link:#select-statement[SELECT Statement]
-. link:#type-expressions[Type Expressions]
-. link:#proof-clauses[Proof Clauses]
-. link:#update-statement[UPDATE Statement]
-. link:#normalization-commands[Normalization Commands]
+. link:#1-create-collection[CREATE COLLECTION]
+. link:#2-insert-statement[INSERT Statement]
+. link:#3-select-statement[SELECT Statement]
+. link:#4-type-expressions[Type Expressions]
+. link:#5-proof-clauses[Proof Clauses]
+. link:#6-update-statement[UPDATE Statement]
+. link:#7-normalization-commands[Normalization Commands]
'''''
+[[1-create-collection]]
=== 1. CREATE COLLECTION
==== Railroad Diagram Source (EBNF)
@@ -67,6 +70,7 @@ Option:
'''''
+[[2-insert-statement]]
=== 2. INSERT Statement
==== Railroad Diagram Source (EBNF)
@@ -116,6 +120,7 @@ InverseClause:
'''''
+[[3-select-statement]]
=== 3. SELECT Statement
==== Railroad Diagram Source (EBNF)
@@ -167,6 +172,7 @@ TypeRefinement:
'''''
+[[4-type-expressions]]
=== 4. Type Expressions
==== Railroad Diagram Source (EBNF)
@@ -192,7 +198,7 @@ RefinedType ::= 'BoundedNat' NatLiteral NatLiteral
DependentType ::= 'Vector' TypeExpr NatLiteral
| 'Tracked' TypeExpr
- | 'PromptScores'
+ | 'Prompores'
| 'NavigationPath' LambdaExpr
| 'Claim' ConfidenceExpr
@@ -228,7 +234,7 @@ RefinedType:
DependentType:
ββ Vector β TypeExpr β Nat βββββββββββ
ββ Tracked β TypeExpr ββββββββββββββββ€
-ββ PromptScores ββββββββββββββββββββββ€
+ββ Prompores ββββββββββββββββββββββ€
ββ NavigationPath β LambdaExpr βββββββ€
ββ Claim β ConfidenceExpr ββββββββββββ
@@ -239,6 +245,7 @@ FunctionType:
'''''
+[[5-proof-clauses]]
=== 5. Proof Clauses
==== Railroad Diagram Source (EBNF)
@@ -289,6 +296,7 @@ TacticExpr:
'''''
+[[6-update-statement]]
=== 6. UPDATE Statement
==== Railroad Diagram Source (EBNF)
@@ -326,6 +334,7 @@ Identifier β = β Value ββ
'''''
+[[7-normalization-commands]]
=== 7. Normalization Commands
==== Railroad Diagram Source (EBNF)
@@ -369,6 +378,7 @@ APPLY NORMALIZATION β Identifier β ProofClause β RationaleClause ββ
'''''
+[[8-lambda-expressions]]
=== 8. Lambda Expressions
==== Railroad Diagram Source (EBNF)
@@ -415,6 +425,7 @@ Expr β InfixOp β Expr ββ
'''''
+[[9-struct-and-array-literals]]
=== 9. Struct and Array Literals
==== Railroad Diagram Source (EBNF)
@@ -455,6 +466,7 @@ Value ββ¬βββββββββββββββ¬ββ
'''''
+[[10-complete-example-diagrams]]
=== 10. Complete Example Diagrams
==== Example: INSERT with All Optional Clauses
@@ -482,6 +494,7 @@ RETURNING β ( β List β ( β Evidence | prompt_overall > 90 β ) β )
'''''
+[[11-usage-instructions]]
=== 11. Usage Instructions
==== Online Railroad Diagram Generator
@@ -489,7 +502,7 @@ RETURNING β ( β List β ( β Evidence | prompt_overall > 90 β ) β )
[arabic]
. Visit https://www.bottlecaps.de/rr/ui
. Paste EBNF from sections above
-. Click "`View Diagram`"
+. Click "View Diagram"
. Export as SVG or PNG
==== CLI Tool
@@ -520,6 +533,7 @@ spec/diagrams/
'''''
+[[12-diagram-conventions]]
=== 12. Diagram Conventions
==== Notation
@@ -550,18 +564,23 @@ spec/diagrams/
[arabic]
. *Railroad Diagram Generator:* https://www.bottlecaps.de/rr/ui
. *EBNF Standard:* ISO/IEC 14977
-. *GQL-DT Grammar:* `+GQL-DT-Grammar.ebnf+`
+. *GQL-DT Grammar:* `GQL-DT-Grammar.ebnf`
. *W3C EBNF Notation:* https://www.w3.org/TR/REC-xml/#sec-notation
'''''
-*Document Status:* Complete railroad diagram specifications for GQL-DT
-v1.0
+*Document Status:* Complete railroad diagram specifications for GQL-DT v1.0
+
+*Next Steps:*
+
+[arabic]
+. Generate SVG diagrams using online tool
+. Place in `spec/diagrams/` directory
+. Reference from main specification document
+. Update as grammar evolves
-*Next Steps:* 1. Generate SVG diagrams using online tool 2. Place in
-`+spec/diagrams/+` directory 3. Reference from main specification
-document 4. Update as grammar evolves
+*See Also:*
-*See Also:* - `+GQL-DT-Grammar.ebnf+` - Formal EBNF grammar source -
-`+GQL-DT-Lexical.md+` - Lexical specification -
-`+GQL_Dependent_Types_Complete_Specification.md+` - Type system spec
+* `GQL-DT-Grammar.ebnf` - Formal EBNF grammar source
+* `GQL-DT-Lexical.adoc` - Lexical specification
+* `GQL_Dependent_Types_Complete_Specification.adoc` - Type system spec
diff --git a/spec/GQL_Dependent_Types_Complete_Specification.adoc b/spec/GQL_Dependent_Types_Complete_Specification.adoc
index fffbfaf..2a9c457 100644
--- a/spec/GQL_Dependent_Types_Complete_Specification.adoc
+++ b/spec/GQL_Dependent_Types_Complete_Specification.adoc
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: CC-BY-SA-4.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
== GQL with Dependent Types: Complete Specification
*Version*: 0.2.0 (Dependent Types Extension) +
@@ -22,19 +24,20 @@
'''''
+[[1-introduction]]
=== 1. Introduction
+[[11-what-this-document-covers]]
==== 1.1 What This Document Covers
-This specification extends GQL with *dependent types*βtypes that can
-depend on values. This enables:
+This specification extends GQL with *dependent types*βtypes that can depend on values. This enables:
-* *Compile-time verification* of constraints (e.g., PROMPT scores in [0,
-100])
-* *Provenance in types* (canβt create data without provenance)
+* *Compile-time verification* of constraints (e.g., PROMPT scores in ++[++0, 100++]++)
+* *Provenance in types* (can't create data without provenance)
* *Reversibility proofs* (prove operations have inverses)
* *Machine-checkable correctness* (types ARE proofs)
+[[12-relationship-to-standard-gql]]
==== 1.2 Relationship to Standard GQL
....
@@ -49,29 +52,31 @@ GQL with Dependent Types (compile-time proofs):
) WITH DEPENDENT_TYPES;
....
-*Backward Compatibility*: Standard GQL is valid in dependent-type mode
-(types are inferred).
+*Backward Compatibility*: Standard GQL is valid in dependent-type mode (types are inferred).
+[[13-implementation-languages]]
==== 1.3 Implementation Languages
-GQL with dependent types can be implemented in: - *Idris 2*: Good
-balance of practicality and power - *Lean 4*: Excellent IDE support,
-strong automation - *Agda*: Most expressive, research-oriented - *F** /
-Dafny**: Refinement types, SMT-based
+GQL with dependent types can be implemented in:
+
+* *Idris 2*: Good balance of practicality and power
+* *Lean 4*: Excellent IDE support, strong automation
+* *Agda*: Most expressive, research-oriented
+* *F*++*++ / Dafny++**++: Refinement types, SMT-based
*Recommendation*: Lean 4 (best LSP support, large proof library).
+[[14-related-specifications]]
==== 1.4 Related Specifications
-* *link:normalization-types.md[Normalization Types]*: Extends this
-specification with type-encoded functional dependencies, normal form
-predicates (1NF through BCNF), and proof-carrying schema evolution.
-Integrates with Lithoglyphβs self-normalizing database feature.
+* *link:normalization-types.adoc[Normalization Types]*: Extends this specification with type-encoded functional dependencies, normal form predicates (1NF through BCNF), and proof-carrying schema evolution. Integrates with Lithoglyph's self-normalizing database feature.
'''''
+[[2-type-system]]
=== 2. Type System
+[[21-type-universe]]
==== 2.1 Type Universe
....
@@ -84,6 +89,7 @@ Type 2 (Sort 2): Type 1 -- Types of types
Type Ο (Sort Ο): Type Ο-1 -- Infinite hierarchy
....
+[[22-primitive-types]]
==== 2.2 Primitive Types
[source,lean]
@@ -98,6 +104,7 @@ Char : Type -- Unicode characters
Unit : Type -- Single value: ()
----
+[[23-type-constructors]]
==== 2.3 Type Constructors
[source,lean]
@@ -111,6 +118,7 @@ Unit : Type -- Single value: ()
Option Ξ± -- Some a | None
----
+[[24-dependent-function-types]]
==== 2.4 Dependent Function Types
[source,lean]
@@ -125,6 +133,7 @@ Option Ξ± -- Some a | None
β (x : Ξ±), P x -- For all x of type Ξ±, P x holds
----
+[[25-dependent-pair-types]]
==== 2.5 Dependent Pair Types
[source,lean]
@@ -138,8 +147,10 @@ Option Ξ± -- Some a | None
'''''
+[[3-refinement-types]]
=== 3. Refinement Types
+[[31-bounded-natural-numbers]]
==== 3.1 Bounded Natural Numbers
[source,lean]
@@ -166,6 +177,7 @@ CREATE COLLECTION evidence (
);
----
+[[32-bounded-floats]]
==== 3.2 Bounded Floats
[source,lean]
@@ -186,6 +198,7 @@ CREATE COLLECTION claims (
);
----
+[[33-non-empty-strings]]
==== 3.3 Non-Empty Strings
[source,lean]
@@ -205,6 +218,7 @@ VALUES ('Some claim')
RATIONALE (r : Rationale); -- Must be non-empty!
----
+[[34-email-addresses]]
==== 3.4 Email Addresses
[source,lean]
@@ -220,6 +234,7 @@ CREATE COLLECTION users (
);
----
+[[35-validated-uuids]]
==== 3.5 Validated UUIDs
[source,lean]
@@ -238,8 +253,10 @@ CREATE COLLECTION entities (
'''''
+[[4-dependent-types]]
=== 4. Dependent Types
+[[41-length-indexed-vectors]]
==== 4.1 Length-Indexed Vectors
[source,lean]
@@ -267,6 +284,7 @@ CREATE COLLECTION survey_responses (
);
----
+[[42-provenance-tracked-values]]
==== 4.2 Provenance-Tracked Values
[source,lean]
@@ -279,7 +297,7 @@ structure Tracked (Ξ± : Type) where
rationale : Rationale
-- Constructor enforces provenance
-def mkTracked (a : Ξ±) (actor : ActorId) (ts : Timestamp) (rat : Rationale)
+def mkTracked (a : Ξ±) (actor : ActorId) (ts : Timestamp) (rat : Rationale)
: Tracked Ξ± :=
β¨a, actor, ts, ratβ©
@@ -304,12 +322,13 @@ RATIONALE "Based on ONS data";
-- Automatically wrapped in Tracked
----
+[[43-prompt-scores-with-proof]]
==== 4.3 PROMPT Scores with Proof
[source,lean]
----
-- Definition
-structure PromptScores where
+structure Prompores where
provenance : PromptDimension
replicability : PromptDimension
objective : PromptDimension
@@ -317,12 +336,12 @@ structure PromptScores where
publication : PromptDimension
transparency : PromptDimension
overall : PromptDimension
- overall_correct : overall.val =
+ overall_correct : overall.val =
(provenance.val + replicability.val + objective.val +
methodology.val + publication.val + transparency.val) / 6
-- Smart constructor
-def mkPromptScores (p r o m pub t : PromptDimension) : PromptScores :=
+def mkPrompores (p r o m pub t : PromptDimension) : Prompores :=
let avg := (p.val + r.val + o.val + m.val + pub.val + t.val) / 6
β¨p, r, o, m, pub, t, β¨avg, by omega, by omegaβ©, by simp [avg]β©
----
@@ -344,14 +363,15 @@ VALUES ({
RATIONALE "Official statistics";
----
+[[44-reversible-operations]]
==== 4.4 Reversible Operations
[source,lean]
----
-- Definition
inductive ReversibleOp (Ξ± : Type) : Type where
- | insert : (data : Tracked Ξ±) β
- (inverse : DeleteOp Ξ±) β
+ | insert : (data : Tracked Ξ±) β
+ (inverse : DeleteOp Ξ±) β
(prf : roundTrip data inverse = data) β
ReversibleOp Ξ±
| update : (old new : Tracked Ξ±) β
@@ -369,7 +389,7 @@ inductive ReversibleOp (Ξ± : Type) : Type where
-- Round-trip property
axiom roundTrip {Ξ± : Type} : Ξ± β (Ξ± β Ξ±) β Ξ±
-axiom roundTripPreservesIdentity {Ξ± : Type} (x : Ξ±) (f : Ξ± β Ξ±)
+axiom roundTripPreservesIdentity {Ξ± : Type} (x : Ξ±) (f : Ξ± β Ξ±)
: roundTrip x f = x
----
@@ -397,6 +417,7 @@ JUSTIFICATION {
};
----
+[[45-confidence-indexed-claims]]
==== 4.5 Confidence-Indexed Claims
[source,lean]
@@ -412,9 +433,9 @@ structure Claim (c : Confidence) where
axiom confidenceJustified : String β List Evidence β Confidence β Prop
-- Type-safe combination
-def combineClaims {c1 c2 : Confidence}
+def combineClaims {c1 c2 : Confidence}
(claim1 : Claim c1) (claim2 : Claim c2)
- (prf : compatible c1 c2)
+ (prf : compatible c1 c2)
: Claim (fuseConfidence c1 c2) := sorry
----
@@ -436,6 +457,7 @@ WHERE compatible(claim1.confidence, claim2.confidence);
-- Type error if not compatible!
----
+[[46-ordered-navigation-paths]]
==== 4.6 Ordered Navigation Paths
[source,lean]
@@ -453,7 +475,7 @@ inductive IsSorted {Ξ± : Type} (r : Ξ± β Ξ± β Bool) : List Ξ± β Prop where
-- Smart constructor (automatically proves sorted)
def createPath {ordering : Evidence β Evidence β Bool}
- (evs : List Evidence)
+ (evs : List Evidence)
: NavigationPath ordering :=
let sorted := List.insertionSort ordering evs
β¨sorted, insertionSortIsSorted ordering evsβ©
@@ -477,8 +499,10 @@ END;
'''''
+[[5-ddl-with-types]]
=== 5. DDL with Types
+[[51-create-collection-with-dependent-types]]
==== 5.1 CREATE COLLECTION (With Dependent Types)
*Syntax*:
@@ -528,7 +552,7 @@ CREATE COLLECTION claims (
CREATE COLLECTION evidence (
id : UUID,
title : NonEmptyString,
- prompt_scores : PromptScores -- Proof of correct computation!
+ prompt_scores : Prompores -- Proof of correct computation!
) WITH DEPENDENT_TYPES;
----
@@ -542,7 +566,8 @@ CREATE COLLECTION survey (
) WITH DEPENDENT_TYPES;
----
-==== 5.2 CREATE EDGE_COLLECTION (With Types)
+[[52-create-edge_collection-with-types]]
+==== 5.2 CREATE EDGE++_++COLLECTION (With Types)
[source,gql]
----
@@ -554,6 +579,7 @@ CREATE EDGE_COLLECTION relationships (
) WITH DEPENDENT_TYPES;
----
+[[53-create-constraint-with-proofs]]
==== 5.3 CREATE CONSTRAINT (With Proofs)
[source,gql]
@@ -568,8 +594,10 @@ APPROVERS "legal_team";
'''''
+[[6-dml-with-proofs]]
=== 6. DML with Proofs
+[[61-insert-with-proof-obligations]]
==== 6.1 INSERT (With Proof Obligations)
*Syntax*:
@@ -642,6 +670,7 @@ WITH_PROOF {
};
----
+[[62-update-with-correction-proof]]
==== 6.2 UPDATE (With Correction Proof)
*Syntax*:
@@ -702,6 +731,7 @@ WITH_PROOF {
};
----
+[[63-delete-with-justification]]
==== 6.3 DELETE (With Justification)
*Reversible Delete*:
@@ -738,8 +768,10 @@ WITH_JUSTIFICATION {
'''''
+[[7-queries-with-refinements]]
=== 7. Queries with Refinements
+[[71-select-with-type-refinements]]
==== 7.1 SELECT with Type Refinements
*Syntax*:
@@ -797,6 +829,7 @@ WHERE EXISTS (
-- Returns pairs (claim, evidence) with proof that e supports c
----
+[[72-aggregates-with-proofs]]
==== 7.2 Aggregates with Proofs
[source,gql]
@@ -813,6 +846,7 @@ GROUP BY investigation_id;
-- Type proves average is in [0, 100]
----
+[[73-join-with-type-safety]]
==== 7.3 JOIN with Type Safety
[source,gql]
@@ -826,8 +860,10 @@ FROM claims c
'''''
+[[8-proof-obligations]]
=== 8. Proof Obligations
+[[81-automatic-proof-search]]
==== 8.1 Automatic Proof Search
*Simple Arithmetic*:
@@ -853,6 +889,7 @@ VALUES ({provenance: 100, ...});
-- overall_correct: by simp [computeOverall]; omega
----
+[[82-manual-proofs]]
==== 8.2 Manual Proofs
*When Auto-Proof Fails*:
@@ -863,7 +900,7 @@ INSERT INTO claims (text, confidence, evidence_list)
VALUES ('Complex claim', 0.92, [e1, e2, e3])
RATIONALE "Multi-source synthesis"
WITH_PROOF {
- confidence_justified:
+ confidence_justified:
-- Manual Lean 4 proof
by
intro text evidence conf
@@ -871,6 +908,7 @@ WITH_PROOF {
};
----
+[[83-proof-tactics]]
==== 8.3 Proof Tactics
*Available Tactics*:
@@ -909,6 +947,7 @@ WITH_PROOF {
}
----
+[[84-proof-libraries]]
==== 8.4 Proof Libraries
*Pre-Proved Theorems*:
@@ -940,8 +979,10 @@ end Lithoglyph.Proofs
'''''
+[[9-tactics-and-automation]]
=== 9. Tactics and Automation
+[[91-lithoglyph-specific-tactics]]
==== 9.1 Lithoglyph-Specific Tactics
[source,lean]
@@ -957,15 +998,15 @@ macro_rules
-- Auto-solve provenance proofs
syntax "lithoglyph_prov" : tactic
macro_rules
- | `(tactic| lithoglyph_prov) => `(tactic|
- simp only [Tracked, NonEmptyString];
+ | `(tactic| lithoglyph_prov) => `(tactic|
+ simp only [Tracked, NonEmptyString];
constructor <;> decide)
-- Auto-solve PROMPT score proofs
syntax "lithoglyph_prompt" : tactic
macro_rules
| `(tactic| lithoglyph_prompt) => `(tactic|
- simp [PromptScores, computeOverall];
+ simp [Prompores, computeOverall];
lithoglyph_bounds)
end Lithoglyph.Tactics
@@ -982,6 +1023,7 @@ WITH_PROOF {
}
----
+[[92-ide-integration]]
==== 9.2 IDE Integration
*Lean 4 VSCode Extension*:
@@ -995,11 +1037,17 @@ Features:
β’ Proof search (find relevant lemmas)
....
-*Example IDE Workflow*: 1. Write GQL with `+VALUES (...)+` 2. IDE shows:
-"`Missing proof of X`" 3. User writes `+WITH_PROOF { x: by }+` 4. IDE
-suggests tactics: `+omega, simp, decide+` 5. User selects tactic, proof
-completes 6. IDE shows: β Type checked successfully
+*Example IDE Workflow*:
+[arabic]
+. Write GQL with `VALUES (...)`
+. IDE shows: "Missing proof of X"
+. User writes `WITH++_++PROOF ++{++ x: by }`
+. IDE suggests tactics: `omega, simp, decide`
+. User selects tactic, proof completes
+. IDE shows: β Type checked successfully
+
+[[93-proof-caching]]
==== 9.3 Proof Caching
*Incremental Type Checking*:
@@ -1026,8 +1074,10 @@ theorem cached_proof_12345 : P := by <...compiled proof...>
'''''
+[[10-complete-examples]]
=== 10. Complete Examples
+[[101-bofig-uk-inflation-2023-fully-typed]]
==== 10.1 BoFIG UK Inflation 2023 (Fully Typed)
[source,gql]
@@ -1039,7 +1089,7 @@ CREATE COLLECTION bofig_evidence (
title : NonEmptyString,
evidence_type : EvidenceType,
url : Option String,
- prompt_scores : PromptScores
+ prompt_scores : Prompores
) WITH DEPENDENT_TYPES, PROVENANCE_TRACKING;
-- Step 2: Insert evidence (type-checked)
@@ -1126,11 +1176,12 @@ FROM bofig_claims c
JOIN bofig_evidence e ON r.to_id = e.id
WHERE c.investigation_id = 'uk_inflation_2023'
AND r.relationship_type = 'SUPPORTS'
-RETURNING (List (Claim Γ Evidence Γ Relationship) |
+RETURNING (List (Claim Γ Evidence Γ Relationship) |
β (c, e, r) β result, c.confidence > 0.85 β§ e.prompt_overall > 90);
-- Return type PROVES all results satisfy conditions!
----
+[[102-correction-workflow-with-reversiibility-proof]]
==== 10.2 Correction Workflow (With Reversiibility Proof)
[source,gql]
@@ -1171,11 +1222,12 @@ WITH_PROOF {
-- Query correction history with proofs
INTROSPECT bofig_claims.claim_123 CORRECTION_HISTORY
-RETURNING (List CorrectionEntry |
+RETURNING (List CorrectionEntry |
β e β result, e.inverse_correct β§ e.reason.length > 0);
-- Type proves all corrections have valid inverses!
----
+[[103-my-newsroom-belief-fusion-type-safe]]
==== 10.3 My-Newsroom Belief Fusion (Type-Safe)
[source,gql]
@@ -1219,7 +1271,7 @@ WITH_PROOF {
-- Fuse beliefs (type-safe)
INSERT INTO belief_fusions (claim_text, fused_belief)
-SELECT
+SELECT
claim_text,
fuseBeliefsDS(b1.belief, b2.belief) -- Type-safe fusion!
FROM agent_beliefs b1, agent_beliefs b2
@@ -1235,6 +1287,7 @@ WITH_PROOF {
-- Type checker proves fusion result is in [0.0, 1.0]!
----
+[[104-navigation-path-with-ordering-proof]]
==== 10.4 Navigation Path (With Ordering Proof)
[source,gql]
@@ -1266,6 +1319,7 @@ RETURNING (NavigationPath (Ξ» eβ eβ. eβ.prompt_objective < eβ.prompt_obj
=== Appendix A: Type Notation Reference
+[[a1-lean-4-notation]]
==== A.1 Lean 4 Notation
[source,lean]
@@ -1292,31 +1346,25 @@ a < b -- Less than
a = b -- Equality
----
+[[a2-gql-notation-mapping]]
==== A.2 GQL Notation Mapping
-[width="100%",cols="36%,38%,26%",options="header",]
+[cols=",,",options="header",]
|===
|GQL Syntax |Lean 4 Type |Meaning
-|`+BoundedNat 0 100+` |`+{n : Nat // 0 β€ n β§ n β€ 100}+` |Nat in [0, 100]
-
-|`+NonEmptyString+` |`+{s : String // s.length > 0}+` |Non-empty string
-
-|`+Confidence+` |`+BoundedFloat 0.0 1.0+` |Float in [0.0, 1.0]
-
-|`+Tracked Ξ±+` |`+(Ξ± Γ ActorId Γ Timestamp Γ Rationale)+`
-|Provenance-tracked value
-
-|`+Vector Ξ± n+` |Dependent array of exactly n elements |Fixed-length
-array
-
-|`+Claim c+` |Claim indexed by confidence level c |Confidence-indexed
-claim
+|`BoundedNat 0 100` |`++{++n : Nat // 0 β€ n β§ n β€ 100}` |Nat in ++[++0, 100++]++
+|`NonEmptyString` |`++{++s : String // s.length ++>++ 0}` |Non-empty string
+|`Confidence` |`BoundedFloat 0.0 1.0` |Float in ++[++0.0, 1.0++]++
+|`Tracked Ξ±` |`(Ξ± Γ ActorId Γ Timestamp Γ Rationale)` |Provenance-tracked value
+|`Vector Ξ± n` |Dependent array of exactly n elements |Fixed-length array
+|`Claim c` |Claim indexed by confidence level c |Confidence-indexed claim
|===
'''''
=== Appendix B: Error Messages
+[[b1-bound-violation]]
==== B.1 Bound Violation
....
@@ -1336,6 +1384,7 @@ Suggestions:
β’ Check if you meant 15 (typo)?
....
+[[b2-missing-proof]]
==== B.2 Missing Proof
....
@@ -1354,6 +1403,7 @@ Suggestions:
β’ Lower confidence to match evidence quality
....
+[[b3-type-mismatch]]
==== B.3 Type Mismatch
....
@@ -1374,6 +1424,7 @@ Suggestion: Filter claims WHERE confidence BETWEEN 0.8 AND 1.0
=== Appendix C: Proof Cookbook
+[[c1-bounded-integers]]
==== C.1 Bounded Integers
[source,lean]
@@ -1386,6 +1437,7 @@ example (a b : BoundedNat 0 100) : let avg := (a.val + b.val) / 2; avg β€ 100 :
omega
----
+[[c2-non-empty-strings]]
==== C.2 Non-Empty Strings
[source,lean]
@@ -1400,12 +1452,13 @@ example (s1 s2 : NonEmptyString) : (s1.val ++ s2.val).length > 0 := by
omega
----
+[[c3-provenance-tracking]]
==== C.3 Provenance Tracking
[source,lean]
----
-- Prove tracked value has provenance
-example (t : Tracked Ξ±) : t.rationale.val.length > 0 :=
+example (t : Tracked Ξ±) : t.rationale.val.length > 0 :=
t.rationale.nonempty
-- Prove all tracked values in list have provenance
@@ -1414,6 +1467,7 @@ example (ts : List (Tracked Ξ±)) : β t β ts, t.rationale.val.length > 0 := b
exact t.rationale.nonempty
----
+[[c4-reversibility]]
==== C.4 Reversibility
[source,lean]
@@ -1437,9 +1491,14 @@ theorem updateReverses {Ξ± : Type} (old new : Tracked Ξ±)
*Implementation*: Lean 4 recommended (best IDE support).
-*Timeline*: - Phase 1 (Month 1-6): Refinement types - Phase 2 (Month
-7-12): Simple dependent types - Phase 3 (Month 13-18): Full verification
+*Timeline*:
+
+* Phase 1 (Month 1-6): Refinement types
+* Phase 2 (Month 7-12): Simple dependent types
+* Phase 3 (Month 13-18): Full verification
+
+*See Also*:
-*See Also*: - WP06: Dependently-Typed Lithoglyph (research proposal) -
-Lithoglyph arXiv paper (Section 14: Future Work) - My-Newsroom Me
-dialect (epistemic types)
+* WP06: Dependently-Typed Lithoglyph (research proposal)
+* Lithoglyph arXiv paper (Section 14: Future Work)
+* My-Newsroom Me dialect (epistemic types)
diff --git a/spec/README.adoc b/spec/README.adoc
index a187a99..83815e0 100644
--- a/spec/README.adoc
+++ b/spec/README.adoc
@@ -1,49 +1,40 @@
== GQL-DT Specification Suite
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
-*Version:* 1.0.0 *Status:* Complete formal specification *Date:*
-2026-02-01
+*Version:* 1.0.0
+*Status:* Complete formal specification
+*Date:* 2026-02-01
=== Overview
-This directory contains the complete formal specification for *GQL-DT*
-(Lithoglyph Query Language with Dependent Types), including grammar,
-semantics, examples, and visual diagrams.
+This directory contains the complete formal specification for *GQL-DT* (Lithoglyph Query Language with Dependent Types), including grammar, semantics, examples, and visual diagrams.
=== Specification Documents
+[[1-core-specifications]]
==== 1. Core Specifications
-[width="100%",cols="31%,26%,23%,20%",options="header",]
+[cols=",,,",options="header",]
|===
|Document |Purpose |Status |Lines
-|*GQL_Dependent_Types_Complete_Specification.md* |Type system,
-semantics, examples |β
Complete |1,337
-
-|*normalization-types.md* |Functional dependencies, normal forms |β
-Complete |753
-
-|*GQL-DT-Grammar.ebnf* |Formal EBNF grammar |β
Complete |800+
-
-|*GQL-DT-Lexical.md* |Lexical specification |β
Complete |700+
-
-|*GQL-DT-Railroad-Diagrams.md* |Visual syntax diagrams |β
Complete
-|600+
+|*GQL_Dependent_Types_Complete_Specification.adoc* |Type system, semantics, examples |β
Complete |1,337
+|*normalization-types.adoc* |Functional dependencies, normal forms |β
Complete |753
+|*GQL-DT-Grammar.ebnf* |Formal EBNF grammar |β
Complete |800{plus}
+|*GQL-DT-Lexical.adoc* |Lexical specification |β
Complete |700{plus}
+|*GQL-DT-Railroad-Diagrams.adoc* |Visual syntax diagrams |β
Complete |600{plus}
|===
+[[2-supporting-documentation]]
==== 2. Supporting Documentation
-[width="100%",cols="35%,31%,34%",options="header",]
+[cols=",,",options="header",]
|===
|Document |Purpose |Location
-|*WP06_Dependently_Typed_Lithoglyph.md* |Research whitepaper
-|`+../docs/+`
-
-|*STATE.scm* |Project state tracking |`+../+`
-
-|*ECOSYSTEM.scm* |Ecosystem positioning |`+../+`
+|*WP06_Dependently_Typed_Lithoglyph.adoc* |Research whitepaper |`../docs/`
+|*STATE.a2ml* |Project state tracking |`../.machine_readable/descriptiles/`
+|*ECOSYSTEM.a2ml* |Ecosystem positioning |`../.machine_readable/descriptiles/`
|===
=== Quick Start
@@ -51,40 +42,35 @@ Complete |753
==== For Implementers
[arabic]
-. *Start with:* `+GQL-DT-Grammar.ebnf+` - Complete syntax
-. *Then read:* `+GQL-DT-Lexical.md+` - Tokenization rules
-. *Reference:* `+GQL_Dependent_Types_Complete_Specification.md+` - Type
-system
-. *Visual aid:* `+GQL-DT-Railroad-Diagrams.md+` - Syntax diagrams
+. *Start with:* `GQL-DT-Grammar.ebnf` - Complete syntax
+. *Then read:* `GQL-DT-Lexical.adoc` - Tokenization rules
+. *Reference:* `GQL_Dependent_Types_Complete_Specification.adoc` - Type system
+. *Visual aid:* `GQL-DT-Railroad-Diagrams.adoc` - Syntax diagrams
==== For Users
[arabic]
-. *Start with:* `+GQL_Dependent_Types_Complete_Specification.md+` -
-Examples and usage
-. *Deep dive:* `+normalization-types.md+` - Database normalization
-. *Visual aid:* `+GQL-DT-Railroad-Diagrams.md+` - See syntax visually
-. *Research:* `+../docs/WP06_Dependently_Typed_Lithoglyph.md+` -
-Motivation and theory
+. *Start with:* `GQL_Dependent_Types_Complete_Specification.adoc` - Examples and usage
+. *Deep dive:* `normalization-types.adoc` - Database normalization
+. *Visual aid:* `GQL-DT-Railroad-Diagrams.adoc` - See syntax visually
+. *Research:* `../docs/WP06_Dependently_Typed_Lithoglyph.adoc` - Motivation and theory
==== For Researchers
[arabic]
-. *Theory:* `+../docs/WP06_Dependently_Typed_Lithoglyph.md+` - Dependent
-types for databases
-. *Type system:* `+GQL_Dependent_Types_Complete_Specification.md+`
-(Section 2-4)
-. *Proofs:* `+GQL_Dependent_Types_Complete_Specification.md+` (Section
-8-9)
-. *Normalization:* `+normalization-types.md+` - Proof-carrying evolution
+. *Theory:* `../docs/WP06_Dependently_Typed_Lithoglyph.adoc` - Dependent types for databases
+. *Type system:* `GQL_Dependent_Types_Complete_Specification.adoc` (Section 2-4)
+. *Proofs:* `GQL_Dependent_Types_Complete_Specification.adoc` (Section 8-9)
+. *Normalization:* `normalization-types.adoc` - Proof-carrying evolution
=== Specification Status
+[[white_check_mark-complete]]
==== β
Complete
* [x] Type system documentation (Lean 4 notation)
* [x] Refinement types (BoundedNat, NonEmptyString, etc.)
-* [x] Dependent types (Vector, Tracked, PromptScores, etc.)
+* [x] Dependent types (Vector, Tracked, Prompores, etc.)
* [x] Proof obligations and tactics
* [x] Complete examples (BoFIG case study)
* [x] Normalization types (functional dependencies, normal forms)
@@ -92,15 +78,17 @@ types for databases
* [x] *Lexical specification* (NEW: 2026-02-01)
* [x] *Railroad diagrams* (NEW: 2026-02-01)
+[[arrows_counterclockwise-in-progress]]
==== π In Progress
-* [ ] Reference implementation (Lean 4 parser + type checker)
+* [ ] Reference implementation (Lean 4 parser {plus} type checker)
* [ ] Proof automation tactics library
* [ ] IDE integration (VSCode extension)
+[[clipboard-planned]]
==== π Planned
-* [ ] Formal semantics in Lean 4 (operational + type soundness)
+* [ ] Formal semantics in Lean 4 (operational {plus} type soundness)
* [ ] Performance benchmarks
* [ ] User study (developer experience)
@@ -109,15 +97,15 @@ types for databases
==== Type System
* *Refinement types:* Values with compile-time constraints
-** `+BoundedNat 0 100+` - Natural numbers in [0, 100]
-** `+NonEmptyString+` - Strings that cannot be empty
-** `+Confidence+` - Floats in [0.0, 1.0]
+** `BoundedNat 0 100` - Natural numbers in ++[++0, 100++]++
+** `NonEmptyString` - Strings that cannot be empty
+** `Confidence` - Floats in ++[++0.0, 1.0++]++
* *Dependent types:* Types that depend on values
-** `+Vector Ξ± n+` - Arrays of exactly n elements
-** `+Tracked Ξ±+` - Values with mandatory provenance
-** `+PromptScores+` - PROMPT framework scores with computed overall
+** `Vector Ξ± n` - Arrays of exactly n elements
+** `Tracked Ξ±` - Values with mandatory provenance
+** `Prompores` - PROMPT framework scores with computed overall
* *Proof obligations:* Compile-time verification
-** `+WITH_PROOF { score_valid: by lithoglyph_prompt }+`
+** `WITH++_++PROOF ++{++ score++_++valid: by lithoglyph++_++prompt }`
** Automatic proof search (omega, simp, decide)
** Manual proofs for complex cases
@@ -129,7 +117,7 @@ types for databases
CREATE COLLECTION evidence (
id : UUID PRIMARY KEY,
title : NonEmptyString,
- prompt_scores : PromptScores
+ prompt_scores : Prompores
) WITH DEPENDENT_TYPES, TARGET_NORMAL_FORM BCNF;
----
@@ -217,7 +205,7 @@ Primitive ::= Nat | Int | String | Bool | Float | UUID | Timestamp
Refined ::= BoundedNat min max | BoundedFloat min max
| NonEmptyString | Email | Confidence
-Dependent ::= Vector Ξ± n | Tracked Ξ± | PromptScores
+Dependent ::= Vector Ξ± n | Tracked Ξ± | Prompores
| NavigationPath ordering | Claim confidence
Function ::= Ξ± -> Ξ² | (params) -> Ξ²
@@ -229,21 +217,24 @@ Quantified ::= β (x : Ξ±), P x | β (x : Ξ±), P x
=== Implementation Status
+[[phase-1-refinement-types-white_check_mark-milestone-1-4-complete]]
==== Phase 1: Refinement Types (β
Milestone 1-4 Complete)
-* [x] Lean 4 project setup (v4.15.0 + Mathlib4)
+* [x] Lean 4 project setup (v4.15.0 {plus} Mathlib4)
* [x] BoundedNat, BoundedInt with proofs
* [x] NonEmptyString, Confidence
-* [x] PromptScores with auto-computed overall
+* [x] Prompores with auto-computed overall
* [x] Provenance tracking (ActorId, Rationale, Tracked)
+[[phase-2-zig-ffi-bridge-hourglass_flowing_sand-milestone-5---next]]
==== Phase 2: Zig FFI Bridge (β³ Milestone 5 - Next)
-* [ ] `+bridge/lith_types.zig+` - FFI type definitions
-* [ ] `+bridge/lith_insert.zig+` - Insert with proof blob
-* [ ] Lean 4 @[extern] declarations
+* [ ] `bridge/lith++_++types.zig` - FFI type definitions
+* [ ] `bridge/lith++_++insert.zig` - Insert with proof blob
+* [ ] Lean 4 @++[++extern++]++ declarations
* [ ] Integration tests
+[[phase-3-gql-parser-clipboard-milestone-6---blocked-on-m5]]
==== Phase 3: GQL Parser (π Milestone 6 - Blocked on M5)
* [ ] Parser from EBNF grammar (NOW UNBLOCKED - grammar complete!)
@@ -282,17 +273,17 @@ lossless_tactic -- Lossless transformation proofs
==== Adding New Types
[arabic]
-. Define type in Lean 4 (`+src/GqlDt/Types/YourType.lean+`)
+. Define type in Lean 4 (`src/GqlDt/Types/YourType.lean`)
. Add constructor proofs
. Add to type system spec (Section 3 or 4)
-. Add to EBNF grammar (`++` or `++`)
+. Add to EBNF grammar (`++<++refined-type++>++` or `++<++dependent-type++>++`)
. Add examples to spec (Section 10)
==== Adding New Syntax
[arabic]
-. Update EBNF grammar (`+GQL-DT-Grammar.ebnf+`)
-. Update railroad diagrams (`+GQL-DT-Railroad-Diagrams.md+`)
+. Update EBNF grammar (`GQL-DT-Grammar.ebnf`)
+. Update railroad diagrams (`GQL-DT-Railroad-Diagrams.adoc`)
. Update lexical spec if new keywords/operators
. Add to main spec with examples
. Implement in parser (once M6 starts)
@@ -311,22 +302,21 @@ lossless_tactic -- Lossless transformation proofs
[arabic]
. *Lean 4 Reference:* https://lean-lang.org/
-. *Mathlib4 Documentation:*
-https://leanprover-community.github.io/mathlib4_docs/
+. *Mathlib4 Documentation:* https://leanprover-community.github.io/mathlib4_docs/
. *Idris 2 Tutorial:* https://idris2.readthedocs.io/
==== Related Work
[arabic]
. *Liquid Haskell:* Refinement types for Haskell
-. **F*:** Dependent types + SMT solving
+. __F_:_++*++ Dependent types {plus} SMT solving
. *Dafny:* Verification-aware programming language
. *Coq:* Proof assistant with dependent types
==== Database Theory
[arabic]
-. *Functional Dependencies:* Armstrongβs Axioms (1974)
+. *Functional Dependencies:* Armstrong's Axioms (1974)
. *Normal Forms:* Codd (1NF-3NF), Boyce-Codd (BCNF)
. *Multi-Valued Dependencies:* Fagin (4NF)
. *Proof-Carrying Code:* Necula (1997)
@@ -335,8 +325,8 @@ https://leanprover-community.github.io/mathlib4_docs/
All specification documents are licensed under *CC-BY-SA-4.0*.
-*SPDX-License-Identifier:* CC-BY-SA-4.0 *SPDX-FileCopyrightText:* 2026
-Jonathan D.A. Jewell (@hyperpolymath)
+*SPDX-License-Identifier:* CC-BY-SA-4.0
+*SPDX-FileCopyrightText:* 2026 Jonathan D.A. Jewell (@hyperpolymath)
=== Contact
@@ -347,5 +337,6 @@ Jonathan D.A. Jewell (@hyperpolymath)
'''''
-*Last Updated:* 2026-02-01 *Specification Version:* 1.0.0
+*Last Updated:* 2026-02-01
+*Specification Version:* 1.0.0
*Implementation Version:* 0.2.0 (65% complete, Milestones 1-4 done)
diff --git a/src/Gnpl.lean b/src/Gnpl.lean
new file mode 100644
index 0000000..fcf01a2
--- /dev/null
+++ b/src/Gnpl.lean
@@ -0,0 +1,5 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Gnpl.Core
+import Gnpl.Surface
+import Gnpl.Json
diff --git a/src/Gnpl/Core.lean b/src/Gnpl/Core.lean
new file mode 100644
index 0000000..2851d28
--- /dev/null
+++ b/src/Gnpl/Core.lean
@@ -0,0 +1,172 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Std
+
+/-! Direct-evidence narration. No inference rules or probabilistic combination
+are assumed. A claim assigns a value to a declared single-valued subject/slot.
+The kernel depends only on Lean/Std, not the experimental storage substrate. -/
+namespace Gnpl
+
+structure Claim where
+ subject : String
+ slot : String
+ value : String
+ deriving Repr, DecidableEq
+
+structure Evidence where
+ id : String
+ source : String
+ claim : Claim
+ rationale : String
+ confidence : Nat
+ audience : List String
+ withdrawn : Bool
+ deriving Repr, DecidableEq
+
+/-- An immutable evidence snapshot; list order makes no temporal/causal claim. -/
+structure Fabula where
+ snapshot : String
+ revision : Nat
+ evidence : List Evidence
+ deriving Repr, DecidableEq
+
+structure Focalization where
+ actor : String
+ minimumConfidence : Nat
+ deriving Repr, DecidableEq
+
+structure AssertionRequest where
+ claim : Claim
+ evidenceId : String
+ deriving Repr, DecidableEq
+
+/-- Assertion order is the declared telling order, not an inferred event order. -/
+structure Projection where
+ name : String
+ focalization : Focalization
+ assertions : List AssertionRequest
+ deriving Repr, DecidableEq
+
+def nonblank (s : String) : Bool := !s.trim.isEmpty
+
+def Claim.wellFormed (c : Claim) : Bool :=
+ nonblank c.subject && nonblank c.slot && nonblank c.value
+
+def Evidence.wellFormed (e : Evidence) : Bool :=
+ nonblank e.id && nonblank e.source && e.claim.wellFormed &&
+ nonblank e.rationale && e.confidence β€ 100
+
+def Fabula.wellFormed (f : Fabula) : Bool :=
+ nonblank f.snapshot && f.evidence.all Evidence.wellFormed &&
+ decide (f.evidence.map Evidence.id).Nodup
+
+def Claim.conflicts (a b : Claim) : Bool :=
+ a.subject == b.subject && a.slot == b.slot && a.value != b.value
+
+def Projection.wellFormed (p : Projection) : Bool :=
+ nonblank p.name && nonblank p.focalization.actor &&
+ p.focalization.minimumConfidence β€ 100 && !p.assertions.isEmpty &&
+ p.assertions.all (fun r => r.claim.wellFormed && nonblank r.evidenceId) &&
+ decide (p.assertions.map AssertionRequest.claim).Nodup &&
+ !p.assertions.any (fun a => p.assertions.any (fun b => a.claim.conflicts b.claim))
+
+/-- Support is traceability and admission under a stance, never external truth. -/
+def Supports (f : Fabula) (s : Focalization) (r : AssertionRequest) (e : Evidence) : Prop :=
+ e β f.evidence β§ e.id = r.evidenceId β§ e.claim = r.claim β§
+ e.withdrawn = false β§ s.actor β e.audience β§ e.wellFormed = true β§
+ s.minimumConfidence β€ e.confidence
+
+instance (f : Fabula) (s : Focalization) (r : AssertionRequest) (e : Evidence) :
+ Decidable (Supports f s r e) := by
+ unfold Supports
+ infer_instance
+
+/-- Indexed by the exact snapshot, stance and requested assertion. -/
+structure Warrant (f : Fabula) (s : Focalization) (r : AssertionRequest) where
+ evidence : Evidence
+ support : Supports f s r evidence
+
+/-- The index fixes both the claims and their telling order. -/
+inductive Narration (f : Fabula) (s : Focalization) : List AssertionRequest β Type where
+ | nil : Narration f s []
+ | cons {r : AssertionRequest} {rs : List AssertionRequest}
+ (warrant : Warrant f s r) (rest : Narration f s rs) : Narration f s (r :: rs)
+
+structure Account (f : Fabula) (p : Projection) where
+ snapshotValid : f.wellFormed = true
+ projectionValid : p.wellFormed = true
+ narration : Narration f p.focalization p.assertions
+
+inductive RefusalCode where
+ | invalidSnapshot | invalidProjection | missingEvidence | evidenceWithdrawn
+ | inaccessibleEvidence | claimMismatch | belowThreshold | invalidEvidence
+ deriving Repr, BEq, DecidableEq
+
+structure Refusal where
+ code : RefusalCode
+ evidenceId : String := ""
+ deriving Repr, BEq, DecidableEq
+
+def checkWarrant (f : Fabula) (s : Focalization) (r : AssertionRequest) :
+ Except Refusal (Warrant f s r) := do
+ let some e := f.evidence.find? (fun e => e.id == r.evidenceId)
+ | throw β¨.missingEvidence, r.evidenceIdβ©
+ if e.withdrawn then throw β¨.evidenceWithdrawn, r.evidenceIdβ©
+ if !e.audience.contains s.actor then throw β¨.inaccessibleEvidence, r.evidenceIdβ©
+ if e.claim != r.claim then throw β¨.claimMismatch, r.evidenceIdβ©
+ if e.confidence < s.minimumConfidence then throw β¨.belowThreshold, r.evidenceIdβ©
+ if h : Supports f s r e then pure β¨e, hβ©
+ else throw β¨.invalidEvidence, r.evidenceIdβ©
+
+def checkNarration (f : Fabula) (s : Focalization) :
+ (rs : List AssertionRequest) β Except Refusal (Narration f s rs)
+ | [] => .ok .nil
+ | r :: rs => do
+ let w β checkWarrant f s r
+ let rest β checkNarration f s rs
+ pure (.cons w rest)
+
+def narrate (f : Fabula) (p : Projection) : Except Refusal (Account f p) :=
+ if hf : f.wellFormed = true then
+ if hp : p.wellFormed = true then do
+ let narration β checkNarration f p.focalization p.assertions
+ pure β¨hf, hp, narrationβ©
+ else .error β¨.invalidProjection, ""β©
+ else .error β¨.invalidSnapshot, ""β©
+
+/-- Counterfactual view only: does not mutate or persist the original snapshot. -/
+def withdraw (f : Fabula) (id : String) : Except Refusal Fabula :=
+ if f.evidence.any (fun e => e.id == id) then
+ .ok { f with
+ revision := f.revision + 1
+ evidence := f.evidence.map (fun e => if e.id == id then { e with withdrawn := true } else e) }
+ else .error β¨.missingEvidence, idβ©
+
+/-- A withdrawn item cannot satisfy the direct-evidence warrant rule. -/
+theorem withdrawn_cannot_support (f : Fabula) (s : Focalization)
+ (r : AssertionRequest) (e : Evidence) (h : e.withdrawn = true) :
+ Β¬ Supports f s r e := by
+ intro hs
+ have active : e.withdrawn = false := hs.2.2.2.1
+ simp [h] at active
+
+def Narration.claims {f : Fabula} {s : Focalization} {rs : List AssertionRequest} :
+ Narration f s rs β List Claim
+ | .nil => []
+ | .cons w rest => w.evidence.claim :: rest.claims
+
+/-- The checked output contains exactly the requested claims, in their order. -/
+theorem narration_preserves_projection {f : Fabula} {s : Focalization}
+ {rs : List AssertionRequest} (n : Narration f s rs) :
+ n.claims = rs.map AssertionRequest.claim := by
+ induction n with
+ | nil => rfl
+ | cons w rest ih =>
+ have matched := w.support.2.2.1
+ simp [Narration.claims, matched, ih]
+
+/-- A limited relation on the single-valued claim fragment, not adjudication. -/
+def rival {f : Fabula} {a b : Projection} (_ : Account f a) (_ : Account f b) : Bool :=
+ a.assertions.any (fun x => b.assertions.any (fun y => x.claim.conflicts y.claim))
+
+end Gnpl
diff --git a/src/Gnpl/Json.lean b/src/Gnpl/Json.lean
new file mode 100644
index 0000000..74eb797
--- /dev/null
+++ b/src/Gnpl/Json.lean
@@ -0,0 +1,73 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Gnpl.Core
+import Lean.Data.Json
+
+namespace Gnpl.Wire
+open Lean
+
+private def fields (j : Json) (allowed : List String) : Except String Unit := do
+ let object β j.getObj?
+ for key in object.fold (fun keys key _ => key :: keys) [] do
+ if !allowed.contains key then throw s!"Unknown field: {key}"
+
+private def claimFromJson (j : Json) : Except String Claim := do
+ fields j ["subject", "slot", "value"]
+ pure β¨β j.getObjValAs? String "subject", β j.getObjValAs? String "slot",
+ β j.getObjValAs? String "value"β©
+
+private def evidenceFromJson (j : Json) : Except String Evidence := do
+ fields j ["id", "source", "claim", "rationale", "confidence", "audience", "withdrawn"]
+ pure β¨β j.getObjValAs? String "id", β j.getObjValAs? String "source",
+ β claimFromJson (β j.getObjVal? "claim"), β j.getObjValAs? String "rationale",
+ β j.getObjValAs? Nat "confidence", β j.getObjValAs? (List String) "audience",
+ β j.getObjValAs? Bool "withdrawn"β©
+
+/-- Versioned evidence import, separate from the narration surface. The import
+boundary trusts source attribution, audience declarations and recorded scores. -/
+def decodeFabula (text : String) : Except String Fabula := do
+ let j β Json.parse text
+ fields j ["format", "snapshot", "revision", "evidence"]
+ let format β j.getObjValAs? String "format"
+ if format != "gnpl-evidence-v1" then throw "Unsupported evidence format"
+ let evidence β (β (β j.getObjVal? "evidence").getArr?).toList.mapM evidenceFromJson
+ pure β¨β j.getObjValAs? String "snapshot", β j.getObjValAs? Nat "revision", evidenceβ©
+
+def claimToJson (c : Claim) : Json := Json.mkObj [
+ ("subject", toJson c.subject), ("slot", toJson c.slot), ("value", toJson c.value)]
+
+private def narrationToJson {f : Fabula} {s : Focalization} {rs : List AssertionRequest} :
+ Narration f s rs β List Json
+ | .nil => []
+ | .cons w rest => Json.mkObj [
+ ("claim", claimToJson w.evidence.claim),
+ ("warrant", Json.mkObj [
+ ("rule", toJson ("direct-evidence" : String)),
+ ("evidence", toJson w.evidence.id), ("source", toJson w.evidence.source),
+ ("rationale", toJson w.evidence.rationale),
+ ("declaredConfidence", toJson w.evidence.confidence)])] :: narrationToJson rest
+
+def accountToJson {f : Fabula} {p : Projection} (a : Account f p) : Json :=
+ Json.mkObj [
+ ("format", toJson ("gnpl-account-v1" : String)),
+ ("status", toJson ("warranted" : String)), ("account", toJson p.name),
+ ("snapshot", toJson f.snapshot), ("revision", toJson f.revision),
+ ("focalization", Json.mkObj [("actor", toJson p.focalization.actor),
+ ("minimumConfidence", toJson p.focalization.minimumConfidence)]),
+ ("assertions", toJson (narrationToJson a.narration))]
+
+def Refusal.codeName : RefusalCode β String
+ | .invalidSnapshot => "invalid-snapshot"
+ | .invalidProjection => "invalid-projection"
+ | .missingEvidence => "missing-evidence"
+ | .evidenceWithdrawn => "evidence-withdrawn"
+ | .inaccessibleEvidence => "inaccessible-evidence"
+ | .claimMismatch => "claim-mismatch"
+ | .belowThreshold => "below-threshold"
+ | .invalidEvidence => "invalid-evidence"
+
+def refusalToJson (r : Refusal) : Json := Json.mkObj [
+ ("status", toJson ("refused" : String)), ("code", toJson (Refusal.codeName r.code)),
+ ("evidence", toJson r.evidenceId)]
+
+end Gnpl.Wire
diff --git a/src/Gnpl/Surface.lean b/src/Gnpl/Surface.lean
new file mode 100644
index 0000000..1863136
--- /dev/null
+++ b/src/Gnpl/Surface.lean
@@ -0,0 +1,68 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Gnpl.Core
+import Lean.Data.Json
+
+namespace Gnpl.Surface
+open Lean
+
+inductive Token where
+ | word : String β Token
+ | quoted : String β Token
+ deriving Repr, BEq
+
+private def quoted (acc : List Char) (escaped : Bool) :
+ List Char β Except String (String Γ List Char)
+ | [] => .error "Unterminated quoted string"
+ | c :: cs =>
+ if c == '"' && !escaped then do
+ let json β Json.parse (String.mk (('"' :: acc).reverse))
+ let value β json.getStr?
+ pure (value, cs)
+ else quoted (c :: acc) (c == '\\' && !escaped) cs
+
+private def scan : Nat β List Char β Except String (List Token)
+ | _, [] => .ok []
+ | 0, _ => .error "Token budget exhausted"
+ | fuel + 1, chars@(c :: cs) => do
+ if c.isWhitespace then scan fuel cs
+ else if c == '"' then
+ let (value, rest) β quoted ['"'] false cs
+ let tokens β scan fuel rest
+ pure (.quoted value :: tokens)
+ else
+ let word := chars.takeWhile (fun c => !c.isWhitespace && c != '"')
+ let tokens β scan fuel (chars.drop word.length)
+ pure (.word (String.mk word) :: tokens)
+
+def tokenizeLine (line : String) : Except String (List Token) :=
+ scan (line.length + 1) line.toList
+
+private def assertion (line : Nat) : List Token β Except String AssertionRequest
+ | [.word "assert", .quoted subject, .quoted slot, .quoted value,
+ .word "citing", .quoted evidenceId] =>
+ .ok β¨β¨subject, slot, valueβ©, evidenceIdβ©
+ | _ => .error s!"Line {line}: expected assert SUBJECT SLOT VALUE citing EVIDENCE"
+
+/-- One complete projection. Quoted strings use JSON escaping; comments occupy
+their own lines. No trailing clauses or extra accounts are silently discarded. -/
+def parse (source : String) : Except String Projection := do
+ let mut lines : List (Nat Γ List Token) := []
+ for (index, text) in source.splitOn "\n" |>.enum do
+ let line := text.trim
+ if line.isEmpty || line.startsWith "--" then continue
+ match tokenizeLine line with
+ | .error e => throw s!"Line {index + 1}: {e}"
+ | .ok tokens => lines := (index + 1, tokens) :: lines
+ match lines.reverse with
+ | (_, [.word "account", .quoted name]) ::
+ (_, [.word "focalized", .word "by", .quoted actor]) ::
+ (_, [.word "threshold", .word score]) :: rest =>
+ let some minimum := score.toNat?
+ | throw "Threshold must be a natural number in [0, 100]"
+ if minimum > 100 then throw "Threshold must be in [0, 100]"
+ let assertions β rest.mapM (fun (line, tokens) => assertion line tokens)
+ pure β¨name, β¨actor, minimumβ©, assertionsβ©
+ | _ => throw "Expected account NAME, focalized by ACTOR, threshold SCORE, then assertions"
+
+end Gnpl.Surface
diff --git a/src/GnplMain.lean b/src/GnplMain.lean
new file mode 100644
index 0000000..4990047
--- /dev/null
+++ b/src/GnplMain.lean
@@ -0,0 +1,52 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Gnpl
+
+open Gnpl Lean
+
+private def emit (j : Json) : IO Unit := IO.println j.compress
+
+private def inputError (message : String) : IO UInt32 := do
+ emit (Json.mkObj [("status", toJson ("input-error" : String)), ("message", toJson message)])
+ return 2
+
+private def loadInputs (evidencePath projectionPath : String) : IO (Except String (Fabula Γ Projection)) := do
+ try
+ let evidence β IO.FS.readFile evidencePath
+ let projection β IO.FS.readFile projectionPath
+ return do
+ let fabula β Wire.decodeFabula evidence
+ let plan β Surface.parse projection
+ pure (fabula, plan)
+ catch e => return .error e.toString
+
+private def run (f : Fabula) (p : Projection) (withdrawId : Option String) : IO UInt32 := do
+ match narrate f p with
+ | .error refusal => emit (Wire.refusalToJson refusal); return 1
+ | .ok before =>
+ match withdrawId with
+ | none => emit (Wire.accountToJson before); return 0
+ | some id =>
+ match withdraw f id with
+ | .error refusal => emit (Wire.refusalToJson refusal); return 1
+ | .ok changed =>
+ let (status, after, code) := match narrate changed p with
+ | .ok account => ("preserved", Wire.accountToJson account, 0)
+ | .error refusal => ("invalidated", Wire.refusalToJson refusal, 1)
+ emit (Json.mkObj [
+ ("format", toJson ("gnpl-counterfactual-v1" : String)),
+ ("status", toJson status), ("withdrawnEvidence", toJson id),
+ ("before", Wire.accountToJson before), ("after", after)])
+ return code.toUInt32
+
+def main (args : List String) : IO UInt32 := do
+ let params := match args with
+ | ["narrate", "--evidence", e, "--projection", p] => some (e, p, none)
+ | ["counterfactual", "--evidence", e, "--projection", p, "--withdraw", id] =>
+ some (e, p, some id)
+ | _ => none
+ let some (e, p, withdrawal) := params
+ | inputError "Usage: gnpl narrate --evidence FILE --projection FILE | gnpl counterfactual --evidence FILE --projection FILE --withdraw ID"
+ match β loadInputs e p with
+ | .error message => inputError message
+ | .ok (f, plan) => run f plan withdrawal
diff --git a/src/GqlDt/AST.lean b/src/GqlDt/AST.lean
index 74ddd05..a975a52 100644
--- a/src/GqlDt/AST.lean
+++ b/src/GqlDt/AST.lean
@@ -138,6 +138,7 @@ inductive TypedValue : TypeExpr β Type where
| bool : Bool β TypedValue .bool
| float : Float β TypedValue .float
| boundedNat : (min max : Nat) β BoundedNat min max β TypedValue (.boundedNat min max)
+ | confidence : BoundedNat 0 100 β TypedValue .confidence
| nonEmptyString : NonEmptyString β TypedValue .nonEmptyString
| promptScores : PromptScores β TypedValue .promptScores
@@ -243,6 +244,7 @@ instance {t : TypeExpr} : Repr (TypedValue t) where
| .bool b, _ => "TypedValue.bool " ++ repr b
| .float f, _ => "TypedValue.float " ++ repr f
| .boundedNat _ _ _, _ => "TypedValue.boundedNat"
+ | .confidence score, _ => "TypedValue.confidence " ++ repr score.val
| .nonEmptyString _, _ => "TypedValue.nonEmptyString"
| .promptScores _, _ => "TypedValue.promptScores"
@@ -339,6 +341,7 @@ structure InsertProofObligation {schema : Schema} (stmt : InsertStmt schema) whe
def satisfiesConstraints {t : TypeExpr} (v : TypedValue t) : Prop :=
match t, v with
| .boundedNat min max, .boundedNat _ _ bn => bn.val β₯ min β§ bn.val β€ max
+ | .confidence, .confidence score => score.val β€ 100
| .nonEmptyString, .nonEmptyString nes => nes.val.length > 0
| _, _ => True -- Other types checked structurally
diff --git a/src/GqlDt/IR.lean b/src/GqlDt/IR.lean
index 65760a7..2677cb1 100644
--- a/src/GqlDt/IR.lean
+++ b/src/GqlDt/IR.lean
@@ -247,8 +247,8 @@ def generateIR_Select
-- CBOR Serialization
-- ============================================================================
-/-- Serialize typed value to CBOR (stub) -/
-private axiom serializeTypedValueCBOR : (Ξ£ t : TypeExpr, TypedValue t) β CBORValue
+/-- Use the implemented value codec; no separate axiomatic encoder. -/
+private def serializeTypedValueCBOR := Serialization.serializeTypedValueCBOR
/-- Serialize PermissionMetadata to CBOR -/
private def serializePermissions (perms : PermissionMetadata) : CBORValue :=
@@ -260,7 +260,7 @@ private def serializePermissions (perms : PermissionMetadata) : CBORValue :=
]
/-- Serialize INSERT to CBOR -/
-private noncomputable def serializeInsert {schema : Schema} (stmt : IR.Insert schema) : ByteArray :=
+private def serializeInsert {schema : Schema} (stmt : IR.Insert schema) : ByteArray :=
let values := stmt.values.map (fun tv => serializeTypedValueCBOR tv)
let cbor := CBORValue.map [
(.textString "type", .textString "insert"),
@@ -297,7 +297,7 @@ private def serializeSelect (stmt : IR.Select Unit) : ByteArray :=
Serialization.encodeCBOR cbor
/-- Serialize UPDATE to CBOR -/
-private noncomputable def serializeUpdate {schema : Schema} (stmt : IR.Update schema) : ByteArray :=
+private def serializeUpdate {schema : Schema} (stmt : IR.Update schema) : ByteArray :=
let assignmentsCBOR := .array (stmt.assignments.map fun a =>
.map [
(.textString "column", .textString a.column),
@@ -335,7 +335,7 @@ private def serializeNormalize {schema : Schema} (stmt : IR.Normalize schema) :
Serialization.encodeCBOR cbor
/-- Serialize IR to CBOR bytes for network transport -/
-noncomputable def serializeIR (ir : IR) : ByteArray :=
+def serializeIR (ir : IR) : ByteArray :=
match ir with
| .insert stmt => serializeInsert stmt
| .select stmt => serializeSelect stmt
@@ -345,7 +345,8 @@ noncomputable def serializeIR (ir : IR) : ByteArray :=
/-- Deserialize CBOR bytes to IR (stub) -/
-- TODO: Implement full CBOR deserialization with schema reconstruction
-axiom deserializeIR (bytes : ByteArray) : Except String IR
+def deserializeIR (_bytes : ByteArray) : Except String IR :=
+ .error "IR decoding requires schema reconstruction and proof validation; not implemented"
-- ============================================================================
-- Permission Validation
@@ -434,6 +435,7 @@ private def valueToSQL {t : TypeExpr} (v : TypedValue t) : String :=
match v with
| .nat n => toString n
| .boundedNat _ _ bn => toString bn.val -- BOUNDS LOST!
+ | .confidence score => toString score.val
| .nonEmptyString nes => s!"'{nes.val}'" -- NON-EMPTY GUARANTEE LOST!
| _ => "NULL" -- TODO: Handle all types
@@ -555,6 +557,7 @@ def typedValueToString : {t : TypeExpr} β TypedValue t β String
| _, .bool b => toString b
| _, .float f => toString f
| _, .boundedNat _ _ bn => toString bn.val
+ | _, .confidence score => toString score.val
| _, .nonEmptyString nes => nes.val
| _, .promptScores ps => toString ps.overall.val
diff --git a/src/GqlDt/Lexer.lean b/src/GqlDt/Lexer.lean
index 59e8cb2..efd3c94 100644
--- a/src/GqlDt/Lexer.lean
+++ b/src/GqlDt/Lexer.lean
@@ -227,7 +227,7 @@ def proofKeywords : List (String Γ TokenType) := [
("WITH_PROOF", .kwWithProof), ("THEOREM", .kwTheorem),
("PROOF", .kwProof), ("QED", .kwQed),
("omega", .kwOmega), ("decide", .kwDecide),
- ("simp", .kwSimp), ("sorry", .kwSorry)
+ ("simp", .kwSimp), ("sorry", .kwSorry) -- hypatia: allow code_safety/sorry -- Recognises the forbidden proof-hole keyword; this string is not a proof. CI checks proof positions and narration axioms.
]
def lithoglyphKeywords : List (String Γ TokenType) := [
diff --git a/src/GqlDt/Parser.lean b/src/GqlDt/Parser.lean
index f5540b7..63853ea 100644
--- a/src/GqlDt/Parser.lean
+++ b/src/GqlDt/Parser.lean
@@ -42,7 +42,7 @@ Typed IR (ready for execution)
-/
-- Universe declaration for polymorphic Parser
-universe u
+universe u v
-- ============================================================================
-- Parser State
@@ -75,6 +75,13 @@ instance : Monad Parser where
| .ok x s' => f x s'
| .error msg s' => .error msg s'
+/-- Bind across universes: typed projections live in Type 1, tokens in Type.
+The ordinary Monad instance is homogeneous and cannot perform this bind. -/
+def bindAcross {Ξ± : Type u} {Ξ² : Type v} (p : Parser Ξ±) (f : Ξ± β Parser Ξ²) : Parser Ξ² := fun s =>
+ match p s with
+ | .ok x s' => f x s'
+ | .error msg s' => .error msg s'
+
/-- Fail with error message -/
def fail {Ξ± : Type u} (msg : String) : Parser Ξ± :=
fun s => .error msg s
@@ -120,43 +127,41 @@ def expectIdentifier : Parser String := fun s =>
| none => .error "Expected identifier, got EOF" s
/-- Parse optional element -/
-def optional {Ξ± : Type} (p : Parser Ξ±) : Parser (Option Ξ±) := fun s =>
+def optional {Ξ± : Type u} (p : Parser Ξ±) : Parser (Option Ξ±) := fun s =>
match p s with
| .ok x s' => .ok (some x) s'
- | .error _ _ => .ok none s
-
-/-- Parse zero or more elements -/
--- TODO: Fix infinite loop in type checker
-axiom many {Ξ± : Type} (p : Parser Ξ±) : Parser (List Ξ±)
--- partial def many {Ξ± : Type} (p : Parser Ξ±) : Parser (List Ξ±) := fun s =>
--- match p s with
--- | .ok x s' =>
--- match many p s' with
--- | .ok xs s'' => .ok (x :: xs) s''
--- | .error _ _ => .ok [x] s' -- Should not happen
--- | .error _ _ => .ok [] s
-
-/-- Parse one or more elements -/
--- TODO: Fix after many is fixed
-axiom many1 {Ξ± : Type} (p : Parser Ξ±) : Parser (List Ξ±)
--- def many1 {Ξ± : Type} (p : Parser Ξ±) : Parser (List Ξ±) := do
--- let x β p
--- let xs β many p
--- return x :: xs
-
-/-- Parse elements separated by delimiter -/
--- TODO: Fix infinite loop in type checker
-axiom sepBy {Ξ± Ξ² : Type} (p : Parser Ξ±) (sep : Parser Ξ²) : Parser (List Ξ±)
--- partial def sepBy {Ξ± Ξ² : Type} (p : Parser Ξ±) (sep : Parser Ξ²) : Parser (List Ξ±) := fun s =>
--- match p s with
--- | .ok x s' =>
--- match sep s' with
--- | .ok _ s'' =>
--- match sepBy p sep s'' with
--- | .ok xs s''' => .ok (x :: xs) s'''
--- | .error _ _ => .ok [x] s'
--- | .error _ _ => .ok [x] s'
--- | .error _ _ => .ok [] s
+ | .error msg s' =>
+ if s'.position > s.position then .error msg s' else .ok none s
+
+/-- Total repetition. Each successful step must consume input; a failure after
+consumption is committed. Fuel is bounded by the initial token count. -/
+private def manyFuel {Ξ± : Type u} (p : Parser Ξ±) : Nat β Parser (List Ξ±)
+ | 0 => fail "Repetition exceeded the token budget"
+ | fuel + 1 => fun s =>
+ match p s with
+ | .error msg s' =>
+ if s'.position > s.position then .error msg s' else .ok [] s
+ | .ok x s' =>
+ if s'.position β€ s.position || s'.position > s.tokens.length then
+ .error "Repeated parser must consume input within the token stream" s'
+ else
+ match manyFuel p fuel s' with
+ | .ok xs s'' => .ok (x :: xs) s''
+ | .error msg s'' => .error msg s''
+
+def many {Ξ± : Type u} (p : Parser Ξ±) : Parser (List Ξ±) := fun s =>
+ manyFuel p (s.tokens.length + 1) s
+
+def many1 {Ξ± : Type u} (p : Parser Ξ±) : Parser (List Ξ±) := do
+ let xs β many p
+ if xs.isEmpty then fail "Expected at least one element" else pure xs
+
+def sepBy {Ξ± : Type u} {Ξ² : Type v} (p : Parser Ξ±) (sep : Parser Ξ²) : Parser (List Ξ±) := do
+ match β optional p with
+ | none => pure []
+ | some x =>
+ let xs β many (bindAcross sep (fun _ => p))
+ pure (x :: xs)
-- ============================================================================
-- Expression Parsing
@@ -219,33 +224,43 @@ def parseTypeExpr : Parser TypeExpr := fun s =>
-- ============================================================================
/-- Parse column list: (col1, col2, col3) -/
-noncomputable def parseColumnList : Parser (List String) := do
+def parseColumnList : Parser (List String) := do
let _ β expect .leftParen
let cols β sepBy expectIdentifier (do let _ β expect .comma; return ())
let _ β expect .rightParen
+ if cols.isEmpty then fail "INSERT needs at least one column"
return cols
/-- Parse column with optional type annotation: name or name : Type -/
def parseColumnWithType : Parser (String Γ Option TypeExpr) := do
let name β expectIdentifier
let typeAnnot β optional (do
- let _ β expect .opDoubleColon
+ let tok β peek
+ match tok with
+ | some t =>
+ if t.type == .opColon || t.type == .opDoubleColon then advance
+ else fail "Expected type annotation"
+ | none => fail "Expected type annotation"
parseTypeExpr)
return (name, typeAnnot)
/-- Parse typed column list: (col1 : Type1, col2 : Type2) -/
-noncomputable def parseTypedColumnList : Parser (List (String Γ TypeExpr)) := do
+def parseTypedColumnList : Parser (List (String Γ TypeExpr)) := do
let _ β expect .leftParen
let cols β sepBy (do
let name β expectIdentifier
- let _ β expect .opDoubleColon
+ let tok β next
+ match tok with
+ | some t => if t.type == .opColon || t.type == .opDoubleColon then pure () else fail "Expected type annotation"
+ | none => fail "Expected type annotation"
let ty β parseTypeExpr
return (name, ty)) (do let _ β expect .comma; return ())
let _ β expect .rightParen
+ if cols.isEmpty then fail "INSERT needs at least one column"
return cols
/-- Parse VALUES clause -/
-noncomputable def parseValues : Parser (List InferredType) := do
+def parseValues : Parser (List InferredType) := do
let _ β expect .kwValues
let _ β expect .leftParen
let vals β sepBy parseLiteral (do let _ β expect .comma; return ())
@@ -264,11 +279,11 @@ def parseRationale : Parser String := fun s =>
| none => .error "Expected RATIONALE value" s'
| .error msg s' => .error msg s'
-/-- Dummy schema for type inference -/
-axiom evidenceSchema : Schema
+/-- The concrete example schema; production callers supply their schema. -/
+def evidenceSchema : Schema := GqlDt.TypeSafe.evidenceSchema
/-- Parse INSERT statement (GQL - no types) -/
-noncomputable def parseInsertGQL : Parser InferredInsert := do
+def parseInsertGQL (schema : Schema := evidenceSchema) : Parser InferredInsert := do
let _ β expect .kwInsert
let _ β expect .kwInto
let table β expectIdentifier
@@ -278,12 +293,12 @@ noncomputable def parseInsertGQL : Parser InferredInsert := do
let _ β optional (expect .semicolon)
-- Type inference happens here
- match inferInsert evidenceSchema table columns values rationale with
+ match inferInsert schema table columns values rationale with
| .ok inferred => return inferred
| .error msg => fail msg
/-- Parse INSERT statement (GQL-DT - explicit types) -/
-noncomputable def parseInsertGQLdt : Parser InferredInsert := do
+def parseInsertGQLdt (schema : Schema := evidenceSchema) : Parser InferredInsert := do
let _ β expect .kwInsert
let _ β expect .kwInto
let table β expectIdentifier
@@ -294,12 +309,14 @@ noncomputable def parseInsertGQLdt : Parser InferredInsert := do
-- Extract columns and types
let columns := typedColumns.map (Β·.1)
- let _expectedTypes := typedColumns.map (Β·.2)
-
- -- Type check values against expected types
- -- TODO: Verify values match expected types
- match inferInsert evidenceSchema table columns values rationale with
- | .ok inferred => return inferred
+ let expectedTypes := typedColumns.map (Β·.2)
+
+ match inferInsert schema table columns values rationale with
+ | .ok inferred =>
+ if (expectedTypes.zip (inferred.inferredValues.map (Β·.inferredType))).all
+ (fun (expected, actual) => expected == actual) then
+ return inferred
+ else fail "Explicit column types do not match the schema"
| .error msg => fail msg
-- ============================================================================
@@ -343,11 +360,19 @@ inductive Statement where
-- SELECT Parsing
-- ============================================================================
-/-- Parse SELECT list (axiomatized due to Type universe issues) -/
-axiom parseSelectList : Parser SelectList
+/-- Parse the supported SELECT projection; richer refinements require a checker. -/
+def parseSelectList : Parser SelectList := bindAcross peek fun tokOpt =>
+ match tokOpt with
+ | some tok =>
+ if tok.type == .opStar then
+ bindAcross next (fun _ => pure .star)
+ else
+ bindAcross (sepBy expectIdentifier (expect .comma)) fun cols =>
+ if cols.isEmpty then fail "SELECT needs a projection" else pure (.columns cols)
+ | none => fail "Expected SELECT projection"
/-- Parse FROM clause -/
-noncomputable def parseFromClause : Parser FromClause := do
+def parseFromClause : Parser FromClause := do
let _ β expect .kwFrom
let tables β sepBy (do
let name β expectIdentifier
@@ -384,19 +409,17 @@ def parseWhereClause : Parser WhereClause := do
}
/-- Parse ORDER BY clause -/
-noncomputable def parseOrderBy : Parser OrderByClause := do
+def parseOrderBy : Parser OrderByClause := do
let _ β expect .kwOrder
let _ β expect .kwBy
let columns β sepBy (do
let col β expectIdentifier
let direction β optional (do
- let tokOpt β peek
- match tokOpt with
- | some tok =>
- match tok.type with
- | _ => return "ASC" -- TODO: Parse ASC/DESC keywords
- | none => return "ASC"
- )
+ let tok β peek
+ match tok with
+ | some { type := .identifier "ASC", .. } => advance; pure "ASC"
+ | some { type := .identifier "DESC", .. } => advance; pure "DESC"
+ | _ => fail "Expected ASC or DESC")
return (col, direction.getD "ASC")
) (do let _ β expect .comma; return ())
return { columns := columns }
@@ -413,8 +436,16 @@ def parseLimit : Parser Nat := fun s =>
| none => .error "Expected LIMIT value" s'
| .error msg s' => .error msg s'
-/-- Parse SELECT statement (axiomatized due to Type universe issues) -/
-axiom parseSelect : Parser ParsedSelect
+def parseSelect : Parser ParsedSelect :=
+ bindAcross (expect .kwSelect) fun _ =>
+ bindAcross parseSelectList fun selectList =>
+ bindAcross parseFromClause fun from_ =>
+ if from_.tables.isEmpty then fail "FROM needs a table" else
+ bindAcross (optional parseWhereClause) fun where_ =>
+ bindAcross (optional parseOrderBy) fun orderBy =>
+ bindAcross (optional parseLimit) fun limit =>
+ bindAcross (optional (expect .semicolon)) fun _ =>
+ pure { selectList, from_, where_, orderBy, limit }
-- ============================================================================
-- Helper Functions
@@ -443,7 +474,7 @@ private def typedValueFromLiteral (lit : InferredType) : TypedValue (inferTypeFr
-- ============================================================================
/-- Parse UPDATE statement -/
-noncomputable def parseUpdate : Parser ParsedUpdate := do
+def parseUpdate : Parser ParsedUpdate := do
let _ β expect .kwUpdate
let table β expectIdentifier
let _ β expect .kwSet
@@ -477,7 +508,7 @@ noncomputable def parseUpdate : Parser ParsedUpdate := do
-- ============================================================================
/-- Parse DELETE statement -/
-noncomputable def parseDelete : Parser ParsedDelete := do
+def parseDelete : Parser ParsedDelete := do
let _ β expect .kwDelete
let _ β expect .kwFrom
let table β expectIdentifier
@@ -500,69 +531,49 @@ noncomputable def parseDelete : Parser ParsedDelete := do
-- Top-Level Statement Parsing
-- ============================================================================
-/-- Parse any statement (axiomatized due to Type universe issues) -/
-axiom parseStatement : Parser Statement
+def parseStatement (schema : Schema := evidenceSchema) : Parser Statement := fun s =>
+ match s.tokens.get? s.position with
+ | none => .error "Expected statement" s
+ | some tok =>
+ match tok.type with
+ | .kwSelect => (bindAcross parseSelect (fun x => pure (Statement.select x))) s
+ | .kwUpdate => (bindAcross parseUpdate (fun x => pure (Statement.update x))) s
+ | .kwDelete => (bindAcross parseDelete (fun x => pure (Statement.delete x))) s
+ | .kwInsert =>
+ let columns := (s.tokens.drop s.position).takeWhile (Β·.type != .rightParen)
+ if columns.any (fun t => t.type == .opColon || t.type == .opDoubleColon) then
+ (bindAcross (parseInsertGQLdt schema) (fun x => pure (Statement.insertGQLdt x))) s
+ else (bindAcross (parseInsertGQL schema) (fun x => pure (Statement.insertGQL x))) s
+ | _ => .error "Unsupported statement" s
+
+/-- Consume exactly one statement and EOF. Never discard a trailing clause or
+second statement. Callers that need batches must handle each statement explicitly. -/
+def parseTokensComplete (tokens : List Token) (schema : Schema := evidenceSchema)
+ : Except String (List Statement) :=
+ match parseStatement schema { tokens, position := 0 } with
+ | .error msg _ => .error msg
+ | .ok stmt s =>
+ match s.tokens.drop s.position with
+ | [] => .ok [stmt]
+ | [tok] => if tok.type == .eof then .ok [stmt] else .error "Unexpected trailing input"
+ | _ => .error "Unexpected trailing input or multiple statements"
-- ============================================================================
-- Public API
-- ============================================================================
/-- Parse source string to statements -/
-noncomputable unsafe def parse (source : String) : Except String (List Statement) := do
- -- Tokenize
+def parse (source : String) (schema : Schema := evidenceSchema) : Except String (List Statement) :=
match tokenize source with
- | .ok tokens =>
- -- Parse
- let initialState : ParserState := {
- tokens := tokens,
- position := 0
- }
-
- match parseStatement initialState with
- | .ok stmt _ => pure [stmt]
- | .error msg _ => throw msg
- | .error msg => throw msg
-
-/-- Parse and generate IR -/
--- TODO: Fix type inference issues
--- def parseToIR (source : String) (permissions : PermissionMetadata) : Except String IR := do
--- let stmts β parse source
---
--- match stmts.head? with
--- | some (.insertGQL inferred) =>
--- -- Convert InferredInsert to IR.Insert
--- -- TODO: Complete this conversion (needs schema)
--- .error "InferredInsert β IR conversion not yet implemented"
---
--- | some (.select selectStmt) =>
--- .ok (generateIR_Select selectStmt permissions)
---
--- | some (.update updateStmt) =>
--- -- TODO: Generate IR.Update (needs schema)
--- .error "UPDATE β IR conversion not yet implemented"
---
--- | some (.delete deleteStmt) =>
--- -- TODO: Generate IR.Delete (needs schema)
--- .error "DELETE β IR conversion not yet implemented"
---
--- | _ => .error "No statement parsed"
-axiom parseToIR (source : String) (permissions : PermissionMetadata) : Except String IR
-
--- ============================================================================
--- Examples
--- ============================================================================
-
--- TODO: Fix type inference for Statement in examples
--- /-- Example: Parse simple INSERT -/
--- def exampleParseInsert : Except String (List Statement) :=
--- parse "INSERT INTO evidence (title, score) VALUES ('ONS Data', 95) RATIONALE 'Official statistics';"
---
--- #eval exampleParseInsert
---
--- /-- Example: Parse SELECT -/
--- def exampleParseSelect : Except String (List Statement) :=
--- parse "SELECT * FROM evidence;"
---
--- #eval exampleParseSelect
+ | .error msg => .error msg
+ | .ok tokens => parseTokensComplete tokens schema
+
+/-- Parse a selection into the private IR. Mutation lowering needs a schema. -/
+def parseToIR (source : String) (permissions : PermissionMetadata) : Except String IR := do
+ match β parse source with
+ | [.select stmt] => pure (.select {
+ selectList := stmt.selectList, from_ := stmt.from_, where_ := stmt.where_,
+ orderBy := stmt.orderBy, limit := stmt.limit, returning := none, permissions })
+ | _ => .error "Mutation lowering requires a schema: use Pipeline.runPipeline"
end GqlDt.Parser
diff --git a/src/GqlDt/Pipeline.lean b/src/GqlDt/Pipeline.lean
index 516f270..33272ca 100644
--- a/src/GqlDt/Pipeline.lean
+++ b/src/GqlDt/Pipeline.lean
@@ -13,37 +13,21 @@ import GqlDt.Serialization
namespace GqlDt.Pipeline
--- Mark entire namespace as noncomputable due to axiomatized parser functions
-noncomputable section
+section
open Lexer Parser TypeChecker TypeInference IR Serialization Serialization.Types AST Provenance
/-!
-# GQL-DT/GQL Complete Parsing Pipeline
-
-Provides end-to-end processing from source text to executable IR.
-
-**Pipeline Stages:**
-
-```
-Source Text (GQL or GQL-DT)
- β 1. Lexer
-Tokens
- β 2. Parser
-Typed AST (with or without explicit types)
- β 3. Type Checker
-Validated AST (proofs verified)
- β 4. IR Generation
-Typed IR (with proof blobs, permissions)
- β 5. Serialization (optional)
-CBOR bytes / JSON
- β 6. Execution
-Lithoglyph Native or SQL Backend
-```
-
-**Two Modes:**
-- **GQL-DT**: Explicit types + proofs β Compile-time verification
-- **GQL**: Type inference + auto-proofs β Runtime validation fallback
+GNPL's private typed evidence substrate.
+
+This module parses a limited storage notation, checks inserts against the supplied
+schema, and builds IR for in-memory evaluation. It does not implement GNPL's
+accounts, stances or warrants. Historical identifiers in this namespace are
+compatibility details, not names of public languages.
+
+Attached-proof verification, persistent execution and a complete IR wire codec
+are unavailable and return errors. Local dependent witnesses are not transferable
+proof certificates. See docs/executable-boundary.adoc.
-/
-- ============================================================================
@@ -104,25 +88,17 @@ def tokenizeSource (source : String) : Except String (List Token) :=
tokenize source
/-- Stage 2: Parse tokens to AST -/
-noncomputable def parseTokens (tokens : List Token) (_config : PipelineConfig) : Except String (List Statement) := do
- let initialState : ParserState := {
- tokens := tokens,
- position := 0
- }
-
- match parseStatement initialState with
- | .ok stmt _ => .ok [stmt]
- | .error msg _ => .error msg
+def parseTokens (tokens : List Token) (config : PipelineConfig) : Except String (List Statement) :=
+ parseTokensComplete tokens config.schema
/-- Stage 3: Type check AST -/
def typeCheckAST (stmt : Statement) (config : PipelineConfig) : Except String Statement :=
- -- For GQL, type inference already happened in parser
- -- For GQL-DT, verify explicit types and proofs
+ -- Runtime type validation does not check an attached proof. The latter
+ -- needs an implemented verifier and is refused until one is connected.
match config.mode with
| .gql => .ok stmt -- Type inference done, runtime validation will catch errors
| .gqld =>
- -- TODO: Verify proofs
- .ok stmt
+ .error "Attached-proof validation is not implemented"
/-- Convert parser-level ParsedSelect to IR.Select Unit -/
def parsedSelectToIR (ps : ParsedSelect) (permissions : PermissionMetadata) : IR :=
@@ -136,21 +112,6 @@ def parsedSelectToIR (ps : ParsedSelect) (permissions : PermissionMetadata) : IR
permissions := permissions
}
-/-- Proof obligation for inferred INSERT types matching schema columns.
-
- At this point, the TypeInference module has already validated that every
- value matches its schema column type. We encode this as an axiom because
- the dynamic schema lookup in inferInsert already performed the check, but
- recreating that proof structurally at compile-time from the dynamic data
- would require reflecting the schema into the type system (future work).
--/
-axiom inferredInsertTypesMatch (schema : Schema) (columns : List String)
- (values : List (Ξ£ t : TypeExpr, TypedValue t))
- : β i, i < values.length β
- β col β schema.columns,
- col.name = columns.get! i β§
- (values.get! i).1 = col.type
-
/-- Convert an InferredInsert to IR.Insert using the pipeline schema.
Each inferred value is lifted into a dependent (Ξ£ t, TypedValue t) pair,
@@ -179,7 +140,7 @@ def inferredInsertToIR (inferred : InferredInsert) (config : PipelineConfig) : E
| .confidence, .nat n =>
if h1 : 0 β€ n then
if h2 : n β€ 100 then
- some β¨.boundedNat 0 100, .boundedNat 0 100 β¨n, h1, h2β©β©
+ some β¨.confidence, .confidence β¨n, h1, h2β©β©
else none
else none
| _, _ => none
@@ -200,19 +161,17 @@ def inferredInsertToIR (inferred : InferredInsert) (config : PipelineConfig) : E
| .confidence =>
some (serializeProof "Confidence" "value β [0, 100]")
| _ => none
- -- Build IR.Select-style for now: use the select IR path with an insert wrapper
- -- We construct an IR.Insert with a proof obligation discharged by the schema.
- -- Since we validated types above, we use a schema-independent construction
- -- via axiom (the type checker already validated at parse time).
- .ok (.insert {
- table := inferred.table,
- columns := inferred.columns,
- values := values,
- rationale := rationale,
- proofs := proofs,
- permissions := config.permissions,
- typesMatch := inferredInsertTypesMatch config.schema inferred.columns values
- })
+ match TypeChecker.validateInsert config.schema inferred.columns values with
+ | .error msg => .error msg
+ | .ok β¨witnessβ© => .ok (@IR.insert config.schema {
+ table := inferred.table,
+ columns := inferred.columns,
+ values := values,
+ rationale := rationale,
+ proofs := proofs,
+ permissions := config.permissions,
+ typesMatch := witness
+ })
else
.error "RATIONALE must be a non-empty string"
@@ -249,19 +208,43 @@ def generateIRFromAST (stmt : Statement) (config : PipelineConfig) : Except Stri
inferredInsertToIR inferred config
| .insertGQLdt inferred =>
inferredInsertToIR inferred config
- | .select selectStmt =>
- .ok (parsedSelectToIR selectStmt config.permissions)
- | .update updateStmt =>
- .ok (parsedUpdateToIR updateStmt config)
- | .delete deleteStmt =>
- .ok (parsedDeleteToIR deleteStmt config)
+ | .select selectStmt => do
+ if selectStmt.from_.tables.length != 1 ||
+ selectStmt.from_.tables.any (fun t => t.name != config.schema.name || t.alias.isSome) then
+ throw "Selection requires exactly the configured table, without aliases"
+ let known := fun name => config.schema.columns.any (Β·.name == name)
+ match selectStmt.selectList with
+ | .columns cols => if !cols.all known then throw "Unknown projection column"
+ | .star => pure PUnit.unit
+ | .typed _ _ => throw "Refined selection validation is not implemented"
+ if let some wc := selectStmt.where_ then
+ let (name, op, value) := wc.predicate
+ let supported := config.schema.columns.any fun col =>
+ col.name == name && match col.type, value with
+ | .nat, .nat _ | .boundedNat _ _, .nat _ | .confidence, .nat _ => true
+ | .string, .string _ | .nonEmptyString, .string _ | .bool, .bool _ =>
+ op == "=" || op == "!="
+ | _, _ => false
+ if !supported then throw "Predicate type or comparison is unsupported by the in-memory evaluator"
+ if let some ob := selectStmt.orderBy then
+ let supportedOrder := fun name => config.schema.columns.any fun col =>
+ col.name == name && match col.type with
+ | .nat | .boundedNat _ _ | .confidence => true
+ | _ => false
+ if ob.columns.length != 1 || !ob.columns.all (fun c => supportedOrder c.1) then
+ throw "Ordering requires one natural-number column"
+ pure (parsedSelectToIR selectStmt config.permissions)
+ | .update _ =>
+ .error "UPDATE schema validation is not implemented in this pipeline"
+ | .delete _ =>
+ .error "DELETE schema validation is not implemented in this pipeline"
/-- Stage 5: Validate permissions -/
def validateIRPermissions (ir : IR) (_config : PipelineConfig) : Except String Unit :=
validatePermissions ir
/-- Stage 6: Serialize IR -/
-noncomputable def serializeIRToBytes (ir : IR) (_config : PipelineConfig) : ByteArray :=
+def serializeIRToBytes (ir : IR) (_config : PipelineConfig) : ByteArray :=
serializeIR ir -- TODO: Use config.serializationFormat
-- ============================================================================
@@ -269,7 +252,7 @@ noncomputable def serializeIRToBytes (ir : IR) (_config : PipelineConfig) : Byte
-- ============================================================================
/-- Run complete pipeline: Source β IR -/
-noncomputable def runPipeline (source : String) (config : PipelineConfig) : Except String IR :=
+def runPipeline (source : String) (config : PipelineConfig) : Except String IR :=
-- Stage 1: Tokenize
match tokenizeSource source with
| .error msg => .error msg
@@ -296,30 +279,28 @@ noncomputable def runPipeline (source : String) (config : PipelineConfig) : Exce
| .ok () => .ok ir
/-- Run pipeline and serialize to bytes -/
-noncomputable def runPipelineAndSerialize (source : String) (config : PipelineConfig) : Except String ByteArray :=
+def runPipelineAndSerialize (source : String) (config : PipelineConfig) : Except String ByteArray :=
match runPipeline source config with
| .error msg => .error msg
- | .ok ir => .ok (serializeIRToBytes ir config)
+ | .ok _ => .error "Complete IR serialization is not implemented; clauses would be lost"
-- ============================================================================
-- Convenience Functions
-- ============================================================================
/-- Parse GQL query (user tier) -/
-noncomputable def parseGQL (source : String) (userId roleId : String) : Except String IR :=
+def parseGQL (source : String) (userId roleId : String) : Except String IR :=
runPipeline source (defaultGQLConfig userId roleId)
/-- Parse GQL-DT query (admin tier) -/
-noncomputable def parseGQLdt (source : String) (userId roleId : String) : Except String IR :=
+def parseGQLdt (source : String) (userId roleId : String) : Except String IR :=
runPipeline source (defaultGQLdtConfig userId roleId)
/-- Parse and execute query -/
def parseAndExecute (source : String) (config : PipelineConfig) : IO (Except String Unit) := do
match runPipeline source config with
- | .ok ir =>
- -- TODO: Execute IR on Lithoglyph
- IO.println s!"β Parsed successfully: {describeIR ir}"
- .ok (.ok ())
+ | .ok _ =>
+ return .error "Persistent execution is not implemented in this pipeline"
| .error msg =>
IO.println s!"β Parse error: {msg}"
.ok (.error msg)
@@ -341,240 +322,9 @@ structure PipelineError where
def formatError (err : PipelineError) : String :=
s!"{err.stage} error at line {err.line}, column {err.column}:\n{err.message}\n\nSource:\n{err.source}"
--- ============================================================================
--- Examples
--- ============================================================================
-
-/-- Example: Parse GQL INSERT -/
-def exampleParseGQL : Except String IR :=
- parseGQL
- "INSERT INTO evidence (title, score) VALUES ('ONS Data', 95) RATIONALE 'Official statistics';"
- "user123" "journalist"
-
--- #eval! exampleParseGQL
-
-/-- Example: Parse GQL-DT INSERT -/
-def exampleParseGQLdt : Except String IR :=
- parseGQLdt
- "INSERT INTO evidence (title : NonEmptyString, score : BoundedNat 0 100) VALUES ('ONS Data', 95) RATIONALE 'Official statistics';"
- "admin456" "admin"
-
--- #eval! exampleParseGQLdt
-
-/-- Example: Parse SELECT -/
-def exampleParseSelect : Except String IR :=
- parseGQL
- "SELECT * FROM evidence;"
- "user123" "journalist"
-
--- #eval! exampleParseSelect
-
-/-- Example: Complete pipeline with serialization -/
-noncomputable def examplePipelineWithSerialization : IO Unit := do
- let config := defaultGQLConfig "user123" "journalist"
-
- match runPipelineAndSerialize
- "INSERT INTO evidence (title, score) VALUES ('ONS Data', 95) RATIONALE 'Official statistics';"
- config with
- | .ok bytes =>
- IO.println s!"β Parsed and serialized: {bytes.size} bytes (CBOR)"
- | .error msg =>
- IO.println s!"β Error: {msg}"
-
--- ============================================================================
--- Testing & Validation
--- ============================================================================
-
-/-- Test: Valid GQL query should parse -/
-def testValidGQL : IO Bool := do
- match parseGQL "INSERT INTO evidence (title) VALUES ('Test') RATIONALE 'Test';" "test" "user" with
- | .ok _ =>
- IO.println "β Valid GQL query parsed"
- return true
- | .error msg =>
- IO.println s!"β Valid GQL query failed: {msg}"
- return false
-
-/-- Test: Invalid query should error -/
-def testInvalidQuery : IO Bool := do
- match parseGQL "INVALID SYNTAX HERE" "test" "user" with
- | .ok _ =>
- IO.println "β Invalid query should not parse"
- return false
- | .error _ =>
- IO.println "β Invalid query correctly rejected"
- return true
-
-/-- Run all tests -/
-def runTests : IO Unit := do
- IO.println "=== GQL-DT Pipeline Tests ==="
- let _ β testValidGQL
- let _ β testInvalidQuery
- IO.println "=== Tests Complete ==="
-
-end -- noncomputable section
-
--- ============================================================================
--- Computable End-to-End Tests (IR Evaluation)
--- ============================================================================
--- These tests bypass the axiomatized parser and directly construct IR,
--- then evaluate it through the evalIR engine. This demonstrates the
--- INSERT β SELECT round-trip working end-to-end.
-
-section EvalTests
-
-open IR AST Types Provenance TypeSafe
-
-/-- Test permissions for eval examples -/
-private def testPerms : PermissionMetadata := {
- userId := "test-user",
- roleId := "admin",
- validationLevel := .runtime,
- allowedTypes := [],
- timestamp := 0
-}
-
-/-- Test: INSERT a row then SELECT it back -/
-def testInsertSelectRoundTrip : String :=
- -- 1. Build an INSERT IR
- let title := NonEmptyString.mk' "ONS CPI Data"
- let score : BoundedNat 0 100 := β¨95, by omega, by omegaβ©
- let rationale := Rationale.fromString "Official statistics"
- let insertIR : IR := @IR.insert evidenceSchema {
- table := "evidence",
- columns := ["title", "prompt_provenance"],
- values := [
- β¨.nonEmptyString, .nonEmptyString titleβ©,
- β¨.boundedNat 0 100, .boundedNat 0 100 scoreβ©
- ],
- rationale := rationale,
- proofs := [
- serializeProof "NonEmptyString" "length > 0",
- serializeProof "BoundedNat" "value β [0, 100]"
- ],
- permissions := testPerms,
- typesMatch := by
- intro i hi
- cases i with
- | zero =>
- exists { name := "title", type := .nonEmptyString, isPrimaryKey := false, isUnique := false }
- constructor
- Β· simp [evidenceSchema]
- Β· simp
- | succ i =>
- cases i with
- | zero =>
- exists { name := "prompt_provenance", type := .boundedNat 0 100, isPrimaryKey := false, isUnique := false }
- constructor
- Β· simp [evidenceSchema]
- Β· simp
- | succ n =>
- have hlen : List.length
- [Sigma.mk TypeExpr.nonEmptyString (TypedValue.nonEmptyString title),
- Sigma.mk (TypeExpr.boundedNat 0 100) (TypedValue.boundedNat 0 100 score)] = 2 := by
- simp [List.length]
- omega
- }
-
- -- 2. Evaluate INSERT on empty database
- let db := EvalDatabase.empty
- let (db2, insertResult) := evalIR db insertIR
-
- -- 3. Build a SELECT IR
- let selectIR : IR := .select {
- selectList := .star,
- from_ := { tables := [{ name := "evidence", alias := none }] },
- where_ := none,
- orderBy := none,
- limit := none,
- returning := none,
- permissions := testPerms
- }
-
- -- 4. Evaluate SELECT
- let (_, selectResult) := evalIR db2 selectIR
-
- -- 5. Format results
- s!"INSERT result: {insertResult.toString}\nSELECT result:\n{selectResult.toString}"
-
-#eval testInsertSelectRoundTrip
-
-/-- Test: INSERT two rows, then SELECT with WHERE filter -/
-def testInsertAndFilter : String :=
- let rationale := Rationale.fromString "Test data"
- -- Insert row 1
- let insert1 : IR := @IR.insert evidenceSchema {
- table := "data",
- columns := ["name", "score"],
- values := [
- β¨.string, .string "Alice"β©,
- β¨.nat, .nat 90β©
- ],
- rationale := rationale,
- proofs := [],
- permissions := testPerms,
- typesMatch := inferredInsertTypesMatch evidenceSchema ["name", "score"]
- [β¨.string, .string "Alice"β©, β¨.nat, .nat 90β©]
- }
- -- Insert row 2
- let insert2 : IR := @IR.insert evidenceSchema {
- table := "data",
- columns := ["name", "score"],
- values := [
- β¨.string, .string "Bob"β©,
- β¨.nat, .nat 75β©
- ],
- rationale := rationale,
- proofs := [],
- permissions := testPerms,
- typesMatch := inferredInsertTypesMatch evidenceSchema ["name", "score"]
- [β¨.string, .string "Bob"β©, β¨.nat, .nat 75β©]
- }
-
- let db := EvalDatabase.empty
- let (db2, _) := evalIR db insert1
- let (db3, _) := evalIR db2 insert2
-
- -- SELECT with WHERE name = "Alice"
- let selectFiltered : IR := .select {
- selectList := .star,
- from_ := { tables := [{ name := "data", alias := none }] },
- where_ := some { predicate := ("name", "=", .string "Alice"), proof := fun _ => trivial },
- orderBy := none,
- limit := none,
- returning := none,
- permissions := testPerms
- }
- let (_, filteredResult) := evalIR db3 selectFiltered
-
- -- SELECT all with LIMIT 1
- let selectLimited : IR := .select {
- selectList := .star,
- from_ := { tables := [{ name := "data", alias := none }] },
- where_ := none,
- orderBy := none,
- limit := some 1,
- returning := none,
- permissions := testPerms
- }
- let (_, limitedResult) := evalIR db3 selectLimited
-
- s!"WHERE name='Alice': {filteredResult.toString}\nLIMIT 1: {limitedResult.toString}"
-
-#eval testInsertAndFilter
-
-/-- Test: Binary serialization round-trip for BoundedNat -/
-def testBinaryRoundTrip : String :=
- let score : BoundedNat 0 100 := β¨95, by omega, by omegaβ©
- let tv : Ξ£ t : TypeExpr, TypedValue t := β¨.boundedNat 0 100, .boundedNat 0 100 scoreβ©
-
- let bytes := Serialization.serializeTypedValueBinary tv
- match Serialization.deserializeTypedValueBinary bytes with
- | .ok β¨t, _vβ© => s!"Round-trip OK: {bytes.size} bytes, type={t}"
- | .error msg => s!"Round-trip FAILED: {msg}"
-
-#eval testBinaryRoundTrip
+-- Executable positive and negative controls live in test/SubstrateTest.lean.
+-- They exercise source parsing as well as IR evaluation.
-end EvalTests
+end
end GqlDt.Pipeline
diff --git a/src/GqlDt/Serialization.lean b/src/GqlDt/Serialization.lean
index 8d77ca4..f343d62 100644
--- a/src/GqlDt/Serialization.lean
+++ b/src/GqlDt/Serialization.lean
@@ -63,6 +63,9 @@ def serializeTypedValueJSON (tv : Ξ£ t : TypeExpr, TypedValue t) : JsonValue :=
("proof", .string "") -- TODO: Actual proof serialization
]
+ | β¨.confidence, .confidence scoreβ© =>
+ .object [("type", .string "Confidence"), ("value", .number score.val.toFloat)]
+
| β¨.nonEmptyString, .nonEmptyString nesβ© =>
.object [
("type", .string "NonEmptyString"),
@@ -120,6 +123,16 @@ def deserializeTypedValueJSON (json : JsonValue) : Except String (Ξ£ t : TypeExp
.error s!"Value {val} out of bounds [{min}, {max}]"
| _, _, _ => .error "Invalid BoundedNat fields"
+ | some (_, .string "Confidence") =>
+ match fields.find? (Β·.1 = "value") with
+ | some (_, .number value) =>
+ let n := value.toUInt64.toNat
+ if value != n.toFloat then .error "Confidence must be an integer"
+ else if h : n β€ 100 then
+ .ok β¨.confidence, .confidence β¨n, Nat.zero_le n, hβ©β©
+ else .error "Confidence must be in [0, 100]"
+ | _ => .error "Invalid 'value' for Confidence"
+
| some (_, .string "NonEmptyString") =>
let value? := fields.find? (Β·.1 = "value")
match value? with
@@ -143,6 +156,8 @@ def deserializeTypedValueJSON (json : JsonValue) : Except String (Ξ£ t : TypeExp
/-- Serialize TypedValue to CBOR -/
def serializeTypedValueCBOR (tv : Ξ£ t : TypeExpr, TypedValue t) : CBORValue :=
match tv with
+ | β¨.confidence, .confidence scoreβ© =>
+ .tag cborTagConfidence (.map [(.textString "value", .unsigned score.val)])
| β¨.nat, .nat nβ© =>
.unsigned n
@@ -327,9 +342,8 @@ def decodeUnsignedCBOR (d : CBORDecoder) (addInfo : UInt8) : Except String (Nat
else if addInfo == 27 then
-- 8-byte follows (big-endian)
do
- let (_bytes, d') β d.readBytes 8
- -- TODO: Implement UInt64.fromBigEndian for Lean 4.15.0
- let val := 0 -- Stub
+ let (bytes, d') β d.readBytes 8
+ let val := bytes.data.foldl (fun acc byte => acc * 256 + byte.toNat) 0
.ok (val, d')
else
.error s!"Invalid CBOR additional info: {addInfo}"
@@ -356,8 +370,9 @@ partial def decodeCBORValue (d : CBORDecoder) : Except String (CBORValue Γ CBOR
| 3 => -- Text string
let (len, d2) β decodeUnsignedCBOR d1 addInfo
- let (_bytes, d3) β d2.readBytes len
- let str := "" -- TODO: Implement String.fromUTF8 for Lean 4.15.0
+ let (bytes, d3) β d2.readBytes len
+ let some str := String.fromUTF8? bytes
+ | .error "Invalid UTF-8 in CBOR text string"
.ok (.textString str, d3)
| 4 => -- Array
@@ -496,6 +511,9 @@ def serializeTypedValueBinary (tv : Ξ£ t : TypeExpr, TypedValue t) : ByteArray :
-- Tag (0x02) + min (8 bytes) + max (8 bytes) + value (8 bytes)
ByteArray.mk #[0x02] ++ natToLE8 min ++ natToLE8 max ++ natToLE8 bn.val
+ | β¨.confidence, .confidence scoreβ© =>
+ ByteArray.mk #[0x09] ++ natToLE8 score.val
+
| β¨.nonEmptyString, .nonEmptyString nesβ© =>
-- Tag (0x03) + length (4 bytes) + UTF-8 bytes
let utf8 := nes.val.toUTF8
@@ -519,6 +537,13 @@ def deserializeTypedValueBinary (bytes : ByteArray) : Except String (Ξ£ t : Type
else
let tag := bytes.get! 0
match tag with
+ | 0x09 => -- Confidence: an integer admission score in [0, 100]
+ if bytes.size != 9 then .error "Confidence requires exactly 9 bytes"
+ else
+ let n := le8ToNat bytes 1
+ if h : n β€ 100 then
+ .ok β¨.confidence, .confidence β¨n, Nat.zero_le n, hβ©β©
+ else .error "Confidence must be in [0, 100]"
| 0x01 => -- Nat
if bytes.size < 9 then
.error "Insufficient bytes for Nat"
@@ -599,6 +624,7 @@ def toSQLValue (tv : Ξ£ t : TypeExpr, TypedValue t) : String :=
match tv with
| β¨_, .nat nβ© => toString n
| β¨_, .boundedNat _ _ bnβ© => toString bn.val -- BOUNDS LOST!
+ | β¨_, .confidence scoreβ© => toString score.val
| β¨_, .nonEmptyString nesβ© => s!"'{nes.val}'" -- PROOF LOST!
| β¨_, .promptScores scoresβ© => toString scores.overall.val -- SCORES AGGREGATED!
| _ => "NULL"
@@ -606,6 +632,13 @@ def toSQLValue (tv : Ξ£ t : TypeExpr, TypedValue t) : String :=
/-- Convert from SQL value to TypedValue (requires type hint) -/
def fromSQLValue (sqlValue : String) (expectedType : TypeExpr) : Except String (Ξ£ t : TypeExpr, TypedValue t) :=
match expectedType with
+ | .confidence =>
+ match sqlValue.toNat? with
+ | some n =>
+ if h : n β€ 100 then
+ .ok β¨.confidence, .confidence β¨n, Nat.zero_le n, hβ©β©
+ else .error "Confidence must be in [0, 100]"
+ | none => .error "Confidence must be an integer in [0, 100]"
| .nat =>
match sqlValue.toNat? with
| some n => .ok β¨.nat, .nat nβ©
@@ -697,7 +730,17 @@ def deserializeTypedValueFromCBOR (cbor : CBORValue) : Except String (Ξ£ t : Typ
.ok β¨.nat, .nat nβ©
| .tag tag value =>
- if tag == cborTagBoundedNat then
+ if tag == cborTagConfidence then
+ match value with
+ | .map fields =>
+ match fields.find? (fun (k, _) => k == .textString "value") with
+ | some (_, .unsigned n) =>
+ if h : n β€ 100 then
+ .ok β¨.confidence, .confidence β¨n, Nat.zero_le n, hβ©β©
+ else .error "Confidence must be in [0, 100]"
+ | _ => .error "Invalid Confidence CBOR structure"
+ | _ => .error "Confidence tag expects map value"
+ else if tag == cborTagBoundedNat then
match value with
| .map fields =>
-- Extract min, max, value
diff --git a/src/GqlDt/TypeChecker.lean b/src/GqlDt/TypeChecker.lean
index a88d2b2..bb79699 100644
--- a/src/GqlDt/TypeChecker.lean
+++ b/src/GqlDt/TypeChecker.lean
@@ -103,7 +103,7 @@ inductive ValidateResult (P : Prop) where
-- Helper: validate all column/value pairs against the schema, building a proof
-- witness one index at a time. Uses an accumulator that carries the proof for
-- all indices already validated.
-private def validateInsert
+def validateInsert
(schema : Schema)
(columns : List String)
(values : List (Ξ£ t : TypeExpr, TypedValue t))
@@ -214,6 +214,8 @@ def generateProofObligations {schema : Schema} (stmt : InsertStmt schema) : List
match t, v with
| .boundedNat min max, .boundedNat _ _ bn =>
.boundsCheck min max bn.val β¨bn.min_le, bn.le_maxβ© :: acc
+ | .confidence, .confidence score =>
+ .boundsCheck 0 100 score.val β¨score.min_le, score.le_maxβ© :: acc
| .nonEmptyString, .nonEmptyString nes =>
.nonEmpty nes.val nes.nonempty :: acc
| _, _ => acc
diff --git a/src/GqlDt/TypeInference.lean b/src/GqlDt/TypeInference.lean
index 60ed885..a8492ba 100644
--- a/src/GqlDt/TypeInference.lean
+++ b/src/GqlDt/TypeInference.lean
@@ -170,13 +170,13 @@ def selectProofStrategy (result : InferenceResult) : ProofStrategy :=
| .confidence => .omega -- 0 β€ n β§ n β€ 100 uses linear arithmetic
| _ => .admit -- No proof needed
-/-- Generate proof term (as string for now, actual Expr later) -/
-def generateProofTerm (strategy : ProofStrategy) : String :=
+/-- Suggest a tactic; an unavailable strategy cannot manufacture proof text. -/
+def generateProofTerm (strategy : ProofStrategy) : Except String String :=
match strategy with
- | .decide => "by decide"
- | .omega => "by omega"
- | .simp => "by simp"
- | .admit => "sorry" -- Represents fallback to runtime validation (not a proof-position sorry)
+ | .decide => .ok "by decide"
+ | .omega => .ok "by omega"
+ | .simp => .ok "by simp"
+ | .admit => .error "No proof strategy is available; an explicit proof is required"
-- ============================================================================
-- Full INSERT Inference
@@ -200,8 +200,7 @@ def inferInsert
: Except String InferredInsert := do
-- 1. Find schema
- let schemaTable? := schema.columns.isEmpty -- TODO: Real schema lookup
- if schemaTable? then
+ if schema.name != table || schema.columns.isEmpty then
throw s!"Table {table} not found in schema"
-- 2. Check column count matches
diff --git a/test/NarrationProofAudit.lean b/test/NarrationProofAudit.lean
new file mode 100644
index 0000000..c563609
--- /dev/null
+++ b/test/NarrationProofAudit.lean
@@ -0,0 +1,18 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Gnpl.Core
+import Lean
+
+-- Lean itself audits the transitive assumptions. Any additional axiom changes
+-- the diagnostic and fails the build. propext is Lean's propositional extensionality.
+/-- info: 'Gnpl.narrate' depends on axioms: [propext] -/
+#guard_msgs in
+#print axioms Gnpl.narrate
+
+/-- info: 'Gnpl.withdrawn_cannot_support' depends on axioms: [propext] -/
+#guard_msgs in
+#print axioms Gnpl.withdrawn_cannot_support
+
+/-- info: 'Gnpl.narration_preserves_projection' depends on axioms: [propext] -/
+#guard_msgs in
+#print axioms Gnpl.narration_preserves_projection
diff --git a/test/NarrationTest.lean b/test/NarrationTest.lean
new file mode 100644
index 0000000..481bafd
--- /dev/null
+++ b/test/NarrationTest.lean
@@ -0,0 +1,126 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+import Gnpl
+import TestHarness
+
+open Gnpl GnplTest Lean
+
+private def closed : Claim := β¨"bridge", "status", "closed"β©
+private def opened : Claim := β¨"bridge", "status", "open"β©
+private def rain : Claim := β¨"site", "weather", "rain"β©
+private def inspection : Evidence :=
+ β¨"inspection-17", "inspector", closed, "Recorded inspection", 90, ["analyst"], falseβ©
+private def witness : Evidence :=
+ β¨"witness-22", "witness", opened, "Recorded witness statement", 80, ["analyst"], falseβ©
+private def weather : Evidence :=
+ β¨"weather-3", "weather-log", rain, "Recorded weather", 95, ["analyst"], falseβ©
+private def snapshot : Fabula := β¨"case", 7, [inspection, witness, weather]β©
+private def plan : Projection :=
+ β¨"inspection", β¨"analyst", 70β©, [β¨closed, "inspection-17"β©, β¨rain, "weather-3"β©]β©
+
+private def refusalIs (f : Fabula) (p : Projection) (code : RefusalCode) : Bool :=
+ match narrate f p with
+ | .error refusal => refusal.code == code
+ | .ok _ => false
+
+private def source := "account \"inspection\"\nfocalized by \"analyst\"\nthreshold 70\nassert \"bridge\" \"status\" \"closed\" citing \"inspection-17\"\nassert \"site\" \"weather\" \"rain\" citing \"weather-3\""
+
+def main : IO UInt32 := do
+ check "source β projection β warranted account with declared order"
+ (match Surface.parse source with
+ | .error _ => false
+ | .ok p => match narrate snapshot p with
+ | .error _ => false
+ | .ok a => a.narration.claims == [closed, rain])
+ check "reversing telling order changes account without inventing claims"
+ (match narrate snapshot { plan with assertions := plan.assertions.reverse } with
+ | .ok a => a.narration.claims == [rain, closed] | .error _ => false)
+ check "invented assertion refused despite a real citation"
+ (refusalIs snapshot { plan with assertions := [β¨opened, "inspection-17"β©] } .claimMismatch)
+ check "missing citation refused"
+ (refusalIs snapshot { plan with assertions := [β¨closed, "missing"β©] } .missingEvidence)
+ check "focalization restricts accessible evidence"
+ (refusalIs snapshot { plan with focalization := β¨"public", 70β© } .inaccessibleEvidence)
+ check "threshold admits a boundary value"
+ (match narrate snapshot { plan with focalization := β¨"analyst", 90β© } with
+ | .ok _ => true | .error _ => false)
+ check "threshold refuses a lower recorded score"
+ (refusalIs snapshot { plan with focalization := β¨"analyst", 91β© } .belowThreshold)
+ check "out-of-domain confidence refused"
+ (refusalIs { snapshot with evidence := [{ inspection with confidence := 101 }, weather] }
+ plan .invalidSnapshot)
+ check "blank rationale refused"
+ (refusalIs { snapshot with evidence := [{ inspection with rationale := " \t " }, weather] }
+ plan .invalidSnapshot)
+ check "duplicate evidence identifiers refused, independent of lookup order"
+ (refusalIs { snapshot with evidence := inspection :: snapshot.evidence } plan .invalidSnapshot)
+ check "empty account refused" (refusalIs snapshot { plan with assertions := [] } .invalidProjection)
+ check "duplicated assertion refused"
+ (refusalIs snapshot { plan with assertions := plan.assertions ++ plan.assertions } .invalidProjection)
+ let other : Projection := β¨"witness", β¨"analyst", 70β©, [β¨opened, "witness-22"β©]β©
+ check "rival accounts both remain warranted without choosing a winner"
+ (match narrate snapshot plan, narrate snapshot other with
+ | .ok a, .ok b => rival a b && rival b a
+ | _, _ => false)
+ check "conflicting assertions cannot be blended into one account"
+ (refusalIs snapshot { plan with assertions := plan.assertions ++ other.assertions } .invalidProjection)
+ check "withdrawal invalidates an account that depends on that source"
+ (match withdraw snapshot "inspection-17" with
+ | .ok f => refusalIs f plan .evidenceWithdrawn && f.revision == 8
+ | .error _ => false)
+ check "withdrawing an uncited rival source preserves the account"
+ (match withdraw snapshot "witness-22" with
+ | .ok f => match narrate f plan with
+ | .ok a => a.narration.claims == [closed, rain] | .error _ => false
+ | .error _ => false)
+ check "counterfactual leaves original snapshot warranted"
+ (match narrate snapshot plan with | .ok _ => true | .error _ => false)
+ check "withdrawal of unknown evidence is an error"
+ (match withdraw snapshot "absent" with
+ | .error r => r.code == .missingEvidence | .ok _ => false)
+ for bad in [source ++ "\nextra", source ++ "\naccount \"second\"",
+ source.replace "threshold 70" "threshold -1",
+ source.replace "threshold 70" "threshold 101",
+ source.replace "citing \"inspection-17\"" "citing", "account \"unterminated"] do
+ check "malformed or trailing source refused"
+ (match Surface.parse bad with | .error _ => true | .ok _ => false)
+ check "quoted strings preserve escaped quotes and Unicode"
+ (match Surface.parse (source.replace "account \"inspection\"" "account \"A \\\"quoted\\\" Ξ»\"") with
+ | .ok p => p.name == "A \"quoted\" Ξ»" | .error _ => false)
+ let fixture β IO.FS.readFile "examples/narration/evidence.json"
+ check "versioned evidence snapshot loads and warrants the projection"
+ (match Wire.decodeFabula fixture with
+ | .ok f => match narrate f plan with | .ok _ => true | .error _ => false
+ | .error _ => false)
+ check "unrecognised evidence fields are not silently discarded"
+ (match Wire.decodeFabula (fixture.replace "\"revision\": 7" "\"revision\": 7, \"proof\": \"trust me\"") with
+ | .error _ => true | .ok _ => false)
+ check "unsupported evidence version refused"
+ (match Wire.decodeFabula (fixture.replace "gnpl-evidence-v1" "gnpl-evidence-v2") with
+ | .error _ => true | .ok _ => false)
+ -- Real process boundary: input files β executable β JSON + exit status.
+ -- The executable must have been built; failures never silently skip this slice.
+ let evidenceArgs := #["--evidence", "examples/narration/evidence.json", "--projection"]
+ for (mode, projection, extra, expectedCode, expectedStatus) in [
+ ("narrate", "inspection.gnpl", #[], 0, "warranted"),
+ ("narrate", "witness.gnpl", #[], 0, "warranted"),
+ ("narrate", "inaccessible.gnpl", #[], 1, "refused"),
+ ("counterfactual", "inspection.gnpl", #["--withdraw", "inspection-17"], 1, "invalidated"),
+ ("counterfactual", "inspection.gnpl", #["--withdraw", "witness-22"], 0, "preserved")
+ ] do
+ let result β IO.Process.output {
+ cmd := ".lake/build/bin/gnpl"
+ args := #[mode] ++ evidenceArgs ++ #["examples/narration/" ++ projection] ++ extra }
+ let status := do
+ let json β Json.parse result.stdout
+ json.getObjValAs? String "status"
+ check s!"CLI {mode} {projection} {extra}: {expectedStatus}"
+ (result.exitCode == expectedCode &&
+ match status with | .ok value => value == expectedStatus | .error _ => false)
+ let missing β IO.Process.output {
+ cmd := ".lake/build/bin/gnpl"
+ args := #["narrate"] ++ evidenceArgs ++ #["examples/narration/nonexistent.gnpl"] }
+ check "CLI missing input returns an input error, not an account" (missing.exitCode == 2)
+ let afterFixture β IO.FS.readFile "examples/narration/evidence.json"
+ check "CLI counterfactual preserves the evidence file byte for byte" (afterFixture == fixture)
+ summarise "GNPL narration"
diff --git a/test/SubstrateTest.lean b/test/SubstrateTest.lean
new file mode 100644
index 0000000..6101b5e
--- /dev/null
+++ b/test/SubstrateTest.lean
@@ -0,0 +1,127 @@
+-- SPDX-License-Identifier: MPL-2.0
+-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (@hyperpolymath)
+import GqlDt.Pipeline
+import TestHarness
+
+open GqlDt GqlDt.Pipeline GqlDt.IR GnplTest
+
+private def config := defaultGQLConfig "substrate-test" "test"
+
+private def insertSource (title : String) (score : Nat) :=
+ s!"INSERT INTO evidence (title, prompt_provenance) VALUES ('{title}', {score}) RATIONALE 'Declared test evidence';"
+
+private def rejects (source : String) : Bool :=
+ match runPipeline source config with
+ | .error _ => true
+ | .ok _ => false
+
+private def roundTrip : Bool :=
+ match runPipeline (insertSource "First" 95) config,
+ runPipeline (insertSource "Second" 75) config,
+ runPipeline "SELECT title FROM evidence WHERE prompt_provenance > 80;" config with
+ | .ok a, .ok b, .ok selected =>
+ let (db1, _) := evalIR EvalDatabase.empty a
+ let (db2, _) := evalIR db1 b
+ match (evalIR db2 selected).2 with
+ | .rows columns rows => columns == ["title"] && rows == [["First"]]
+ | _ => false
+ | _, _, _ => false
+
+private def confidenceIs (expected : Nat)
+ (result : Except String (Ξ£ t : AST.TypeExpr, AST.TypedValue t)) : Bool :=
+ match result with
+ | .ok β¨.confidence, .confidence valueβ© => value.val == expected
+ | _ => false
+
+def main : IO UInt32 := do
+ check "source β schema validation β insertion β filtered retrieval"
+ roundTrip
+ for (name, source) in [
+ ("empty INSERT", "INSERT INTO evidence () VALUES () RATIONALE 'r';"),
+ ("out-of-range evidence", insertSource "Bad" 150),
+ ("unknown table", "INSERT INTO other (title) VALUES ('x') RATIONALE 'r';"),
+ ("unknown column", "INSERT INTO evidence (missing) VALUES ('x') RATIONALE 'r';"),
+ ("empty refined string", "INSERT INTO evidence (title) VALUES ('') RATIONALE 'r';"),
+ ("empty rationale", "INSERT INTO evidence (title) VALUES ('x') RATIONALE '';"),
+ ("column/value arity", "INSERT INTO evidence (title) VALUES ('x', 'y') RATIONALE 'r';"),
+ ("incorrect annotation", "INSERT INTO evidence (title : Nat) VALUES ('x') RATIONALE 'r';"),
+ ("trailing comma", "SELECT title, FROM evidence;"),
+ ("malformed optional WHERE", "SELECT * FROM evidence WHERE title =;"),
+ ("malformed optional LIMIT", "SELECT * FROM evidence LIMIT nope;"),
+ ("unconsumed suffix", "SELECT * FROM evidence nonsense;"),
+ ("second statement", "SELECT * FROM evidence; SELECT * FROM evidence;"),
+ ("unknown projection", "SELECT missing FROM evidence;"),
+ ("predicate type mismatch", "SELECT * FROM evidence WHERE prompt_provenance > '80';"),
+ ("unsupported text ordering", "SELECT * FROM evidence ORDER BY title;"),
+ ("unsupported ordered text predicate", "SELECT * FROM evidence WHERE title > '10';"),
+ ("unsupported join", "SELECT * FROM evidence, other;"),
+ ("unchecked update", "UPDATE evidence SET title = '' RATIONALE 'r';")
+ ] do check ("reject " ++ name) (rejects source)
+ check "explicit matching type annotation"
+ (!rejects "INSERT INTO evidence (title :: NonEmptyString) VALUES ('x') RATIONALE 'r';")
+ let custom := { config with schema := { config.schema with name := "accounts" } }
+ check "use caller's schema"
+ (match runPipeline "INSERT INTO accounts (title) VALUES ('x') RATIONALE 'r';" custom with
+ | .ok _ => true | .error _ => false)
+ let confidenceConfig := { config with schema := { config.schema with
+ name := "scores", columns := [{
+ name := "score", type := .confidence, isPrimaryKey := false, isUnique := false }] } }
+ for score in [0, 85, 100] do
+ check s!"preserve Confidence type and value {score} through lowering"
+ (match runPipeline s!"INSERT INTO scores (score) VALUES ({score}) RATIONALE 'r';"
+ confidenceConfig with
+ | .ok (.insert stmt) =>
+ match stmt.values with
+ | [β¨.confidence, .confidence valueβ©] =>
+ value.val == score && typedValueToString (.confidence value) == toString score
+ | _ => false
+ | _ => false)
+ check "reject Confidence above its upper bound"
+ (match runPipeline "INSERT INTO scores (score) VALUES (101) RATIONALE 'r';"
+ confidenceConfig with
+ | .error _ => true | .ok _ => false)
+ let confidence : Ξ£ t : AST.TypeExpr, AST.TypedValue t :=
+ β¨.confidence, .confidence β¨85, by decide, by decideβ©β©
+ check "Confidence JSON preserves the type and value"
+ (confidenceIs 85 (Serialization.deserializeTypedValueJSON
+ (Serialization.serializeTypedValueJSON confidence)))
+ for format in [Serialization.Types.SerializationFormat.binary, .cbor] do
+ check s!"Confidence {repr format} preserves the type and value"
+ (confidenceIs 85 (Serialization.deserialize format
+ (Serialization.serialize format confidence) .confidence))
+ check "Confidence SQL conversion requires the distinct type hint"
+ (confidenceIs 85 (Serialization.fromSQLValue
+ (Serialization.toSQLValue confidence) .confidence))
+ for bad in [-1.0, 85.5, 101.0] do
+ check "Confidence JSON refuses out-of-range or fractional scores"
+ (match Serialization.deserializeTypedValueJSON
+ (.object [("type", .string "Confidence"), ("value", .number bad)]) with
+ | .error _ => true | .ok _ => false)
+ check "Confidence binary refuses an out-of-range score"
+ (match Serialization.deserializeTypedValueBinary
+ (ByteArray.mk #[0x09, 101, 0, 0, 0, 0, 0, 0, 0]) with
+ | .error _ => true | .ok _ => false)
+ check "CBOR eight-byte scores cannot collapse to zero"
+ (match Serialization.decodeCBOR (ByteArray.mk #[0x1b, 0, 0, 0, 0, 0, 0, 1, 0]) with
+ | .ok (.unsigned n) => n == 256 | _ => false)
+ check "CBOR text rejects invalid UTF-8"
+ (match Serialization.decodeCBOR (ByteArray.mk #[0x61, 0xff]) with
+ | .error _ => true | .ok _ => false)
+ check "reject non-consuming repetition"
+ (match Parser.many (pure () : Parser.Parser Unit) { tokens := [], position := 0 } with
+ | .error _ _ => true | .ok _ _ => false)
+ check "attached-proof mode refuses unverified input"
+ (match runPipeline (insertSource "First" 95) (defaultGQLdtConfig "test" "test") with
+ | .error _ => true | .ok _ => false)
+ check "unavailable proof strategy cannot emit an unchecked proof"
+ (match TypeInference.generateProofTerm .admit with
+ | .error _ => true | .ok _ => false)
+ check "incomplete wire codec refuses success"
+ (match runPipelineAndSerialize "SELECT * FROM evidence WHERE title = 'First';" config with
+ | .error _ => true | .ok _ => false)
+ check "wire decoding refuses unsupported proof reconstruction"
+ (match deserializeIR ByteArray.empty with | .error _ => true | .ok _ => false)
+ check "persistent execution refuses success"
+ (match β parseAndExecute (insertSource "First" 95) config with
+ | .error _ => true | .ok _ => false)
+ summarise "GNPL private substrate"
diff --git a/test/TypeSafetyTests.lean b/test/TypeSafetyTests.lean
index 165c5d9..cc8a890 100644
--- a/test/TypeSafetyTests.lean
+++ b/test/TypeSafetyTests.lean
@@ -105,6 +105,7 @@ def test_execution_safety : IO Unit := do
private def valueInvariant (pair : Ξ£ t : TypeExpr, TypedValue t) : Prop :=
match pair with
| β¨.boundedNat min max, .boundedNat _ _ bnβ© => min β€ bn.val β§ bn.val β€ max
+ | β¨.confidence, .confidence scoreβ© => score.val β€ 100
| β¨.nonEmptyString, .nonEmptyString nesβ© => nes.val.length > 0
| _ => True
@@ -123,6 +124,7 @@ private theorem valueInvariant_holds (pair : Ξ£ t : TypeExpr, TypedValue t)
| .float, .float _ => trivial
| .boundedNat min max, .boundedNat _ _ bn =>
exact β¨bn.min_le, bn.le_maxβ©
+ | .confidence, .confidence score => exact score.le_max
| .nonEmptyString, .nonEmptyString nes =>
exact nes.nonempty
| .promptScores, .promptScores _ => trivial