From 90665d8da2d6e6b83da264947915aad111d979a6 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 20 Sep 2026 12:15:12 +0000 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20real=20repo-deed,=20ABI=E2=86=94FFI?= =?UTF-8?q?=20P2P=20coupling,=20evidence=20kinds=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - panoply_chora.deed plus STATE/META/ECOSYSTEM as s-expression repo-deeds (ABNF heads; no TOML [section] on those files). - P2P test: Idris Result and C symbols must match Zig FFI; align Result and panoply_* foreign names (ABI is Idris SSOT). - Evidence kinds/format specified; example bundle is an honest refused check. Remaining 0.x-AI-MANIFEST.deed files are gatekeeper prose, not DEED grammar. Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- .machine_readable/6a2/ECOSYSTEM.deed | 40 ++++----- .machine_readable/6a2/META.deed | 67 ++++----------- .machine_readable/6a2/STATE.deed | 81 +++++++----------- Justfile | 2 +- panoply_chora.deed | 26 ++++++ src/evidence/EVIDENCE-KINDS.adoc | 92 +++++++++++++++++++++ src/evidence/README.adoc | 5 +- src/evidence/examples/core-typing.evidence | 14 ++++ src/interface/Abi/Foreign.idr | 8 +- src/interface/ffi/src/main.zig | 17 ++-- src/interface/ffi/test/integration_test.zig | 8 +- tests/evidence_spec.sh | 21 +++++ tests/p2p.sh | 71 ++++++++++++---- 13 files changed, 283 insertions(+), 169 deletions(-) create mode 100644 panoply_chora.deed create mode 100644 src/evidence/EVIDENCE-KINDS.adoc create mode 100644 src/evidence/examples/core-typing.evidence create mode 100755 tests/evidence_spec.sh diff --git a/.machine_readable/6a2/ECOSYSTEM.deed b/.machine_readable/6a2/ECOSYSTEM.deed index fcb1132..a2e1b00 100644 --- a/.machine_readable/6a2/ECOSYSTEM.deed +++ b/.machine_readable/6a2/ECOSYSTEM.deed @@ -1,28 +1,16 @@ -# SPDX-License-Identifier: MPL-2.0 -# ECOSYSTEM.deed — Ecosystem position -# +;; SPDX-FileCopyrightText: © 2026 Jonathan D.A. Jewell (hyperpolymath) +;; SPDX-License-Identifier: MPL-2.0 +(repo-deed + :schema-version "1.0.0" + :canonical-name "panoply" + :repo-uuid #u5"hyperpolymath/panoply" + :beholding-chora #u5"estate/chora" + :ecosystem hyperpolymath + :type language-discipline -[metadata] -project = "panoply" -ecosystem = "hyperpolymath" + (related + (project :name affinescript :relationship lessons-source) + (project :name standards :relationship standard-source)) -[position] -type = "language-discipline" -purpose = "An envelope-first language discipline extracted from the lessons of AffineScript: make every safety claim explicit, scoped, inspectable, and mechanically accountable via a checked Core, explicit evidence, and a safety-envelope manifest." - -[pipeline] -position = "research" -chain = "affinescript (broad surface) → panoply (envelope-first discipline)" -notes = "Panoply narrows one lesson from AffineScript — that broad language surfaces need explicit trust envelopes — into a founding principle." -coordination = "standards" - -[related-projects] -projects = [ - { name = "affinescript", relationship = "lessons-source", notes = "Broad experimental language exploring affine types, borrowing, effects, rows, traits, faces, and multiple backends. Panoply is a narrowing of one of its lessons, not a rejection of it; the two share no AST, typing, borrow-checker, or codegen." }, - { name = "standards", relationship = "standard-source", notes = "Defines the RSR standard, contractile canon, and estate policies this repository follows." }, -] - -[boundaries] -not-the-same-as = [ - { name = "affinescript", why = "AffineScript is a broad surface language; Panoply is an envelope-first discipline. Distinct projects, distinct artefacts." }, -] + (not-the-same-as + (project :name affinescript :why "broad surface language vs envelope-first discipline"))) diff --git a/.machine_readable/6a2/META.deed b/.machine_readable/6a2/META.deed index 7463c71..5902a58 100644 --- a/.machine_readable/6a2/META.deed +++ b/.machine_readable/6a2/META.deed @@ -1,53 +1,14 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# META.deed — Project meta-level information -# Architecture decisions, design rationale, governance. - -[metadata] -version = "0.1.0" -last-updated = "2026-04-11" - -[project-info] -type = "monorepo" # library | binary | monorepo | service | website -languages = ["idris2", "zig"] # ABI/FFI seam today; Core/checker languages TBD -license = "MPL-2.0" -author = "Jonathan D.A. Jewell (hyperpolymath)" - -[architecture-decisions] -# ADR format: status = proposed | accepted | deprecated | superseded | rejected -# - { id = "ADR-001", title = "Use Zig for FFI", status = "accepted", date = "2026-02-14" } - -[development-practices] -build-tool = "just" -container-runtime = "podman" -ci-platform = "github-actions" -package-manager = "guix" # guix | nix | cargo | mix - -[maintenance-axes] -scoping-first = true -execution-order = "axis-1 > axis-2 > axis-3" -axis-1 = "must > intend > like" -axis-2 = "corrective > adaptive > perfective" -axis-3 = "systems > compliance > effects" - -[scoping] -sources = "README, roadmap, status docs, maintenance checklist, CI/security docs" -marker-scan = "TODO/FIXME/XXX/HACK/STUB/PARTIAL" -idris-unsound-scan = "believe_me/assert_total" - -[axis-2-maintenance-rules] -corrective-first = true -adaptive-second = true -adaptive-focus = "scope-change reconciliation, stale-reference removal, obsolete-work culling" -perfective-third = true -perfective-source = "axis-1 honest state after corrective/adaptive updates" - -[axis-3-audit-rules] -audit-focus = "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed" -compliance-focus = "seams/compromises/exception register, bounded exceptions, anti-drift checks" -drift-risk-example = "single exception broadening into policy violation (e.g. ReScript->TypeScript spread)" -effects-evidence = "benchmark execution/results and maintainer status dialogue/review" - -[design-rationale] -# Key design decisions and their reasoning +;; SPDX-FileCopyrightText: © 2026 Jonathan D.A. Jewell (hyperpolymath) +;; SPDX-License-Identifier: MPL-2.0 +(repo-deed + :schema-version "1.0.0" + :canonical-name "panoply" + :repo-uuid #u5"hyperpolymath/panoply" + :beholding-chora #u5"estate/chora" + :type library + :languages (idris2 zig) + :license "MPL-2.0" + :author "Jonathan D.A. Jewell (hyperpolymath)" + :build-tool just + :container-runtime podman + :package-manager guix) diff --git a/.machine_readable/6a2/STATE.deed b/.machine_readable/6a2/STATE.deed index f42df45..beb46fd 100644 --- a/.machine_readable/6a2/STATE.deed +++ b/.machine_readable/6a2/STATE.deed @@ -1,53 +1,28 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# STATE.deed — Project state checkpoint -# - -[metadata] -project = "panoply" -version = "0.1.0" -last-updated = "2026-06-21" -status = "active" # active | paused | archived - -[project-context] -name = "Panoply" -purpose = "An envelope-first language discipline: every safety claim explicit, scoped, inspectable, and mechanically accountable. Defined by three artefacts — a checked Core, explicit evidence, and a safety-envelope manifest." -completion-percentage = 5 - -[position] -phase = "design" # design | implementation | testing | maintenance | archived -maturity = "experimental" # experimental | alpha | beta | production | lts - -[route-to-mvp] -milestones = [ - { name = "Charter: envelope-first design discipline (docs/architecture/DESIGN-DISCIPLINE.adoc + ADR-0002)", completion = 100 }, - { name = "Core: the checked core language and its checker", completion = 0 }, - { name = "Evidence: witness formats for claims (proof / check / runtime discipline)", completion = 0 }, - { name = "Manifest: per-program, per-backend safety-envelope manifest schema", completion = 0 }, - { name = "Projections: first surface projection + projection-equivalence witnesses", completion = 0 }, - { name = "Backend contracts: first backend envelope and its contract", completion = 0 }, -] - -[blockers-and-issues] -# No active blockers. The mechanisms named by the charter are not yet implemented; -# this is expected at the design phase, not a blocker. - -[critical-next-actions] -actions = [ - "Specify the Core: abstract syntax, typing/checking judgements, and the projection target.", - "Specify the evidence model: what counts as a witness for each guarantee class.", - "Specify the manifest schema: how earned and un-earned guarantees are recorded per backend.", - "Define the first backend contract and what guarantees it can uphold.", -] - -[maintenance-status] -last-run-utc = "never" -last-report = "docs/reports/maintenance/latest.json" -last-result = "unknown" # unknown | pass | warn | fail -open-warnings = 0 -open-failures = 0 - -[ecosystem] -part-of = ["hyperpolymath"] -related = ["affinescript"] +;; SPDX-FileCopyrightText: © 2026 Jonathan D.A. Jewell (hyperpolymath) +;; SPDX-License-Identifier: MPL-2.0 +;; +;; Project state as a repo-deed body fragment stored under 6a2 for +;; existing Justfile readers. Canonical identity lives in +;; ../../panoply_chora.deed. This file is a repo-deed so the ABNF +;; applies; do not reintroduce TOML [section] form. +(repo-deed + :schema-version "1.0.0" + :canonical-name "panoply" + :repo-uuid #u5"hyperpolymath/panoply" + :beholding-chora #u5"estate/chora" + :last-updated "2026-09-20" + :status active + :phase design + :maturity experimental + :completion-percentage 5 + + (purpose + "An envelope-first language discipline: every safety claim explicit, scoped, inspectable, and mechanically accountable.") + + (milestones + (milestone :name charter :completion 100) + (milestone :name core :completion 20) + (milestone :name evidence :completion 20) + (milestone :name manifest :completion 0) + (milestone :name projections :completion 0) + (milestone :name backends :completion 0))) diff --git a/Justfile b/Justfile index 6db2d9d..9dbefd1 100644 --- a/Justfile +++ b/Justfile @@ -511,7 +511,7 @@ state-touch: # Show current phase from STATE.deed state-phase: - @grep -oP 'phase\s*=\s*"\K[^"]+' .machine_readable/6a2/STATE.deed 2>/dev/null | head -1 || echo "unknown" + @grep -oP ':phase\s+\K[A-Za-z]+' .machine_readable/6a2/STATE.deed 2>/dev/null | head -1 || echo "unknown" # ═══════════════════════════════════════════════════════════════════════════════ # GUIX (channels — Nix is deprecated in this estate) diff --git a/panoply_chora.deed b/panoply_chora.deed new file mode 100644 index 0000000..02a81d5 --- /dev/null +++ b/panoply_chora.deed @@ -0,0 +1,26 @@ +;; SPDX-FileCopyrightText: © 2026 Jonathan D.A. Jewell (hyperpolymath) +;; SPDX-License-Identifier: MPL-2.0 +(repo-deed + :schema-version "1.0.0" + :canonical-name "panoply" + :repo-uuid #u5"hyperpolymath/panoply" + :beholding-chora #u5"estate/chora" + + (project + :purpose "envelope-first language discipline" + :phase design + :maturity experimental + :completion-percentage 5 + :license "MPL-2.0") + + (artefacts + (artefact :name core :status specified :issue 5) + (artefact :name evidence :status specified :issue 6) + (artefact :name manifest :status sketch :issue 7) + (artefact :name projections :status sketch :issue 8) + (artefact :name backends :status sketch :issue 9)) + + (warrant + :kind check + :claim "no-global-safety" + :note "charter forbids a whole-language safety theorem")) diff --git a/src/evidence/EVIDENCE-KINDS.adoc b/src/evidence/EVIDENCE-KINDS.adoc new file mode 100644 index 0000000..0d726a9 --- /dev/null +++ b/src/evidence/EVIDENCE-KINDS.adoc @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += Panoply Evidence — Three Kinds and Formats +:toc: + +Normative for issue #6. Core judgements (`src/core/CORE-JUDGEMENTS.adoc`) +yield a bundle `E`. This document says what `E` *is* on disk and in memory. + +A check is **never** labelled a proof. A runtime discipline is never +labelled a check. + +== Kinds + +[cols="1,2,3",options="header"] +|=== +| `kind` | What it is | Honest use + +| `proof` +| Mechanised derivation in Coq / Agda / Idris2 / Lean, no `Admitted` / + `sorry` / `believe_me` on the load-bearing path. `Print Assumptions` + (or equivalent) clean. +| Metatheory (issue #10). Core typing facts may *become* proof-kind only + after a mechanised theorem names them. + +| `check` +| Result of a *decision procedure* that ran (Core checker, ABI layout + checker, schema validator). Reproducible command + exit + artefact hash. +| Default for `Γ ⊢ t ↝ E : q A` until metatheory exists. + +| `runtime-discipline` +| A named invariant enforced while the program runs (affine drop, lock, + capability check). Not a theorem. Must name the enforcer. +| Backend contracts (issue #9) that cannot be proved or decided statically. +|=== + +== In-memory record + +---- +E ::= { + kind : proof | check | runtime-discipline + obligation-id : symbol ; e.g. core.typing, abi.layout + subject : sha256 of Core AST or artefact + facts : list of named facts (see CORE-JUDGEMENTS) + status : established | refused + witness-ref : path or prover locator + produced-by : tool@version +} +---- + +== On-disk (not a DEED chora) + +Evidence instances are **not** `*_chora.deed` files. They live as: + +`src/evidence/examples/.evidence` + +UTF-8, SPDX header as `#` comments (not DEED `;;`), then a single +s-expression whose head is `evidence`: + +---- +# SPDX-License-Identifier: MPL-2.0 +(evidence + :schema-version "0.1.0" + :kind check + :obligation-id core.typing + :subject "sha256:…" + :status refused + :witness-ref "none" + :produced-by "panoply-spec@0.1.0" + (facts)) +---- + +`:kind` MUST be one of the three symbols above. A manifest emitter +(issue #7) MUST refuse an envelope whose evidence file is missing, whose +`:status` is `refused`, or whose `:kind` is not in that set. + +== Link from Core + +`Γ ⊢ t ↝ E : q A` constructs this record. Until a checker exists, the +only honest on-disk example is `:status refused` with empty `(facts)` — +silence is not a result; a refused bundle *is*. + +== Validation rules (for the future emitter) + +. Missing file → refuse envelope. +. `:kind proof` without a prover artefact path → refuse (do not + relabel as check). +. `:kind check` citing a `.v`/`.idr` proof file → refuse (wrong kind). +. `:kind runtime-discipline` without `:enforcer` field → refuse. + +== Status + +Specified. No emitter. Example: `examples/core-typing.evidence`. diff --git a/src/evidence/README.adoc b/src/evidence/README.adoc index bd034d7..3154fff 100644 --- a/src/evidence/README.adoc +++ b/src/evidence/README.adoc @@ -8,9 +8,8 @@ [IMPORTANT] ==== -*Not yet implemented.* Sketch area per the -xref:../../docs/architecture/DESIGN-DISCIPLINE.adoc[charter]. The evidence -formats do not exist yet (design phase). +*Formats specified; no emitter yet.* See xref:EVIDENCE-KINDS.adoc[EVIDENCE-KINDS.adoc] +and `examples/core-typing.evidence` (honest `:status refused`). ==== == The three kinds of evidence diff --git a/src/evidence/examples/core-typing.evidence b/src/evidence/examples/core-typing.evidence new file mode 100644 index 0000000..b428d62 --- /dev/null +++ b/src/evidence/examples/core-typing.evidence @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# Honest refused check: no Core checker exists yet. This file exists so +# the evidence format is instantiated, not so a guarantee is claimed. +(evidence + :schema-version "0.1.0" + :kind check + :obligation-id core.typing + :subject "sha256:none" + :status refused + :witness-ref "none" + :produced-by "panoply-spec@0.1.0" + (facts)) diff --git a/src/interface/Abi/Foreign.idr b/src/interface/Abi/Foreign.idr index ca66b08..39d0476 100644 --- a/src/interface/Abi/Foreign.idr +++ b/src/interface/Abi/Foreign.idr @@ -17,11 +17,11 @@ import Abi.Layout -------------------------------------------------------------------------------- ||| Raw FFI call to initialize the library -%foreign "C:rsr_init,librsr" +%foreign "C:panoply_init,libpanoply" prim__init : PrimIO Bits64 ||| Raw FFI call to free library resources -%foreign "C:rsr_free,librsr" +%foreign "C:panoply_free,libpanoply" prim__free : Bits64 -> PrimIO () ||| Safe wrapper for initialization @@ -41,7 +41,7 @@ free h = primIO (prim__free h.ptr) -------------------------------------------------------------------------------- ||| Raw FFI call for main processing -%foreign "C:rsr_process,librsr" +%foreign "C:panoply_process,libpanoply" prim__process : Bits64 -> Bits32 -> PrimIO Bits32 ||| Safe wrapper with error handling @@ -58,7 +58,7 @@ process h input = do -------------------------------------------------------------------------------- ||| Get the current error description from the library -%foreign "C:rsr_get_error,librsr" +%foreign "C:panoply_last_error,libpanoply" prim__getError : Bits64 -> PrimIO (Ptr String) ||| Detailed error string helper diff --git a/src/interface/ffi/src/main.zig b/src/interface/ffi/src/main.zig index 55fe233..dbdd6fa 100644 --- a/src/interface/ffi/src/main.zig +++ b/src/interface/ffi/src/main.zig @@ -29,13 +29,12 @@ fn clearError() void { // Core Types (must match src/abi/Types.idr) //============================================================================== -/// Result codes (must match Idris2 Result type) +/// Result codes (must match Idris2 `data Result = Ok | Error | InvalidParam | Busy`) pub const Result = enum(c_int) { ok = 0, @"error" = 1, invalid_param = 2, - out_of_memory = 3, - null_pointer = 4, + busy = 3, }; /// Library handle. Declared as a plain struct (not `opaque`) because Zig @@ -90,7 +89,7 @@ pub export fn panoply_free(handle: ?*Handle) void { pub export fn panoply_process(handle: ?*Handle, input: u32) Result { const h = handle orelse { setError("Null handle"); - return .null_pointer; + return .invalid_param; }; if (!h.initialized) { @@ -153,12 +152,12 @@ pub export fn panoply_process_array( ) Result { const h = handle orelse { setError("Null handle"); - return .null_pointer; + return .invalid_param; }; const buf = buffer orelse { setError("Null buffer"); - return .null_pointer; + return .invalid_param; }; if (!h.initialized) { @@ -219,12 +218,12 @@ pub export fn panoply_register_callback( ) Result { const h = handle orelse { setError("Null handle"); - return .null_pointer; + return .invalid_param; }; const cb = callback orelse { setError("Null callback"); - return .null_pointer; + return .invalid_param; }; if (!h.initialized) { @@ -262,7 +261,7 @@ test "lifecycle" { test "error handling" { const result = panoply_process(null, 0); - try std.testing.expectEqual(Result.null_pointer, result); + try std.testing.expectEqual(Result.invalid_param, result); const err = panoply_last_error(); try std.testing.expect(err != null); diff --git a/src/interface/ffi/test/integration_test.zig b/src/interface/ffi/test/integration_test.zig index 9e2b6d6..a627f8a 100644 --- a/src/interface/ffi/test/integration_test.zig +++ b/src/interface/ffi/test/integration_test.zig @@ -30,7 +30,7 @@ test "operations: process with a valid handle" { test "operations: process with a null handle returns null_pointer" { const result = panoply.panoply_process(null, 0); - try std.testing.expectEqual(panoply.Result.null_pointer, result); + try std.testing.expectEqual(panoply.Result.invalid_param, result); } test "operations: process_array with a valid buffer" { @@ -47,13 +47,13 @@ test "operations: process_array with a null buffer returns null_pointer" { defer panoply.panoply_free(handle); const result = panoply.panoply_process_array(handle, null, 0); - try std.testing.expectEqual(panoply.Result.null_pointer, result); + try std.testing.expectEqual(panoply.Result.invalid_param, result); } test "operations: process_array with a null handle returns null_pointer" { const buf = [_]u8{1}; const result = panoply.panoply_process_array(null, &buf, buf.len); - try std.testing.expectEqual(panoply.Result.null_pointer, result); + try std.testing.expectEqual(panoply.Result.invalid_param, result); } test "strings: get_string returns a value that can be freed" { @@ -123,7 +123,7 @@ test "callbacks: register_callback with a null callback returns null_pointer" { defer panoply.panoply_free(handle); const result = panoply.panoply_register_callback(handle, null); - try std.testing.expectEqual(panoply.Result.null_pointer, result); + try std.testing.expectEqual(panoply.Result.invalid_param, result); } test "utility: is_initialized is false for a null handle" { diff --git a/tests/evidence_spec.sh b/tests/evidence_spec.sh new file mode 100755 index 0000000..c2cbdb1 --- /dev/null +++ b/tests/evidence_spec.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" +FAIL=0 +fail() { echo "FAIL: $*"; FAIL=$((FAIL+1)); } +pass() { echo "PASS: $*"; } + +[[ -f src/evidence/EVIDENCE-KINDS.adoc ]] && pass "kinds spec" || fail "missing EVIDENCE-KINDS" +[[ -f src/evidence/examples/core-typing.evidence ]] && pass "example evidence" || fail "missing example" +grep -q ':kind check' src/evidence/examples/core-typing.evidence || fail "example kind" +grep -q ':status refused' src/evidence/examples/core-typing.evidence && pass "honest refused check" || fail "example must be refused until a checker exists" +# ABNF-shaped chora +head -5 panoply_chora.deed | grep -q 'repo-deed' && pass "panoply_chora.deed is repo-deed" || fail "chora" +grep -q '\[metadata\]' panoply_chora.deed && fail "chora must not be TOML" || pass "chora is not TOML" +grep -q '\[metadata\]' .machine_readable/6a2/STATE.deed && fail "STATE still TOML" || pass "STATE is s-expression" + +echo "FAIL=$FAIL" +exit "$FAIL" diff --git a/tests/p2p.sh b/tests/p2p.sh index 717db46..be945e3 100755 --- a/tests/p2p.sh +++ b/tests/p2p.sh @@ -2,26 +2,65 @@ # SPDX-License-Identifier: MPL-2.0 # Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) # -# P2P tests — peer/process composition of envelopes. -# Design phase: there is no runtime peer protocol. This gate documents -# the obligation and fails closed only if a claimed P2P surface appears -# without tests. +# P2P / coupling: Idris2 ABI (Types + Foreign) ↔ Zig FFI. +# Taxonomy: a single seam (caller→callee / FFI boundary). set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" +FAIL=0 +fail() { echo "FAIL: $*"; FAIL=$((FAIL + 1)); } +pass() { echo "PASS: $*"; } -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -cd "$PROJECT_DIR" +echo "PANOPLY — P2P (ABI ↔ FFI seam)" -echo "PANOPLY — P2P tests" +IDR="src/interface/Abi/Types.idr" +ZIG="src/interface/ffi/src/main.zig" +FOR="src/interface/Abi/Foreign.idr" -# If a peer protocol lands under src/bridges or src/backends, this file -# must grow real cases. Until then, skip is the honest result. -if grep -RIl --include='*.zig' --include='*.idr' -E 'p2p|peer.?to.?peer' src/ 2>/dev/null | grep -q .; then - echo "FAIL: P2P-shaped source exists without a real P2P test harness" - exit 1 +# Idris Result constructors (data Result = Ok | Error | …) +IDR_RES=$(grep -E '^data Result' "$IDR" | sed 's/.*= //; s/|//g') +echo " Idris Result: $IDR_RES" + +# Zig Result tags +ZIG_TAGS=$(awk '/pub const Result = enum/,/};/' "$ZIG" | grep -E '^\s+(ok|@"error"|error|invalid_param|busy)' | sed 's/[=,].*//; s/@"error"/error/; s/[[:space:]]//g') +echo " Zig Result tags:" +echo "$ZIG_TAGS" + +echo "$IDR_RES" | grep -qw Ok || fail "Idris Result missing Ok" +echo "$IDR_RES" | grep -qw Error || fail "Idris Result missing Error" +echo "$IDR_RES" | grep -qw InvalidParam || fail "Idris Result missing InvalidParam" +echo "$IDR_RES" | grep -qw Busy || fail "Idris Result missing Busy" + +echo "$ZIG_TAGS" | grep -qx ok || fail "Zig Result missing ok=0" +echo "$ZIG_TAGS" | grep -qx error || fail "Zig Result missing error" +echo "$ZIG_TAGS" | grep -qx invalid_param || fail "Zig Result missing invalid_param" +echo "$ZIG_TAGS" | grep -qx busy || fail "Zig Result missing busy" + +# Drift: Zig must not grow extra ABI codes Idris cannot name +if echo "$ZIG_TAGS" | grep -Eq 'out_of_memory|null_pointer'; then + fail "Zig Result has codes not in Idris Result (ABI is Idris SSOT)" +else + pass "Zig Result tags ⊆ Idris Result constructors" fi -echo "SKIP: no peer protocol in this repository yet (charter design phase)" -echo "PASS=0 FAIL=0 SKIP=1" -exit 0 +# C symbol names: %foreign "C:name,lib" vs pub export fn name +IDR_SYMS=$(grep '%foreign' "$FOR" | sed 's/.*C://; s/,.*//' | sort) +ZIG_SYMS=$(grep -E '^pub export fn ' "$ZIG" | sed 's/pub export fn //; s/(.*//' | sort) +echo " Idris C symbols:"; echo "$IDR_SYMS" +echo " Zig exports:"; echo "$ZIG_SYMS" + +while read -r s; do + [ -z "$s" ] && continue + if echo "$ZIG_SYMS" | grep -qx "$s"; then + pass "export $s present on both sides" + else + fail "Idris %foreign C:$s has no Zig pub export fn $s" + fi +done <<< "$IDR_SYMS" + +# Handle non-null: Idris createHandle 0 = Nothing; Zig init must not return a zero page as success — structural check only +grep -q 'createHandle 0 = Nothing' "$IDR" && pass "Idris rejects null handle" || fail "Idris createHandle null rule missing" + +echo "FAIL=$FAIL" +exit "$FAIL" From 72de62affe479fe76cece044b2285efdcdfc5fd6 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 20 Sep 2026 12:56:11 +0000 Subject: [PATCH 2/3] chore(rsr): Phase 1 structural alignment with rsr-template-repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add template holdings (ci/, archetypes/, descriptiles pointer, contractile subdirs, src/api/zig, tests/shape, www/dns), root dots (mise, mailmap, agent rules), SECURITY.md, CITATION.cff, AFFIRMATION.adoc, panoply_chora allowlist, JS runtime order (Bun→Deno→pnpm→npm), and repair pre-commit (local deed + root-shape; drop dead a2ml hook). Placeholders are TODOs in docs/status/ROADMAP.adoc. Not a Core checker. Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- .cicd-hygiene-allow | 12 + .clinerules | 43 ++ .cursorrules | 47 +++ .gitleaksignore | 4 + .gitmessage | 18 + .../arrival-pack/0.1-AI-MANIFEST.deed | 6 + .machine_readable/arrival-pack/README.adoc | 8 + .../coaptation/0.1-AI-MANIFEST.deed | 6 + .machine_readable/coaptation/README.adoc | 8 + .../coaptation/core/0.1-AI-MANIFEST.deed | 6 + .machine_readable/coaptation/core/README.adoc | 8 + .../coaptation/receipts/0.1-AI-MANIFEST.deed | 6 + .../coaptation/receipts/README.adoc | 8 + .../contractiles/adjust/0.1-AI-MANIFEST.deed | 6 + .../contractiles/adjust/README.adoc | 8 + .../contractiles/intend/0.1-AI-MANIFEST.deed | 6 + .../contractiles/intend/README.adoc | 8 + .../contractiles/must/0.1-AI-MANIFEST.deed | 6 + .../contractiles/must/README.adoc | 8 + .../contractiles/trust/0.1-AI-MANIFEST.deed | 6 + .../contractiles/trust/README.adoc | 8 + .../descriptiles/0.1-AI-MANIFEST.deed | 6 + .machine_readable/descriptiles/README.adoc | 9 + .machine_readable/root-allow.txt | 13 + .mailmap | 4 + .pre-commit-config.yaml | 38 +- .windsurfrules | 43 ++ AFFIRMATION.adoc | 137 +++++++ CITATION.cff | 17 + CLAUDE.md | 5 + CONTRIBUTING.md | 125 ++++++ GEMINI.md | 4 + SECURITY.md | 376 ++++++++++++++++++ archetypes/0.1-AI-MANIFEST.deed | 6 + archetypes/README.adoc | 8 + benches/README.adoc | 6 + ci/.pre-commit-config.yaml | 50 +++ ci/0.1-AI-MANIFEST.deed | 6 + ci/README.adoc | 8 + ci/gitlab-ci.yml | 154 +++++++ docs/practice/JS-RUNTIME-ORDER.adoc | 16 + docs/status/ROADMAP.adoc | 37 +- mise.toml | 13 + scripts/README.adoc | 6 + session/README.adoc | 7 + src/api/0.1-AI-MANIFEST.deed | 6 + src/api/README.adoc | 8 + src/api/zig/0.1-AI-MANIFEST.deed | 6 + src/api/zig/README.adoc | 8 + tests/README.adoc | 7 + tests/e2e/0.1-AI-MANIFEST.deed | 6 + tests/e2e/README.adoc | 8 + tests/shape/0.1-AI-MANIFEST.deed | 6 + tests/shape/README.adoc | 8 + www/dns/0.1-AI-MANIFEST.deed | 6 + www/dns/README.adoc | 8 + 56 files changed, 1369 insertions(+), 38 deletions(-) create mode 100644 .cicd-hygiene-allow create mode 100644 .clinerules create mode 100644 .cursorrules create mode 100644 .gitleaksignore create mode 100644 .gitmessage create mode 100644 .machine_readable/arrival-pack/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/arrival-pack/README.adoc create mode 100644 .machine_readable/coaptation/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/coaptation/README.adoc create mode 100644 .machine_readable/coaptation/core/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/coaptation/core/README.adoc create mode 100644 .machine_readable/coaptation/receipts/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/coaptation/receipts/README.adoc create mode 100644 .machine_readable/contractiles/adjust/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/contractiles/adjust/README.adoc create mode 100644 .machine_readable/contractiles/intend/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/contractiles/intend/README.adoc create mode 100644 .machine_readable/contractiles/must/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/contractiles/must/README.adoc create mode 100644 .machine_readable/contractiles/trust/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/contractiles/trust/README.adoc create mode 100644 .machine_readable/descriptiles/0.1-AI-MANIFEST.deed create mode 100644 .machine_readable/descriptiles/README.adoc create mode 100644 .mailmap create mode 100644 .windsurfrules create mode 100644 AFFIRMATION.adoc create mode 100644 CITATION.cff create mode 100644 CLAUDE.md create mode 100644 CONTRIBUTING.md create mode 100644 GEMINI.md create mode 100644 SECURITY.md create mode 100644 archetypes/0.1-AI-MANIFEST.deed create mode 100644 archetypes/README.adoc create mode 100644 benches/README.adoc create mode 100644 ci/.pre-commit-config.yaml create mode 100644 ci/0.1-AI-MANIFEST.deed create mode 100644 ci/README.adoc create mode 100644 ci/gitlab-ci.yml create mode 100644 docs/practice/JS-RUNTIME-ORDER.adoc create mode 100644 mise.toml create mode 100644 scripts/README.adoc create mode 100644 src/api/0.1-AI-MANIFEST.deed create mode 100644 src/api/README.adoc create mode 100644 src/api/zig/0.1-AI-MANIFEST.deed create mode 100644 src/api/zig/README.adoc create mode 100644 tests/README.adoc create mode 100644 tests/e2e/0.1-AI-MANIFEST.deed create mode 100644 tests/e2e/README.adoc create mode 100644 tests/shape/0.1-AI-MANIFEST.deed create mode 100644 tests/shape/README.adoc create mode 100644 www/dns/0.1-AI-MANIFEST.deed create mode 100644 www/dns/README.adoc diff --git a/.cicd-hygiene-allow b/.cicd-hygiene-allow new file mode 100644 index 0000000..1513822 --- /dev/null +++ b/.cicd-hygiene-allow @@ -0,0 +1,12 @@ +# Code-hygiene gate allowlist (consumed by cicd-suite actions/code-hygiene-check). +# Patterns are git pathspec excludes, applied to both the debt-marker scan and +# the proof-circumvention scan. +# +# The two entries below are TEMPLATE SCAFFOLDS, not implementation debt: +# their TODOs are the instantiation seams every minted repo is meant to fill +# in (entrypoint command, e2e sections). Excluding them keeps the gate's +# debt-tracking signal clean for real source in instantiated repos, which +# inherit this file. If an instantiated repo later owns genuine debt in +# these paths, resolve or issue-link it there — do not widen this list. +build/container/entrypoint.sh +tests/e2e.sh diff --git a/.clinerules b/.clinerules new file mode 100644 index 0000000..fe11e22 --- /dev/null +++ b/.clinerules @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# Authoritative source: docs/AI-CONVENTIONS.md + +# STARTUP: Read 0-AI-MANIFEST.deed first, then .machine_readable/6a2/STATE.deed. + +# LICENSE +# All original code: MPL-2.0. +# Never AGPL-3.0. MPL-2.0 only as platform-required fallback. +# SPDX header required on every source file. +# Copyright: Jonathan D.A. Jewell (hyperpolymath) + +# STATE FILES (.machine_readable/ ONLY) +# Never create in repo root: STATE.deed, META.deed, ECOSYSTEM.deed, +# AGENTIC.deed, NEUROSYM.deed, PLAYBOOK.deed. +# The .machine_readable/ directory is the single source of truth. + +# BANNED PATTERNS +# Idris2: believe_me, assert_total, assert_smaller, unsafePerformIO +# Haskell: unsafeCoerce, unsafePerformIO, undefined, error +# OCaml: Obj.magic, Obj.repr, Obj.obj +# Coq: Admitted +# Lean: sorry +# Rust: transmute (unless FFI with // SAFETY: comment) + +# BANNED LANGUAGES +# TypeScript -> ReScript +# Node.js / npm / bun -> Deno +# Go -> Rust +# Python -> Julia or Rust + +# CONTAINERS +# Runtime: Podman (never Docker). +# File: Containerfile (never Dockerfile). +# Base: cgr.dev/chainguard/wolfi-base:latest or cgr.dev/chainguard/static:latest. + +# ABI/FFI +# ABI: Idris2 with dependent types (src/interface/abi/). +# FFI: Zig with C ABI (src/interface/ffi/). +# Headers: src/interface/generated/. + +# BUILD: Use just (justfile) for all tasks. +# STYLE: Descriptive names. Document all files. SPDX headers everywhere. diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..e7b19ba --- /dev/null +++ b/.cursorrules @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# Authoritative source: docs/AI-CONVENTIONS.md + +# Read 0-AI-MANIFEST.deed in the repo root FIRST for canonical file locations. + +# LICENSE +# All original code: MPL-2.0 (SPDX header required on every file). +# Never use AGPL-3.0. Fallback to MPL-2.0 only when platform requires it. +# Copyright: Jonathan D.A. Jewell (hyperpolymath) + +# STATE FILES +# .deed metadata files go in .machine_readable/ ONLY. +# Never create STATE.deed, META.deed, ECOSYSTEM.deed, AGENTIC.deed, +# NEUROSYM.deed, or PLAYBOOK.deed in the repository root. + +# BANNED PATTERNS +# Idris2: believe_me, assert_total, assert_smaller, unsafePerformIO +# Haskell: unsafeCoerce, unsafePerformIO, undefined, error +# OCaml: Obj.magic, Obj.repr, Obj.obj +# Coq: Admitted +# Lean: sorry +# Rust: transmute (unless FFI with // SAFETY: comment) + +# BANNED LANGUAGES +# TypeScript -> use ReScript +# Node.js / npm / bun -> use Deno +# Go -> use Rust +# Python -> use Julia or Rust + +# CONTAINERS +# Runtime: Podman (never Docker) +# File: Containerfile (never Dockerfile) +# Base: cgr.dev/chainguard/wolfi-base:latest + +# ABI/FFI STANDARD +# ABI definitions: Idris2 with dependent types (src/interface/abi/) +# FFI implementation: Zig with C ABI (src/interface/ffi/) +# Generated C headers: src/interface/generated/ + +# BUILD SYSTEM +# Use just (justfile) for all build, test, lint, and format tasks. + +# CODE STYLE +# Use descriptive variable names. +# Annotate and document all files. +# Add SPDX-License-Identifier header to every source file. diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 0000000..76765a3 --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,4 @@ +874cfd89ae9e1567275202e829a187d5d2e465c3:build/templates/CHORA.deed.in:generic-api-key:21 +8f8cc39824c23b1badc8cc04862755fcb2c6f8d5:build/templates/CHORA.deed.in:generic-api-key:21 +874cfd89ae9e1567275202e829a187d5d2e465c3:build/templates/CLADE.a2ml.in:generic-api-key:21 +8f8cc39824c23b1badc8cc04862755fcb2c6f8d5:build/templates/CLADE.a2ml.in:generic-api-key:21 diff --git a/.gitmessage b/.gitmessage new file mode 100644 index 0000000..ef6021d --- /dev/null +++ b/.gitmessage @@ -0,0 +1,18 @@ +# (): (Max 50 chars) +# |<------------------------------------------------>| + +# Explain WHY this change is being made (Max 72 chars per line) +# |<---------------------------------------------------------------------->| + +# Explain HOW this change was implemented (if not obvious) + +# [ ] Tests added/updated +# [ ] Documentation updated +# [ ] ABI/FFI boundaries verified (if applicable) + +# Issue tracking: +# Resolves: # +# See also: # +# +# --- +# Allowed Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert diff --git a/.machine_readable/arrival-pack/0.1-AI-MANIFEST.deed b/.machine_readable/arrival-pack/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..a71e6b3 --- /dev/null +++ b/.machine_readable/arrival-pack/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/arrival-pack" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/arrival-pack/README.adoc b/.machine_readable/arrival-pack/README.adoc new file mode 100644 index 0000000..05095c8 --- /dev/null +++ b/.machine_readable/arrival-pack/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += arrival-pack + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/coaptation/0.1-AI-MANIFEST.deed b/.machine_readable/coaptation/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..daf7a41 --- /dev/null +++ b/.machine_readable/coaptation/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/coaptation" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/coaptation/README.adoc b/.machine_readable/coaptation/README.adoc new file mode 100644 index 0000000..66cd2b8 --- /dev/null +++ b/.machine_readable/coaptation/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += coaptation + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/coaptation/core/0.1-AI-MANIFEST.deed b/.machine_readable/coaptation/core/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..9d48b0f --- /dev/null +++ b/.machine_readable/coaptation/core/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/coaptation/core" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/coaptation/core/README.adoc b/.machine_readable/coaptation/core/README.adoc new file mode 100644 index 0000000..ff5339d --- /dev/null +++ b/.machine_readable/coaptation/core/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += core + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/coaptation/receipts/0.1-AI-MANIFEST.deed b/.machine_readable/coaptation/receipts/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..c9747e8 --- /dev/null +++ b/.machine_readable/coaptation/receipts/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/coaptation/receipts" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/coaptation/receipts/README.adoc b/.machine_readable/coaptation/receipts/README.adoc new file mode 100644 index 0000000..68afa66 --- /dev/null +++ b/.machine_readable/coaptation/receipts/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += receipts + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/contractiles/adjust/0.1-AI-MANIFEST.deed b/.machine_readable/contractiles/adjust/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..6b2c24c --- /dev/null +++ b/.machine_readable/contractiles/adjust/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/contractiles/adjust" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/contractiles/adjust/README.adoc b/.machine_readable/contractiles/adjust/README.adoc new file mode 100644 index 0000000..b6da5bd --- /dev/null +++ b/.machine_readable/contractiles/adjust/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += adjust + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/contractiles/intend/0.1-AI-MANIFEST.deed b/.machine_readable/contractiles/intend/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..ca9f79c --- /dev/null +++ b/.machine_readable/contractiles/intend/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/contractiles/intend" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/contractiles/intend/README.adoc b/.machine_readable/contractiles/intend/README.adoc new file mode 100644 index 0000000..5c257b6 --- /dev/null +++ b/.machine_readable/contractiles/intend/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += intend + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/contractiles/must/0.1-AI-MANIFEST.deed b/.machine_readable/contractiles/must/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..0a4a822 --- /dev/null +++ b/.machine_readable/contractiles/must/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/contractiles/must" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/contractiles/must/README.adoc b/.machine_readable/contractiles/must/README.adoc new file mode 100644 index 0000000..b5557a3 --- /dev/null +++ b/.machine_readable/contractiles/must/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += must + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/contractiles/trust/0.1-AI-MANIFEST.deed b/.machine_readable/contractiles/trust/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..acb4ffe --- /dev/null +++ b/.machine_readable/contractiles/trust/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/contractiles/trust" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/contractiles/trust/README.adoc b/.machine_readable/contractiles/trust/README.adoc new file mode 100644 index 0000000..9e42dca --- /dev/null +++ b/.machine_readable/contractiles/trust/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += trust + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/.machine_readable/descriptiles/0.1-AI-MANIFEST.deed b/.machine_readable/descriptiles/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..c4ce431 --- /dev/null +++ b/.machine_readable/descriptiles/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = ".machine_readable/descriptiles" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/.machine_readable/descriptiles/README.adoc b/.machine_readable/descriptiles/README.adoc new file mode 100644 index 0000000..d6ca9a7 --- /dev/null +++ b/.machine_readable/descriptiles/README.adoc @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += descriptiles + +The RSR template stores STATE/META/ECOSYSTEM here. +Panoply's live descriptiles are `.machine_readable/6a2/*.deed` (s-expression +repo-deed form). This directory is a holding pointer so the template path exists. + +See `../6a2/README.adoc`. diff --git a/.machine_readable/root-allow.txt b/.machine_readable/root-allow.txt index 90383e1..482a919 100644 --- a/.machine_readable/root-allow.txt +++ b/.machine_readable/root-allow.txt @@ -38,6 +38,19 @@ coordination.k9 # repo-local session binding (template-mandated) .gitignore .tool-versions .hypatia-ignore # repo-scoped Hypatia scanner exemptions (read from repo root) +.cicd-hygiene-allow # rsr-template-repo +.clinerules # agent roots (copies of .machine_readable/ai/) +.cursorrules +.windsurfrules +.gitleaksignore +.gitmessage +.mailmap +mise.toml # local toolchain helper; Guix remains packager +CITATION.cff # citation-file-format (also docs/attribution/) +CLAUDE.md # thin pointer to 0-AI-MANIFEST.deed +GEMINI.md # same +panoply_chora.deed # DEED ABNF repo-deed (filename dispatch *_chora.deed) +archetypes/ # RSR template holding; panoply is not a julia mint # ─── Directories ───────────────────────────────────────────────────────────── .devcontainer/ # VS Code dev container spec; tool-required at root diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..e416ced --- /dev/null +++ b/.mailmap @@ -0,0 +1,4 @@ +# Format: Canonical Name Alias Name +Jonathan D.A. Jewell hyperpolymath +# Bot identities +gitbot-fleet[bot] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b048d1c..96435c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,9 @@ # SPDX-License-Identifier: MPL-2.0 -# Pre-commit hooks for hyperpolymath RSR repos. -# Install: pip install pre-commit && pre-commit install -# Run manually: pre-commit run --all-files +# Pre-commit hooks for panoply. +# Optional host tool. Install: pre-commit install +# Run: pre-commit run --all-files repos: - # --- Standard hooks --- - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: @@ -18,33 +17,26 @@ repos: - id: check-added-large-files args: ['--maxkb=1024'] - # --- A2ML manifest validation --- - - repo: https://github.com/hyperpolymath/a2ml-pre-commit - rev: main + - repo: local hooks: - - id: validate-a2ml - name: Validate A2ML manifests + - id: validate-deed + name: Validate DEED manifests + entry: bash .github/hooks/validate-deed.sh + language: system + pass_filenames: false + - id: root-shape + name: Root allowlist + entry: bash scripts/check-root-shape.sh + language: system + pass_filenames: false - # --- K9 contract validation --- - - repo: https://github.com/hyperpolymath/k9-pre-commit - rev: main - hooks: - - id: validate-k9 - name: Validate K9 contracts - - # --- Shell linting --- - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.10.0.1 hooks: - id: shellcheck - # --- EditorConfig --- - repo: https://github.com/editorconfig-checker/editorconfig-checker.python rev: 3.2.1 hooks: - id: editorconfig-checker - exclude: '(\.git|node_modules|target|_build|deps|\.deno|external_corpora|\.lake)/' - - # --- Secret detection --- - rev: v8.24.3 - hooks: + exclude: '(\\.git|node_modules|target|_build|deps|\\.deno|external_corpora|\\.lake|\\.zig-cache)/' diff --git a/.windsurfrules b/.windsurfrules new file mode 100644 index 0000000..fe11e22 --- /dev/null +++ b/.windsurfrules @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# Authoritative source: docs/AI-CONVENTIONS.md + +# STARTUP: Read 0-AI-MANIFEST.deed first, then .machine_readable/6a2/STATE.deed. + +# LICENSE +# All original code: MPL-2.0. +# Never AGPL-3.0. MPL-2.0 only as platform-required fallback. +# SPDX header required on every source file. +# Copyright: Jonathan D.A. Jewell (hyperpolymath) + +# STATE FILES (.machine_readable/ ONLY) +# Never create in repo root: STATE.deed, META.deed, ECOSYSTEM.deed, +# AGENTIC.deed, NEUROSYM.deed, PLAYBOOK.deed. +# The .machine_readable/ directory is the single source of truth. + +# BANNED PATTERNS +# Idris2: believe_me, assert_total, assert_smaller, unsafePerformIO +# Haskell: unsafeCoerce, unsafePerformIO, undefined, error +# OCaml: Obj.magic, Obj.repr, Obj.obj +# Coq: Admitted +# Lean: sorry +# Rust: transmute (unless FFI with // SAFETY: comment) + +# BANNED LANGUAGES +# TypeScript -> ReScript +# Node.js / npm / bun -> Deno +# Go -> Rust +# Python -> Julia or Rust + +# CONTAINERS +# Runtime: Podman (never Docker). +# File: Containerfile (never Dockerfile). +# Base: cgr.dev/chainguard/wolfi-base:latest or cgr.dev/chainguard/static:latest. + +# ABI/FFI +# ABI: Idris2 with dependent types (src/interface/abi/). +# FFI: Zig with C ABI (src/interface/ffi/). +# Headers: src/interface/generated/. + +# BUILD: Use just (justfile) for all tasks. +# STYLE: Descriptive names. Document all files. SPDX headers everywhere. diff --git a/AFFIRMATION.adoc b/AFFIRMATION.adoc new file mode 100644 index 0000000..66479ec --- /dev/null +++ b/AFFIRMATION.adoc @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += AFFIRMATION — panoply, as of 2026-09-20 +:toc: macro +:toclevels: 2 + +_the No-Bullshit file: what we affirm was true and checkable at this moment._ + +toc::[] + +== What this is, and how it works + +A dated snapshot of what can honestly be claimed about *panoply* at one +commit. Not a promise about Core, evidence emitters, or safety. + +== The epistemic contract + +You may conclude that the commands below were run in this session. +You may *not* conclude that anything is true *now*, that unlisted things +pass, or that a Core checker exists. + +== Verifiable anchor + +[cols="1,3",options="header"] +|=== +| Field | Value + +| Project | panoply +| Repo | `hyperpolymath/panoply` +| Branch | `chore/deed-guix-core-tests` +| Commit (HEAD) | `d18c5aeaf4d46f342624685ad80d24332ce6caac` +| Permalink | https://github.com/hyperpolymath/panoply/tree/d18c5aeaf4d46f342624685ad80d24332ce6caac +| Verified (UTC) | `2026-09-20T12:45:00Z` +| Working-tree delta at verification +| *dirty* — Phase 1 structural files uncommitted (dots, holdings, AFFIRMATION). + Zig tests were run against the FFI sources on that dirty tree; they are not + affected by AsciiDoc holdings. +| Toolchain | zig 0.15.1; just 1.58.0; idris2 *not* on PATH +| Affirmed by | engineering agent on Arena.ai (report of runs); owner signs by `-S` commit +|=== + +If you are reading this at a later commit, re-run <>. + +== Companion documents + +* `README.adoc` — aspiration +* `EXPLAINME.adoc` — mechanism +* `panoply_chora.deed` — repo-deed identity +* `docs/status/TEST-NEEDS.adoc` — test inventory (may lag) + +== The honest state (one breath) + +Panoply is a design-phase envelope-first *discipline*: charter and RSR +spine exist; Core checker does not; Zig FFI tests pass; Idris2 was not +run here. + +=== What is solid (and how we checked) + +[cols="2,1,3",options="header"] +|=== +| Claim | Status | Evidence + +| Zig FFI unit+integration tests +| affirmed +| `cd src/interface/ffi && zig build test --summary all` — 20/20 pass (zig 0.15.1) + +| Aspect tests (SPDX + banned-pattern code scan) +| affirmed +| `bash tests/aspect_tests.sh` — PASS=3 FAIL=0 + +| ABI↔FFI P2P coupling +| affirmed +| `bash tests/p2p.sh` — FAIL=0 (Idris Result tags match Zig; `panoply_*` C names) + +| Core spec artefacts exist +| affirmed +| `bash tests/core_spec.sh` — FAIL=0 + +| Evidence kinds spec + refused example +| affirmed +| `bash tests/evidence_spec.sh` — FAIL=0; example `:status refused` + +| Idris2 ABI typecheck +| *not checked* +| idris2 not on PATH in this session + +| Core checker / manifest emitter +| *not claimed* +| not implemented +|=== + +=== The honest nuance you must not lose + +* 20 Zig tests exercise the *FFI scaffold*, not Core typing. +* Files named `.deed` that are `0.x-AI-MANIFEST` are still gatekeeper + prose, not DEED ABNF choruses. +* CRG remains **X**. + +=== Known-incomplete but honestly fenced + +* P2P skip for a *network* peer protocol — fenced by `tests/p2p.sh` + failing if Idris/Zig Result drift returns. +* No Idris2 in this environment — fenced by e2e/lifecycle SKIP, not a fake pass. + +=== Outstanding / weak / refuted + +* Hypatia scan still advisory-red (issue #11). +* `e2e.yml` jobs still commented. +* Remaining template `www/dns` etc. are holdings only. + +[#reproduce] +== Reproduce it yourself + +[source,bash] +---- +git clone https://github.com/hyperpolymath/panoply +cd panoply +git checkout d18c5aeaf4d46f342624685ad80d24332ce6caac +# zig 0.15.1 on PATH +cd src/interface/ffi && zig build test --summary all +cd ../../.. +bash tests/aspect_tests.sh +bash tests/p2p.sh +bash tests/core_spec.sh +bash tests/evidence_spec.sh +---- + +== One-line characterisation (quote this) + +> Panoply disciplines claims; it does not yet check Core, and the only +> tests we re-ran here are Zig FFI plus spec/coupling shells. + +== Joint attestation + +* *Engineering party (AI):* Arena.ai Agent Mode — ran the checks named + above at 2026-09-20T12:45:00Z. +* *Owner / maintainer:* Jonathan D.A. Jewell — signs by `git commit -S -s`. diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..dbb86e2 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,17 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: +- family-names: "Jewell" + given-names: "Jonathan D.A." + orcid: "https://orcid.org/0000-0000-0000-0000" # Placeholder +title: "Panoply" +version: 0.1.0 +date-released: 2026-06-21 +url: "https://github.com/hyperpolymath/panoply" +repository-code: "https://github.com/hyperpolymath/panoply" +license: MPL-2.0 +keywords: + - "rsr" + - "formal-verification" + - "neurosymbolic" + - "provenance" diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..bdcc37d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ + +# Agent entry + +Read `0-AI-MANIFEST.deed` first, then `panoply_chora.deed`. +Do not invent guarantees. Core checker is not implemented. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..48aced9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,125 @@ + +# Clone the repository +git clone https://github.com/hyperpolymath/panoply.git +cd panoply + +# Using Nix (recommended for reproducibility) +nix develop + +# Or using toolbox/distrobox +toolbox create panoply-dev +toolbox enter panoply-dev +# Install dependencies manually + +# Verify setup +just check # or: cargo check / mix compile / etc. +just test # Run test suite +``` + +### Repository Structure +``` +panoply/ +├── src/ # Source code (Perimeter 1-2) +├── lib/ # Library code (Perimeter 1-2) +├── extensions/ # Extensions (Perimeter 2) +├── plugins/ # Plugins (Perimeter 2) +├── tools/ # Tooling (Perimeter 2) +├── docs/ # Documentation (Perimeter 3) +│ ├── architecture/ # ADRs, specs (Perimeter 2) +│ └── proposals/ # RFCs (Perimeter 3) +├── examples/ # Examples (Perimeter 3) +├── spec/ # Spec tests (Perimeter 3) +├── tests/ # Test suite (Perimeter 2-3) +├── .machine_readable/ # ALL machine-readable content (Perimeter 1) +│ ├── *.deed # State files (STATE, META, ECOSYSTEM, etc.) +│ ├── bot_directives/ # Bot configs +│ └── contractiles/ # Policy contracts (k9, dust, lust, must, trust) +├── .well-known/ # Protocol files (Perimeter 1-3) +├── .github/ # GitHub config (Perimeter 1) +│ ├── CONTRIBUTING.md # This file +│ ├── ISSUE_TEMPLATE/ +│ └── workflows/ +├── CHANGELOG.md +├── CODE_OF_CONDUCT.md +├── GOVERNANCE.md +├── LICENSE +├── MAINTAINERS.md +├── README.adoc +├── SECURITY.md +├── build/guix.scm # Guix manifest + channels (Perimeter 1) +├── guix.scm # Guix package — primary (Perimeter 1) +└── Justfile # Task runner (Perimeter 1) +``` + +--- + +## How to Contribute + +### Reporting Bugs + +**Before reporting**: +1. Search existing issues +2. Check if it's already fixed in `main` +3. Determine which perimeter the bug affects + +**When reporting**: + +Use the [bug report template](.github/ISSUE_TEMPLATE/bug_report.md) and include: + +- Clear, descriptive title +- Environment details (OS, versions, toolchain) +- Steps to reproduce +- Expected vs actual behaviour +- Logs, screenshots, or minimal reproduction + +### Suggesting Features + +**Before suggesting**: +1. Check the [roadmap](ROADMAP.md) if available +2. Search existing issues and discussions +3. Consider which perimeter the feature belongs to + +**When suggesting**: + +Use the [feature request template](.github/ISSUE_TEMPLATE/feature_request.md) and include: + +- Problem statement (what pain point does this solve?) +- Proposed solution +- Alternatives considered +- Which perimeter this affects + +### Your First Contribution + +Look for issues labelled: + +- [`good first issue`](https://github.com/hyperpolymath/panoply/labels/good%20first%20issue) — Simple Perimeter 3 tasks +- [`help wanted`](https://github.com/hyperpolymath/panoply/labels/help%20wanted) — Community help needed +- [`documentation`](https://github.com/hyperpolymath/panoply/labels/documentation) — Docs improvements +- [`perimeter-3`](https://github.com/hyperpolymath/panoply/labels/perimeter-3) — Community sandbox scope + +--- + +## Development Workflow + +### Branch Naming +``` +docs/short-description # Documentation (P3) +test/what-added # Test additions (P3) +feat/short-description # New features (P2) +fix/issue-number-description # Bug fixes (P2) +refactor/what-changed # Code improvements (P2) +security/what-fixed # Security fixes (P1-2) +``` + +### Commit Messages + +We follow [Conventional Commits](https://www.conventionalcommits.org/): +``` +(): + +[optional body] + +[optional footer] diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..1059577 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,4 @@ + +# Agent entry + +Read `0-AI-MANIFEST.deed` first. Same rules as `CLAUDE.md`. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..b41dc09 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,376 @@ + +# Security Policy + +We take security seriously. We appreciate your efforts to responsibly disclose vulnerabilities and will make every effort to acknowledge your contributions. + +## Table of Contents + +- [Reporting a Vulnerability](#reporting-a-vulnerability) +- [What to Include](#what-to-include) +- [Response Timeline](#response-timeline) +- [Disclosure Policy](#disclosure-policy) +- [Scope](#scope) +- [Safe Harbour](#safe-harbour) +- [Recognition](#recognition) +- [Security Updates](#security-updates) +- [Security Best Practices](#security-best-practices) + +--- + +## Reporting a Vulnerability + +### Preferred Method: GitHub Security Advisories + +The preferred method for reporting security vulnerabilities is through GitHub's Security Advisory feature: + +1. Navigate to [Report a Vulnerability](https://github.com/hyperpolymath/panoply/security/advisories/new) +2. Click **"Report a vulnerability"** +3. Complete the form with as much detail as possible +4. Submit — we'll receive a private notification + +This method ensures: + +- End-to-end encryption of your report +- Private discussion space for collaboration +- Coordinated disclosure tooling +- Automatic credit when the advisory is published + +### Alternative: Email + +If you cannot use GitHub Security Advisories, you may email us directly at +j.d.a.jewell@open.ac.uk. PGP-encrypted reports are not currently offered; please use +GitHub Security Advisories for end-to-end-encrypted disclosure. + +> **⚠️ Important:** Do not report security vulnerabilities through public GitHub issues, pull requests, discussions, or social media. + +--- + +## What to Include + +A good vulnerability report helps us understand and reproduce the issue quickly. + +### Required Information + +- **Description**: Clear explanation of the vulnerability +- **Impact**: What an attacker could achieve (confidentiality, integrity, availability) +- **Affected versions**: Which versions/commits are affected +- **Reproduction steps**: Detailed steps to reproduce the issue + +### Helpful Additional Information + +- **Proof of concept**: Code, scripts, or screenshots demonstrating the vulnerability +- **Attack scenario**: Realistic attack scenario showing exploitability +- **CVSS score**: Your assessment of severity (use [CVSS 3.1 Calculator](https://www.first.org/cvss/calculator/3.1)) +- **CWE ID**: Common Weakness Enumeration identifier if known +- **Suggested fix**: If you have ideas for remediation +- **References**: Links to related vulnerabilities, research, or advisories + +### Example Report Structure + +```markdown +## Summary +[One-sentence description of the vulnerability] + +## Vulnerability Type +[e.g., SQL Injection, XSS, SSRF, Path Traversal, etc.] + +## Affected Component +[File path, function name, API endpoint, etc.] + +## Affected Versions +[Version range or specific commits] + +## Severity Assessment +- CVSS 3.1 Score: [X.X] +- CVSS Vector: [CVSS:3.1/AV:X/AC:X/PR:X/UI:X/S:X/C:X/I:X/A:X] + +## Description +[Detailed technical description] + +## Steps to Reproduce +1. [First step] +2. [Second step] +3. [...] + +## Proof of Concept +[Code, curl commands, screenshots, etc.] + +## Impact +[What can an attacker achieve?] + +## Suggested Remediation +[Optional: your ideas for fixing] + +## References +[Links to related issues, CVEs, research] +``` + +--- + +## Response Timeline + +We commit to the following response times: + +| Stage | Timeframe | Description | +|-------|-----------|-------------| +| **Initial Response** | 48 hours | We acknowledge receipt and confirm we're investigating | +| **Triage** | 7 days | We assess severity, confirm the vulnerability, and estimate timeline | +| **Status Update** | Every 7 days | Regular updates on remediation progress | +| **Resolution** | 90 days | Target for fix development and release (complex issues may take longer) | +| **Disclosure** | 90 days | Public disclosure after fix is available (coordinated with you) | + +> **Note:** These are targets, not guarantees. Complex vulnerabilities may require more time. We'll communicate openly about any delays. + +--- + +## Disclosure Policy + +We follow **coordinated disclosure** (also known as responsible disclosure): + +1. **You report** the vulnerability privately +2. **We acknowledge** and begin investigation +3. **We develop** a fix and prepare a release +4. **We coordinate** disclosure timing with you +5. **We publish** security advisory and fix simultaneously +6. **You may publish** your research after disclosure + +### Our Commitments + +- We will not take legal action against researchers who follow this policy +- We will work with you to understand and resolve the issue +- We will credit you in the security advisory (unless you prefer anonymity) +- We will notify you before public disclosure +- We will publish advisories with sufficient detail for users to assess risk + +### Your Commitments + +- Report vulnerabilities promptly after discovery +- Give us reasonable time to address the issue before disclosure +- Do not access, modify, or delete data beyond what's necessary to demonstrate the vulnerability +- Do not degrade service availability (no DoS testing on production) +- Do not share vulnerability details with others until coordinated disclosure + +### Disclosure Timeline + +``` +Day 0 You report vulnerability +Day 1-2 We acknowledge receipt +Day 7 We confirm vulnerability and share initial assessment +Day 7-90 We develop and test fix +Day 90 Coordinated public disclosure + (earlier if fix is ready; later by mutual agreement) +``` + +If we cannot reach agreement on disclosure timing, we default to 90 days from your initial report. + +--- + +## Scope + +### In Scope ✅ + +The following are within scope for security research: + +- This repository (`hyperpolymath/panoply`) and all its code +- Official releases and packages published from this repository +- Documentation that could lead to security issues +- Build and deployment configurations in this repository +- Dependencies (report here, we'll coordinate with upstream) + +### Out of Scope ❌ + +The following are **not** in scope: + +- Third-party services we integrate with (report directly to them) +- Social engineering attacks against maintainers +- Physical security +- Denial of service attacks against production infrastructure +- Spam, phishing, or other non-technical attacks +- Issues already reported or publicly known +- Theoretical vulnerabilities without proof of concept + +### Qualifying Vulnerabilities + +We're particularly interested in: + +- Remote code execution +- SQL injection, command injection, code injection +- Authentication/authorisation bypass +- Cross-site scripting (XSS) and cross-site request forgery (CSRF) +- Server-side request forgery (SSRF) +- Path traversal / local file inclusion +- Information disclosure (credentials, PII, secrets) +- Cryptographic weaknesses +- Deserialisation vulnerabilities +- Memory safety issues (buffer overflows, use-after-free, etc.) +- Supply chain vulnerabilities (dependency confusion, etc.) +- Significant logic flaws + +### Non-Qualifying Issues + +The following generally do not qualify as security vulnerabilities: + +- Missing security headers on non-sensitive pages +- Clickjacking on pages without sensitive actions +- Self-XSS (requires victim to paste code) +- Missing rate limiting (unless it enables a specific attack) +- Username/email enumeration (unless high-risk context) +- Missing cookie flags on non-sensitive cookies +- Software version disclosure +- Verbose error messages (unless exposing secrets) +- Best practice deviations without demonstrable impact + +--- + +## Safe Harbour + +We support security research conducted in good faith. + +### Our Promise + +If you conduct security research in accordance with this policy: + +- ✅ We will not initiate legal action against you +- ✅ We will not report your activity to law enforcement +- ✅ We will work with you in good faith to resolve issues +- ✅ We consider your research authorised under the Computer Fraud and Abuse Act (CFAA), UK Computer Misuse Act, and similar laws +- ✅ We waive any potential claim against you for circumvention of security controls + +### Good Faith Requirements + +To qualify for safe harbour, you must: + +- Comply with this security policy +- Report vulnerabilities promptly +- Avoid privacy violations (do not access others' data) +- Avoid service degradation (no destructive testing) +- Not exploit vulnerabilities beyond proof-of-concept +- Not use vulnerabilities for profit (beyond bug bounties where offered) + +> **⚠️ Important:** This safe harbour does not extend to third-party systems. Always check their policies before testing. + +--- + +## Recognition + +We believe in recognising security researchers who help us improve. + +### Hall of Fame + +Researchers who report valid vulnerabilities will be acknowledged in our [Security Acknowledgments](SECURITY-ACKNOWLEDGMENTS.md) (unless they prefer anonymity). + +Recognition includes: + +- Your name (or chosen alias) +- Link to your website/profile (optional) +- Brief description of the vulnerability class +- Date of report + +### What We Offer + +- ✅ Public credit in security advisories +- ✅ Acknowledgment in release notes +- ✅ Entry in our Hall of Fame +- ✅ Reference/recommendation letter upon request (for significant findings) + +### What We Don't Currently Offer + +- ❌ Monetary bug bounties +- ❌ Hardware or swag +- ❌ Paid security research contracts + +> **Note:** We're a community project with limited resources. Your contributions help everyone who uses this software. + +--- + +## Security Updates + +### Receiving Updates + +To stay informed about security updates: + +- **Watch this repository**: Click "Watch" → "Custom" → Select "Security alerts" +- **GitHub Security Advisories**: Published at [Security Advisories](https://github.com/hyperpolymath/panoply/security/advisories) +- **Release notes**: Security fixes noted in [CHANGELOG](CHANGELOG.md) + +### Update Policy + +| Severity | Response | +|----------|----------| +| **Critical/High** | Patch release as soon as fix is ready | +| **Medium** | Included in next scheduled release (or earlier) | +| **Low** | Included in next scheduled release | + +### Supported Versions + + + +| Version | Supported | Notes | +|---------|-----------|-------| +| `main` branch | ✅ Yes | Latest development | +| Latest release | ✅ Yes | Current stable | +| Previous minor release | ✅ Yes | Security fixes backported | +| Older versions | ❌ No | Please upgrade | + +--- + +## Security Best Practices + +When using Panoply, we recommend: + +### General + +- Keep dependencies up to date +- Use the latest stable release +- Subscribe to security notifications +- Review configuration against security documentation +- Follow principle of least privilege + +### For Contributors + +- Never commit secrets, credentials, or API keys +- Use signed commits (`git config commit.gpgsign true`) +- Review dependencies before adding them +- Run security linters locally before pushing +- Report any concerns about existing code + +--- + +## Additional Resources + +- [Security Advisories](https://github.com/hyperpolymath/panoply/security/advisories) +- [Changelog](CHANGELOG.md) +- [Contributing Guidelines](CONTRIBUTING.md) +- [CVE Database](https://cve.mitre.org/) +- [CVSS Calculator](https://www.first.org/cvss/calculator/3.1) + +--- + +## Contact + +| Purpose | Contact | +|---------|---------| +| **Security issues** | [Report via GitHub](https://github.com/hyperpolymath/panoply/security/advisories/new) or j.d.a.jewell@open.ac.uk | +| **General questions** | [GitHub Discussions](https://github.com/hyperpolymath/panoply/discussions) | +| **Other enquiries** | See [README](README.md) for contact information | + +--- + +## Policy Changes + +This security policy may be updated from time to time. Significant changes will be: + +- Committed to this repository with a clear commit message +- Noted in the changelog +- Announced via GitHub Discussions (for major changes) + +--- + +*Thank you for helping keep Panoply and its users safe.* 🛡️ + +--- + +Last updated: 2026 · Policy version: 1.0.0 diff --git a/archetypes/0.1-AI-MANIFEST.deed b/archetypes/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..1868460 --- /dev/null +++ b/archetypes/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "archetypes" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/archetypes/README.adoc b/archetypes/README.adoc new file mode 100644 index 0000000..3f97d61 --- /dev/null +++ b/archetypes/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += archetypes + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/benches/README.adoc b/benches/README.adoc new file mode 100644 index 0000000..4a6f1b2 --- /dev/null +++ b/benches/README.adoc @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += benches + +`template_bench.sh` — Zig build/test + workflow validation timings. +Not a Core-language benchmark (no checker yet). diff --git a/ci/.pre-commit-config.yaml b/ci/.pre-commit-config.yaml new file mode 100644 index 0000000..b048d1c --- /dev/null +++ b/ci/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: MPL-2.0 +# Pre-commit hooks for hyperpolymath RSR repos. +# Install: pip install pre-commit && pre-commit install +# Run manually: pre-commit run --all-files + +repos: + # --- Standard hooks --- + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-merge-conflict + - id: detect-private-key + - id: check-added-large-files + args: ['--maxkb=1024'] + + # --- A2ML manifest validation --- + - repo: https://github.com/hyperpolymath/a2ml-pre-commit + rev: main + hooks: + - id: validate-a2ml + name: Validate A2ML manifests + + # --- K9 contract validation --- + - repo: https://github.com/hyperpolymath/k9-pre-commit + rev: main + hooks: + - id: validate-k9 + name: Validate K9 contracts + + # --- Shell linting --- + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: v0.10.0.1 + hooks: + - id: shellcheck + + # --- EditorConfig --- + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python + rev: 3.2.1 + hooks: + - id: editorconfig-checker + exclude: '(\.git|node_modules|target|_build|deps|\.deno|external_corpora|\.lake)/' + + # --- Secret detection --- + rev: v8.24.3 + hooks: diff --git a/ci/0.1-AI-MANIFEST.deed b/ci/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..e2a5ebf --- /dev/null +++ b/ci/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "ci" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/ci/README.adoc b/ci/README.adoc new file mode 100644 index 0000000..e5e2944 --- /dev/null +++ b/ci/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += ci + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/ci/gitlab-ci.yml b/ci/gitlab-ci.yml new file mode 100644 index 0000000..b08314a --- /dev/null +++ b/ci/gitlab-ci.yml @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: MPL-2.0 +# Primary CI/CD - GitLab is the source of truth + +stages: + - security + - lint + - test + - build +variables: + CARGO_HOME: ${CI_PROJECT_DIR}/.cargo +cache: + key: ${CI_COMMIT_REF_SLUG} + paths: + - .cargo/ + - target/ +# ================== +# Security Scanning +# ================== +trivy: + stage: security + image: aquasec/trivy:latest + script: + - trivy fs --exit-code 0 --severity HIGH,CRITICAL --format table . + - trivy fs --exit-code 1 --severity CRITICAL . + allow_failure: false +semgrep: + stage: security + image: returntocorp/semgrep + script: + - semgrep --config auto --error . + allow_failure: true +cargo-audit: + stage: security + image: rust:latest + script: + - cargo install cargo-audit + - cargo audit + rules: + - exists: + - Cargo.toml +cargo-deny: + stage: security + image: rust:latest + script: + - cargo install cargo-deny + - cargo deny check + rules: + - exists: + - Cargo.toml + allow_failure: true +mix-audit: + stage: security + image: elixir:latest + script: + - mix local.hex --force + - mix archive.install hex mix_audit --force + - mix deps.get + - mix deps.audit + rules: + - exists: + - mix.exs + allow_failure: true +# ================== +# Linting +# ================== +rustfmt: + stage: lint + image: rust:latest + script: + - rustup component add rustfmt + - cargo fmt -- --check + rules: + - exists: + - Cargo.toml +clippy: + stage: lint + image: rust:latest + script: + - rustup component add clippy + - cargo clippy -- -D warnings + rules: + - exists: + - Cargo.toml + allow_failure: true +mix-format: + stage: lint + image: elixir:latest + script: + - mix format --check-formatted + rules: + - exists: + - mix.exs +credo: + stage: lint + image: elixir:latest + script: + - mix local.hex --force + - mix deps.get + - mix credo --strict + rules: + - exists: + - mix.exs + allow_failure: true +# ================== +# Testing +# ================== +cargo-test: + stage: test + image: rust:latest + script: + - cargo test --all-features + rules: + - exists: + - Cargo.toml +mix-test: + stage: test + image: elixir:latest + script: + - mix local.hex --force + - mix deps.get + - mix test + rules: + - exists: + - mix.exs +# ================== +# Build +# ================== +cargo-build: + stage: build + image: rust:latest + script: + - cargo build --release + artifacts: + paths: + - target/release/ + expire_in: 1 week + rules: + - exists: + - Cargo.toml +mix-build: + stage: build + image: elixir:latest + script: + - mix local.hex --force + - mix deps.get + - MIX_ENV=prod mix compile + rules: + - exists: + - mix.exs +trufflehog: + stage: security + image: trufflesecurity/trufflehog:latest + script: + - trufflehog git file://. --only-verified --fail diff --git a/docs/practice/JS-RUNTIME-ORDER.adoc b/docs/practice/JS-RUNTIME-ORDER.adoc new file mode 100644 index 0000000..8d44329 --- /dev/null +++ b/docs/practice/JS-RUNTIME-ORDER.adoc @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += JavaScript runtime reach order (panoply) +:revdate: 2026-09-20 + +Owner ruling for this repository (overrides the older “Deno first / Bun +banned” table in `hyperpolymath/standards` language policy until that +document is amended): + +. **Bun** — default JS runtime and package manager +. **Deno** — fallback +. **pnpm** — if a Node-shaped tree is unavoidable +. **npm** — last resort only + +Do not add Python or Go. Zig remains the FFI/API layer; Idris2 the ABI. +Guix remains the packager (`build/guix.scm`); Nix stays out. diff --git a/docs/status/ROADMAP.adoc b/docs/status/ROADMAP.adoc index bafe0ce..b74851c 100644 --- a/docs/status/ROADMAP.adoc +++ b/docs/status/ROADMAP.adoc @@ -1,23 +1,30 @@ // SPDX-License-Identifier: CC-BY-SA-4.0 // Copyright (c) Jonathan D.A. Jewell -= YOUR Template Repo Roadmap += Panoply roadmap -== Current Status +== Current status -Initial development phase. +Design phase. Charter + RSR spine + Core/Evidence *specs*. No Core checker. -== Milestones +== Phase 1 structural placeholders (TODO) -=== v0.1.0 - Foundation -* [ ] Core functionality -* [ ] Basic documentation -* [ ] CI/CD pipeline +* [ ] Populate `.machine_readable/arrival-pack/` and `coaptation/` or drop if unused +* [ ] Collapse `6a2/` into template `descriptiles/` *or* document 6a2 as the live path +* [ ] Fill `src/api/zig/` (interface law) or record an explicit escape +* [ ] `www/dns` and related site-ops trees — panoply is not a site; keep holding or delete after owner ruling +* [ ] `archetypes/` — not a minting template; candidate for removal +* [ ] Relocate `.gitlab-ci.yml` → `ci/` after GitLab setting update +* [ ] Relocate `.pre-commit-config.yaml` → `ci/` after invocation pattern decided +* [ ] Convert remaining `0.x-AI-MANIFEST.deed` files from TOML/prose or keep as exempt gatekeeper docs +* [ ] Wire `e2e.yml` jobs (aspect + zig) with SHA-pinned actions +* [ ] Root `Mustfile` (contractile, not Makefile) -=== v1.0.0 - Stable Release -* [ ] Full feature set -* [ ] Comprehensive tests -* [ ] Production ready +== Charter product -== Future Directions - -_To be determined based on community feedback._ +* [x] #5 Core syntax + judgements specified (checker not implemented) +* [x] #6 Evidence kinds specified (no emitter) +* [ ] #7 Manifest schema + emitter +* [ ] #8 Projections +* [ ] #9 Backends +* [ ] #10 First mechanised obligation +* [ ] #11 Hypatia ignore from findings dump diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..8eee28c --- /dev/null +++ b/mise.toml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: MPL-2.0 +# Panoply toolchain pins (mise). +# JS reach order (owner 2026-09-20): Bun → Deno → pnpm → npm. +# Packager remains Guix (`build/guix.scm`); mise is a local version helper. + +[tools] +just = "latest" +zig = "0.15.1" +bun = "latest" +deno = "latest" + +[env] +# Idris2 is not a mise registry tool; install via Guix. diff --git a/scripts/README.adoc b/scripts/README.adoc new file mode 100644 index 0000000..a630635 --- /dev/null +++ b/scripts/README.adoc @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += scripts + +Root-shape, docs-format, and invariant-path helpers. Git hooks: see +`session/local-hooks.sh` and `.pre-commit-config.yaml`. diff --git a/session/README.adoc b/session/README.adoc index d14a6d7..cc1a05f 100644 --- a/session/README.adoc +++ b/session/README.adoc @@ -39,6 +39,13 @@ Run `+just session-help+` to list aliases, then use recipes such as: * `+just close-planned path=.+` * `+just handover-model path=.+` +=== Git hooks + +* `.pre-commit-config.yaml` at root (tool-required); a copy may live under `ci/` later. +* `just install-hooks` writes `.git/hooks/pre-commit` (fmt-check, lint, assail). +* `session/local-hooks.sh` is the session-protocol hook, not a Git hook. +* Do not use `pip` as a project language; `pre-commit` is an optional host tool. + === Runtime Artifacts Runtime files are generated per repository in `+.session/+` and are not diff --git a/src/api/0.1-AI-MANIFEST.deed b/src/api/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..1ac1164 --- /dev/null +++ b/src/api/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "src/api" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/src/api/README.adoc b/src/api/README.adoc new file mode 100644 index 0000000..25435ac --- /dev/null +++ b/src/api/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += api + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/src/api/zig/0.1-AI-MANIFEST.deed b/src/api/zig/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..47aaba9 --- /dev/null +++ b/src/api/zig/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "src/api/zig" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/src/api/zig/README.adoc b/src/api/zig/README.adoc new file mode 100644 index 0000000..6dbd8b5 --- /dev/null +++ b/src/api/zig/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += zig + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/tests/README.adoc b/tests/README.adoc new file mode 100644 index 0000000..fa7dcdb --- /dev/null +++ b/tests/README.adoc @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += tests + +Shell gates: `e2e.sh`, `aspect_tests.sh`, `lifecycle.sh`, `p2p.sh`, +`core_spec.sh`, `evidence_spec.sh`. Zig tests live under +`src/interface/ffi/`. See `docs/status/TEST-NEEDS.adoc`. diff --git a/tests/e2e/0.1-AI-MANIFEST.deed b/tests/e2e/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..18e80a2 --- /dev/null +++ b/tests/e2e/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "tests/e2e" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/tests/e2e/README.adoc b/tests/e2e/README.adoc new file mode 100644 index 0000000..0adbc8f --- /dev/null +++ b/tests/e2e/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += e2e + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/tests/shape/0.1-AI-MANIFEST.deed b/tests/shape/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..2e2e054 --- /dev/null +++ b/tests/shape/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "tests/shape" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/tests/shape/README.adoc b/tests/shape/README.adoc new file mode 100644 index 0000000..0030505 --- /dev/null +++ b/tests/shape/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += shape + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). diff --git a/www/dns/0.1-AI-MANIFEST.deed b/www/dns/0.1-AI-MANIFEST.deed new file mode 100644 index 0000000..ea2ba0e --- /dev/null +++ b/www/dns/0.1-AI-MANIFEST.deed @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +[metadata] +version = "0.1.0" +layer = "www/dns" +note = "Holding 0.1-AI-MANIFEST — gatekeeper prose, not DEED ABNF chora." diff --git a/www/dns/README.adoc b/www/dns/README.adoc new file mode 100644 index 0000000..b137fba --- /dev/null +++ b/www/dns/README.adoc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += dns + +Holding directory required by `rsr-template-repo`. +Not yet populated with panoply-specific content. + +TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). From 6f1aa4d582b6100672d26acc5c66dbab730c2229 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 20 Sep 2026 13:14:47 +0000 Subject: [PATCH 3/3] feat(phase2): language audit, Zig API stub, launcher bind, CLI arity src/ languages are Idris2+Zig+Bash only. No NIFs. API adapter is a fail-closed Zig stub. Vendor standards/launcher path helpers. Document just as the CLI (help, man, arity). Coq/Agda/Lean/TLA remain template proof holdings pending owner ruling. Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- .machine_readable/root-allow.txt | 1 + Justfile | 15 +++ docs/cli-arity.adoc | 28 ++++++ docs/reports/LANGUAGE-AUDIT.adoc | 50 ++++++++++ docs/status/ROADMAP.adoc | 3 + launcher/README.adoc | 12 +++ launcher/gui-error.sh | 69 ++++++++++++++ launcher/keepopen.sh | 153 ++++++++++++++++++++++++++++++ launcher/resolve-desktop-tools.sh | 104 ++++++++++++++++++++ launcher/soft-attach.sh | 80 ++++++++++++++++ src/api/zig/README.adoc | 9 +- src/api/zig/adapter.zig | 19 ++++ 12 files changed, 538 insertions(+), 5 deletions(-) create mode 100644 docs/cli-arity.adoc create mode 100644 docs/reports/LANGUAGE-AUDIT.adoc create mode 100644 launcher/README.adoc create mode 100755 launcher/gui-error.sh create mode 100755 launcher/keepopen.sh create mode 100755 launcher/resolve-desktop-tools.sh create mode 100755 launcher/soft-attach.sh create mode 100644 src/api/zig/adapter.zig diff --git a/.machine_readable/root-allow.txt b/.machine_readable/root-allow.txt index 482a919..8c5edae 100644 --- a/.machine_readable/root-allow.txt +++ b/.machine_readable/root-allow.txt @@ -76,6 +76,7 @@ features/ scripts/ verification/ container/ # may host Containerfile if not at build/ +launcher/ # estate launcher helpers (standards/launcher thin bind) # ─── Tolerated pending follow-up (re-evaluate when item lands) ─────────────── .gitlab-ci.yml # TODO: relocate to ci/.gitlab-ci.yml after GitLab project-setting update diff --git a/Justfile b/Justfile index 9dbefd1..08c96c6 100644 --- a/Justfile +++ b/Justfile @@ -176,6 +176,21 @@ crg-badge: esac echo "[![CRG ${grade}](https://img.shields.io/badge/CRG-${grade}-${color}?style=flat-square)](https://github.com/hyperpolymath/standards/tree/main/component-readiness-grades)" +# CLI help (library: just is the CLI) +cli-help: + @just --list --unsorted + @echo "" + @echo "Man: just man → docs/man/panoply.1" + @echo "Arity: docs/cli-arity.adoc" + +# Language / interface audit notes +language-audit: + @echo "See docs/reports/LANGUAGE-AUDIT.adoc" + +# API adapter stub tests +api-test: + cd src/api/zig && zig test adapter.zig + # Run the full merge-requirement test suite # Categories: execution (`test`) + E2E + aspect + bench + lifecycle + P2P test-all: test e2e aspect bench lifecycle p2p diff --git a/docs/cli-arity.adoc b/docs/cli-arity.adoc new file mode 100644 index 0000000..ca38609 --- /dev/null +++ b/docs/cli-arity.adoc @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += CLI arity (panoply) + +Panoply ships **no application binary**. The CLI is `just`. + +== Help + +* `just` / `just --list` — all recipes +* `just help ` — recipe body +* `just --help` — just(1) itself + +== Man page + +`just man` writes `docs/man/panoply.1` (groff). Install is not packaged. + +== High-arity surface (recipes, not flags) + +Build:: `just build`, `just build-release`, `just clean`, `just install prefix=` +Test:: `just test`, `just e2e`, `just aspect`, `just bench`, `just lifecycle`, `just p2p`, `just test-all` +Quality:: `just fmt`, `just fmt-check`, `just lint`, `just quality` +Guix:: `just guix-shell`, `just guix-build`, `just guix-channel` +Proofs:: imported from `build/just/proofs.just` +Session:: `just intake-repo`, `just verify-maintenance`, … +CRG:: `just crg-grade`, `just crg-badge` + +There is no `panoply --verbose --output --format` tree until a checker +exists. Do not invent flags. diff --git a/docs/reports/LANGUAGE-AUDIT.adoc b/docs/reports/LANGUAGE-AUDIT.adoc new file mode 100644 index 0000000..7825c19 --- /dev/null +++ b/docs/reports/LANGUAGE-AUDIT.adoc @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += Language audit — panoply (Phase 2.1) +:revdate: 2026-09-20 + +== Application / interface languages (in `src/`) + +[cols="1,2,1",options="header"] +|=== +| Language | Role | Policy + +| Idris2 | ABI (`src/interface/Abi`) | allowed (sole ABI) +| Zig | FFI (`src/interface/ffi`) + API stub (`src/api/zig`) | allowed +| Bash | tests, scripts, Just recipes | allowed +| Nickel | K9 contracts (`.k9.ncl`) | allowed +| Guile Scheme | `build/guix.scm` only | allowed (packaging) +| Just | Justfile | allowed (not Makefile) +|=== + +No TypeScript, Python, Go, Java, Rust, Ada, V-lang application code. + +== Proof-scaffold languages (RSR template, not application) + +These live only under `verification/proofs/` as **stubs**: Coq (`.v`), +Agda, Lean4, TLA+. Estate language policy names Idris2 as the sole +*formal-verification language* for new work. These files are template +holdings, not a second ABI. + +**Check with owner:** keep as multi-prover sketch (RSR template) or +delete non-Idris2 proof trees? Not deleted in this phase. + +== Config / docs (not CCCP “languages”) + +AsciiDoc, YAML (Actions), TOML, Markdown (GitHub-required `SECURITY.md` +etc.), JSON, jq. + +== JS runtimes (if JS ever appears) + +Owner 2026-09-20: Bun → Deno → pnpm → npm. No JS sources today. + +== NIF / SNIF (2.2) + +No NIFs. `hyperpolymath/snifs` does not apply until a BEAM host exists. +Marked N/A. + +== ABI / FFI / API (2.3–2.4) + +* ABI = Idris2 (`src/interface/Abi`). `%foreign` symbols `panoply_*`. +* FFI = Zig (`src/interface/ffi`). +* API adapter = Zig stub `src/api/zig/adapter.zig` (no HTTP gateway yet). diff --git a/docs/status/ROADMAP.adoc b/docs/status/ROADMAP.adoc index b74851c..3586768 100644 --- a/docs/status/ROADMAP.adoc +++ b/docs/status/ROADMAP.adoc @@ -17,6 +17,9 @@ Design phase. Charter + RSR spine + Core/Evidence *specs*. No Core checker. * [ ] Relocate `.pre-commit-config.yaml` → `ci/` after invocation pattern decided * [ ] Convert remaining `0.x-AI-MANIFEST.deed` files from TOML/prose or keep as exempt gatekeeper docs * [ ] Wire `e2e.yml` jobs (aspect + zig) with SHA-pinned actions +* [ ] Owner: keep or delete Coq/Agda/Lean/TLA proof stubs (Idris2-only FV policy vs RSR template) +* [ ] Implement Zig API adapter beyond `NotImplemented` when a gateway exists +* [ ] Desktop launcher via launch-scaffolder when a GUI exists * [ ] Root `Mustfile` (contractile, not Makefile) == Charter product diff --git a/launcher/README.adoc b/launcher/README.adoc new file mode 100644 index 0000000..d46a258 --- /dev/null +++ b/launcher/README.adoc @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += Launcher (thin bind) + +Panoply is a *library discipline*, not a desktop app. This directory +vendors the estate path-resolution helpers from +`hyperpolymath/standards/launcher` so a future GUI/CLI can source them. + +* `resolve-desktop-tools.sh` — `hp_resolve_desktop_tools` / `hp_resolve_standard` +* Cross-platform: POSIX bash; no Nix. + +`just` is the developer launcher today (`just --list`, `just help `). diff --git a/launcher/gui-error.sh b/launcher/gui-error.sh new file mode 100755 index 0000000..b4ffd88 --- /dev/null +++ b/launcher/gui-error.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# gui-error.sh — reference implementation of [error-visibility] from +# launcher/launcher-standard.a2ml. +# +# When the launcher runs in a GUI context (no TTY + DISPLAY or +# WAYLAND_DISPLAY set), errors written only to stderr disappear: the +# user sees a brief terminal flash and nothing else. This script +# surfaces such errors via a graphical dialog AND stderr. +# +# Downstream launchers SHOULD source this script and call +# hp_gui_error "Title" "message" +# rather than re-implementing the dialog ladder. +# +# Dialog ladder (matches [error-visibility].gui-dialog-chain): +# 1. kdialog — KDE Plasma +# 2. zenity — GNOME / Cinnamon / Xfce +# 3. notify-send — libnotify (less prominent than a dialog, but standard) +# 4. xmessage — X11 last resort +# +# Returns 0 if any dialog succeeded, non-zero if all failed. stderr is +# always written regardless (per [error-visibility].always-also-to-stderr). +# +# Env overrides: +# NO_GUI_ERROR=1 — suppress the dialog attempt; stderr only. +# Useful in CI / scripted invocation. + +hp_gui_error() { + local title="${1:-Error}" + local message="${2:-}" + + # Always write to stderr regardless of dialog outcome. + printf '[%s] %s\n' "${title}" "${message}" >&2 + + # Skip dialogs when we have a TTY (the user will see stderr fine) + # or when explicitly suppressed. + if [[ -t 2 ]] || [[ -n "${NO_GUI_ERROR:-}" ]]; then + return 0 + fi + + # GUI requires a display. + if [[ -z "${DISPLAY:-}" ]] && [[ -z "${WAYLAND_DISPLAY:-}" ]]; then + return 1 + fi + + # Try the ladder; first present + successful wins. + if command -v kdialog >/dev/null 2>&1; then + kdialog --title "${title}" --error "${message}" >/dev/null 2>&1 && return 0 + fi + if command -v zenity >/dev/null 2>&1; then + zenity --title="${title}" --error --text="${message}" >/dev/null 2>&1 && return 0 + fi + if command -v notify-send >/dev/null 2>&1; then + notify-send -u critical "${title}" "${message}" >/dev/null 2>&1 && return 0 + fi + if command -v xmessage >/dev/null 2>&1; then + xmessage -title "${title}" -center "${message}" >/dev/null 2>&1 && return 0 + fi + + return 1 +} + +# CLI mode (not sourced): forward args to hp_gui_error. +# ./gui-error.sh "Launcher failed" "Server died — see ~/.local/state/app/server.log" +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + hp_gui_error "$@" +fi diff --git a/launcher/keepopen.sh b/launcher/keepopen.sh new file mode 100755 index 0000000..0a18ae3 --- /dev/null +++ b/launcher/keepopen.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# keepopen.sh — standard desktop launcher fallback ladder. +# +# Canonical location: developer-ecosystem/standards/launcher/keepopen.sh +# Deployed copy: .desktop-tools/keepopen.sh (symlinked) +# Documented in: standards/docs/UX-standards/launcher-standard.adoc §Fallback Ladder +# +# Its job is to turn a possibly-broken launcher into something that ALWAYS +# lands the user somewhere useful — even when every upstream hook fails. +# +# Usage: +# keepopen.sh APP_NAME REPO_DIR "GUI_CMD" "TUI_CMD" [LOG_FILE] +# +# Fallback ladder (each fallback shows a LOUD banner so the failure is +# visible — the point is that the user CAN see a tool is broken): +# +# 1. GUI_CMD — primary path. Silent on success. If it fails ↓ +# 2. TUI_CMD — loud yellow banner, then fallback. If it fails ↓ +# 3. bash -l — loud red banner, then cd into REPO_DIR and drop into +# an interactive login shell. Never just "press enter +# to close" — the user lands in the repo so they can +# actually fix the thing that's broken. +# +# Each CMD is evaluated as `bash -c "$cmd"`, so pipelines and shell quoting +# work normally. Pass an empty string to skip a stage (e.g. an app with no +# GUI can use `""` for GUI_CMD and go straight to the TUI banner → TUI). +# +# Banners are intentionally loud and ugly — visibility beats aesthetics. + +set -u + +APP_NAME="${1:?keepopen: APP_NAME required (arg 1)}" +REPO_DIR="${2:?keepopen: REPO_DIR required (arg 2)}" +GUI_CMD="${3:?keepopen: GUI_CMD required (arg 3) — pass '' if not applicable}" +TUI_CMD="${4:?keepopen: TUI_CMD required (arg 4) — pass '' if not applicable}" +LOG_FILE="${5:-}" + +# Honour NO_COLOR (https://no-color.org/) and auto-detect non-TTY stdout. +# When set, banners and prefix labels emit no ANSI escapes — still loud +# and clearly labelled, just plain text. The freedesktop-style desktop +# launch redirects stdout to a real terminal so this rarely triggers +# automatically, but covers `keepopen.sh ... | tee` and CI captures. +if [[ -n "${NO_COLOR:-}" ]] || [[ ! -t 1 ]]; then + C_RED='' C_YEL='' C_CYA='' C_GRN='' C_BOLD='' C_RST='' +else + C_RED=$'\033[1;31m' + C_YEL=$'\033[1;33m' + C_CYA=$'\033[1;36m' + C_GRN=$'\033[1;32m' + C_BOLD=$'\033[1m' + C_RST=$'\033[0m' +fi + +banner() { + # $1 = colour; $2 = title; remaining args = body lines. + local colour="$1"; shift + local title="$1"; shift + echo + echo "${colour}${C_BOLD}================================================================${C_RST}" + echo "${colour}${C_BOLD} ${title}${C_RST}" + echo "${colour}${C_BOLD}================================================================${C_RST}" + local line + for line in "$@"; do + [[ -z "${line}" ]] && { echo; continue; } + echo " ${colour}${line}${C_RST}" + done + echo +} + +# ----------------------------------------------------------------------------- +# STAGE 1 — GUI +# ----------------------------------------------------------------------------- + +gui_exit=0 +if [[ -n "${GUI_CMD}" ]]; then + echo "${C_CYA}[keepopen:${APP_NAME}] GUI → ${GUI_CMD}${C_RST}" + bash -c "${GUI_CMD}" + gui_exit=$? + if [[ ${gui_exit} -eq 0 ]]; then + exit 0 + fi + banner "${C_YEL}" "FALLBACK 1/2 — GUI FAILED (exit ${gui_exit})" \ + "APP : ${APP_NAME}" \ + "GUI cmd : ${GUI_CMD}" \ + "${LOG_FILE:+LOG FILE: ${LOG_FILE}}" \ + "" \ + "The primary GUI path exited non-zero." \ + "Something needs fixing. Falling back to the TUI path." \ + "(If this keeps happening, edit the .desktop file or the" \ + "keepopen invocation to point at a working GUI command.)" +else + banner "${C_YEL}" "STAGE 1/2 SKIPPED — NO GUI CONFIGURED" \ + "APP : ${APP_NAME}" \ + "" \ + "This app was launched with no GUI command. Going straight to TUI." +fi + +# ----------------------------------------------------------------------------- +# STAGE 2 — TUI +# ----------------------------------------------------------------------------- + +tui_exit=0 +if [[ -n "${TUI_CMD}" ]]; then + echo "${C_CYA}[keepopen:${APP_NAME}] TUI → ${TUI_CMD}${C_RST}" + bash -c "${TUI_CMD}" + tui_exit=$? + if [[ ${tui_exit} -eq 0 ]]; then + exit 0 + fi + banner "${C_RED}" "FALLBACK 2/2 — TUI ALSO FAILED (exit ${tui_exit})" \ + "APP : ${APP_NAME}" \ + "GUI cmd : ${GUI_CMD:-}" \ + "TUI cmd : ${TUI_CMD}" \ + "${LOG_FILE:+LOG FILE: ${LOG_FILE}}" \ + "REPO : ${REPO_DIR}" \ + "" \ + "BOTH the GUI and the TUI paths failed." \ + "Something needs fixing — you are being dropped into a shell" \ + "at the repo root so you can investigate, not just closed out." +else + banner "${C_RED}" "STAGE 2/2 SKIPPED — NO TUI CONFIGURED" \ + "APP : ${APP_NAME}" \ + "REPO: ${REPO_DIR}" \ + "" \ + "No TUI command was provided either. Dropping into a shell at the repo root." +fi + +# ----------------------------------------------------------------------------- +# STAGE 3 — interactive shell at repo root (final fallback) +# ----------------------------------------------------------------------------- + +if [[ -d "${REPO_DIR}" ]]; then + cd "${REPO_DIR}" || true + echo "${C_GRN}[keepopen:${APP_NAME}] Dropping into bash at ${REPO_DIR}${C_RST}" +else + echo "${C_RED}[keepopen:${APP_NAME}] REPO_DIR does not exist: ${REPO_DIR}${C_RST}" >&2 + echo "${C_RED}[keepopen:${APP_NAME}] Staying in ${PWD} instead.${C_RST}" >&2 +fi + +cat < +# +# resolve-desktop-tools.sh — reference implementation of the path-resolution +# ladders declared in launcher/launcher-standard.deed §[resolution]. +# +# Downstream launchers SHOULD `source` this script and call +# `hp_resolve_desktop_tools` / `hp_resolve_standard` rather than rolling +# their own path-discovery logic — the standard's ladder will evolve, and +# centralising the implementation here keeps the estate aligned. +# +# Each function: +# - Echoes the first existing matching path to stdout, exits 0. +# - Echoes nothing and exits 1 if no candidate exists. The caller decides +# whether that is fatal (e.g. missing keepopen.sh wrapper) or recoverable +# (e.g. missing optional verify-desktop-integrity.sh). +# +# The ladders mirror [resolution].desktop-tools-search and +# [resolution].standard-search in the a2ml. They MUST stay in sync — see the +# CI gate referenced in launcher/README.adoc §Sync requirement. + +# --------------------------------------------------------------------------- +# hp_resolve_desktop_tools [TOOL_NAME] +# +# With no argument: echoes the first existing .desktop-tools/ directory. +# With an argument: echoes the first existing .desktop-tools/. +# --------------------------------------------------------------------------- +hp_resolve_desktop_tools() { + local tool="${1:-}" + local -a candidates=( + "${HP_DESKTOP_TOOLS:-}" + "${HP_ESTATE_ROOT:+${HP_ESTATE_ROOT}/.desktop-tools}" + "${XDG_DATA_HOME:-${HOME}/.local/share}/hyperpolymath/.desktop-tools" + "/var/mnt/eclipse/repos/.desktop-tools" + "${HOME}/developer/repos/.desktop-tools" + "${HOME}/dev/repos/.desktop-tools" + ) + + local candidate + for candidate in "${candidates[@]}"; do + [[ -z "${candidate}" ]] && continue + local target="${candidate}${tool:+/${tool}}" + if [[ -e "${target}" ]]; then + echo "${target}" + return 0 + fi + done + return 1 +} + +# --------------------------------------------------------------------------- +# hp_resolve_standard +# +# Echoes the first existing launcher-standard.deed found via the +# [resolution].standard-search ladder. Used by launch-scaffolder and any +# other consumer that needs the canonical contract file. +# --------------------------------------------------------------------------- +hp_resolve_standard() { + local -a candidates=( + "${LAUNCH_SCAFFOLDER_STANDARD:-}" + "${HP_ESTATE_ROOT:+${HP_ESTATE_ROOT}/standards/launcher/launcher-standard.deed}" + "${XDG_DATA_HOME:-${HOME}/.local/share}/hyperpolymath/standards/launcher/launcher-standard.deed" + "/var/mnt/eclipse/repos/standards/launcher/launcher-standard.deed" + "${HOME}/developer/repos/standards/launcher/launcher-standard.deed" + "${HOME}/dev/repos/standards/launcher/launcher-standard.deed" + ) + + local candidate + for candidate in "${candidates[@]}"; do + [[ -z "${candidate}" ]] && continue + if [[ -f "${candidate}" ]]; then + echo "${candidate}" + return 0 + fi + done + return 1 +} + +# When invoked directly (not sourced) act as a CLI that prints the resolved +# path for the requested tool, or all ladder candidates with --list. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + case "${1:-}" in + --standard) + hp_resolve_standard + ;; + --list) + echo "desktop-tools-search:" + printf ' %s\n' \ + "${HP_DESKTOP_TOOLS:-}" \ + "${HP_ESTATE_ROOT:+${HP_ESTATE_ROOT}/.desktop-tools}" \ + "${XDG_DATA_HOME:-${HOME}/.local/share}/hyperpolymath/.desktop-tools" \ + "/var/mnt/eclipse/repos/.desktop-tools" \ + "${HOME}/developer/repos/.desktop-tools" \ + "${HOME}/dev/repos/.desktop-tools" + ;; + "") + hp_resolve_desktop_tools + ;; + *) + hp_resolve_desktop_tools "$1" + ;; + esac +fi diff --git a/launcher/soft-attach.sh b/launcher/soft-attach.sh new file mode 100755 index 0000000..1658849 --- /dev/null +++ b/launcher/soft-attach.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# soft-attach.sh — reference implementation of [soft-attach] from +# launcher/launcher-standard.a2ml. +# +# Soft-attach = optional ecosystem integrations that the launcher invokes +# IF they are installed, and silently skips otherwise. Downstream +# launchers SHOULD source this script rather than re-implementing the +# "if-installed-then-invoke" pattern, so the spec stays consistent +# across the estate. +# +# All primitives are non-fatal — a missing or failing soft-attach tool +# never breaks the launcher (per the §soft-attach spec: "called if +# present, silently skipped if absent"). +# +# Primitives: +# +# hp_soft_attach_present "command" +# Returns 0 if the command is on PATH, 1 otherwise. Building +# block; rarely called directly. +# +# hp_soft_attach_run "command-line" +# If the first token of command-line is on PATH, runs the whole +# line via `bash -c`. Otherwise silent no-op. Suitable for +# [soft-attach].tools entries that use `command = "..."`. +# Template substitution ({app-name}, {log-file}, {repo-dir}) is +# the CALLER's responsibility — substitute before passing in. +# +# hp_soft_attach_event "tool" "event-name" [extra args...] +# If `tool` is on PATH, invokes `tool emit event-name [args]`. +# The `emit` verb is the soft-attach convention for event-style +# integrations (e.g. feedback-o-tron). Tools that use a different +# verb should be called via hp_soft_attach_run with the full +# command line. +# +# Recommended call sites: +# - on launcher start failure: emit start_failed event to feedback-o-tron; +# run hypatia diagnose; run panic-attack assail. +# - on --integ failure: same pattern. +# See the comprehensive-launcher-template.sh for the full hook layout. + +hp_soft_attach_present() { + command -v "${1:?soft-attach: command required}" >/dev/null 2>&1 +} + +hp_soft_attach_run() { + local cmd_line="${1:?soft-attach: command line required}" + local first_token + first_token=$(printf '%s' "${cmd_line}" | awk '{print $1}') + if hp_soft_attach_present "${first_token}"; then + bash -c "${cmd_line}" || true + fi +} + +hp_soft_attach_event() { + local tool="${1:?soft-attach: tool required}" + local event="${2:?soft-attach: event-name required}" + shift 2 + if hp_soft_attach_present "${tool}"; then + "${tool}" emit "${event}" "$@" || true + fi +} + +# CLI mode (not sourced): provide a thin wrapper for ad-hoc invocation. +# ./soft-attach.sh run "hypatia diagnose --app foo --log /tmp/foo.log" +# ./soft-attach.sh event feedback-o-tron launcher:start_failed +# ./soft-attach.sh present hypatia +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + case "${1:-}" in + run) shift; hp_soft_attach_run "$@" ;; + event) shift; hp_soft_attach_event "$@" ;; + present) shift; hp_soft_attach_present "$@" ;; + *) + printf 'usage: %s {run|event|present} ...\n' "${0##*/}" >&2 + exit 64 # EX_USAGE + ;; + esac +fi diff --git a/src/api/zig/README.adoc b/src/api/zig/README.adoc index 6dbd8b5..1879caf 100644 --- a/src/api/zig/README.adoc +++ b/src/api/zig/README.adoc @@ -1,8 +1,7 @@ // SPDX-License-Identifier: CC-BY-SA-4.0 // Copyright (c) Jonathan D.A. Jewell -= zig += API adapter (Zig) -Holding directory required by `rsr-template-repo`. -Not yet populated with panoply-specific content. - -TODO: see `docs/status/ROADMAP.adoc` (Phase 1 structural placeholders). +Interface law: API layer is Zig. `adapter.zig` is a fail-closed stub +(`NotImplemented`). There is no unified-api-adapter vendored until a +gateway exists. Roadmap: Phase 8 / `docs/status/ROADMAP.adoc`. diff --git a/src/api/zig/adapter.zig b/src/api/zig/adapter.zig new file mode 100644 index 0000000..a9e5d83 --- /dev/null +++ b/src/api/zig/adapter.zig @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) Jonathan D.A. Jewell +// +// Unified API adapter (Zig). Panoply has no HTTP/gateway surface yet. +// This module is the Interface Law API layer stub: Zig, not Rust/C. +// Callers must not treat a successful build as a safety envelope. + +const std = @import("std"); + +pub const AdapterError = error{NotImplemented}; + +/// Envelope-aware entry: refuse to claim guarantees without a manifest. +pub fn dispatch(_: []const u8) AdapterError!void { + return error.NotImplemented; +} + +test "adapter refuses silent success" { + try std.testing.expectError(error.NotImplemented, dispatch("ping")); +}