diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 144741d..48ca2e4 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -3,15 +3,15 @@ ## Machine-Readable Artefacts -The following files in `.machine_readable/6a2/` contain structured project +The following files in `.machine_readable/descriptiles/` contain structured project metadata (a2ml format; the earlier `.scm` root-level names are retired): -- `6a2/STATE.a2ml` - Current project state and progress -- `6a2/META.a2ml` - Architecture decisions (ADRs) and development practices -- `6a2/ECOSYSTEM.a2ml` - Position in the ecosystem and related projects -- `6a2/AGENTIC.a2ml` - AI agent interaction patterns -- `6a2/NEUROSYM.a2ml` - Neurosymbolic integration config -- `6a2/PLAYBOOK.a2ml` - Operational runbook +- `descriptiles/STATE.a2ml` - Current project state and progress +- `descriptiles/META.a2ml` - Architecture decisions (ADRs) and development practices +- `descriptiles/ECOSYSTEM.a2ml` - Position in the ecosystem and related projects +- `descriptiles/AGENTIC.a2ml` - AI agent interaction patterns +- `descriptiles/NEUROSYM.a2ml` - Neurosymbolic integration config +- `descriptiles/PLAYBOOK.a2ml` - Operational runbook Self-validation / service metadata lives in `.machine_readable/svc/` (`svc/k9/my-lang-metadata.k9.ncl`, `svc/README.adoc`). The scope-arrest anchor @@ -36,7 +36,7 @@ is the top-level `ANCHOR.scope-arrest.2026-01-01.Jewell.scm`. | **Bash/POSIX Shell** | Scripts, automation | Keep minimal | | **JavaScript** | Only where AffineScript cannot | MCP protocol glue, Bun APIs | | **Nickel** | Configuration language | For complex configs | -| **Guile Scheme** | State/meta files | `.machine_readable/6a2/{STATE,META,ECOSYSTEM}.a2ml` (the earlier `.scm` names are retired) | +| **Guile Scheme** | State/meta files | `.machine_readable/descriptiles/{STATE,META,ECOSYSTEM}.a2ml` (the earlier `.scm` names are retired) | | **Julia** | Batch scripts, data processing | Per RSR | | **OCaml** | AffineScript compiler | Language-specific | | **Ada** | Safety-critical systems | Where required | diff --git a/.github/workflows/hypatia-scan.yml b/.github/workflows/hypatia-scan.yml index 251da4a..6b6edf5 100644 --- a/.github/workflows/hypatia-scan.yml +++ b/.github/workflows/hypatia-scan.yml @@ -20,4 +20,6 @@ permissions: jobs: scan: - uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@84355587cb2a1f86e6882de83514a32db2646e7a + uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@469605210e767ee94d1c7a9c13cb6a1d0a78cad1 + with: + block-on-high: true diff --git a/.github/workflows/label-triage.yml b/.github/workflows/label-triage.yml index 9886e92..e61baef 100644 --- a/.github/workflows/label-triage.yml +++ b/.github/workflows/label-triage.yml @@ -46,6 +46,7 @@ permissions: jobs: triage: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: Classify and label env: diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index c80b676..e4a5601 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -32,6 +32,7 @@ permissions: jobs: sync: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: Apply canonical labels env: diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index d2ed55e..2a96278 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,5 +1,5 @@ -# SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. +# SPDX-License-Identifier: MPL-2.0 # SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell name: GitHub Pages (Ddraig SSG) @@ -54,4 +54,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 diff --git a/.machine_readable/contractiles/Adjustfile.a2ml b/.machine_readable/contractiles/Adjustfile.a2ml index ebeed11..8b73d08 100644 --- a/.machine_readable/contractiles/Adjustfile.a2ml +++ b/.machine_readable/contractiles/Adjustfile.a2ml @@ -40,7 +40,7 @@ actions. Advisory — it warns and trends, it does not block. - severity: advisory ### status-doc-currency -- description: proofs/STATUS.md + 6a2/STATE.a2ml reflect the actual proof state +- description: proofs/STATUS.md + descriptiles/STATE.a2ml reflect the actual proof state - tolerance: Status registry matches the mechanised cores - corrective: Refresh STATUS.md / STATE.a2ml after any proof rung lands - severity: advisory diff --git a/.machine_readable/contractiles/Mustfile.a2ml b/.machine_readable/contractiles/Mustfile.a2ml index b14c4c8..77d3cfa 100644 --- a/.machine_readable/contractiles/Mustfile.a2ml +++ b/.machine_readable/contractiles/Mustfile.a2ml @@ -33,8 +33,8 @@ pre-commit hooks fail if any check fails. my-lang is a CONSUMER of the RSR - severity: critical ### ai-manifest -- description: 0-AI-MANIFEST.a2ml must exist (under 6a2/) -- run: test -f .machine_readable/6a2/0-AI-MANIFEST.a2ml +- description: 0-AI-MANIFEST.a2ml must exist (under descriptiles/) +- run: test -f .machine_readable/descriptiles/0-AI-MANIFEST.a2ml - severity: critical ### governance-docs @@ -68,8 +68,8 @@ pre-commit hooks fail if any check fails. my-lang is a CONSUMER of the RSR - severity: critical ### six-directory-present -- description: 6a2 directory exists with required files -- run: test -d .machine_readable/6a2 && test -f .machine_readable/6a2/META.a2ml && test -f .machine_readable/6a2/ECOSYSTEM.a2ml && test -f .machine_readable/6a2/STATE.a2ml && test -f .machine_readable/6a2/PLAYBOOK.a2ml && test -f .machine_readable/6a2/AGENTIC.a2ml && test -f .machine_readable/6a2/NEUROSYM.a2ml +- description: descriptiles directory exists with required files +- run: test -d .machine_readable/descriptiles && test -f .machine_readable/descriptiles/META.a2ml && test -f .machine_readable/descriptiles/ECOSYSTEM.a2ml && test -f .machine_readable/descriptiles/STATE.a2ml && test -f .machine_readable/descriptiles/PLAYBOOK.a2ml && test -f .machine_readable/descriptiles/AGENTIC.a2ml && test -f .machine_readable/descriptiles/NEUROSYM.a2ml - severity: critical ### scope-arrest-anchor diff --git a/.machine_readable/contractiles/dust/detach-echo-types-plugin.a2ml b/.machine_readable/contractiles/dust/detach-echo-types-plugin.a2ml index ff593b1..bc68939 100644 --- a/.machine_readable/contractiles/dust/detach-echo-types-plugin.a2ml +++ b/.machine_readable/contractiles/dust/detach-echo-types-plugin.a2ml @@ -62,7 +62,7 @@ be a significant architectural change requiring a clear extension boundary. ### 5-update-6a2-state - description: Update STATE.a2ml to reflect echo-types as plugin, not built-in - corrective: > - In 6a2/STATE.a2ml: update echo_integration_status from 'built_in' to 'plugin'. + In descriptiles/STATE.a2ml: update echo_integration_status from 'built_in' to 'plugin'. Add an ADR in META.a2ml documenting the boundary decision. ## Completion Criteria diff --git a/.machine_readable/contractiles/dust/uninstall-coq-toolchain.a2ml b/.machine_readable/contractiles/dust/uninstall-coq-toolchain.a2ml index 57583df..a55ff51 100644 --- a/.machine_readable/contractiles/dust/uninstall-coq-toolchain.a2ml +++ b/.machine_readable/contractiles/dust/uninstall-coq-toolchain.a2ml @@ -47,7 +47,7 @@ what must be preserved, and what downstream consumers must be informed of. ### 5-update-6a2-state - description: Update STATE.a2ml and META.a2ml to reflect Coq retirement - corrective: > - In 6a2/STATE.a2ml: mark coq_core as retired; in 6a2/META.a2ml: remove + In descriptiles/STATE.a2ml: mark coq_core as retired; in descriptiles/META.a2ml: remove ADR-009 (open-context subst) as Coq-specific or generalise it. ### 6-notify-downstream diff --git a/.machine_readable/6a2/0-AI-MANIFEST.a2ml b/.machine_readable/descriptiles/0-AI-MANIFEST.a2ml similarity index 74% rename from .machine_readable/6a2/0-AI-MANIFEST.a2ml rename to .machine_readable/descriptiles/0-AI-MANIFEST.a2ml index 89f4d36..7f05b3e 100644 --- a/.machine_readable/6a2/0-AI-MANIFEST.a2ml +++ b/.machine_readable/descriptiles/0-AI-MANIFEST.a2ml @@ -1,11 +1,11 @@ # SPDX-License-Identifier: MPL-2.0 # SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell -# AI Manifest for 6a2 Directory +# AI Manifest for Descriptiles Directory ## Purpose -This manifest declares the AI-assistant context for the 6a2 machine-readable metadata directory. +This manifest declares the AI-assistant context for the descriptiles machine-readable metadata directory. ## Canonical Locations diff --git a/.machine_readable/6a2/AGENTIC.a2ml b/.machine_readable/descriptiles/AGENTIC.a2ml similarity index 100% rename from .machine_readable/6a2/AGENTIC.a2ml rename to .machine_readable/descriptiles/AGENTIC.a2ml diff --git a/.machine_readable/6a2/ECOSYSTEM.a2ml b/.machine_readable/descriptiles/ECOSYSTEM.a2ml similarity index 100% rename from .machine_readable/6a2/ECOSYSTEM.a2ml rename to .machine_readable/descriptiles/ECOSYSTEM.a2ml diff --git a/.machine_readable/6a2/META.a2ml b/.machine_readable/descriptiles/META.a2ml similarity index 100% rename from .machine_readable/6a2/META.a2ml rename to .machine_readable/descriptiles/META.a2ml diff --git a/.machine_readable/6a2/NEUROSYM.a2ml b/.machine_readable/descriptiles/NEUROSYM.a2ml similarity index 100% rename from .machine_readable/6a2/NEUROSYM.a2ml rename to .machine_readable/descriptiles/NEUROSYM.a2ml diff --git a/.machine_readable/6a2/PLAYBOOK.a2ml b/.machine_readable/descriptiles/PLAYBOOK.a2ml similarity index 91% rename from .machine_readable/6a2/PLAYBOOK.a2ml rename to .machine_readable/descriptiles/PLAYBOOK.a2ml index bc3004c..22bdf45 100644 --- a/.machine_readable/6a2/PLAYBOOK.a2ml +++ b/.machine_readable/descriptiles/PLAYBOOK.a2ml @@ -12,7 +12,7 @@ last-updated = "2026-04-11" # target = "container" # container | binary | library | wasm [incident-response] -# 1. Check .machine_readable/STATE.a2ml for current status +# 1. Check .machine_readable/descriptiles/STATE.a2ml for current status # 2. Review recent commits and CI results # 3. Run `just validate` to check compliance # 4. Run `just security` to audit for vulnerabilities diff --git a/.machine_readable/6a2/README.adoc b/.machine_readable/descriptiles/README.adoc similarity index 96% rename from .machine_readable/6a2/README.adoc rename to .machine_readable/descriptiles/README.adoc index 8342608..64f16e6 100644 --- a/.machine_readable/6a2/README.adoc +++ b/.machine_readable/descriptiles/README.adoc @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CC-BY-SA-4.0 // SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell -# A2ML 6a2 Directory +# A2ML Descriptiles Directory This directory contains the 6 core A2ML machine-readable metadata files for this repository. diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/descriptiles/STATE.a2ml similarity index 98% rename from .machine_readable/6a2/STATE.a2ml rename to .machine_readable/descriptiles/STATE.a2ml index 0d4ae6c..0021c81 100644 --- a/.machine_readable/6a2/STATE.a2ml +++ b/.machine_readable/descriptiles/STATE.a2ml @@ -162,3 +162,8 @@ ci-pr = "PRs #143/#146/#147 merged 2026-07-27; no open PRs" proof-build = "pass — coqc 10/10 solo-core modules (Quantity, EchoMode, ResourceAlgebra, SoloCore, Tropical, Context, ContextProps, EchoResidue, EchoMeasure, SessionPi; local full clean rebuild 2026-06-14); idris2 --build OK; all per-rung Print Assumptions closed (R-ladder, M1, S1.0–S3c.3-msg, E4)" known-local-limitation = "my-llvm cannot be built in the maintainer's WSL environment (no system LLVM 21). `cargo build --workspace` FAILS there; `--exclude my-llvm` succeeds. Do not read a bare workspace build failure as a regression without checking for the llvm-sys compile_error." superseded-branch = "origin/feat/stdlib-fs-env-format — SUPERSEDED, safe to delete: main carries every builtin it adds PLUS fs_list_dir, its stdlib.rs is 355 lines behind, it conflicts on stdlib.rs + CONTRIBUTING.md, and it is 188 commits behind main" + +[language-portfolio-audit-20260907] +scope = "Evidence audit and scoped repairs; no blanket readiness upgrade" +report = "https://github.com/hyperpolymath/nextgen-languages/blob/main/docs/audits/2026-09-07-language-portfolio.md" +metadata-path = ".machine_readable/descriptiles/" diff --git a/.well-known/security.txt b/.well-known/security.txt new file mode 100644 index 0000000..08c7fcd --- /dev/null +++ b/.well-known/security.txt @@ -0,0 +1,4 @@ +Contact: https://github.com/hyperpolymath/my-lang/security/advisories/new +Expires: 2027-09-07T00:00:00Z +Preferred-Languages: en +Policy: https://github.com/hyperpolymath/my-lang/blob/main/SECURITY.md diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 21abb76..9c6235c 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -52,7 +52,7 @@ described `+src/+`, `+config/+` and `+scripts/+` directories that do not exist) with the real 15-crate workspace layout, the `+solo ⊂ duet ⊂ ensemble+` containment hierarchy (with `+me+` as a projector outside it), and the CI gate map. -* docs: `+README.md+` and `+.machine_readable/6a2/STATE.a2ml+` now +* docs: `+README.md+` and `+.machine_readable/descriptiles/STATE.a2ml+` now record the dialects as nested subsets rather than four co-equal surfaces, and carry a security-posture section distinguishing expiring baseline debt from permanent scoped exemptions. diff --git a/DEBT.adoc b/DEBT.adoc index c4fa4d8..b550018 100644 --- a/DEBT.adoc +++ b/DEBT.adoc @@ -11,7 +11,7 @@ duplicating them: proof-status registry * link:PROOF-NEEDS.md[`+PROOF-NEEDS.md+`] — proof-side cleanup notes * link:TESTING.md[`+TESTING.md+`] — per-crate coverage measurements -* link:.machine_readable/6a2/STATE.a2ml[`+.machine_readable/6a2/STATE.a2ml+`] +* link:.machine_readable/descriptiles/STATE.a2ml[`+.machine_readable/descriptiles/STATE.a2ml+`] — authoritative machine state Severity: *HIGH* = correctness, licensing or security exposure · @@ -140,7 +140,7 @@ licences. ==== L-4 — AGPL text committed while policy bans AGPL · MEDIUM `+LICENSES/AGPL-3.0-or-later.txt+` (34 KB) is present; nothing in the -tree declares AGPL, and `+.machine_readable/6a2/AGENTIC.a2ml+` states +tree declares AGPL, and `+.machine_readable/descriptiles/AGENTIC.a2ml+` states _"`Never use AGPL licence`"_. Licence scanners will report AGPL for this repository. *Next:* delete unless a dependency genuinely requires the text. @@ -478,7 +478,7 @@ reconcile or scope the patterns to new code. nearly all commented placeholders; `+AGENTIC.a2ml+` (2026-04-11) is comment-only and states _"`Never place state files in repository root`"_ while four sit at root. Two different `+0-AI-MANIFEST.a2ml+` files exist -(root = S-expression, `+6a2/+` = Markdown) with contradictory content. +(root = S-expression, `+descriptiles/+` = Markdown) with contradictory content. `+svc/README.adoc+` documents a `+k9/+` directory that does not exist (the file lives in `+self-validating/+`). *Next:* fill or delete; deduplicate the manifest. diff --git a/Justfile b/Justfile index 470785c..6b19c55 100644 --- a/Justfile +++ b/Justfile @@ -70,7 +70,7 @@ pipeline: # Prepare a release release VERSION: @echo "Releasing {{VERSION}}..." - @echo "Set version = \"{{VERSION}}\" in Cargo.toml [workspace.package] and .machine_readable/6a2/STATE.a2ml, then tag." + @echo "Set version = \"{{VERSION}}\" in Cargo.toml [workspace.package] and .machine_readable/descriptiles/STATE.a2ml, then tag." # Run dialect demos (per golden-path contract) # Usage: just demo [dialect] @@ -124,7 +124,7 @@ verify: #!/usr/bin/env bash set -uo pipefail fail=0 - for p in .machine_readable .machine_readable/6a2/STATE.a2ml \ + for p in .machine_readable .machine_readable/descriptiles/STATE.a2ml \ .hypatia-baseline.json .hypatia-ignore \ proofs/STATUS.md Cargo.toml; do if [[ -e "$p" ]]; then echo "[OK] $p" diff --git a/README.adoc b/README.adoc index d17278f..dbb198d 100644 --- a/README.adoc +++ b/README.adoc @@ -44,7 +44,7 @@ note]. |`+frontier-practices/+` |Forward-looking research experiments (not shipped). -|`+.machine_readable/+` |Machine-facing state. `+6a2/STATE.a2ml+` is the +|`+.machine_readable/+` |Machine-facing state. `+descriptiles/STATE.a2ml+` is the authoritative project-state file for agents; `+contractiles/+` holds the Mustfile / Dustfile invariant and recovery contracts. @@ -430,7 +430,7 @@ cannot be satisfied (a keyword-matching `+coq_axiom+`, a keyword-matching `+transmute+`, and `+unsafe_block+` — a bare `+unsafe\s*\{+` regex whose "`requires SAFETY comment`" is never actually checked). See `+[security-posture]+` in -link:.machine_readable/6a2/STATE.a2ml[`+.machine_readable/6a2/STATE.a2ml+`] +link:.machine_readable/descriptiles/STATE.a2ml[`+.machine_readable/descriptiles/STATE.a2ml+`] for the machine-readable version. === Contributing diff --git a/ROADMAP.adoc b/ROADMAP.adoc index 3f904be..03ba132 100644 --- a/ROADMAP.adoc +++ b/ROADMAP.adoc @@ -11,7 +11,7 @@ toc::[] [NOTE] ==== This roadmap is *derived*, not authoritative. The machine-readable source of -truth is `.machine_readable/6a2/STATE.a2ml`; for proofs specifically it is +truth is `.machine_readable/descriptiles/STATE.a2ml`; for proofs specifically it is `proofs/STATUS.md`. Where they disagree with this file, they win. ==== diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..9fbb409 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ + +# Security policy + +Report suspected vulnerabilities privately to the contact listed in +[security.txt](.well-known/security.txt). Include the affected commit, reproduction +steps and expected impact. Do not include credentials in public issues or PRs. + +This repository contains research and development work; a successful CI run +does not certify all language designs, proofs or deployment configurations. diff --git a/docs/proof-debt.md b/docs/proof-debt.md new file mode 100644 index 0000000..79229ea --- /dev/null +++ b/docs/proof-debt.md @@ -0,0 +1,43 @@ + +# Proof debt and the trusted boundary + +This register distinguishes abstract interface obligations from global axioms. +It records the published source inspected on 2026-09-07; it does not promote +unpublished proof work or establish that every language feature is verified. + +## (a) Discharged in concrete instances + +The 15 `Axiom` declarations in +`proofs/verification/coq/solo-core/ResourceAlgebra.v` are fields of Coq module +types: ten `SEMIRING` laws, three additional `ORDERED_SEMIRING` order laws, and +two `RESIDUE_MEASURE` homomorphism laws. An abstract soundness functor is +conditional on these fields. A concrete implementation must supply proofs of +the fields when checked against its module signature. + +The source identifies `Linear3`, `Tropical` and `EchoTraceTropical` as concrete +instances. Their instantiated theorem dependencies, rather than the spelling +`Axiom` inside a module type, determine the global trusted base. The existing +`proofs.yml` workflow checks concrete assumption closure. Passing the structural +trusted-base policy only establishes that these sites are documented; it is +not a new execution of the Coq checker or a proof of the Rust implementation. + +## (b) Budgeted boundaries + +No new refutation budget or runtime extraction guarantee is claimed by this +audit. See `proofs/STATUS.adoc` for the scope of existing checks. + +## (c) Necessary global axioms + +The interface fields above are not classified as necessary global axioms. +This review does not certify the dependency closure of every proof in the tree. + +## (d) Open obligations + +- **Owner:** repository maintainer, @hyperpolymath. +- **Scope:** the model/implementation correspondence and remaining obligations + recorded in `proofs/STATUS.adoc` and `proofs/ALIGNMENT-PLAN.adoc`. +- **Plan:** keep each theorem tied to its actual language fragment, concrete + resource algebra and executable checker; close the correspondence obligations + with compiler/proof checks and counterexample tests before expanding claims. +- **Deadline:** INDEFINITE: these are separate research obligations, not + discharged by the documentation and CI repairs in this PR. diff --git a/docs/wiki/README.md b/docs/wiki/README.md index 9486ea3..a1a1e3b 100644 --- a/docs/wiki/README.md +++ b/docs/wiki/README.md @@ -105,7 +105,7 @@ integration is one capability among many — not the defining feature. ## Project status - **Version:** `0.2.0` (early-alpha, experimental; no tagged release) — see - [`.machine_readable/6a2/STATE.a2ml`](../../.machine_readable/6a2/STATE.a2ml) + [`.machine_readable/descriptiles/STATE.a2ml`](../../.machine_readable/descriptiles/STATE.a2ml) for the authoritative state, and [`proofs/STATUS.md`](../../proofs/STATUS.md) for the proof-status registry. - **Scope:** Solo dialect only in `f0` (per the diff --git a/docs/wiki/internals/formal-verification.md b/docs/wiki/internals/formal-verification.md index 294864b..0fcb9d0 100644 --- a/docs/wiki/internals/formal-verification.md +++ b/docs/wiki/internals/formal-verification.md @@ -107,4 +107,4 @@ and asserts `progress` is axiom-free. a typed hole (`?todo_*`) or a bare `Definition : Prop` is an *obligation*, never a result. - Architecture decisions are recorded as ADRs in - [`.machine_readable/6a2/META.a2ml`](../../../.machine_readable/6a2/META.a2ml). + [`.machine_readable/descriptiles/META.a2ml`](../../../.machine_readable/descriptiles/META.a2ml). diff --git a/docs/wiki/roadmap/compiler.md b/docs/wiki/roadmap/compiler.md index c43e052..6ffb162 100644 --- a/docs/wiki/roadmap/compiler.md +++ b/docs/wiki/roadmap/compiler.md @@ -4,7 +4,7 @@ # Compiler Roadmap > [!WARNING] -> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/6a2/STATE.a2ml` are authoritative. +> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/descriptiles/STATE.a2ml` are authoritative. This document outlines the development plan for the My Language compiler infrastructure. diff --git a/docs/wiki/roadmap/language.md b/docs/wiki/roadmap/language.md index e9e8ce7..f11d182 100644 --- a/docs/wiki/roadmap/language.md +++ b/docs/wiki/roadmap/language.md @@ -4,7 +4,7 @@ # Language Roadmap > [!WARNING] -> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/6a2/STATE.a2ml` are authoritative. +> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/descriptiles/STATE.a2ml` are authoritative. This document details the evolution of My Language's core features and syntax. diff --git a/docs/wiki/roadmap/overview.md b/docs/wiki/roadmap/overview.md index cb54803..0376519 100644 --- a/docs/wiki/roadmap/overview.md +++ b/docs/wiki/roadmap/overview.md @@ -4,7 +4,7 @@ # My Language Roadmap Overview > [!WARNING] -> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/6a2/STATE.a2ml` are authoritative. +> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/descriptiles/STATE.a2ml` are authoritative. *Last Updated: 2025-12-17* diff --git a/docs/wiki/roadmap/tooling.md b/docs/wiki/roadmap/tooling.md index 13acca2..17674fb 100644 --- a/docs/wiki/roadmap/tooling.md +++ b/docs/wiki/roadmap/tooling.md @@ -4,7 +4,7 @@ # Tooling Roadmap > [!WARNING] -> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/6a2/STATE.a2ml` are authoritative. +> **Status markers on this page are stale** (last updated 2025-12-17). Several items marked *Planned* have shipped (LLVM backend, formatter, linter, LSP), and the Type Checker marked *Complete* is in fact the open `#typeck` obligation. [`ROADMAP.adoc`](https://github.com/hyperpolymath/my-lang/blob/main/ROADMAP.adoc) and `.machine_readable/descriptiles/STATE.a2ml` are authoritative. This document outlines the development plan for My Language development tools. diff --git a/playground/.machine_readable/6a2/PLAYBOOK.a2ml b/playground/.machine_readable/6a2/PLAYBOOK.a2ml index bc3004c..22bdf45 100644 --- a/playground/.machine_readable/6a2/PLAYBOOK.a2ml +++ b/playground/.machine_readable/6a2/PLAYBOOK.a2ml @@ -12,7 +12,7 @@ last-updated = "2026-04-11" # target = "container" # container | binary | library | wasm [incident-response] -# 1. Check .machine_readable/STATE.a2ml for current status +# 1. Check .machine_readable/descriptiles/STATE.a2ml for current status # 2. Review recent commits and CI results # 3. Run `just validate` to check compliance # 4. Run `just security` to audit for vulnerabilities diff --git a/scripts/apply-baseline.sh b/scripts/apply-baseline.sh new file mode 100644 index 0000000..d6baa55 --- /dev/null +++ b/scripts/apply-baseline.sh @@ -0,0 +1,298 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# +# apply-baseline.sh — filter Hypatia findings against a per-repo baseline. +# +# Inputs: +# $1 = path to findings JSON (array of {severity, rule_module, type, file, ...}) +# $2 = path to .hypatia-baseline.json (array of baseline entries, see schema) +# $3 = mode: "advisory" | "blocking" (default: advisory) +# +# Outputs (stdout): +# Filtered findings JSON. Each finding gets one of: +# - removed entirely (matched by baseline, no severity_override) +# - kept with downgraded `severity` (matched, severity_override set) +# - kept unchanged with `baseline_status: "new"` +# Plus a top-level summary written to $GITHUB_STEP_SUMMARY if set. +# +# Exit codes: +# 0 = all unfiltered findings have severity below blocking threshold +# (or advisory mode) +# 1 = one or more unfiltered findings >= high in blocking mode +# 2 = invalid input (missing files, malformed JSON, or a baseline that +# violates the schema — see below) +# +# Dependencies: bash, jq. +# +# Schema enforcement: the baseline is structurally validated here, in jq, +# mirroring .machine_readable/hypatia-baseline.schema.json (required keys, +# file XOR file_pattern, closed key set, severity enums, rule_module/type/ +# tracking_issue/expires_at shapes). This script is the single place every +# baseline passes through (both reusable workflows call it), so validating +# here needs no extra tooling or checkout — and a malformed baseline FAILS +# (exit 2) rather than silently matching nothing, which is how suppression +# bugs creep in. Keep this mirror in sync when the schema changes. + +set -euo pipefail + +FINDINGS_FILE="${1:-}" +BASELINE_FILE="${2:-}" +MODE="${3:-advisory}" +BLOCKING_THRESHOLD="${BLOCKING_THRESHOLD:-high}" +case "$MODE" in + advisory|blocking) ;; + *) echo "error: invalid baseline mode: $MODE" >&2; exit 2 ;; +esac +case "$BLOCKING_THRESHOLD" in + info|low|medium|high|critical) ;; + *) echo "error: invalid blocking threshold: $BLOCKING_THRESHOLD" >&2; exit 2 ;; +esac +TODAY="$(date -u +%Y-%m-%d)" + +if [[ -z "$FINDINGS_FILE" || -z "$BASELINE_FILE" ]]; then + echo "usage: apply-baseline.sh <.hypatia-baseline.json> [advisory|blocking]" >&2 + exit 2 +fi + +if [[ ! -f "$FINDINGS_FILE" ]]; then + echo "error: findings file not found: $FINDINGS_FILE" >&2 + exit 2 +fi + +# Missing baseline is not an error — treat as empty array. +if [[ ! -f "$BASELINE_FILE" ]]; then + BASELINE_JSON='[]' +else + BASELINE_JSON="$(cat "$BASELINE_FILE")" +fi + +FINDINGS_JSON="$(cat "$FINDINGS_FILE")" + +# Validate inputs are JSON arrays. +echo "$FINDINGS_JSON" | jq -e 'type == "array"' >/dev/null || { + echo "error: findings JSON is not an array" >&2 + exit 2 +} +INVALID_FINDING_SEVERITIES="$(jq -r ' + [ .[] | (try .severity catch null) + | select(. as $severity | ["critical", "high", "medium", "low", "info", "advisory"] | index($severity) | not) ] + | unique + | .[] | @json +' <<<"$FINDINGS_JSON")" +if [[ -n "$INVALID_FINDING_SEVERITIES" ]]; then + echo "error: findings contain unrecognized severity values:" >&2 + echo "$INVALID_FINDING_SEVERITIES" >&2 + exit 2 +fi +echo "$BASELINE_JSON" | jq -e 'type == "array"' >/dev/null || { + echo "error: baseline JSON is not an array" >&2 + exit 2 +} + +# Structural validation against the baseline schema (see header). +SCHEMA_ERRORS="$(jq -r ' + # Return every key permitted in a baseline entry. + def known: ["severity","rule_module","type","file","file_pattern", + "severity_override","expires_at","note","tracking_issue"]; + # Return the values permitted in the `severity` field of a baseline entry. + def sevs: ["critical","high","medium","low","info"]; + [ to_entries[] | .key as $i | .value as $e | + if ($e|type) != "object" then "entry[\($i)]: not an object" + else ( + (["severity","rule_module","type"][] + | select(($e[.]|type) != "string") + | "entry[\($i)]: required key \(.) missing or not a string"), + (if (($e|has("file")) == ($e|has("file_pattern"))) + then "entry[\($i)]: exactly one of file / file_pattern is required" + else empty end), + ($e | keys[] + | select(. as $k | known | index($k) | not) + | "entry[\($i)]: unknown key \(.)"), + (if ($e.severity|type) == "string" and ((sevs|index($e.severity))|not) + then "entry[\($i)]: invalid severity \($e.severity)" else empty end), + (if ($e.rule_module|type) == "string" + and (($e.rule_module|test("^[a-z][a-z0-9_]*$"))|not) + then "entry[\($i)]: rule_module fails pattern: \($e.rule_module)" + else empty end), + # `type` accepts three shapes, and the third is not cosmetic: + # snake_case — the Hypatia rule modules (unsafe_block, ...) + # SD007/HYP-S009 codes — structural_drift and canonical-home rules + # CamelCase — SCORECARD PROBE NAMES (DependencyPinning, + # BranchProtection, ...). Hypatia emits these + # verbatim from Scorecard, and without this + # alternative NO SCORECARD FINDING COULD BE + # BASELINED BY ANY REPOSITORY — the validator + # rejected the whole file with exit 2, which + # reads as "your baseline is malformed" rather + # than "this finding is unrepresentable". + # Found 2026-08-06 in metadatastician/stapeln. + (if ($e.type|type) == "string" + and (($e.type|test("^([a-z][a-z0-9_]*|[A-Z]{2,3}(-[A-Z])?[0-9]{3}|[A-Z][A-Za-z0-9]+)$"))|not) + then "entry[\($i)]: type fails pattern: \($e.type)" else empty end), + (if ($e|has("file")) and ((($e.file|type) != "string") or ($e.file == "")) + then "entry[\($i)]: file must be a non-empty string" else empty end), + (if ($e|has("file_pattern")) + and ((($e.file_pattern|type) != "string") or ($e.file_pattern == "")) + then "entry[\($i)]: file_pattern must be a non-empty string" + else empty end), + (if ($e|has("severity_override")) + and (((sevs + ["advisory"])|index($e.severity_override))|not) + then "entry[\($i)]: invalid severity_override \($e.severity_override)" + else empty end), + (if ($e|has("expires_at")) + and ((($e.expires_at|type) != "string") + or (($e.expires_at|test("^[0-9]{4}-[0-9]{2}-[0-9]{2}$"))|not)) + then "entry[\($i)]: expires_at must be an ISO date (YYYY-MM-DD)" + else empty end), + (if ($e|has("tracking_issue")) + and ((($e.tracking_issue|type) != "string") + or (($e.tracking_issue|test("^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+#[0-9]+$"))|not)) + then "entry[\($i)]: tracking_issue must look like owner/repo#N" + else empty end) + ) end + ] | .[] +' <<<"$BASELINE_JSON")" + +if [[ -n "$SCHEMA_ERRORS" ]]; then + echo "error: baseline violates hypatia-baseline.schema.json:" >&2 + echo "$SCHEMA_ERRORS" >&2 + exit 2 +fi + +# Pre-filter baseline: drop expired entries (>=today). +ACTIVE_BASELINE="$(jq --arg today "$TODAY" ' + map(select((.expires_at // "9999-12-31") >= $today)) +' <<<"$BASELINE_JSON")" + +EXPIRED_COUNT="$(jq 'length' <<<"$BASELINE_JSON")" +ACTIVE_COUNT="$(jq 'length' <<<"$ACTIVE_BASELINE")" +EXPIRED_COUNT=$((EXPIRED_COUNT - ACTIVE_COUNT)) + +# Match each finding against the active baseline. Returns the matched +# baseline entry (or null) for each finding. +ANNOTATED="$(jq -n \ + --argjson findings "$FINDINGS_JSON" \ + --argjson baseline "$ACTIVE_BASELINE" ' + # Convert a glob pattern to an anchored regular expression. `*` matches + # within one path segment, while `**` can cross directory boundaries. + # All other characters are matched literally. + def glob_regex: + [scan("\\*\\*|\\*|[^*]") + | if . == "**" then ".*" + elif . == "*" then "[^/]*" + elif inside(".\\+?^$()[]{}|") then "\\" + . + else . end] + | "\\A" + join("") + "\\z"; + # Return the first active baseline entry whose severity, rule module, and type + # match a finding, and whose exact file path equals the finding file or whose + # file pattern matches it; return null if there is no match. + def match_entry(f): + f as $finding + | $baseline + | map(select( + .severity == $finding.severity + and .rule_module == $finding.rule_module + and .type == $finding.type + and ( + (.file? // null) == $finding.file + or ( + (.file_pattern? // null) as $pat + | $pat != null + and ($finding.file | test( + $pat + | glob_regex + )) + ) + ) + )) + | first // null; + + $findings + | map( + . as $f + | match_entry(.) as $m + | if $m == null then + . + {baseline_status: "new"} + else + . + { + baseline_status: "acknowledged", + baseline_note: ($m.note // null), + baseline_tracking_issue: ($m.tracking_issue // null) + } + | if $m.severity_override then + .severity = $m.severity_override + | .baseline_status = "downgraded" + else + . + end + end + ) +')" + +# Split into kept (will be evaluated by the gate) and suppressed (silently +# acknowledged, surfaced only in summary). +KEPT="$(jq '[.[] | select(.baseline_status != "acknowledged")]' <<<"$ANNOTATED")" +SUPPRESSED="$(jq '[.[] | select(.baseline_status == "acknowledged")]' <<<"$ANNOTATED")" + +# Print the numeric rank used to compare a validated severity with the blocking +# threshold. Exit with status 2 if called with any other value. +rank() { + case "$1" in + critical) echo 5 ;; + high) echo 4 ;; + medium) echo 3 ;; + low) echo 2 ;; + info) echo 1 ;; + advisory) echo 0 ;; + *) exit 2 ;; + esac +} + +THRESHOLD_RANK="$(rank "$BLOCKING_THRESHOLD")" +MAX_KEPT_RANK=0 +while IFS= read -r sev; do + r="$(rank "$sev")" + if (( r > MAX_KEPT_RANK )); then MAX_KEPT_RANK=$r; fi +done < <(jq -r '.[].severity' <<<"$KEPT") + +KEPT_COUNT="$(jq 'length' <<<"$KEPT")" +SUPPRESSED_COUNT="$(jq 'length' <<<"$SUPPRESSED")" +TOTAL_COUNT="$(jq 'length' <<<"$FINDINGS_JSON")" + +# Write summary if running inside Actions. +if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then + { + echo "## Hypatia baseline filter" + echo + echo "| | Count |" + echo "|---|---|" + echo "| Total findings | $TOTAL_COUNT |" + echo "| Acknowledged by baseline | $SUPPRESSED_COUNT |" + echo "| Remaining (kept for gate) | $KEPT_COUNT |" + echo "| Expired baseline entries | $EXPIRED_COUNT |" + echo + echo "Mode: \`$MODE\` · Blocking threshold: \`$BLOCKING_THRESHOLD\`" + if (( EXPIRED_COUNT > 0 )); then + echo + echo ":warning: $EXPIRED_COUNT baseline entries are past their \`expires_at\` and were ignored." + fi + } >> "$GITHUB_STEP_SUMMARY" +fi + +# Always emit the annotated findings so downstream steps can use them. +jq -n --argjson kept "$KEPT" --argjson suppressed "$SUPPRESSED" '{ + findings_kept: $kept, + findings_suppressed: $suppressed +}' + +# Gate decision. +if [[ "$MODE" == "advisory" ]]; then + exit 0 +fi + +if (( MAX_KEPT_RANK >= THRESHOLD_RANK )); then + echo "::error::Gate failed: $KEPT_COUNT unfiltered finding(s) at or above '$BLOCKING_THRESHOLD'." >&2 + exit 1 +fi + +exit 0 diff --git a/spec/FRG-PROFILE.adoc b/spec/FRG-PROFILE.adoc index 2582231..215a892 100644 --- a/spec/FRG-PROFILE.adoc +++ b/spec/FRG-PROFILE.adoc @@ -9,9 +9,9 @@ |=== | Field | Value -| Language | My (`.my`, four dialects) +| Language | My (`.my`; Solo, Duet, Ensemble; Me projection) | Repository | https://github.com/hyperpolymath/my-lang -| Current FRG Grade | *X* (no formalisation in any qualifying prover; PROOF-NEEDS.md explicitly records that template ABI scaffolding was removed without replacement) +| Historical FRG Grade (2026-05-28) | *X* (no formalisation in any qualifying prover; PROOF-NEEDS.md explicitly records that template ABI scaffolding was removed without replacement) | Assessed | 2026-05-28 | Assessor | Jonathan D.A. Jewell | FRG Spec Version | 1.0 @@ -21,7 +21,20 @@ | Qualifying Prover(s) | (none mechanised at the calculus level) |=== -== About this profile +== Assessment horizon and reassessment + +This document preserves the 2026-05-28 assessment; its absence claims must not +be treated as a fresh inventory. The September portfolio audit found additional +formal development and a proof-status registry in a local My checkout which was +not present at the fetched main revision. Reconcile and validate that unpublished +work before assigning a new grade to main. No grade upgrade is made here. + +The current dialect hierarchy is Solo, Duet, Ensemble. Me is an agent-generated +projection over it. Historical references below to a fourth static Me dialect +are superseded; a future profile must state the projection's elaboration and +behavior obligations separately from dialect inclusion. + +== Historical assessment My is FRG-X. The `proofs/` directory exists with dialect-aligned subdirectories suggesting *intended* per-dialect formalisation, but @@ -60,7 +73,7 @@ foundations evidence starts to interact). * *TypeLL level claimed:* L4 (Type compatibility) *operationally* * *Honest level for FRG:* L4 — implementation enforces affine / borrow / progressive-disclosure types, but no mechanised soundness - claim. The dialect structure (solo / duet / ensemble / me) + claim. The dialect structure (solo / duet / ensemble; Me is a projection) *aspires* to layered type-safety progression but no formal encoding establishes this. * *Levels not yet claimed:* L5-L10. Progressive-disclosure pedagogy @@ -156,9 +169,9 @@ For My, the following FRG tightening applies: formalisation must start at the simplest and add layered obligations. * *Grade D tightening:* Preservation MUST be stated *per dialect*: - preservation-solo, preservation-duet, preservation-ensemble, - preservation-me, with explicit composition rules for the - inclusion `solo ⊆ duet ⊆ ensemble ⊆ me`. + preservation-solo, preservation-duet, preservation-ensemble, with + explicit composition rules for `solo ⊆ duet ⊆ ensemble`. The Me + projection requires its own elaboration and behavior correspondence. * *Grade C tightening:* The borrow checker MUST be modelled in the formal calculus, not stubbed out. (My's borrow-check is genuine per `crates/my-lint/`; the formal encoding must match.)