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