From 226b0b4359b8c63de9b47e28badd9ed1d54ec1d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 18 Jun 2026 10:30:35 +0000 Subject: [PATCH 1/2] =?UTF-8?q?docs(theory):=20add=20correspondence=20mode?= =?UTF-8?q?l=20=E2=80=94=20the=20engine=20that=20classifies,=20not=20trans?= =?UTF-8?q?lates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Canonical design spec for the comprehension/transfer engine: the Concept/Form/Transition object model, the levels-of-objects strata, the Dyadic+Echo formal carrier, and the Rosetta false-friends taxonomy (cognate / false-friend / antonym / alien-realization / novel / vanished) as graded Echo fibres. Also records the engine<->cartridge division of labour, the overlay-protocol / accessibility / PanLL-emit downstream contracts, and the knot-theory honesty caveat. JTV grammar v2 is stubbed pending repo access. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01A1BaAhqxUjkgVb1yg1sZap --- docs/theory/CORRESPONDENCE-MODEL.adoc | 237 ++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 docs/theory/CORRESPONDENCE-MODEL.adoc diff --git a/docs/theory/CORRESPONDENCE-MODEL.adoc b/docs/theory/CORRESPONDENCE-MODEL.adoc new file mode 100644 index 0000000..b3bd7a0 --- /dev/null +++ b/docs/theory/CORRESPONDENCE-MODEL.adoc @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: MPL-2.0 += Correspondence Model: the engine that *classifies*, not translates +:toc: macro +:toclevels: 3 +:icons: font + +[NOTE] +==== +*Status: living design spec.* This is the conceptual foundation for the engine — +authored ahead of the toolchain (AffineScript/Idris2/Zig not yet installable here), so +it is verified by inspection against estate exemplars, not yet by build. One worked +example (JTV grammar v2) is stubbed pending repository access; see <>. +==== + +toc::[] + +== What this engine is (and is not) + +This is *Duolingo / Rosetta Stone for programming languages* — a +language-*comprehension and transfer* engine. It works **one layer above text +editing**, on *syntactic and semantic intention*, so that the effort a person spent +learning language A *transfers* when they move to B (JS → TypeScript, Ruby, Prolog, C, +or exotic targets like QPL, Arrow, JTV). *Transfer learning across languages is the +product.* + +It is *not*: + +* *Not "the next best IDE."* It does not compete on contrast, project-management + widgets, pop-up notepads, shortcuts, or well-trodden attention/memory/workflow + ergonomics. That is **PanLL**'s job (PanLL + eNSAID = the _contact_ between human, + tool, task, and environment). This engine *feeds* PanLL; it is not PanLL. +* *Not a linter.* "Proximal/distal scope-colouring" and "spot the missing `;` / extra + `)`" are precisely what this is *not*. The differentiator is an engine that + **computes and classifies cross-language equivalence**, not one that looks it up. +* *Not a universal translator.* A verified any-language→any-language compiler with full + Curry–Howard fidelity would be nice; it is *not the goal*. We do not need — and will + not attempt — to do this "to the dot" on everything. + +== Division of labour + +[cols="1,3"] +|=== +| *We build* | the general engine + the interface + the classification vocabulary + +the residue model + a reference language pack. +| *The community builds* | the *per-language modules* — which pairs of constructs are +cognate vs. false-friend vs. novel, with their residues. These are authored as +**cartridges** (see `standards/cartridges/`). +|=== + +The engine is language-agnostic. The nextgen-language collection is merely the +substrate we dogfood. + +== The object model: Concept / Form / Transition + +[cols="1,3"] +|=== +| *Concept* | The invariant / equivalence-class — the recurring _trope_ (e.g. +"bind a name to a value", "iterate a collection", "fail recoverably"). +| *Form* | A representative of a Concept *in one language* (e.g. `let` in ReScript, +`=` in Erlang, `def` in Python). A Concept has many Forms across many languages. +| *Transition* | A directed correspondence Form(A) → Form(B): the Echo-refined map +plus its *residue* (what is lost, added, or inverted in crossing). +|=== + +A *lesson* is a Concept presented through the learner's known Form, the target Form, +and the Transition between them — narrated without shame ("you already know this; +here's the catch"). + +== Levels of objects (strata) + +Classification runs *per stratum of meaning*, not on flat text: + +. *Surface* — tokens, lexemes (`=`, `def`, `match`). +. *Structure* — AST shape, scoping, arity. +. *Semantic intention* — what the construct _does_ (bind? mutate? branch?). +. *Abstraction / trope* — the Concept it instantiates. +. *Cross-language invariant* — the preserved quantity certifying "same idea". + +The interface lets a learner move *up and down* these strata and *across* view-modes. +A correspondence can hold at one stratum and break at another — and that divergence is +itself the most valuable signal (see false friends, below). + +== The formal carrier + +The model is grounded in the estate's own formalism, not a bespoke mapping table. + +* *Carrier = Dyadic `Relation`* + (`proven-tests-and-benches/src/ProvenTests/TypeSafe/Dyadic.idr`): + `{ relates; reflexive; symmetric; transitive }`. Equivalence = refl ∧ sym ∧ trans — + the symmetries and transitivities, as a checkable structure. +* *Crossings are lossy-with-residue = Echo fibre* + (`Echo f y := Σ (x : A), f x ≡ y`, `hyperpolymath/echo-types`, Agda): the residue + (a proof term) is precisely _what is lost or added_ going A→B. A non-isomorphic + Transition (e.g. the absence of `return` in ReScript) is a map whose residue we + *surface*, never hide. +* *Typed residue-lenses = the three Echo bridges* (`Bridge.idr`): `EchoChoreo` + (protocol/sequencing), `EchoEpistemic` (visibility/knowledge), `EchoTropical` + (cost, min-plus). Extensible. +* *Composition = transitivity; symmetry distinguishes iso from retraction.* A clean + isomorphism ⇒ no residue (true equivalence); a retraction ⇒ one-way loss + (residue = the delta). +* *`invariant-path` = the governance front-end.* It anchors each equivalence _claim_ to + its two code locations plus a witness (proof/test), human-in-the-loop and editable. + +[IMPORTANT] +==== +*Honesty note on "knot theory."* The owner's framing — *types → carrier · tropes → +recurring equivalence-figures · knot theory → certificate* — is load-bearing for +intuition, but there is *no literal knot-invariant computation* here, and the +knot-theory lens is flagged (by the owner) as "perceived as rhetoric, pending +historical confirmation". We use *invariant* in the precise sense of a _preserved +quantity that certifies "same idea"_, and keep knot theory as an aspirational lens, not +a faked dependency. +==== + +[#taxonomy] +== The Rosetta false-friends taxonomy + +The one judgement that matters is *"is this safe to transfer, or is it a trap?"* +`def` → `define` might be _nothing but a rename_ — or it might look like that and not +be. So the Dyadic relation is not a boolean `relates`; it is a *typed/graded* +`CorrespondenceKind`, realised as grades of the Echo fibre: + +[cols="1,3,2"] +|=== +| Kind | Signature | Pedagogy + +| *Cognate / true friend* +| Intention + behaviour coincide; residue ≈ ∅. _Example:_ `def` → `define`. + But "just a rename" is a hypothesis to *verify*, never assume. +| *Transfer directly.* + +| *False friend / homonym* +| Surface matches, semantics diverge. _Example:_ BASIC `=` (mutable assignment) vs. + Erlang `=` (single-assignment bind/unify). Detected by *per-stratum* classification: + surface-corresponds ∧ semantics-diverge **is** the false-friend signature. +| *Flag the trap.* + +| *Antonym / inverted* +| Related but behaves oppositely. _Examples:_ 0- vs. 1-indexing; truthiness + conventions; stack-growth direction. Residue = the flip. +| *Remap the intuition.* + +| *Alien realization* +| Same intention, foreign mechanism, large residue. _Example:_ subtraction in a + reversible/add-only language (JTV) is `add` run backwards; divide via reversed + repeated-add. Also: recursion-only languages, CPS, monadic IO for "just print". +| *Bridge with effort; explain the machinery.* + +| *Novel / no anchor* +| Forward fibre empty: `∄ x. f x ≡ y`. The target has a concept with nothing to map + _from_. _Examples:_ static types coming from assembly + JS; ownership/borrowing; + affine/linear use-once; Prolog `cut`; JTV totality and information-flow labels. +| *Teach de novo — there is no transfer.* + +| *Vanished* +| Backward fibre empty: `∄ y`. A concept the learner relied on is _gone_. + _Examples:_ `return` in ReScript; `null` in a null-free language; mutable variables + in a pure language. +| *Un-learn / re-route.* +|=== + +The residue therefore ranges from ∅ (true iso) through inverted/large to +empty-in-either-direction (novel / vanished). This taxonomy *is* the Duolingo/Rosetta +pedagogy: transfer cognates, warn on false friends, remap antonyms, bridge the alien, +teach the novel, re-route the vanished. + +== Engine ↔ cartridge boundary + +We cannot do this "to the dot", and we do not try. Responsibilities split cleanly: + +* *Engine (ours):* the `CorrespondenceKind` vocabulary, the residue/fibre model, the + per-stratum classifier, the Dyadic/Echo carrier, and the certifiable Idris2/Echo math + — applied *where it pays* (high-value or dangerous correspondences), not everywhere. +* *Cartridge (per-language, community):* the _facts_ — for this language, which Forms + instantiate which Concepts, and for each Transition the kind + residue + a witness. + +A cartridge fact, sketched: + +[source] +---- +(transition + (concept "name-binding") + (from (lang "basic") (form "X = 5")) + (to (lang "erlang") (form "X = 5")) + (kind false-friend) ; surface-cognate, semantic-divergent + (strata (surface corresponds) (semantic diverges)) + (residue "BASIC rebinds destructively; Erlang binds once and unifies — \ + re-`=` fails unless the value matches") + (witness "proofs/erlang_single_assignment.idr")) ; optional, where it pays +---- + +== Rendering: "levels of objects", not chrome + +The view-modes are the rendered strata, switchable and non-destructive (each conforms +to the estate *overlay-protocol* — additive, non-modifying, idempotent, Idris2-ABI +proved): + +* *focus* — show only what's needed now; +* *glyph* — Makaton-style symbols (accessible, low-cognitive-load); +* *blockly / scratch* — flowchart of structure; +* *raw code* — the text itself; +* *side-by-side* — multi-language diff with step-sync. + +Accessibility is a first-class contract, not a coat of paint: Hyperpolymath +Accessibility Standard, Level *A* minimum → *AA* (keyboard-only operation, ≥4.5:1 +contrast, colourblind-safe palettes, ARIA/screen-reader, reduced-motion, plain-language +mode, high-contrast glyph variants). + +== Downstream: feeding PanLL + +The engine *emits*, it does not own the IDE. Analyses become `octads` written to +VeriSimDB (`:8097`) plus `Groove` signals; PanLL panels subscribe and re-render. +Relevant octad types: `inline-annotation` (per-construct claims), +`ecosystem-link` (intra-program relationships), `proof-status` (where a Transition +carries a witness). Ergonomics are read from `.machine_readable/ENSAID_CONFIG.a2ml`. + +[#open-questions] +== Open questions / placeholders + +* *JTV grammar v2* — the canonical worked example for *alien-realization* and + *novel/no-anchor* kinds. The `julia-the-viper` repo is a not-checked-out submodule + and currently outside session scope; constructs to be tagged against <> + once the grammar is available. From the T1 proof spec, JTV is reversible + total + + effect-typed (I/O, state, crypto) + information-flow-typed (public/private/secret) + + capability-secured — i.e. dense with novel-concept correspondences. +* *Stratum granularity* — whether 5 strata suffice, or "intention" needs splitting + (operational vs. denotational). +* *Where the math pays* — the policy for when a Transition _must_ carry an Idris2/Echo + witness vs. an asserted-but-unproven classification. + +== References + +* `proven-tests-and-benches/src/ProvenTests/TypeSafe/Dyadic.idr`, `…/Bridge.idr` +* `hyperpolymath/echo-types` — loss-with-residue (Agda) +* `standards/overlay-protocol/`, `standards/ensaid-config/`, + `standards/accessibility/`, `standards/cartridges/`, `standards/panll-panels/` From ddd3d4444282b9d669b45b821c996c0f04b68e08 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 18 Jun 2026 11:02:31 +0000 Subject: [PATCH 2/2] chore(standards): complete 6a2 manifest set + panic-attack gate + eNSAID config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add the missing .machine_readable/6a2 manifests — AGENTIC, NEUROSYM, PLAYBOOK — completing the canonical six alongside STATE/META/ECOSYSTEM, tuned to the correspondence-engine identity (no-shame voice, classify-not- translate, toolchain-deferred build honesty, no-relicense guardrail). - Add .github/workflows/static-analysis-gate.yml: panic-attack assail + hypatia scan + patch-bridge triage. Fails only on critical findings and skips gracefully when the binaries are unavailable in the runner. - Add .machine_readable/ENSAID_CONFIG.a2ml: PanLL / eNSAID per-repo config with a correspondence-engine view-layer portfolio. - Justfile: fix stale panic-attacker -> panic-attack references (tool renamed 2026-02-08). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01A1BaAhqxUjkgVb1yg1sZap --- .github/workflows/static-analysis-gate.yml | 400 +++++++++++++++++++++ .machine_readable/6a2/AGENTIC.a2ml | 43 +++ .machine_readable/6a2/NEUROSYM.a2ml | 33 ++ .machine_readable/6a2/PLAYBOOK.a2ml | 31 ++ .machine_readable/ENSAID_CONFIG.a2ml | 65 ++++ Justfile | 4 +- 6 files changed, 574 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/static-analysis-gate.yml create mode 100644 .machine_readable/6a2/AGENTIC.a2ml create mode 100644 .machine_readable/6a2/NEUROSYM.a2ml create mode 100644 .machine_readable/6a2/PLAYBOOK.a2ml create mode 100644 .machine_readable/ENSAID_CONFIG.a2ml diff --git a/.github/workflows/static-analysis-gate.yml b/.github/workflows/static-analysis-gate.yml new file mode 100644 index 0000000..8bd1606 --- /dev/null +++ b/.github/workflows/static-analysis-gate.yml @@ -0,0 +1,400 @@ +# SPDX-License-Identifier: MPL-2.0 +# Static Analysis Gate — Required by branch protection rules. +# Runs panic-attack and hypatia, deposits findings for gitbot-fleet learning. +name: Static Analysis Gate +on: + pull_request: + branches: ['**'] + push: + branches: [main, master] +permissions: + contents: read +jobs: + # --------------------------------------------------------------------------- + # Job 1: panic-attack assail + # --------------------------------------------------------------------------- + panic-attack-assail: + name: panic-attack assail + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - name: Install panic-attack (if available) + id: install + run: | + # Try to fetch the latest release binary from the org + PA_URL="https://github.com/hyperpolymath/panic-attack/releases/latest/download/panic-attack-linux-x86_64" + if curl -fsSL --head "$PA_URL" >/dev/null 2>&1; then + curl -fsSL -o /usr/local/bin/panic-attack "$PA_URL" + chmod +x /usr/local/bin/panic-attack + echo "installed=true" >> "$GITHUB_OUTPUT" + else + echo "::notice::panic-attack binary not available — skipping assail" + echo "installed=false" >> "$GITHUB_OUTPUT" + fi + - name: Run panic-attack assail + id: assail + if: steps.install.outputs.installed == 'true' + run: | + set +e + panic-attack assail --format json . > panic-attack-findings.json 2>&1 + PA_EXIT=$? + set -e + + if [ ! -s panic-attack-findings.json ]; then + echo "[]" > panic-attack-findings.json + fi + + # Parse finding counts + TOTAL=$(jq '. | length' panic-attack-findings.json 2>/dev/null || echo 0) + CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' panic-attack-findings.json 2>/dev/null || echo 0) + HIGH=$(jq '[.[] | select(.severity == "high")] | length' panic-attack-findings.json 2>/dev/null || echo 0) + MEDIUM=$(jq '[.[] | select(.severity == "medium")] | length' panic-attack-findings.json 2>/dev/null || echo 0) + LOW=$(jq '[.[] | select(.severity == "low")] | length' panic-attack-findings.json 2>/dev/null || echo 0) + + echo "total=$TOTAL" >> "$GITHUB_OUTPUT" + echo "critical=$CRITICAL" >> "$GITHUB_OUTPUT" + echo "high=$HIGH" >> "$GITHUB_OUTPUT" + echo "medium=$MEDIUM" >> "$GITHUB_OUTPUT" + echo "low=$LOW" >> "$GITHUB_OUTPUT" + echo "exit_code=$PA_EXIT" >> "$GITHUB_OUTPUT" + - name: Emit check annotations + if: steps.install.outputs.installed == 'true' + run: | + # Convert JSON findings into GitHub Actions annotations + jq -r '.[] | select(.file != null) | + if .severity == "critical" then + "::error file=\(.file),line=\(.line // 1)::[panic-attack] \(.message)" + elif .severity == "high" then + "::error file=\(.file),line=\(.line // 1)::[panic-attack] \(.message)" + else + "::warning file=\(.file),line=\(.line // 1)::[panic-attack] \(.message)" + end + ' panic-attack-findings.json || true + - name: Write step summary + if: steps.install.outputs.installed == 'true' + run: | + cat <> "$GITHUB_STEP_SUMMARY" + ## panic-attack assail Results + + | Severity | Count | + |----------|-------| + | Critical | ${{ steps.assail.outputs.critical }} | + | High | ${{ steps.assail.outputs.high }} | + | Medium | ${{ steps.assail.outputs.medium }} | + | Low | ${{ steps.assail.outputs.low }} | + | **Total**| ${{ steps.assail.outputs.total }} | + EOF + - name: Create stub findings (when panic-attack unavailable) + if: steps.install.outputs.installed != 'true' + run: | + echo "[]" > panic-attack-findings.json + echo "## panic-attack assail" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Skipped: panic-attack not available in this environment." >> "$GITHUB_STEP_SUMMARY" + - name: Upload panic-attack findings + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: panic-attack-findings + path: panic-attack-findings.json + retention-days: 90 + - name: Fail on critical findings + if: steps.install.outputs.installed == 'true' && steps.assail.outputs.critical > 0 + run: | + echo "::error::panic-attack found ${{ steps.assail.outputs.critical }} critical issue(s) — blocking merge" + exit 1 + # --------------------------------------------------------------------------- + # Job 2: hypatia-scan + # --------------------------------------------------------------------------- + hypatia-scan: + name: Hypatia neurosymbolic scan + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - name: Setup Elixir for Hypatia scanner + id: beam + continue-on-error: true + uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9 # v1.18.2 + with: + elixir-version: '1.19.4' + otp-version: '28.3' + - name: Clone and build Hypatia + id: build + continue-on-error: true + run: | + git clone https://github.com/hyperpolymath/hypatia.git "$HOME/hypatia" 2>/dev/null || true + if [ -f "$HOME/hypatia/mix.exs" ]; then + cd "$HOME/hypatia" + # Build escript if neither hypatia nor hypatia-v2 exists + if [ ! -f hypatia ] && [ ! -f hypatia-v2 ]; then + mix deps.get + mix escript.build + fi + echo "ready=true" >> "$GITHUB_OUTPUT" + else + echo "::notice::Hypatia scanner not available — skipping scan" + echo "ready=false" >> "$GITHUB_OUTPUT" + fi + - name: Run Hypatia scan + id: scan + if: steps.build.outputs.ready == 'true' + run: | + set +e + HYPATIA_FORMAT=json "$HOME/hypatia/hypatia-cli.sh" scan . > hypatia-findings.json 2>&1 + HYP_EXIT=$? + set -e + + if [ ! -s hypatia-findings.json ] || ! jq empty hypatia-findings.json 2>/dev/null; then + echo "[]" > hypatia-findings.json + fi + + TOTAL=$(jq '. | length' hypatia-findings.json 2>/dev/null || echo 0) + CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' hypatia-findings.json 2>/dev/null || echo 0) + HIGH=$(jq '[.[] | select(.severity == "high")] | length' hypatia-findings.json 2>/dev/null || echo 0) + MEDIUM=$(jq '[.[] | select(.severity == "medium")] | length' hypatia-findings.json 2>/dev/null || echo 0) + LOW=$(jq '[.[] | select(.severity == "low")] | length' hypatia-findings.json 2>/dev/null || echo 0) + + echo "total=$TOTAL" >> "$GITHUB_OUTPUT" + echo "critical=$CRITICAL" >> "$GITHUB_OUTPUT" + echo "high=$HIGH" >> "$GITHUB_OUTPUT" + echo "medium=$MEDIUM" >> "$GITHUB_OUTPUT" + echo "low=$LOW" >> "$GITHUB_OUTPUT" + - name: Emit check annotations + if: steps.build.outputs.ready == 'true' + run: | + jq -r '.[] | select(.file != null) | + if .severity == "critical" then + "::error file=\(.file),line=\(.line // 1)::[hypatia] \(.message)" + elif .severity == "high" then + "::error file=\(.file),line=\(.line // 1)::[hypatia] \(.message)" + else + "::warning file=\(.file),line=\(.line // 1)::[hypatia] \(.message)" + end + ' hypatia-findings.json || true + - name: Write step summary + if: steps.build.outputs.ready == 'true' + run: | + cat <> "$GITHUB_STEP_SUMMARY" + ## Hypatia Scan Results + + | Severity | Count | + |----------|-------| + | Critical | ${{ steps.scan.outputs.critical }} | + | High | ${{ steps.scan.outputs.high }} | + | Medium | ${{ steps.scan.outputs.medium }} | + | Low | ${{ steps.scan.outputs.low }} | + | **Total**| ${{ steps.scan.outputs.total }} | + EOF + - name: Create stub findings (when Hypatia unavailable) + if: steps.build.outputs.ready != 'true' + run: | + echo "[]" > hypatia-findings.json + echo "## Hypatia Scan" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Skipped: Hypatia scanner not available in this environment." >> "$GITHUB_STEP_SUMMARY" + - name: Upload hypatia findings + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: hypatia-findings + path: hypatia-findings.json + retention-days: 90 + - name: Fail on critical security findings + if: steps.build.outputs.ready == 'true' && steps.scan.outputs.critical > 0 + run: | + echo "::error::Hypatia found ${{ steps.scan.outputs.critical }} critical security issue(s) — blocking merge" + exit 1 + # --------------------------------------------------------------------------- + # Job 3: patch-bridge triage (CVE contextual assessment) + # --------------------------------------------------------------------------- + patch-bridge-triage: + name: Patch Bridge CVE triage + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - name: Install panic-attack (if available) + id: install + run: | + PA_URL="https://github.com/hyperpolymath/panic-attack/releases/latest/download/panic-attack-linux-x86_64" + if curl -fsSL --head "$PA_URL" >/dev/null 2>&1; then + curl -fsSL -o /usr/local/bin/panic-attack "$PA_URL" + chmod +x /usr/local/bin/panic-attack + echo "installed=true" >> "$GITHUB_OUTPUT" + else + echo "::notice::panic-attack binary not available — skipping Patch Bridge" + echo "installed=false" >> "$GITHUB_OUTPUT" + fi + - name: Run Patch Bridge triage + id: triage + if: steps.install.outputs.installed == 'true' + run: | + set +e + panic-attack bridge triage --format json . > bridge-report.json 2>&1 + PB_EXIT=$? + set -e + + if [ ! -s bridge-report.json ] || ! jq empty bridge-report.json 2>/dev/null; then + echo '{"cves":[],"mitigated":0,"unmitigable":0,"concatenative":0,"informational":0}' > bridge-report.json + fi + + UNMITIGABLE=$(jq '.unmitigable // 0' bridge-report.json) + MITIGATED=$(jq '.mitigated // 0' bridge-report.json) + CONCATENATIVE=$(jq '.concatenative // 0' bridge-report.json) + INFORMATIONAL=$(jq '.informational // 0' bridge-report.json) + + echo "unmitigable=$UNMITIGABLE" >> "$GITHUB_OUTPUT" + echo "mitigated=$MITIGATED" >> "$GITHUB_OUTPUT" + echo "concatenative=$CONCATENATIVE" >> "$GITHUB_OUTPUT" + echo "informational=$INFORMATIONAL" >> "$GITHUB_OUTPUT" + - name: Write step summary + if: steps.install.outputs.installed == 'true' + run: | + cat <> "$GITHUB_STEP_SUMMARY" + ## Patch Bridge CVE Triage + + | Classification | Count | + |----------------|-------| + | Unmitigable | ${{ steps.triage.outputs.unmitigable }} | + | Mitigated | ${{ steps.triage.outputs.mitigated }} | + | Concatenative | ${{ steps.triage.outputs.concatenative }} | + | Informational | ${{ steps.triage.outputs.informational }} | + + Unmitigable CVEs require dependency replacement or rearchitecture. + Mitigated CVEs have active controls with soundness proofs. + Concatenative risks are CVE combinations that multiply severity. + EOF + - name: Create stub report (when unavailable) + if: steps.install.outputs.installed != 'true' + run: | + echo '{"cves":[],"mitigated":0,"unmitigable":0,"concatenative":0,"informational":0}' > bridge-report.json + echo "## Patch Bridge CVE Triage" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Skipped: panic-attack not available in this environment." >> "$GITHUB_STEP_SUMMARY" + - name: Upload bridge report + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: bridge-report + path: bridge-report.json + retention-days: 90 + - name: Fail on unmitigable CVEs in critical paths + if: steps.install.outputs.installed == 'true' && steps.triage.outputs.unmitigable > 0 + run: | + echo "::warning::Patch Bridge found ${{ steps.triage.outputs.unmitigable }} unmitigable CVE(s) — review required" + # Warning only, not blocking. Unmitigable means the developer needs + # to make an architectural decision, not that the PR is wrong. + # --------------------------------------------------------------------------- + # Job 4: deposit-findings (combines + archives for gitbot-fleet) + # --------------------------------------------------------------------------- + deposit-findings: + name: Deposit findings for gitbot-fleet + runs-on: ubuntu-latest + timeout-minutes: 15 + needs: [panic-attack-assail, hypatia-scan, patch-bridge-triage] + if: always() + steps: + - name: Download panic-attack findings + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + with: + name: panic-attack-findings + path: findings/ + - name: Download hypatia findings + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + with: + name: hypatia-findings + path: findings/ + - name: Download bridge report + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + with: + name: bridge-report + path: findings/ + - name: Combine findings into unified report + id: combine + run: | + PA_FILE="findings/panic-attack-findings.json" + HYP_FILE="findings/hypatia-findings.json" + + # Ensure both files exist and are valid JSON arrays + for f in "$PA_FILE" "$HYP_FILE"; do + if [ ! -s "$f" ] || ! jq empty "$f" 2>/dev/null; then + echo "[]" > "$f" + fi + done + + # Tag each finding with its source scanner + jq '[.[] | . + {"scanner": "panic-attack"}]' "$PA_FILE" > /tmp/pa-tagged.json + jq '[.[] | . + {"scanner": "hypatia"}]' "$HYP_FILE" > /tmp/hyp-tagged.json + + # Read bridge report (CVE triage, not findings array) + BRIDGE_FILE="findings/bridge-report.json" + if [ ! -s "$BRIDGE_FILE" ] || ! jq empty "$BRIDGE_FILE" 2>/dev/null; then + echo '{"cves":[],"mitigated":0,"unmitigable":0,"concatenative":0,"informational":0}' > "$BRIDGE_FILE" + fi + + # Build unified report envelope + jq -n \ + --arg repo "${{ github.repository }}" \ + --arg sha "${{ github.sha }}" \ + --arg ref "${{ github.ref }}" \ + --arg run_id "${{ github.run_id }}" \ + --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + --slurpfile pa /tmp/pa-tagged.json \ + --slurpfile hyp /tmp/hyp-tagged.json \ + --slurpfile bridge "$BRIDGE_FILE" \ + '{ + schema_version: "1.1.0", + repository: $repo, + commit_sha: $sha, + ref: $ref, + run_id: $run_id, + timestamp: $ts, + findings: ($pa[0] + $hyp[0]), + patch_bridge: $bridge[0] + }' > findings/unified-findings.json + + TOTAL=$(jq '.findings | length' findings/unified-findings.json) + CRITICAL=$(jq '[.findings[] | select(.severity == "critical")] | length' findings/unified-findings.json) + HIGH=$(jq '[.findings[] | select(.severity == "high")] | length' findings/unified-findings.json) + MEDIUM=$(jq '[.findings[] | select(.severity == "medium")] | length' findings/unified-findings.json) + LOW=$(jq '[.findings[] | select(.severity == "low")] | length' findings/unified-findings.json) + + echo "total=$TOTAL" >> "$GITHUB_OUTPUT" + echo "critical=$CRITICAL" >> "$GITHUB_OUTPUT" + echo "high=$HIGH" >> "$GITHUB_OUTPUT" + echo "medium=$MEDIUM" >> "$GITHUB_OUTPUT" + echo "low=$LOW" >> "$GITHUB_OUTPUT" + - name: Upload unified findings (fleet scanner picks these up) + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: unified-findings + path: findings/unified-findings.json + retention-days: 90 + - name: Write deposit summary + run: | + cat <> "$GITHUB_STEP_SUMMARY" + ## Unified Findings Deposit + + **Repository:** ${{ github.repository }} + **Commit:** \`${{ github.sha }}\` + **Deposited at:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") + + | Severity | Count | + |----------|-------| + | Critical | ${{ steps.combine.outputs.critical }} | + | High | ${{ steps.combine.outputs.high }} | + | Medium | ${{ steps.combine.outputs.medium }} | + | Low | ${{ steps.combine.outputs.low }} | + | **Total**| ${{ steps.combine.outputs.total }} | + + Findings saved as \`unified-findings\` artifact. + The gitbot-fleet scanner will ingest these on its next pass. + EOF diff --git a/.machine_readable/6a2/AGENTIC.a2ml b/.machine_readable/6a2/AGENTIC.a2ml new file mode 100644 index 0000000..433bdc4 --- /dev/null +++ b/.machine_readable/6a2/AGENTIC.a2ml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# AGENTIC.a2ml — AI agent constraints and capabilities +[metadata] +version = "0.1.0" +last-updated = "2026-06-18" +project = "nextgen-languages-evangeliser" + +[agent-permissions] +can-edit-source = true +can-edit-tests = true +can-edit-docs = true +can-edit-config = true +can-create-files = true + +[agent-constraints] +# What AI agents must NOT do in this repo: +# - Never relicense. This is a sole-owner repo; keep SPDX = MPL-2.0 on every +# file. No bulk SPDX sweeps (estate licence guardrail). +# - Never use banned languages (TypeScript, Python, Go, V) or Makefiles (use +# the Justfile). +# - Never reframe this as a universal translator or a Curry-Howard-fidelity +# compiler. It *classifies* cross-language correspondences and teaches the +# transfer; see docs/theory/CORRESPONDENCE-MODEL.adoc. +# - Never shame the source language. Narratives keep the +# celebrate / minimise / better / safety / example voice. +# - Never claim a green build from an untooled environment. AffineScript, +# Idris2, Zig and Deno may be absent here — author now, verify in CI. +# - Never place state files in the repository root (must live in +# .machine_readable/). + +[maintenance-integrity] +fail-closed = true +require-evidence-per-step = true +allow-silent-skip = false +require-rerun-after-fix = true +release-claim-requires-hard-pass = true + +[automation-hooks] +# on-enter: Read 0-AI-MANIFEST.a2ml, then .machine_readable/6a2/STATE.a2ml +# on-exit: Update 6a2/STATE.a2ml with session outcomes +# on-commit: Run `just validate-rsr` diff --git a/.machine_readable/6a2/NEUROSYM.a2ml b/.machine_readable/6a2/NEUROSYM.a2ml new file mode 100644 index 0000000..d33f7f5 --- /dev/null +++ b/.machine_readable/6a2/NEUROSYM.a2ml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# NEUROSYM.a2ml — Neurosymbolic integration metadata +[metadata] +version = "0.1.0" +last-updated = "2026-06-18" +project = "nextgen-languages-evangeliser" + +[hypatia-config] +scan-enabled = true +scan-depth = "standard" # quick | standard | deep +report-format = "logtalk" + +[static-analysis-gate] +# panic-attack assail runs in .github/workflows/static-analysis-gate.yml. +# It fails the build only on critical findings and skips gracefully when the +# binary is unavailable in the runner. +panic-attack-enabled = true +fail-on = "critical" + +[symbolic-rules] +# Project-specific symbolic rules (illustrative): +# - { name = "no-shame-narrative", pattern = "stupid|wrong code|bad code", severity = "high" } +# - { name = "no-universal-translator-claim", pattern = "universal translator|curry-?howard fidelity", severity = "medium" } + +[neural-config] +# The engine's own correspondence classifier IS this repo's domain +# neurosymbolic surface: a symbolic Dyadic relation + a graded Echo +# loss-with-residue fibre -> a typed CorrespondenceKind +# (cognate / false-friend / antonym / alien-realization / novel / vanished). +# See docs/theory/CORRESPONDENCE-MODEL.adoc. +# confidence-threshold = 0.85 diff --git a/.machine_readable/6a2/PLAYBOOK.a2ml b/.machine_readable/6a2/PLAYBOOK.a2ml new file mode 100644 index 0000000..f1ee58a --- /dev/null +++ b/.machine_readable/6a2/PLAYBOOK.a2ml @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# PLAYBOOK.a2ml — Operational playbook +[metadata] +version = "0.1.0" +last-updated = "2026-06-18" +project = "nextgen-languages-evangeliser" + +[deployment] +# Host: ReScript today (compiles to JS, run under Deno); AffineScript after the +# Phase-3 host port. Surfaces: Deno CLI (bin/evangeliser.js) and the browser +# GUI (gui/server.js + gui/app.js). +# method = "ci-triggered" +# target = "library + cli + browser-gui" + +[incident-response] +# 1. Read .machine_readable/6a2/STATE.a2ml for current status. +# 2. Review recent commits and CI (Static Analysis Gate, RSR Compliance). +# 3. Run `just validate-rsr` to check compliance. +# 4. Run `just assail` for the panic-attack static-analysis scan. + +[release-process] +# 1. Update version in 6a2/STATE.a2ml and 6a2/META.a2ml. +# 2. Run `just validate-rsr` and `just crg-grade`. +# 3. Tag and push. + +[maintenance-operations] +# RSR validation: just validate-rsr +# Static-analysis scan: just assail +# Component readiness: just crg-grade diff --git a/.machine_readable/ENSAID_CONFIG.a2ml b/.machine_readable/ENSAID_CONFIG.a2ml new file mode 100644 index 0000000..3bfbd3f --- /dev/null +++ b/.machine_readable/ENSAID_CONFIG.a2ml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# ENSAID_CONFIG.a2ml — eNSAID Environment Configuration +# Per-repo configuration for PanLL and eNSAID-compatible tools. +# Spec: https://github.com/hyperpolymath/standards/tree/main/ensaid-config +# +# This engine *emits into* PanLL (octads -> VeriSimDB -> panels) and renders its +# "levels of objects" through overlay-protocol view-layers. See +# docs/theory/CORRESPONDENCE-MODEL.adoc, "Rendering" and "Downstream: feeding PanLL". + +# ───────────────────────────────────────────────────────────────── +# [ensaid] — Core eNSAID identity and version +# ───────────────────────────────────────────────────────────────── +[ensaid] +version = "1.0.0" +tool = "panll" + +# ───────────────────────────────────────────────────────────────── +# [workspace] — Workspace mode, protection, and execution policy +# ───────────────────────────────────────────────────────────────── +[workspace] +mode = "rhodium" # rhodium | gold | silver | bronze +protection = "open" # open | guarded | locked +execution = "live" # live | dry-run | approval-required + +# ───────────────────────────────────────────────────────────────── +# [preferences] — Display and behaviour preferences +# ───────────────────────────────────────────────────────────────── +[preferences] +humidity = "medium" # high | medium | low (drift aura intensity) +default-arrangement = "correspondence-3-panel" +auto-connect = true + +# ───────────────────────────────────────────────────────────────── +# [panels] — View-layers render the engine's "levels of objects": +# focus | glyph | blockly | raw-code | side-by-side (overlay-protocol). +# ───────────────────────────────────────────────────────────────── +[panels] +version = "1.0.0" + +# ───────────────────────────────────────────────────────────────── +# [workflows] — Automation Router event-driven cross-panel rules +# ───────────────────────────────────────────────────────────────── +[workflows] +version = "1.0.0" + +# ───────────────────────────────────────────────────────────────── +# [clades] — Panel clade trait/capability overrides +# ───────────────────────────────────────────────────────────────── +[clades] +version = "1.0.0" + +# ───────────────────────────────────────────────────────────────── +# [portfolios] — Custom panel bundles for this repo's workflow +# ───────────────────────────────────────────────────────────────── +[portfolios] +version = "1.0.0" + +[[portfolios.custom]] +id = "correspondence-dev" +name = "Correspondence Engine Development" +description = "Cross-language correspondence panes: side-by-side + residue + glyph + focus" +panels = ["raw-code", "side-by-side", "glyph", "focus"] +default-isolation = "native" diff --git a/Justfile b/Justfile index a7caa0e..ae32a1f 100644 --- a/Justfile +++ b/Justfile @@ -237,9 +237,9 @@ help-me: @echo "" @echo "Include the output of 'just doctor' in your report." -# Run panic-attacker pre-commit scan +# Run panic-attack pre-commit scan assail: - @command -v panic-attack >/dev/null 2>&1 && panic-attack assail . || echo "panic-attack not found — install from https://github.com/hyperpolymath/panic-attacker" + @command -v panic-attack >/dev/null 2>&1 && panic-attack assail . || echo "panic-attack not found — install from https://github.com/hyperpolymath/panic-attack" # Print the current CRG grade (reads from READINESS.md '**Current Grade:** X' line)