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/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/.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..8c5edae 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 @@ -63,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/.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/Justfile b/Justfile index 6db2d9d..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 @@ -511,7 +526,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/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/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/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/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 bafe0ce..3586768 100644 --- a/docs/status/ROADMAP.adoc +++ b/docs/status/ROADMAP.adoc @@ -1,23 +1,33 @@ // 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 +* [ ] 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) -=== 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/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/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/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/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..1879caf --- /dev/null +++ b/src/api/zig/README.adoc @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Copyright (c) Jonathan D.A. Jewell += API adapter (Zig) + +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")); +} 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/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/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" 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).