From 9963bf342fe34fe2ce184c60379b49aca9ea9d72 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sat, 10 Oct 2026 20:03:30 +0000 Subject: [PATCH 1/5] feat: align prototype with RSR tooling and setup Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com> --- .claude/CLAUDE.md | 101 +-- .editorconfig | 44 +- .gitattributes | 87 +- .github/CODEOWNERS | 36 +- .github/CONTRIBUTING.md | 137 +-- .github/SECURITY.md | 7 + .github/copilot/coding-agent.yml | 11 +- .github/dependabot.yml | 33 +- .github/funding.yml | 4 - .github/label-classifier.json | 4 +- .github/labels.json | 2 - .github/scripts/classify-issue.jq | 18 +- .github/workflows/bun-ci.yml | 33 + .github/workflows/codeql.yml | 11 +- .../generator-generic-ossf-slsa3-publish.yml | 64 -- .github/workflows/governance.yml | 6 +- .github/workflows/hypatia-scan.yml | 7 +- .github/workflows/instant-sync.yml | 43 +- .github/workflows/julia-ci.yml | 30 + .github/workflows/mirror.yml | 3 +- .github/workflows/pages.yml | 37 +- .github/workflows/rescript-deno-ci.yml | 46 - .github/workflows/rust-ci.yml | 22 + .github/workflows/scorecard.yml | 6 +- .github/workflows/secret-scanner.yml | 15 +- .github/workflows/static.yml | 40 - .github/workflows/workflow-linter.yml | 139 ++- .gitignore | 59 +- .gitlab-ci.yml | 255 +----- .machine_readable/6a2/0-AI-MANIFEST.a2ml | 22 - .machine_readable/6a2/AGENTIC.a2ml | 34 - .machine_readable/6a2/ECOSYSTEM.a2ml | 20 - .machine_readable/6a2/META.a2ml | 27 - .machine_readable/6a2/NEUROSYM.a2ml | 21 - .machine_readable/6a2/PLAYBOOK.a2ml | 26 - .machine_readable/6a2/README.adoc | 20 - .machine_readable/6a2/STATE.a2ml | 38 - .../contractiles/Adjustfile.a2ml | 72 -- .../contractiles/Intentfile.a2ml | 99 --- .machine_readable/contractiles/Mustfile.a2ml | 102 --- .machine_readable/contractiles/Trustfile.a2ml | 88 -- .machine_readable/descriptiles/README.adoc | 48 + .../descriptiles/provisioning_praxis.deed | 27 + .well-known/ai.txt | 14 + .well-known/humans.txt | 16 + .well-known/security.txt | 9 + 0-AI-MANIFEST.a2ml | 116 --- ARCHITECTURE.adoc | 73 +- CHANGELOG.adoc | 218 ++--- CLAUDE.md | 441 ++-------- CODE_OF_CONDUCT.adoc | 2 + src/core/Cargo.lock => Cargo.lock | 0 Cargo.toml | 14 + EXPLAINME.adoc | 114 +-- GOVERNANCE.adoc | 78 +- Justfile | 377 ++------ MAINTAINERS | 44 +- MAINTAINERS.adoc | 168 +--- Mustfile | 13 - PALIMPSEST.adoc | 57 +- PLATINUM_UPGRADE.adoc | 425 +-------- PROJECT_SUMMARY.adoc | 430 +-------- Project.toml | 24 + QUICKSTART.adoc | 248 +----- README.adoc | 300 ++----- RESCRIPT_MIGRATION.adoc | 485 +--------- RSR_COMPLIANCE.adoc | 389 +------- SECURITY.adoc | 181 +--- TEST-NEEDS.adoc | 94 +- build/just/provision-check.sh | 112 +++ build/just/provision-lib.sh | 832 ++++++++++++++++++ build/just/provision-modes.sh | 158 ++++ build/just/provision.just | 108 +++ case-studies/synapcor/README.adoc | 52 +- channels.scm | 15 + compose.yml | 18 +- deno.lock | 0 docs/AI_INSTALLATION_GUIDE.adoc | 94 ++ docs/CITATIONS.adoc | 4 +- docs/SETUP.adoc | 533 ++++------- docs/architecture/ARCHITECTURE.adoc | 418 +-------- docs/architecture/OMG-ODM-MOF.adoc | 10 +- docs/architecture/TOGAF-ADM.adoc | 98 +-- docs/diagrams/class-diagram.puml | 4 +- docs/diagrams/deployment-diagram.puml | 114 +-- docs/diagrams/dfd-context.puml | 3 +- docs/diagrams/dfd-detailed.puml | 3 +- docs/diagrams/employee-state-machine.puml | 3 +- docs/diagrams/er-diagram.puml | 3 +- docs/diagrams/focus-sprint-failure.puml | 3 +- docs/diagrams/sequence-diagram.puml | 110 +-- docs/diagrams/use-case-diagram.puml | 4 +- docs/onboarding/llm-warmup-dev.adoc | 50 ++ docs/onboarding/llm-warmup-maintainer.adoc | 39 + docs/onboarding/llm-warmup-user.adoc | 32 + ...TRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc | 298 +++++++ docs/tech-debt-2026-05-26.adoc | 8 + guix.scm | 69 ++ launcher.sh | 43 + manifest.scm | 36 +- mise.toml | 64 +- package.json | 11 + phantom-metal-taste_chora.deed | 124 +++ scripts/build-site.mjs | 178 ++-- scripts/build-site.test.js | 73 ++ scripts/check-action-pinning.js | 112 +++ scripts/check-no-a2ml.sh | 33 + scripts/check-site-reproducible.sh | 17 + scripts/demo.sh | 107 +-- site.json | 72 +- src/PhantomAnalytics.jl | 22 + src/analytics/Project.toml | 10 - src/core/Cargo.toml | 10 +- src/core/src/lib.rs | 26 +- test/runtests.jl | 44 + 115 files changed, 4119 insertions(+), 6332 deletions(-) create mode 100644 .github/SECURITY.md delete mode 100644 .github/funding.yml create mode 100644 .github/workflows/bun-ci.yml delete mode 100644 .github/workflows/generator-generic-ossf-slsa3-publish.yml create mode 100644 .github/workflows/julia-ci.yml delete mode 100644 .github/workflows/rescript-deno-ci.yml create mode 100644 .github/workflows/rust-ci.yml delete mode 100644 .github/workflows/static.yml delete mode 100644 .machine_readable/6a2/0-AI-MANIFEST.a2ml delete mode 100644 .machine_readable/6a2/AGENTIC.a2ml delete mode 100644 .machine_readable/6a2/ECOSYSTEM.a2ml delete mode 100644 .machine_readable/6a2/META.a2ml delete mode 100644 .machine_readable/6a2/NEUROSYM.a2ml delete mode 100644 .machine_readable/6a2/PLAYBOOK.a2ml delete mode 100644 .machine_readable/6a2/README.adoc delete mode 100644 .machine_readable/6a2/STATE.a2ml delete mode 100644 .machine_readable/contractiles/Adjustfile.a2ml delete mode 100644 .machine_readable/contractiles/Intentfile.a2ml delete mode 100644 .machine_readable/contractiles/Mustfile.a2ml delete mode 100644 .machine_readable/contractiles/Trustfile.a2ml create mode 100644 .machine_readable/descriptiles/README.adoc create mode 100644 .machine_readable/descriptiles/provisioning_praxis.deed create mode 100644 .well-known/ai.txt create mode 100644 .well-known/humans.txt create mode 100644 .well-known/security.txt delete mode 100644 0-AI-MANIFEST.a2ml rename src/core/Cargo.lock => Cargo.lock (100%) create mode 100644 Cargo.toml delete mode 100644 Mustfile create mode 100644 Project.toml create mode 100755 build/just/provision-check.sh create mode 100755 build/just/provision-lib.sh create mode 100755 build/just/provision-modes.sh create mode 100644 build/just/provision.just create mode 100644 channels.scm delete mode 100644 deno.lock create mode 100644 docs/AI_INSTALLATION_GUIDE.adoc create mode 100644 docs/onboarding/llm-warmup-dev.adoc create mode 100644 docs/onboarding/llm-warmup-maintainer.adoc create mode 100644 docs/onboarding/llm-warmup-user.adoc create mode 100644 docs/plans/ULTRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc create mode 100644 guix.scm create mode 100755 launcher.sh create mode 100644 package.json create mode 100644 phantom-metal-taste_chora.deed create mode 100644 scripts/build-site.test.js create mode 100755 scripts/check-action-pinning.js create mode 100755 scripts/check-no-a2ml.sh create mode 100755 scripts/check-site-reproducible.sh create mode 100644 src/PhantomAnalytics.jl delete mode 100644 src/analytics/Project.toml create mode 100644 test/runtests.jl diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 355db68..f3cfb3b 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,88 +1,13 @@ - -## Machine-Readable Artefacts - -The following files in `.machine_readable/` contain structured project metadata: - -- `STATE.scm` - Current project state and progress -- `META.scm` - Architecture decisions and development practices -- `ECOSYSTEM.scm` - Position in the ecosystem and related projects -- `AGENTIC.scm` - AI agent interaction patterns -- `NEUROSYM.scm` - Neurosymbolic integration config -- `PLAYBOOK.scm` - Operational runbook - ---- - -# CLAUDE.md - AI Assistant Instructions - -## Language Policy (Hyperpolymath Standard) - -### ALLOWED Languages & Tools - -| Language/Tool | Use Case | Notes | -|---------------|----------|-------| -| **AffineScript** | Primary application code | Compiles to JS, type-safe | -| **Bun** | JS runtime & package management (tier 1) | Default for all new work. Runs compiled ESM/JS directly — no bundler step. Uses an npm-compatible `package.json` plus `bun.lock` — both are expected, not anti-patterns. | -| **Rust** | Performance-critical, systems, WASM | Preferred for CLI tools | -| **Tauri 2.0+** | Mobile apps (iOS/Android) | Rust backend + web UI | -| **Dioxus** | Mobile apps (native UI) | Pure Rust, React-like | -| **Gleam** | Backend services | Runs on BEAM or compiles to JS | -| **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 | STATE.scm, META.scm, ECOSYSTEM.scm | -| **Julia** | Batch scripts, data processing | Per RSR | -| **OCaml** | AffineScript compiler | Language-specific | -| **Ada** | Safety-critical systems | Where required | - -### BANNED - Do Not Use - -| Banned | Replacement | -|--------|-------------| -| TypeScript | AffineScript | -| ReScript | AffineScript | -| Deno | Bun | -| Node.js | Bun | -| npm | Bun | -| pnpm/yarn | Bun | -| Go | Rust | -| Python | Julia/Rust/AffineScript | -| Java/Kotlin | Rust/Tauri/Dioxus | -| Swift | Tauri/Dioxus | -| React Native | Tauri/Dioxus | -| Flutter/Dart | Tauri/Dioxus | - -### Mobile Development - -**No exceptions for Kotlin/Swift** - use Rust-first approach: - -1. **Tauri 2.0+** - Web UI (AffineScript) + Rust backend, MIT/Apache-2.0 -2. **Dioxus** - Pure Rust native UI, MIT/Apache-2.0 - -Both are FOSS with independent governance (no Big Tech). - -### Enforcement Rules - -1. **No new TypeScript files** - Convert existing TS to AffineScript -2. **Use `package.json` + `bun.lock` for JS runtime deps** - Bun is npm-compatible; a manifest is REQUIRED -3. **`bun install --production` for production deps** - resolved from `package.json`, pinned via `bun.lock` -4. **No Go code** - Use Rust instead -5. **No Python anywhere** - Use Julia for data/batch, Rust for systems, AffineScript for apps -6. **No Kotlin/Swift for mobile** - Use Tauri 2.0+ or Dioxus - -### Package Management - -- **Primary**: Guix (guix.scm) -- **Fallback**: Nix (flake.nix) -- **JS deps**: Bun (`package.json` + `bun.lock`). Declare tooling as a devDependency and run `bunx --no-install --bun ` — a bare `bunx ` can fetch an unpinned package and may start Node via its shebang. - -### Security Requirements - -- No MD5/SHA1 for security (use SHA256+) -- HTTPS only (no HTTP URLs) -- No hardcoded secrets -- SHA-pinned dependencies -- SPDX license headers on all files - + + +# Claude Code project notes + +Use the repository-wide agent instructions in [`../CLAUDE.md`](../CLAUDE.md). +Repository-wide descriptive facts live in [`../phantom-metal-taste_chora.deed`](../phantom-metal-taste_chora.deed) +in the current DEED format. Do not recreate retired `.a2ml` files or the +former root-level `.scm` state layout. + +Project-specific facts: Rust and Julia libraries plus a Bun site builder are +implemented to experimental depth; the AffineScript orchestrator is unfinished; +there is no HTTP API or database integration. All changes and claims must match +what the source and tests actually demonstrate. diff --git a/.editorconfig b/.editorconfig index 51f3044..abea954 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,5 @@ -# phantom-metal-taste - Editor Configuration -# https://editorconfig.org +# SPDX-License-Identifier: MPL-2.0 +# Editor configuration for the current Rust / Julia / Bun / Guix toolchain. root = true @@ -20,49 +20,15 @@ trim_trailing_whitespace = false [*.rs] indent_size = 4 -[*.ex] -indent_size = 2 - -[*.exs] -indent_size = 2 - -[*.zig] +[*.jl] indent_size = 4 -[*.ada] -indent_size = 3 - -[*.adb] -indent_size = 3 - -[*.ads] -indent_size = 3 - -[*.hs] -indent_size = 2 - -[*.res] -indent_size = 2 - -[*.resi] -indent_size = 2 - -[*.ncl] -indent_size = 2 - -[*.rkt] +[*.affine] indent_size = 2 -[*.scm] -indent_size = 2 - -[*.nix] +[*.{js,mjs,json,yml,yaml,toml,scm,sh}] indent_size = 2 [Justfile] indent_style = space indent_size = 4 - -[justfile] -indent_style = space -indent_size = 4 diff --git a/.gitattributes b/.gitattributes index e860a85..08ac996 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,54 +1,43 @@ # SPDX-License-Identifier: MPL-2.0 -# RSR-compliant .gitattributes +# RSR-compliant text and diff attributes for the current repository languages. * text=auto eol=lf -# Source -*.rs text eol=lf diff=rust -*.ex text eol=lf diff=elixir -*.exs text eol=lf diff=elixir -*.jl text eol=lf -*.res text eol=lf -*.resi text eol=lf -*.ada text eol=lf diff=ada -*.adb text eol=lf diff=ada -*.ads text eol=lf diff=ada -*.hs text eol=lf -*.chpl text eol=lf -*.scm text eol=lf -*.ncl text eol=lf -*.nix text eol=lf - -# Docs -*.md text eol=lf diff=markdown -*.adoc text eol=lf -*.txt text eol=lf - -# Data -*.json text eol=lf -*.yaml text eol=lf -*.yml text eol=lf -*.toml text eol=lf - -# Config -.gitignore text eol=lf -.gitattributes text eol=lf -justfile text eol=lf -Makefile text eol=lf -Containerfile text eol=lf - -# Scripts -*.sh text eol=lf - -# Binary -*.png binary -*.jpg binary -*.gif binary -*.pdf binary +# Rust and Julia source +*.rs text eol=lf diff=rust +*.jl text eol=lf + +# Bun site tooling +*.js text eol=lf +*.mjs text eol=lf + +# AffineScript source/scaffolds +*.affine text eol=lf + +# Guix Scheme and configuration +*.scm text eol=lf +*.toml text eol=lf +*.json text eol=lf +*.yaml text eol=lf +*.yml text eol=lf +*.sh text eol=lf + +# Documentation +*.md text eol=lf diff=markdown +*.adoc text eol=lf +*.txt text eol=lf + +# Build/task files +Justfile text eol=lf +justfile text eol=lf +Cargo.lock text eol=lf -diff + +# Binary assets +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.pdf binary *.woff2 binary -*.zip binary -*.gz binary - -# Lock files -Cargo.lock text eol=lf -diff -flake.lock text eol=lf -diff +*.zip binary +*.gz binary diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3a3b7f2..fb69259 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,34 +1,24 @@ # SPDX-License-Identifier: MPL-2.0 -# CODEOWNERS - Define code review assignments for GitHub -# See: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners - -# Default: sole maintainer for all files +# Repository owner is the default reviewer; repository permissions govern merge authority. * @hyperpolymath -# Security-sensitive files require explicit ownership -SECURITY.md @hyperpolymath +# Security-sensitive and governance files. +SECURITY.adoc @hyperpolymath .github/workflows/ @hyperpolymath .machine_readable/ @hyperpolymath -contractiles/ @hyperpolymath -# License files +# Licences and project policy. LICENSE @hyperpolymath LICENSES/ @hyperpolymath - -# Configuration -.gitignore @hyperpolymath -.github/ @hyperpolymath - -# Documentation -README* @hyperpolymath -CONTRIBUTING* @hyperpolymath -CODE_OF_CONDUCT* @hyperpolymath -GOVERNANCE* @hyperpolymath +GOVERNANCE.adoc @hyperpolymath MAINTAINERS* @hyperpolymath -CHANGELOG* @hyperpolymath -ROADMAP* @hyperpolymath +CHANGELOG.adoc @hyperpolymath -# Build and CI +# Source, build, and provisioning. +Cargo.toml @hyperpolymath +Cargo.lock @hyperpolymath +Project.toml @hyperpolymath +mise.toml @hyperpolymath Justfile @hyperpolymath -Makefile @hyperpolymath -*.sh @hyperpolymath +build/just/ @hyperpolymath +launcher.sh @hyperpolymath diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 152ddaf..c8f72be 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,105 +1,40 @@ - -# Getting started -```bash -git clone https://github.com/hyperpolymath/phantom-metal-taste.git -cd phantom-metal-taste - -# Using mise (recommended: provision the pinned toolchain) -mise install - -# Task runner (see Justfile) -just --list # available tasks -just check # verify setup / static checks -just test # run the test suite -``` - ---- - -## 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](../docs/status/ROADMAP.adoc) 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/phantom-metal-taste/labels/good%20first%20issue) — Simple Perimeter 3 tasks -- [`help wanted`](https://github.com/hyperpolymath/phantom-metal-taste/labels/help%20wanted) — Community help needed -- [`documentation`](https://github.com/hyperpolymath/phantom-metal-taste/labels/documentation) — Docs improvements -- [`perimeter-3`](https://github.com/hyperpolymath/phantom-metal-taste/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] + + +# Contributing + +Thanks for helping improve Phantom Metal Taste. The project is experimental; +please distinguish implemented behavior from design proposals and TODO +scaffolds in reports and pull requests. + +## Before changing code + +1. Read [`CLAUDE.md`](../CLAUDE.md), [`docs/SETUP.adoc`](../docs/SETUP.adoc), + and the relevant machine-readable project state. +2. Follow current `hyperpolymath/standards` and + `hyperpolymath/rsr-template-repo` policy. +3. Do not introduce a new runtime, service, database integration, or claim of + AffineScript completion without tests and an explicit scope decision. + +## Local workflow + +```sh +./launcher.sh --setup +just doctor +just build +just test +just lint +just fmt-check +just site-check ``` -## Signed commits +`just validate` runs the principal local gates. If Rust or Julia is unavailable, +state that the corresponding tests were not run; do not mark them as passing. -Every commit that reaches the default branch must be signed; a ruleset refuses -unsigned pushes. Estate policy: -[SIGNING-POLICY](https://github.com/hyperpolymath/standards/blob/main/docs/SIGNING-POLICY.adoc). +## Pull requests -- **People and interactive agents** sign with an SSH key registered on GitHub - as a *signing* key (`gpg.format=ssh`, `user.signingkey=.pub`, - `commit.gpgsign=true`). The committer email must be verified on that account. -- **Apps, bots and workflows** never `git push` local commits. They write - through the API (`createCommitOnBranch` or the estate `signed-push` action) - so that GitHub signs each commit. -- Merge PRs with **squash**. The ruleset checks every commit on the PR branch, - not just the result, so one unsigned commit blocks the merge. Re-create such a - branch with signed commits (`git cherry-pick -S`) and open a new PR. - Rebase-merge replays commits unsigned and is disabled. +- Keep changes focused and link relevant issues. +- Include tests for behavioral changes and update user-facing docs. +- Use Conventional Commit messages. +- Do not commit secrets, credentials, generated build output, or hand-written + `mise.lock` / `.github/workflows/actions.lock` data. +- Respect the repository's currently configured required checks and merge settings; do not bypass branch protection or required review. diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..5efe58b --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,7 @@ + +# Security Policy + +The detailed security boundary and disclosure guidance is maintained in +[SECURITY.adoc](../SECURITY.adoc). Please report suspected vulnerabilities +privately through [GitHub Security Advisories](https://github.com/hyperpolymath/phantom-metal-taste/security/advisories/new); +do not post exploit details or private data in public issues. diff --git a/.github/copilot/coding-agent.yml b/.github/copilot/coding-agent.yml index a719a77..0e22a84 100644 --- a/.github/copilot/coding-agent.yml +++ b/.github/copilot/coding-agent.yml @@ -1,6 +1,5 @@ -mcp_servers: - boj-server: - command: npx - args: ["-y", "@hyperpolymath/boj-server@latest"] - env: - BOJ_URL: http://localhost:7700 +# SPDX-License-Identifier: MPL-2.0 +# This optional editor integration previously invoked an out-of-tree MCP server +# on localhost:7700 via an unpinned npm package. The service is not part of this +# repository and is not needed for setup or development. +mcp_servers: {} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f16b295..8607ce1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,21 +1,8 @@ # SPDX-License-Identifier: MPL-2.0 +# Dependabot configuration for the current Rust, GitHub Actions, and Bun project. version: 2 updates: - - package-ecosystem: "cargo" - directory: "/" - schedule: - interval: "weekly" - # `open-pull-requests-limit: 0` suppresses routine version-update PRs - # while leaving Dependabot SECURITY PRs flowing. The previous - # `ignore: "*" patch` rule also silenced security PRs under GitHub\'s - # current Dependabot behaviour. See rsr-template-repo commit 78b050e - # and 007-lang/audits/audit-dependabot-automation-gap-2026-04-17.md. - open-pull-requests-limit: 0 - package-ecosystem: "github-actions" - # Ruby is banned for this estate: bump the action, or delete it? Delete. - ignore: - - dependency-name: "ruby/setup-ruby" - - dependency-name: "actions/jekyll-build-pages" directory: "/" schedule: interval: "weekly" @@ -25,18 +12,24 @@ updates: - "*" open-pull-requests-limit: 2 ignore: - # HOLD: github/codeql-action at v4.38.0 (SHA-pinned). v4.38.1 fails - # GitHub workflow-startup validation estate-wide (nexia-list#100; - # SHA-form re-bump bypassed versions-scoped ignores - nexia-list#101). - # Hold until upstream clears 4.38.1 or a new release verifies green. - - dependency-name: "github/codeql-action" + # HOLD: v4.38.1 fails GitHub workflow-startup validation estate-wide; + # revisit when upstream has a verified newer release. The wildcard is + # required because workflow refs use subpaths (/init and /analyze). + - dependency-name: "github/codeql-action*" - - package-ecosystem: "nix" + - package-ecosystem: "cargo" directory: "/" schedule: interval: "weekly" + # Suppress routine version PRs while allowing security updates. + open-pull-requests-limit: 0 + - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" open-pull-requests-limit: 3 + groups: + dependency-updates: + patterns: + - "*" diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index e4f7c07..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Funding Configuration -# See: https://docs.github.com/en/repositories/managing-your-repositorys-custom-fields/displaying-a-sponsor-button-in-your-repository - -github: metadatastician diff --git a/.github/label-classifier.json b/.github/label-classifier.json index d349eaa..af5b9f2 100644 --- a/.github/label-classifier.json +++ b/.github/label-classifier.json @@ -1,6 +1,4 @@ { - "_generated_from": ".github/label-classifier.yml + .github/labels.yml in hyperpolymath/.git-private-farm", - "_do_not_edit": "regenerate with scripts/gen-classifier-json.py", "version": 1, "prefix_split_on": "/", "title_prefix": { @@ -421,7 +419,7 @@ "migration": [ "rescript", "to-affinescript", - "\u2192 affinescript", + "→ affinescript", "port", "deno", "bun" diff --git a/.github/labels.json b/.github/labels.json index 78786d4..ad277ee 100644 --- a/.github/labels.json +++ b/.github/labels.json @@ -1,6 +1,4 @@ { - "_generated_from": ".github/labels.yml in hyperpolymath/.git-private-farm", - "_do_not_edit": "regenerate with scripts/gen-labels-json.py", "version": 1, "labels": [ { diff --git a/.github/scripts/classify-issue.jq b/.github/scripts/classify-issue.jq index 6467c74..cb865c1 100644 --- a/.github/scripts/classify-issue.jq +++ b/.github/scripts/classify-issue.jq @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MPL-2.0 # -# Classify one issue title against the estate label taxonomy. +# Classify one issue title using the checked-in label-classifier.json taxonomy. # # jq -r --arg title "docs: fix the README" \ # --argjson have '[]' \ @@ -10,20 +10,8 @@ # confidently. Nothing printed means "leave it for a human" -- a correct # outcome, not a failure. # -# WHY jq AND NOT PYTHON -# -# Python is fully banned estate-wide: the `governance / Language / package -# anti-pattern policy` gate runs `git ls-files '*.py'` and fails the PR -# ("Python is fully banned -- use AffineScript/Rust/SPARK/Julia"). This file -# is dispatched into every repo in the estate, so shipping it as .py would -# mean shipping an exemption into every repo too -- normalising the policy -# away by sweep. jq is preinstalled on every GitHub runner, is not on the -# banned list, needs no action (so no actions.lock entry can drift), and the -# rules are already JSON. -# -# The canonical implementation remains scripts/label-classify.py in the hub, -# which never runs in CI. tests/test-classifier-parity.py asserts this file -# agrees with it on every title in the corpus. +# The checked-in JSON is the configuration consumed by label-triage.yml. This +# repository has no private generator or out-of-tree parity-suite dependency. # # `$have` lists labels the issue already carries. Anything already present is # never re-suggested, and the classifier stays out of any max-1 tier the issue diff --git a/.github/workflows/bun-ci.yml b/.github/workflows/bun-ci.yml new file mode 100644 index 0000000..68bf4c7 --- /dev/null +++ b/.github/workflows/bun-ci.yml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: MPL-2.0 +name: Bun CI + +on: + push: + branches: [main, master] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: + contents: read + +jobs: + bun: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: 1.4.3 + - name: Test site-builder helpers + run: bun test + - name: Build the allowlisted site + run: bun run build + - name: Verify reproducibility + run: sh scripts/check-site-reproducible.sh diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 84ae761..052d16b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,7 +14,10 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -permissions: read-all +permissions: + actions: read + contents: read + security-events: write jobs: analyze: runs-on: ubuntu-latest @@ -28,17 +31,19 @@ jobs: include: - language: actions build-mode: none + - language: javascript-typescript + build-mode: none - language: rust build-mode: none steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.0 (4.38.1 blocked estate-wide; nexia-list#100) + uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 (4.38.1 blocked estate-wide; nexia-list#100) with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.0 (4.38.1 blocked estate-wide; nexia-list#100) + uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 (4.38.1 blocked estate-wide; nexia-list#100) with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/generator-generic-ossf-slsa3-publish.yml b/.github/workflows/generator-generic-ossf-slsa3-publish.yml deleted file mode 100644 index 05d92af..0000000 --- a/.github/workflows/generator-generic-ossf-slsa3-publish.yml +++ /dev/null @@ -1,64 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow lets you generate SLSA provenance file for your project. -# The generation satisfies level 3 for the provenance requirements - see https://slsa.dev/spec/v0.1/requirements -# The project is an initiative of the OpenSSF (openssf.org) and is developed at -# https://github.com/slsa-framework/slsa-github-generator. -# The provenance file can be verified using https://github.com/slsa-framework/slsa-verifier. -# For more information about SLSA and how it improves the supply-chain, visit slsa.dev. - -name: SLSA generic generator -on: - workflow_dispatch: - release: - types: [created] -permissions: read-all -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 15 - outputs: - digests: ${{ steps.hash.outputs.digests }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4 - # ======================================================== - # - # Step 1: Build your artifacts. - # - # ======================================================== - - name: Build artifacts - run: | - # These are some amazing artifacts. - echo "artifact1" > artifact1 - echo "artifact2" > artifact2 - # ======================================================== - # - # Step 2: Add a step to generate the provenance subjects - # as shown below. Update the sha256 sum arguments - # to include all binaries that you generate - # provenance for. - # - # ======================================================== - - name: Generate subject for provenance - id: hash - run: | - set -euo pipefail - - # List the artifacts the provenance will refer to. - files=$(ls artifact*) - # Generate the subjects (base64 encoded). - echo "hashes=$(sha256sum $files | base64 -w0)" >> "${GITHUB_OUTPUT}" - provenance: - needs: [build] - permissions: - actions: read # To read the workflow path. - id-token: write # To sign the provenance. - contents: write # To add assets to a release. - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a # v2.1.0 - with: - base64-subjects: "${{ needs.build.outputs.digests }}" - upload-assets: true # Optional: Upload to a new release diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index d8c88d3..215c71c 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -8,9 +8,13 @@ on: branches: [main, master] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true permissions: + actions: read contents: read jobs: governance: - uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@81dbf2dd854b1444fd6236fa2352474383b2c2b9 + uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@da2c748aad55c1a1dcba00b60fe4a35017bc6540 diff --git a/.github/workflows/hypatia-scan.yml b/.github/workflows/hypatia-scan.yml index 6699de9..84f9ea8 100644 --- a/.github/workflows/hypatia-scan.yml +++ b/.github/workflows/hypatia-scan.yml @@ -1,4 +1,5 @@ # SPDX-License-Identifier: MPL-2.0 +# Standalone Hypatia security scan (push / PR / weekly). name: Hypatia Security Scan on: @@ -10,10 +11,14 @@ on: - cron: '0 0 * * 0' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true permissions: + actions: read contents: read security-events: write jobs: hypatia: - uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@81dbf2dd854b1444fd6236fa2352474383b2c2b9 + uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@da2c748aad55c1a1dcba00b60fe4a35017bc6540 diff --git a/.github/workflows/instant-sync.yml b/.github/workflows/instant-sync.yml index 78c70e7..dbd26ea 100644 --- a/.github/workflows/instant-sync.yml +++ b/.github/workflows/instant-sync.yml @@ -13,18 +13,45 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - name: Trigger Propagation + - name: Monitor outbound egress + uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1 + with: + egress-policy: audit + - name: Check propagation credential + id: credential + env: + FARM_DISPATCH_TOKEN: ${{ secrets.FARM_DISPATCH_TOKEN }} + run: | + if [ -n "$FARM_DISPATCH_TOKEN" ]; then + echo "available=true" >> "$GITHUB_OUTPUT" + else + echo "available=false" >> "$GITHUB_OUTPUT" + fi + - name: Build propagation payload + id: payload + if: steps.credential.outputs.available == 'true' + env: + REPOSITORY: ${{ github.event.repository.name }} + REF_NAME: ${{ github.ref }} + COMMIT_SHA: ${{ github.sha }} + run: | + payload=$(jq -cn \ + --arg repo "$REPOSITORY" \ + --arg ref "$REF_NAME" \ + --arg sha "$COMMIT_SHA" \ + '{repo: $repo, ref: $ref, sha: $sha, forges: ""}') + echo "json=$payload" >> "$GITHUB_OUTPUT" + - name: Trigger propagation + if: steps.credential.outputs.available == 'true' uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1 with: token: ${{ secrets.FARM_DISPATCH_TOKEN }} repository: hyperpolymath/.git-private-farm event-type: propagate - client-payload: |- - { - "repo": "${{ github.event.repository.name }}", - "ref": "${{ github.ref }}", - "sha": "${{ github.sha }}", - "forges": "" - } + client-payload: ${{ steps.payload.outputs.json }} + - name: Report skipped propagation + if: steps.credential.outputs.available != 'true' + run: echo "::warning::Propagation skipped because FARM_DISPATCH_TOKEN is not configured." - name: Confirm + if: steps.credential.outputs.available == 'true' run: echo "::notice::Propagation triggered for ${{ github.event.repository.name }}" diff --git a/.github/workflows/julia-ci.yml b/.github/workflows/julia-ci.yml new file mode 100644 index 0000000..37c1dc2 --- /dev/null +++ b/.github/workflows/julia-ci.yml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: MPL-2.0 +name: Julia CI + +on: + push: + branches: [main, master] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: + contents: read + +jobs: + analytics: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Julia + uses: julia-actions/setup-julia@4c0cb0fce8556fdb04a90347310e5db8b1f98fb9 # v2 + with: + version: "1.10" + project: "." + - name: Instantiate and test the analytics package + run: julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.test()' diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index 31a0d69..212bd4d 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -4,7 +4,8 @@ on: push: branches: [main] workflow_dispatch: -permissions: read-all +permissions: + contents: read jobs: mirror-gitlab: runs-on: ubuntu-latest diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 2e79f97..c62aa61 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,13 +1,11 @@ # SPDX-License-Identifier: MPL-2.0 -# -# Generated by scripts/estate-ruby-exit.mjs — Ruby-free Pages deploy. -# Replaces the Jekyll workflow (ruby/setup-ruby or actions/jekyll-build-pages): -# Ruby is banned for this estate, see hyperpolymath/verisimdb-data ADR-0002. +# Publish only the paths allowlisted by site.json. The two-run hash check makes +# the build's reproducibility a gate before any Pages artifact is uploaded. name: Deploy Pages site on: push: - branches: ["main", "master"] + branches: [main, master] workflow_dispatch: permissions: @@ -22,22 +20,30 @@ concurrency: jobs: build: runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + pages: read steps: - name: Checkout - uses: actions/checkout@v7.0.1 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: 1.4.3 - name: Setup Pages id: pages - uses: actions/configure-pages@v6.0.0 - - name: Build site and prove reproducibility + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + - name: Build site twice and verify the hashes env: BASE_PATH: ${{ steps.pages.outputs.base_path }} run: | set -euo pipefail - if command -v bun >/dev/null 2>&1; then runtime="bun run"; else runtime="node"; fi - echo "build runtime: $runtime" - $runtime scripts/build-site.mjs --config site.json --baseurl "$BASE_PATH" | tee /tmp/build-1.log + bun scripts/build-site.mjs --config site.json --baseurl "$BASE_PATH" --out _site | tee /tmp/build-1.log rm -rf _site - $runtime scripts/build-site.mjs --config site.json --baseurl "$BASE_PATH" | tee /tmp/build-2.log + bun scripts/build-site.mjs --config site.json --baseurl "$BASE_PATH" --out _site | tee /tmp/build-2.log first=$(sed -n 's/.*\(sha256=[0-9a-f]\{64\}\).*/\1/p' /tmp/build-1.log | head -1) second=$(sed -n 's/.*\(sha256=[0-9a-f]\{64\}\).*/\1/p' /tmp/build-2.log | head -1) if [ -z "$first" ] || [ "$first" != "$second" ]; then @@ -45,7 +51,7 @@ jobs: exit 1 fi - name: Upload artifact - uses: actions/upload-pages-artifact@v5.0.0 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: _site include-hidden-files: true @@ -56,7 +62,10 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build + permissions: + pages: write + id-token: write steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5.0.1 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/rescript-deno-ci.yml b/.github/workflows/rescript-deno-ci.yml deleted file mode 100644 index a614007..0000000 --- a/.github/workflows/rescript-deno-ci.yml +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -name: ReScript/Deno CI -on: - push: - branches: [main, master] - pull_request: - -# Estate guardrail: scope push to default branches so a PR fires once (not -# push+PR), and cancel superseded runs. Safe — read-only PR-triggered check. -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -permissions: read-all -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4 - - uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2 - with: - deno-version: v1.x - - name: Deno lint - run: deno lint - - name: Deno fmt check - run: deno fmt --check - - name: Deno test - run: deno test --allow-all --coverage=coverage - - name: ReScript build - run: | - if [ -f "rescript.json" ] || [ -f "bsconfig.json" ]; then - npm install - npx rescript - fi - - name: Type check - run: deno check **/*.ts || true - security: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4 - - uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2 - - name: Check permissions - run: | - # Audit for dangerous permissions - grep -rE "allow-run|allow-write|allow-env" . || echo "No dangerous permissions" diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml new file mode 100644 index 0000000..26ad3d8 --- /dev/null +++ b/.github/workflows/rust-ci.yml @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: MPL-2.0 +# Thin wrapper around the shared RSR Rust CI. The Rust crate is the workspace +# member under src/core; the root Cargo.lock pins its dependencies. +name: Rust CI + +on: + push: + branches: [main, master] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: + actions: read + contents: read + +jobs: + rust-ci: + uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@da2c748aad55c1a1dcba00b60fe4a35017bc6540 + with: + working_directory: src/core diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 11d9b2a..55f9636 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -6,12 +6,16 @@ on: - cron: '0 4 * * *' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true permissions: + actions: read contents: read jobs: scorecard: - uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@81dbf2dd854b1444fd6236fa2352474383b2c2b9 + uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@da2c748aad55c1a1dcba00b60fe4a35017bc6540 permissions: contents: read security-events: write diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index fa6eb1f..4abc0bb 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -1,13 +1,7 @@ # SPDX-License-Identifier: MPL-2.0 # Prevention workflow - scans for hardcoded secrets before they reach main. -# -# Calls the estate's shared secret scanner (gitleaks + rust-secrets + -# shell-secrets). The job key MUST stay `scan`: the estate-wide -# Secret-Scan-Floor ruleset requires the check context `scan / gitleaks`. -# -# No `secrets:` line, deliberately: the reusable references no secrets -# (gitleaks runs as a checksum-verified binary, not gitleaks-action), so -# `secrets: inherit` would only hand it every repo and org secret (CWE-250). +# Keep the `scan` job identity: Secret-Scan-Floor requires `scan / gitleaks`. +# No secrets are inherited; the reusable uses none. name: Secret Scanner on: @@ -20,8 +14,11 @@ concurrency: cancel-in-progress: true permissions: + actions: read contents: read jobs: scan: - uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@74d2f66f575246cf6e313ae7775f44df6e097ff2 + permissions: + contents: read + uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@da2c748aad55c1a1dcba00b60fe4a35017bc6540 diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml deleted file mode 100644 index 3666332..0000000 --- a/.github/workflows/static.yml +++ /dev/null @@ -1,40 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Simple workflow for deploying static content to GitHub Pages -name: Deploy static content to Pages -on: - # Runs on pushes targeting the default branch - push: - branches: ["main"] - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false -jobs: - # Single deploy job since we're just deploying - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4 - - name: Setup Pages - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - - name: Upload artifact - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 - with: - # Upload entire repository - path: '.' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/workflow-linter.yml b/.github/workflows/workflow-linter.yml index 5844dfb..5f20328 100644 --- a/.github/workflows/workflow-linter.yml +++ b/.github/workflows/workflow-linter.yml @@ -1,54 +1,125 @@ # SPDX-License-Identifier: MPL-2.0 -# Prevention workflow - validates all workflows have proper security config +# Local checks for immutable action refs and workflow hygiene. name: Workflow Security Linter on: - pull_request: - paths: - - '.github/workflows/**' push: paths: - - '.github/workflows/**' + - ".github/workflows/**" + - "scripts/check-action-pinning.js" + - "scripts/check-no-a2ml.sh" + - "Justfile" + - "phantom-metal-taste_chora.deed" + - ".machine_readable/**" + - "**/*.a2ml" + - "**/*.A2ML" + pull_request: + paths: + - ".github/workflows/**" + - "scripts/check-action-pinning.js" + - "scripts/check-no-a2ml.sh" + - "Justfile" + - "phantom-metal-taste_chora.deed" + - ".machine_readable/**" + - "**/*.a2ml" + - "**/*.A2ML" + workflow_dispatch: -permissions: read-all +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read jobs: lint-workflows: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 + timeout-minutes: 15 + permissions: + contents: read steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4 + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: 1.4.3 - - name: Check SPDX headers + - name: Check SPDX headers and least-privilege defaults + shell: bash run: | - errors=0 - for f in .github/workflows/*.yml .github/workflows/*.yaml; do - [ -f "$f" ] || continue - if ! head -1 "$f" | grep -q "SPDX-License-Identifier"; then - echo "ERROR: $f missing SPDX header" - errors=$((errors + 1)) + set -euo pipefail + for file in .github/workflows/*.yml .github/workflows/*.yaml; do + [[ -f "$file" ]] || continue + if ! awk '/^# SPDX-License-Identifier:/ { found=1 } /^[^#[:space:]]/ { exit } END { exit !found }' "$file"; then + echo "::error file=$file::SPDX identifier missing from leading comment block" + exit 1 fi + grep -q '^permissions:' "$file" || { + echo "::error file=$file::top-level permissions block is missing" + exit 1 + } done - exit $errors - - name: Check permissions declaration + - name: Check immutable action references + run: bun scripts/check-action-pinning.js + + - name: Check retired A2ML format is absent + run: bash scripts/check-no-a2ml.sh + + - name: Check current CodeQL coverage + shell: bash run: | - errors=0 - for f in .github/workflows/*.yml .github/workflows/*.yaml; do - [ -f "$f" ] || continue - if ! grep -q "^permissions:" "$f"; then - echo "ERROR: $f missing permissions declaration" - errors=$((errors + 1)) - fi + set -euo pipefail + workflow=.github/workflows/codeql.yml + [[ -f "$workflow" ]] || { echo "::error::CodeQL workflow missing"; exit 1; } + for language in actions javascript-typescript rust; do + grep -Fq -- "- language: $language" "$workflow" || { + echo "::error::$language missing from the CodeQL matrix" + exit 1 + } done - exit $errors + js_source=$(find . -type f \( -name '*.js' -o -name '*.mjs' -o -name '*.cjs' \) \ + -not -path './.git/*' -not -path './node_modules/*' -not -path './_site/*' -print -quit) + [[ -n "$js_source" ]] || { echo "::error::JavaScript source expected but none found"; exit 1; } + echo "CodeQL matrix covers Actions, Rust, and Bun JavaScript tooling" - - name: Check pinned actions + - name: Check feature-gated mirror secrets + shell: bash run: | - errors=0 - for f in .github/workflows/*.yml .github/workflows/*.yaml; do - [ -f "$f" ] || continue - # Look for uses: without SHA - if grep -E "uses:.*@v[0-9]" "$f" | grep -v "#"; then - echo "WARNING: $f has unpinned actions (missing SHA comment)" - fi - done + set -euo pipefail + workflow=.github/workflows/mirror.yml + [[ -f "$workflow" ]] || exit 0 + grep -Fq "vars.GITLAB_MIRROR_ENABLED == 'true'" "$workflow" + grep -Fq 'secrets.GITLAB_SSH_KEY' "$workflow" + grep -Fq "vars.BITBUCKET_MIRROR_ENABLED == 'true'" "$workflow" + grep -Fq 'secrets.BITBUCKET_SSH_KEY' "$workflow" + echo "Mirror secret use is guarded by its corresponding feature flag" + + - name: Check optional farm-dispatch credential guard + shell: bash + run: | + set -euo pipefail + workflow=.github/workflows/instant-sync.yml + secret_ref='$''{{ secrets.FARM_DISPATCH_TOKEN }}' + grep -Fq "FARM_DISPATCH_TOKEN: $secret_ref" "$workflow" + grep -Fq 'payload=$(jq -cn' "$workflow" + grep -Fq "if: steps.credential.outputs.available == 'true'" "$workflow" + grep -Fq "if: steps.credential.outputs.available != 'true'" "$workflow" + echo "Farm dispatch is skipped with a warning when its credential is absent" + + - name: Check secret-bearing workflow egress monitoring + shell: bash + run: | + set -euo pipefail + workflow=.github/workflows/instant-sync.yml + grep -Fq 'uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25' "$workflow" + grep -Fq 'egress-policy: audit' "$workflow" + awk '/uses: step-security\/harden-runner@/ { monitor=NR } + /FARM_DISPATCH_TOKEN: \$\{\{ secrets\.FARM_DISPATCH_TOKEN \}\}/ { secret=NR } + END { exit !(monitor > 0 && secret > monitor) }' "$workflow" + echo "Instant Sync audits egress before reading the dispatch secret" diff --git a/.gitignore b/.gitignore index 671331e..f17a150 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MPL-2.0 -# RSR-compliant .gitignore +# RSR-compliant .gitignore; keep the provisioning engine under /build/ tracked. -# OS & Editor +# OS & editor .DS_Store Thumbs.db *.swp @@ -10,12 +10,14 @@ Thumbs.db .idea/ .vscode/ -# Build +# Build outputs /target/ /_build/ -/build/ /dist/ /out/ +/_site/ +/coverage/ +htmlcov/ # Dependencies /node_modules/ @@ -24,24 +26,14 @@ Thumbs.db /.elixir_ls/ # Rust -# Cargo.lock # Keep for binaries - -# Elixir -/cover/ -/doc/ -*.ez -erl_crash.dump +# Cargo.lock is intentionally tracked. # Julia *.jl.cov *.jl.mem /Manifest.toml -# ReScript -/lib/bs/ -/.bsb.lock - -# Python (SaltStack only) +# Generic caches from external tooling; Python is not a project runtime. __pycache__/ *.py[cod] .venv/ @@ -63,28 +55,27 @@ __pycache__/ .env.* *.pem *.key +*.secret secrets/ - -# Test/Coverage -/coverage/ -htmlcov/ - -# Logs +credentials/ +.ssh/ +.aws/ +.kube/ +.docker/ +token.* +secret.* +.npmrc +.netrc +.pypirc +*.token +*.p12 +*.pfx +credentials.json + +# Logs and temporary files *.log /logs/ - -# Temp /tmp/ *.tmp *.bak -target/ -node_modules/ -_build/ -deps/ -.elixir_ls/ .cache/ -build/ -dist/ - -# Pages output -/_site/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6a5e794..dfee4f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,236 +1,67 @@ -# GitLab CI/CD Configuration for Phantom Metal Taste -# RSR-compliant continuous integration - +# SPDX-License-Identifier: MPL-2.0 +# GitLab mirrors use the same implemented-language gates as local Just recipes. stages: - validate - - build - test - - security - deploy + +workflow: + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + - if: '$CI_PIPELINE_SOURCE == "web"' + variables: - DENO_VERSION: "1.38.0" - RUST_VERSION: "1.74.0" - JULIA_VERSION: "1.9.4" - DOCKER_DRIVER: overlay2 -# Default image -image: debian:bookworm-slim -# Cache dependencies + CARGO_HOME: "$CI_PROJECT_DIR/.cargo" + JULIA_DEPOT_PATH: "$CI_PROJECT_DIR/.julia" + cache: - key: ${CI_COMMIT_REF_SLUG} + key: "$CI_COMMIT_REF_SLUG" paths: - - .deno/ - - .cargo/ - - node_modules/ + - .cargo/registry/ + - .cargo/git/ - target/ -# ============================================================================ -# Validation Stage -# ============================================================================ -rsr-compliance: - stage: validate - script: - - "echo \"\U0001F4CB Verifying RSR compliance...\"" - - | - # Check required documentation - for file in README.md LICENSE SECURITY.md CODE_OF_CONDUCT.md CONTRIBUTING.md MAINTAINERS.md CHANGELOG.md; do - test -f "$file" || (echo "❌ Missing $file" && exit 1) - echo "✓ $file" - done - - | - # Check .well-known/ - for file in security.txt ai.txt humans.txt; do - test -f ".well-known/$file" || (echo "❌ Missing .well-known/$file" && exit 1) - echo "✓ .well-known/$file" - done - - | - # Check build system - test -f justfile || (echo "❌ Missing justfile" && exit 1) - test -f flake.nix || (echo "❌ Missing flake.nix" && exit 1) - echo "✓ Build system files present" - - echo "✅ RSR compliance verified" - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -code-format: - stage: validate - image: denoland/deno:${DENO_VERSION} - script: - - echo "✨ Checking code formatting..." - - deno fmt --check - allow_failure: true - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" -code-lint: + - .julia/ + +bun-quality: stage: validate - image: denoland/deno:${DENO_VERSION} - script: - - "echo \"\U0001F50D Linting code...\"" - - deno lint - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" -# ============================================================================ -# Build Stage -# ============================================================================ -build-rescript: - stage: build - image: node:20-slim - script: - - "echo \"\U0001F528 Building ReScript → JavaScript...\"" - - npm install --save-dev rescript - - npx rescript build - artifacts: - paths: - - src/**/*.bs.js - - lib/ - expire_in: 1 hour - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -build-wasm: - stage: build - image: rust:${RUST_VERSION} + image: oven/bun:1.4.3 script: - - "echo \"\U0001F980 Building Rust → WASM...\"" - - rustup target add wasm32-unknown-unknown - - cd src/core - - cargo build --target wasm32-unknown-unknown --release - - ls -lh target/wasm32-unknown-unknown/release/*.wasm - artifacts: - paths: - - src/core/target/wasm32-unknown-unknown/release/*.wasm - expire_in: 1 hour - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -# ============================================================================ -# Test Stage -# ============================================================================ -test-deno: - stage: test - image: denoland/deno:${DENO_VERSION} - needs: - - build-rescript - script: - - "echo \"\U0001F9EA Running Deno tests...\"" - - deno test --allow-net --allow-env --allow-read tests/ - coverage: '/Lines\s*:\s*(\d+\.\d+)%/' + - bun test + - bun run build + - sh scripts/check-site-reproducible.sh rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -test-rust: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + +rust-quality: stage: test - image: rust:${RUST_VERSION} - needs: - - build-wasm + image: rust:1.90.0 script: - - "echo \"\U0001F9EA Running Rust tests...\"" - - cd src/core - - cargo test --verbose - - cargo clippy -- -D warnings + - cargo fmt --all -- --check + - cargo clippy --locked --all-targets -- -D warnings + - cargo test --locked --all-targets rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -test-julia: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + +julia-tests: stage: test - image: julia:${JULIA_VERSION} + image: julia:1.10 script: - - "echo \"\U0001F9EA Running Julia tests...\"" - - cd src/analytics - - julia --project=. -e 'using Pkg; Pkg.instantiate()' - - julia --project=. -e 'using Pkg; Pkg.test()' - allow_failure: true # Julia setup can be complex + - julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.test()' rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -# ============================================================================ -# Security Stage -# ============================================================================ -security-scan-dependencies: - stage: security - image: aquasec/trivy:latest - script: - - "echo \"\U0001F512 Scanning dependencies for vulnerabilities...\"" - - trivy fs --security-checks vuln . - allow_failure: true - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -security-scan-rust: - stage: security - image: rust:${RUST_VERSION} - script: - - "echo \"\U0001F512 Auditing Rust dependencies...\"" - - cargo install cargo-audit - - cd src/core - - cargo audit - allow_failure: true - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -security-check-secrets: - stage: security - image: trufflesecurity/trufflehog:latest - script: - - "echo \"\U0001F50D Scanning for secrets...\"" - - trufflehog filesystem . --no-update --fail - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" -# ============================================================================ -# Deploy Stage -# ============================================================================ -build-docker: - stage: deploy - image: docker:latest - services: - - docker:dind - needs: - - build-rescript - - build-wasm - script: - - echo "Building container image..." - - podman build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - - podman build -t $CI_REGISTRY_IMAGE:latest . - - | - if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then - podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - podman push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - podman push $CI_REGISTRY_IMAGE:latest - fi - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - only: - - main - - master + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + pages: stage: deploy - image: node:20-slim + image: oven/bun:1.4.3 script: - - "echo \"\U0001F4DA Building documentation for GitLab Pages...\"" - - mkdir -p public - - cp -r docs/* public/ - - cp README.md public/index.md - # Optional: Convert markdown to HTML - # - npx markdown-it README.md > public/index.html + - base_path="$(printf '%s\n' "$CI_PAGES_URL" | sed -E 's#^https?://[^/]+##; s#/$##')" + - bun scripts/build-site.mjs --config site.json --out public --baseurl "$base_path" artifacts: paths: - public rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -# ============================================================================ -# Workflow Rules -# ============================================================================ -workflow: - rules: - # Run on merge requests - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - # Run on main branch - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - # Run on tags - - if: $CI_COMMIT_TAG - # Manual pipelines - - if: $CI_PIPELINE_SOURCE == "web" -# ============================================================================ -# Includes -# ============================================================================ -# Optional: Include additional configuration -# include: -# - template: Security/SAST.gitlab-ci.yml -# - template: Security/Dependency-Scanning.gitlab-ci.yml -# - template: Security/License-Scanning.gitlab-ci.yml + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' diff --git a/.machine_readable/6a2/0-AI-MANIFEST.a2ml b/.machine_readable/6a2/0-AI-MANIFEST.a2ml deleted file mode 100644 index cede8a9..0000000 --- a/.machine_readable/6a2/0-AI-MANIFEST.a2ml +++ /dev/null @@ -1,22 +0,0 @@ -# AI Manifest for 6a2 Directory - -## Purpose - -This manifest declares the AI-assistant context for the 6a2 machine-readable metadata directory. - -## Canonical Locations - -The 6 core A2ML files MUST exist in this directory: -1. AGENTIC.a2ml -2. ECOSYSTEM.a2ml -3. META.a2ml -4. NEUROSYM.a2ml -5. PLAYBOOK.a2ml -6. STATE.a2ml - -## Invariants - -- No duplicate files in root directory -- Single source of truth: this directory is authoritative -- No stale metadata - diff --git a/.machine_readable/6a2/AGENTIC.a2ml b/.machine_readable/6a2/AGENTIC.a2ml deleted file mode 100644 index cd1fb1d..0000000 --- a/.machine_readable/6a2/AGENTIC.a2ml +++ /dev/null @@ -1,34 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# AGENTIC.a2ml — AI agent constraints and capabilities -[metadata] -version = "0.1.0" -last-updated = "2026-04-11" - -[agent-permissions] -can-edit-source = true -can-edit-tests = true -can-edit-docs = true -can-edit-config = true -can-create-files = true - -[agent-constraints] -# What AI agents must NOT do: -# - Never use banned language patterns (believe_me, unsafeCoerce, etc.) -# - Never commit secrets or credentials -# - Never use banned languages (TypeScript, Python, Go, etc.) -# - Never place state files in repository root (must be in .machine_readable/) -# - Never use AGPL license (use MPL-2.0) - -[maintenance-integrity] -fail-closed = true -require-evidence-per-step = true -allow-silent-skip = false -require-rerun-after-fix = true -release-claim-requires-hard-pass = true - -[automation-hooks] -# on-enter: Read 0-AI-MANIFEST.a2ml, then STATE.a2ml -# on-exit: Update STATE.a2ml with session outcomes -# on-commit: Run just validate-rsr diff --git a/.machine_readable/6a2/ECOSYSTEM.a2ml b/.machine_readable/6a2/ECOSYSTEM.a2ml deleted file mode 100644 index 9b3408d..0000000 --- a/.machine_readable/6a2/ECOSYSTEM.a2ml +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# ECOSYSTEM.a2ml — Phantom Metal Taste ecosystem position -[metadata] -version = "1.0" -last-updated = "2026-04-11" - -[project] -name = "Phantom Metal Taste" -purpose = "" -role = "" - -[position-in-ecosystem] -category = "" - -[related-projects] -projects = [ - # No related projects recorded -] diff --git a/.machine_readable/6a2/META.a2ml b/.machine_readable/6a2/META.a2ml deleted file mode 100644 index 78ec387..0000000 --- a/.machine_readable/6a2/META.a2ml +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# META.a2ml — Phantom Metal Taste meta-level information -[metadata] -version = "0.1.0" -last-updated = "2026-04-11" - -[project-info] -license = "MPL-2.0" -author = "Jonathan D.A. Jewell (hyperpolymath)" - -[architecture-decisions] -decisions = [ - # No ADRs recorded -] - -[development-practices] -versioning = "SemVer" -documentation = "AsciiDoc" -build-tool = "just" - -[maintenance-axes] -scoping-first = true -axis-1 = "must > intend > like" -axis-2 = "corrective > adaptive > perfective" -axis-3 = "systems > compliance > effects" diff --git a/.machine_readable/6a2/NEUROSYM.a2ml b/.machine_readable/6a2/NEUROSYM.a2ml deleted file mode 100644 index e1d34c0..0000000 --- a/.machine_readable/6a2/NEUROSYM.a2ml +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# NEUROSYM.a2ml — Neurosymbolic integration metadata -[metadata] -version = "0.1.0" -last-updated = "2026-04-11" - -[hypatia-config] -scan-enabled = true -scan-depth = "standard" # quick | standard | deep -report-format = "logtalk" - -[symbolic-rules] -# Custom symbolic rules for this project -# - { name = "no-unsafe-ffi", pattern = "believe_me|unsafeCoerce", severity = "critical" } - -[neural-config] -# Neural pattern detection settings -# confidence-threshold = 0.85 -# model = "hypatia-v2" diff --git a/.machine_readable/6a2/PLAYBOOK.a2ml b/.machine_readable/6a2/PLAYBOOK.a2ml deleted file mode 100644 index 5003fd0..0000000 --- a/.machine_readable/6a2/PLAYBOOK.a2ml +++ /dev/null @@ -1,26 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# PLAYBOOK.a2ml — Operational playbook -[metadata] -version = "0.1.0" -last-updated = "2026-04-11" - -[deployment] -# method = "gitops" # gitops | manual | ci-triggered -# target = "container" # container | binary | library | wasm - -[incident-response] -# 1. Check .machine_readable/STATE.a2ml for current status -# 2. Review recent commits and CI results -# 3. Run `just validate` to check compliance -# 4. Run `just security` to audit for vulnerabilities - -[release-process] -# 1. Update version in STATE.a2ml, META.a2ml -# 2. Run `just release-preflight` (validate + quality + security + maint-hard-pass) -# 3. Tag and push - -[maintenance-operations] -# Baseline audit: just maint-audit -# Hard release gate: just maint-hard-pass diff --git a/.machine_readable/6a2/README.adoc b/.machine_readable/6a2/README.adoc deleted file mode 100644 index c851cfb..0000000 --- a/.machine_readable/6a2/README.adoc +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: CC-BY-SA-4.0 -// Copyright (c) Jonathan D.A. Jewell -# A2ML 6a2 Directory - -This directory contains the 6 core A2ML machine-readable metadata files for this repository. - -## Files - -- `AGENTIC.a2ml` - AI agent operational gating, safety controls -- `ECOSYSTEM.a2ml` - Project ecosystem position, relationships, explicit boundaries -- `META.a2ml` - Architecture decisions (ADRs), development practices, design rationale -- `NEUROSYM.a2ml` - Symbolic semantics, composition algebra -- `PLAYBOOK.a2ml` - Executable plans, operational runbooks -- `STATE.a2ml` - Project state, phase, milestones, session history - -## Standards Compliance - -These files follow the A2ML Format Family specification from: -https://github.com/hyperpolymath/standards/tree/main/a2ml - diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/6a2/STATE.a2ml deleted file mode 100644 index cfec6d1..0000000 --- a/.machine_readable/6a2/STATE.a2ml +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) -# -# STATE.a2ml — Phantom Metal Taste project state -[metadata] -project = "phantom-metal-taste" -version = "0.0.1" -last-updated = "2026-01-03" -status = "active" -session = "converted from scheme — 2026-04-11" - -[project-context] -name = "Phantom Metal Taste" -purpose = """""" -completion-percentage = 0 - -[position] -phase = "initial" # design | implementation | testing | maintenance | archived -maturity = "experimental" # experimental | alpha | beta | production | lts - -[route-to-mvp] -milestones = [ - # No milestones recorded -] - -[blockers-and-issues] -issues = [ - # No blockers recorded -] - -[critical-next-actions] -actions = [ - # No actions recorded -] - -[maintenance-status] -last-run-utc = "2026-01-03T00:00:00Z" -last-result = "unknown" # unknown | pass | warn | fail diff --git a/.machine_readable/contractiles/Adjustfile.a2ml b/.machine_readable/contractiles/Adjustfile.a2ml deleted file mode 100644 index 6f01e89..0000000 --- a/.machine_readable/contractiles/Adjustfile.a2ml +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Adjustfile — Drift-tolerance contract for rsr-template-repo -# Author: Jonathan D.A. Jewell -# -# Cumulative-drift catchment: tolerance bands + corrective actions. -# Authority: advisory (Yard) — continue-with-warnings; auto_fix where deterministic. -# Run with: adjust check -# Fix with: adjust fix (applies deterministic patches; advisory otherwise) - -@abstract: -Drift tolerances and corrective actions for rsr-template-repo. Unlike -MUST (hard gate), ADJUST tracks cumulative drift against tolerance bands -and proposes corrective actions. Advisory — it warns and trends, it does -not block. -@end - -## Template Drift - -### placeholder-drift -- description: Template placeholders should be replaced when copied -- tolerance: 0 placeholder markers in copied repos -- corrective: Search and replace all {{PLACEHOLDER}} markers -- severity: advisory -- notes: This check only applies to repos that copied from this template - -### template-version-drift -- description: Template version should match RSR spec version -- tolerance: Template version matches current RSR spec -- corrective: Update template to match latest RSR spec -- severity: advisory - -## Documentation Drift - -### readme-completeness -- description: README should document all template features -- tolerance: README covers all contractiles and directory structure -- corrective: Update README.adoc with missing sections -- severity: advisory - -### example-accuracy -- description: Examples in documentation should match actual template content -- tolerance: All code examples in docs are accurate -- corrective: Audit and fix examples in documentation -- severity: advisory - -## Structural Drift - -### contractile-sync -- description: All contractiles should have matching a2ml and ncl implementations -- tolerance: Every .a2ml has a corresponding .ncl -- corrective: Generate missing .ncl files from .a2ml -- severity: advisory - -### no-broken-symlinks -- description: No broken symbolic links in template structure -- tolerance: 0 broken symlinks -- corrective: Run symlink-check script -- severity: advisory - -## Accessibility Drift - -### adoc-not-md -- description: Template docs should prefer AsciiDoc -- tolerance: New prose docs are *.adoc -- corrective: Convert any new *.md to *.adoc -- severity: advisory - -### spdx-header-consistency -- description: All template files have correct SPDX headers -- tolerance: 0 files missing SPDX-License-Identifier -- corrective: Add SPDX headers to files that need them -- severity: advisory diff --git a/.machine_readable/contractiles/Intentfile.a2ml b/.machine_readable/contractiles/Intentfile.a2ml deleted file mode 100644 index ef74f45..0000000 --- a/.machine_readable/contractiles/Intentfile.a2ml +++ /dev/null @@ -1,99 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Intentfile (A2ML Canonical) — north-star contractile for rsr-template-repo -# Author: Jonathan D.A. Jewell -# -# Paired runner: intend.ncl -# Verb: intend -# -# Semantics: North-star contractile. Declares BOTH concrete committed -# next-actions AND horizon aspirations the project wishes to -# become. Two sections share one file because they answer -# the same question at different ranges: -# [[intents]] — "we WILL do this; track progress" -# status: declared → in_progress → done | -# deferred | retired -# [[wishes]] — "we WISH this were true; revisit later" -# status: declared → in_progress → achieved | -# abandoned -# grouped by horizon: near / mid / far. -# Non-gating — this is a report, not a gate. See the `must` -# contractile for hard gates. - -@abstract: -North-star contractile for rsr-template-repo. This repository is the -canonical template for Rhodium Standard Repository compliance. It provides -the scaffold that all hyperpolymath repos should copy and customize. -@end - -## Purpose - -The rsr-template-repo serves as the master template for all hyperpolymath -repositories. It contains the complete set of contractile files, machine-readable -specifications, and governance documentation that define the Rhodium Standard. - -Every new repository in the hyperpolymath estate should be initialized by -copying this template and substituting the placeholder values with -repo-specific content. - -## Anti-Purpose - -This repository is NOT: -- A general-purpose project scaffold for external use (hyperpolymath-only) -- A replacement for per-repo customization (all files must be bespoke) -- A static template that never changes (evolves with RSR spec) -- A runtime library or framework (build-time only) - -## If In Doubt - -If you are unsure whether a change is in scope, ask. Sensitive areas: -- .machine_readable/ contractile definitions -- RSR specification files -- Governance templates -- License policy documents - -## Committed Next-Actions - -### repo-initialization -- description: Provide just copy-and-substitute template for new repos -- probe: test -f scripts/init-repo.sh -- status: done -- notes: Run with source scripts/init-repo.sh - -### contractile-completeness -- description: Every RSR contractile has an a2ml and ncl implementation -- probe: ls .machine_readable/contractiles/*.a2ml | wc -l | grep -q "^6$" -- status: in_progress -- notes: Currently 6 contractile verbs: intend, must, trust, adjust, bust, dust - -### automation-scripts -- description: All repetitive tasks have just recipes -- probe: grep -c "^# " Justfile | grep -q "^[6-9][0-9]*$" -- status: in_progress - -## Wishes - -### Near Horizon - -#### cross-repo-validation -- description: Tooling to validate all repos against RSR spec -- horizon: near -- status: declared - -#### automated-substitution -- description: Script to automate repo-specific substitution in template -- horizon: near -- status: declared - -### Mid Horizon - -#### formal-verification -- description: Idris2 proofs for all critical contractile invariants -- horizon: mid -- status: declared - -### Far Horizon - -#### ecosystem-visualization -- description: Interactive graph of all hyperpolymath repos and dependencies -- horizon: far -- status: declared diff --git a/.machine_readable/contractiles/Mustfile.a2ml b/.machine_readable/contractiles/Mustfile.a2ml deleted file mode 100644 index 55f8ab4..0000000 --- a/.machine_readable/contractiles/Mustfile.a2ml +++ /dev/null @@ -1,102 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Mustfile — Physical state contract for rsr-template-repo -# Author: Jonathan D.A. Jewell -# -# What MUST be true about this repository. Hard requirements. -# Run with: must check -# Fix with: must fix (where a deterministic fix exists) - -@abstract: -Physical-state invariants for rsr-template-repo. This is the canonical -RSR template repository. These are hard requirements — CI and pre-commit -hooks fail if any check fails. -@end - -## File Presence - -### license-present -- description: LICENSE file must exist -- run: test -f LICENSE -- severity: critical - -### readme-present -- description: README.adoc must exist -- run: test -f README.adoc -- severity: critical - -### security-policy -- description: SECURITY.md must exist -- run: test -f SECURITY.md -- severity: critical - -### ai-manifest -- description: 0-AI-MANIFEST.a2ml must exist -- run: test -f 0-AI-MANIFEST.a2ml -- severity: critical - -### governance-docs -- description: GOVERNANCE.adoc, MAINTAINERS.adoc, CODEOWNERS must exist -- run: test -f GOVERNANCE.adoc && test -f MAINTAINERS.adoc && test -f .github/CODEOWNERS -- severity: critical - -### machine-readable-dir -- description: .machine_readable/ directory must exist -- run: test -d .machine_readable -- severity: critical - -## Directory Structure - -### contractiles-complete -- description: All required contractile directories exist -- run: test -d .machine_readable/contractiles && test -d .machine_readable/contractiles/bust && test -d .machine_readable/contractiles/dust -- severity: critical - -### contractiles-files-present -- description: All four primary contractile files exist -- run: test -f .machine_readable/contractiles/Intentfile.a2ml && test -f .machine_readable/contractiles/Mustfile.a2ml && test -f .machine_readable/contractiles/Trustfile.a2ml && test -f .machine_readable/contractiles/Adjustfile.a2ml -- severity: critical - -### bust-dust-files-present -- description: Bustfile and Dustfile exist in their directories -- run: test -f .machine_readable/contractiles/bust/Bustfile.a2ml && test -f .machine_readable/contractiles/dust/Dustfile.a2ml -- 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 -- severity: critical - -### anchors-directory -- description: anchors directory exists in 6a2 -- run: test -d .machine_readable/6a2/anchors -- severity: warning - -### self-validating-structure -- description: self-validating directory has k9-svc and examples -- run: test -d .machine_readable/self-validating && test -d .machine_readable/self-validating/k9-svc && test -d .machine_readable/self-validating/examples -- severity: warning - -## Template Integrity - -### no-placeholder-values -- description: No placeholder values remain in template files -- run: test -z "$(grep -r '{{' .machine_readable/contractiles/ 2>/dev/null)" -- severity: critical -- notes: All placeholders must be substituted when copying this template - -### template-readonly -- description: Template marker files are not modified -- run: grep -q 'RSR_TEMPLATE_DO_NOT_EDIT' .machine_readable/0.1-AI-MANIFEST.a2ml -- severity: warning - -## Git State - -### no-untracked-contractiles -- description: All contractile files are tracked in git -- run: test -z "$(git ls-files -o --exclude-standard .machine_readable/contractiles/ 2>/dev/null)" -- severity: critical - -### signed-commits -- description: All commits must be signed -- run: git verify-commit HEAD -- severity: critical diff --git a/.machine_readable/contractiles/Trustfile.a2ml b/.machine_readable/contractiles/Trustfile.a2ml deleted file mode 100644 index e2028b5..0000000 --- a/.machine_readable/contractiles/Trustfile.a2ml +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Trustfile — Trust boundaries and integrity invariants for rsr-template-repo -# Author: Jonathan D.A. Jewell -# -# Defines what LLM/SLM agents are trusted to do without asking, and -# integrity invariants that verify the repo has not been tampered with. - -@abstract: -Trust boundaries and integrity checks for rsr-template-repo. This file -combines the trust-level definitions from the original TRUST.contractile -with the integrity invariants from the old Trustfile.a2ml. It defines -what AI agents may do autonomously and what requires human approval, -plus checks that verify repository integrity. -@end - -## Trust Levels - -The rsr-template-repo operates at trust level: maximal - -Trust levels: -- maximal: Agent may read, build, test, lint, format, heal freely. - Only destructive/external actions require approval. -- standard: Agent may read and build. Test/lint need approval. -- restricted: Agent may read only. All modifications need approval. -- minimal: Agent may read specific files only. Everything else blocked. - -Current trust level: maximal - -## Integrity Invariants - -### Secrets - -#### no-secrets-committed -- description: No credential files in repo -- run: test ! -f .env && test ! -f credentials.json && test ! -f .env.local && test ! -f .env.production -- severity: critical - -#### no-private-keys -- description: No private key files committed -- run: "! find . -name '*.pem' -o -name '*.key' -o -name 'id_rsa' -o -name 'id_ed25519' 2>/dev/null | grep -v node_modules | head -1 | grep -q ." -- severity: critical - -#### no-tokens-in-source -- description: No hardcoded API tokens in source -- run: "! grep -rE '(api[_-]?key|secret|token|password)\s*[:=]\s*[\"'\\''][A-Za-z0-9]{16,}' --include='*.js' --include='*.ts' --include='*.res' --include='*.py' . 2>/dev/null | grep -v node_modules | head -1 | grep -q ." -- severity: critical - -## Provenance - -#### author-correct -- description: Git author matches expected identity -- run: "git log -1 --format='%ae' | grep -qE '(hyperpolymath|j\\.d\\.a\\.jewell)'" -- severity: warning - -#### license-content -- description: LICENSE contains expected identifier -- run: grep -q 'PMPL\|MPL\|MIT\|Apache\|LGPL' LICENSE -- severity: warning - -## Template-Specific Trust - -### template-files-readonly -- description: Template scaffold files should not be modified except by maintainer -- run: test -z "$(git status --short .machine_readable/ 2>/dev/null | grep -v '^??' || true)" -- severity: advisory -- notes: Changes to template files require careful review - -### trust-deny-areas -- description: Sensitive areas from INTENT.contractile require explicit approval -- run: echo "Check .machine_readable/ contractiles and governance docs" -- severity: advisory -- areas: - - .machine_readable/ - - GOVERNANCE.adoc - - MAINTAINERS.adoc - - .github/CODEOWNERS - -## Container Security - -#### container-images-pinned -- description: Containerfile uses pinned base images -- run: test ! -f Containerfile || grep -q 'cgr.dev\|@sha256:' Containerfile -- severity: warning - -#### no-dockerfile -- description: No Dockerfile (use Containerfile) -- run: test ! -f Dockerfile -- severity: warning diff --git a/.machine_readable/descriptiles/README.adoc b/.machine_readable/descriptiles/README.adoc new file mode 100644 index 0000000..83c19d9 --- /dev/null +++ b/.machine_readable/descriptiles/README.adoc @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Descriptiles +:toc: + +The *descriptiles* record what this repository is and what state it is in. +Repository-wide descriptive facts live in the repo deed at +`../../phantom-metal-taste_chora.deed`. Provisioning-specific facts for the +canonical setup engine live in `provisioning_praxis.deed`. + +[IMPORTANT] +==== +The current RSR template retires the format formerly called A2ML: no `.a2ml` +file may exist in this repository. The repo deed uses the DEED s-expression +grammar; it is not TOML, YAML, or a key-value file. Resolve syntax questions +against the normative +https://github.com/hyperpolymath/standards/blob/main/1-formats/deed/spec/DEED-GRAMMAR-SPEC.adoc[DEED grammar] +in `hyperpolymath/standards` and the current +https://github.com/hyperpolymath/rsr-template-repo[RSR template]. +==== + +== Current records + +`phantom-metal-taste_chora.deed` (repository root):: +The single repo deed. It carries identity, status, maturity, ecosystem, +metadata, agent guidance, symbolic-system boundaries, and the project +playbook. It replaces the retired descriptive A2ML records and root AI +manifest. + +`provisioning_praxis.deed`:: +Repository-specific facts consumed by `build/just/provision-lib.sh` and the +launcher mode family in `build/just/provision-modes.sh`. + +== Contractiles + +The old `.a2ml` contractile declarations were retired and removed; they were +not executable checks. The unreferenced root `Mustfile` for the never-built +legacy CLI was removed as well. This repository has not yet adopted the +current contractile trident (`.k9.ncl` declarations paired with Nickel runners). +Assess and implement applicable project-specific contractiles as a separate +remediation item rather than treating the removed files as active controls. + +== Generation and editing + +The root deed follows the current DEED grammar. Do not recreate A2ML files or +the former root-level `.scm` state layout. Keep project facts in the repo deed +and provisioning-engine inputs in `provisioning_praxis.deed`; update the +human-readable remediation plan when verified status changes. diff --git a/.machine_readable/descriptiles/provisioning_praxis.deed b/.machine_readable/descriptiles/provisioning_praxis.deed new file mode 100644 index 0000000..af1ab4f --- /dev/null +++ b/.machine_readable/descriptiles/provisioning_praxis.deed @@ -0,0 +1,27 @@ +;; SPDX-License-Identifier: MPL-2.0 +;; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +;; +;; Repository-specific facts for the canonical provisioning engine. +;; :name and :version keep launcher identity stable when downloaded without Git metadata. +;; Canon: hyperpolymath/standards 3-practice/provisioning/PROVISIONING-STANDARD.adoc +(praxis-deed + :schema-version "1.0.0" + :canonical-name "phantom-metal-taste-provisioning" + :repo "hyperpolymath/phantom-metal-taste" + :name "phantom-metal-taste" + :version "0.1.0" + :archetype "library" + :languages "rust julia bun" + :build "" + :test "" + :bench "" + :lint "" + :fmt "" + :fmt-check "" + :run "echo N/A: no application entry point is implemented; exit 0" + :deps "" + :config "Cargo.toml, Project.toml, package.json, site.json, mise.toml" + :ports "" + :system-deps "git" + :ai-say-it "" + :opsm-note "") diff --git a/.well-known/ai.txt b/.well-known/ai.txt new file mode 100644 index 0000000..b5c7031 --- /dev/null +++ b/.well-known/ai.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MPL-2.0 +# AI usage and training policy for Phantom Metal Taste. +# Informal crawler directives; follow the repository licence and agent guidance. + +User-Agent: * + +# Do not use repository content to train models without attribution under the +# repository licence. Reference and indexing for search or contributor assistance +# are permitted when licence terms are retained. +Disallow-Training: / +Allow: / + +Contact: https://github.com/hyperpolymath/phantom-metal-taste/security/advisories/new +Policy: https://github.com/hyperpolymath/phantom-metal-taste/blob/main/.claude/CLAUDE.md diff --git a/.well-known/humans.txt b/.well-known/humans.txt new file mode 100644 index 0000000..7f5cf9f --- /dev/null +++ b/.well-known/humans.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: MPL-2.0 +# humanstxt.org — the people and tools behind this repository. + +/* TEAM */ + Maintainer: Jonathan D.A. Jewell (hyperpolymath) + Contact: 6759885+hyperpolymath@users.noreply.github.com + From: United Kingdom + Site: https://github.com/hyperpolymath/phantom-metal-taste + +/* SITE */ + Last update: 2026-10-10 + Standards: Rhodium Standard Repository (RSR) + Components: Rust core, Julia analytics, Bun site builder, conceptual artefacts; + AffineScript orchestration remains an incomplete scaffold + Tools: just, mise, Guix, Rust, Julia, Bun + Licence: MPL-2.0 (source) / CC-BY-SA-4.0 (documentation) diff --git a/.well-known/security.txt b/.well-known/security.txt new file mode 100644 index 0000000..b526315 --- /dev/null +++ b/.well-known/security.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MPL-2.0 +# RFC 9116 security.txt for Phantom Metal Taste +# https://securitytxt.org/ + +Contact: https://github.com/hyperpolymath/phantom-metal-taste/security/advisories/new +Expires: 2027-10-10T23:59:59Z +Preferred-Languages: en +Canonical: https://hyperpolymath.github.io/phantom-metal-taste/.well-known/security.txt +Policy: https://github.com/hyperpolymath/phantom-metal-taste/blob/main/.github/SECURITY.md diff --git a/0-AI-MANIFEST.a2ml b/0-AI-MANIFEST.a2ml deleted file mode 100644 index 2566473..0000000 --- a/0-AI-MANIFEST.a2ml +++ /dev/null @@ -1,116 +0,0 @@ -# ⚠️ STOP - CRITICAL READING REQUIRED - -**THIS FILE MUST BE READ FIRST BY ALL AI AGENTS** - -## WHAT IS THIS? - -This is the AI manifest for **phantom-metal-taste**. It declares: -- Canonical file locations (where things MUST be, and nowhere else) -- Critical invariants (rules that must NEVER be violated) -- Repository structure and organization - -## CANONICAL LOCATIONS (UNIVERSAL RULE) - -### Machine-Readable Metadata: `.machine_readable/` ONLY - -These 6 SCM files MUST exist in `.machine_readable/` directory ONLY: -1. **STATE.scm** - Project state, progress, blockers -2. **META.scm** - Architecture decisions, governance -3. **ECOSYSTEM.scm** - Position in ecosystem, relationships -4. **AGENTIC.scm** - AI agent interaction patterns -5. **NEUROSYM.scm** - Neurosymbolic integration config -6. **PLAYBOOK.scm** - Operational runbook - -**CRITICAL:** If ANY of these files exist in the root directory, this is an ERROR. - -### Bot Directives: `.bot_directives/` ONLY - -Bot-specific instructions for: -- rhodibot - Git operations -- echidnabot - Code quality -- sustainabot - Dependency updates -- glambot - Documentation -- seambot - Integration -- finishbot - Task completion - -### Agent Instructions - -- `.claude/CLAUDE.md` - Claude-specific patterns (if exists) -- `0-AI-MANIFEST.a2ml` - THIS FILE (universal entry point) - -## CORE INVARIANTS - -1. **No SCM duplication** - Root must NOT contain STATE.scm, META.scm, etc. -2. **Single source of truth** - `.machine_readable/` is authoritative -3. **No stale metadata** - If root SCMs exist, they are OUT OF DATE -4. **License consistency** - All code MPL-2.0 unless platform requires MPL-2.0 -5. **Author attribution** - Always "Jonathan D.A. Jewell " - -## REPOSITORY STRUCTURE - - - -This repo contains: - -``` -phantom-metal-taste/ -├── 0-AI-MANIFEST.a2ml # THIS FILE (start here) -├── README.md # Project overview -├── [your source files] # Main code -├── .machine_readable/ # SCM files (6 files) -│ ├── STATE.scm -│ ├── META.scm -│ ├── ECOSYSTEM.scm -│ ├── AGENTIC.scm -│ ├── NEUROSYM.scm -│ └── PLAYBOOK.scm -└── .bot_directives/ # Bot instructions -``` - -## SESSION STARTUP CHECKLIST - -✅ Read THIS file (0-AI-MANIFEST.a2ml) first -✅ Understand canonical locations (.machine_readable/, .bot_directives/) -✅ Know the invariants (no SCM duplication, etc.) -✅ Check for MCP enforcement (if applicable) -✅ Read `.machine_readable/STATE.scm` for current status -✅ Read `.machine_readable/AGENTIC.scm` for interaction patterns - -## LIFECYCLE HOOKS - -### on-enter (Session Start) - -When starting a new session: - -1. Read and acknowledge this manifest -2. Log session start (optional but recommended) - - Format: `[YYYY-MM-DD HH:MM:SS] Session started: [agent-name]` - - Location: `.machine_readable/session-log.txt` -3. Read `.machine_readable/STATE.scm` -4. Check for blockers -5. State understanding of canonical locations - -### on-exit (Session End) - -When ending a session: - -1. Update `.machine_readable/STATE.scm` if changes made -2. Log session end (optional but recommended) - - Format: `[YYYY-MM-DD HH:MM:SS] Session ended: [summary]` - - Location: `.machine_readable/session-log.txt` -3. Document new blockers -4. Summarize outcomes - -## ATTESTATION PROOF - -After reading this file, demonstrate understanding by stating: - -**"I have read the AI manifest. SCM files are located in `.machine_readable/` ONLY, bot directives in `.bot_directives/`, and I will not create duplicate files in the root directory."** - -## META - -- **Format Version:** 1.0.0 -- **Created:** [DATE] -- **Maintained By:** [YOUR-NAME/ORG] -- **License:** MPL-2.0 -- **Protocol:** https://github.com/hyperpolymath/0-ai-gatekeeper-protocol diff --git a/ARCHITECTURE.adoc b/ARCHITECTURE.adoc index 1c0a7a6..2938a80 100644 --- a/ARCHITECTURE.adoc +++ b/ARCHITECTURE.adoc @@ -1,48 +1,51 @@ -== Architecture +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Architecture and current implementation +:toc: -=== Overview +== Purpose -This repository follows a modular, maintainable architecture designed -for clarity, scalability, and long-term sustainability. +Phantom Metal Taste explores the gap between organisational intentions and +observed outcomes. It is currently a set of experimental libraries and research +artefacts, not a deployed application. -=== Directory Structure +== Implemented components -.... -. -├── src/ # Source code -├── tests/ # Test suites -├── docs/ # Documentation -├── scripts/ # Utility scripts -├── config/ # Configuration files -├── LICENSE # License file -├── LICENSES/ # Full license texts -└── README.adoc # Project documentation -.... +[cols="1,2,3",options="header"] +|=== +|Component |Location |Verified scope -=== Design Principles +|Rust core +|`Cargo.toml`, `src/core/` +|A `wasm-bindgen` library with unit tests. WASM output is optional and requires the wasm32 target. -* *Separation of Concerns*: Each module has a single responsibility -* *Testability*: Code is written to be easily testable -* *Documentation*: All public APIs are documented -* *Configuration*: Environment-specific settings are externalized +|Julia analytics +|`Project.toml`, `src/PhantomAnalytics.jl`, `src/analytics/`, `test/` +|Prototype statistical and causal-analysis functions with a Julia package test suite. -=== Dependencies +|Static site tooling +|`package.json`, `scripts/build-site.mjs`, `site.json` +|Bun builds an allowlisted site artifact; CI checks reproducibility. -* External dependencies are minimized and clearly declared -* Version pinning is used for reproducibility +|AffineScript orchestration +|`src/orchestrator/*.affine` +|Scaffolds only; each file still requires semantic implementation and compiler verification. -=== Security Considerations +|Database design +|`compose.yml`, diagrams, case study +|Conceptual/optional only. Current source does not connect to ArangoDB or Virtuoso. +|=== -* Sensitive data is never committed to the repository -* Secrets are managed through environment variables or secure vaults -* Regular dependency audits are performed +== Not implemented -=== Maintainability +There is no HTTP API, runtime server, case-study loader, graph persistence, +SPARQL integration, or end-to-end application flow. Database services are not +required to build, test, or run the Julia example. The TLA+ files and diagrams +are design artefacts; no current CI job claims that they have been model-checked +or generated from a running application. -* Code follows consistent style guidelines -* Pull requests require review and CI checks -* Issues and discussions are tracked transparently +== Local verification -''''' - -_Last updated: 2026-07-18_ +Use `just build`, `just test`, `just lint`, `just fmt-check`, and `just +site-check`. The supported setup routes are in `docs/SETUP.adoc`; do not follow +historical Deno/ReScript instructions elsewhere in the repository. diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 225a8d1..44c328a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,163 +1,55 @@ -== Changelog - -All notable changes to this project will be documented in this file. - -The format is based on https://keepachangelog.com/en/1.0.0/[Keep a -Changelog], and this project adheres to -https://semver.org/spec/v2.0.0.html[Semantic Versioning]. - -=== https://github.com/Hyperpolymath/phantom-metal-taste/compare/v0.1.0...HEAD[Unreleased] - -==== Added - -* RSR (Rhodium Standard Repository) compliance initiative -* SECURITY.md with 10-dimensional security model -* CODE_OF_CONDUCT.md based on Contributor Covenant 2.1 -* MAINTAINERS.md with TPCF (Tri-Perimeter Contribution Framework) -* CHANGELOG.md (this file) -* .well-known/ directory for RFC 9116 compliance -* Justfile with 20+ build/test/verification recipes -* flake.nix for Nix reproducible builds -* GitLab CI/CD configuration - -=== https://github.com/Hyperpolymath/phantom-metal-taste/releases/tag/v0.1.0[0.1.0] - 2024-11-22 - -==== Added - -*Core Architecture* - Multi-model database architecture (ArangoDB graph -+ Virtuoso RDF/semantic) - ReScript functional programming layer (sound -type system) - Deno secure runtime (explicit permissions model) - -Rust/WASM performance modules (zero unsafe blocks) - Julia statistical -analysis (gaming detection, causal inference) - -*Database Layer* - ArangoDB connection with automatic initialization - -Graph schema: initiatives, outcomes, employees, departments, metrics - -Edge collections: causes, participates_in, measures, belongs_to, -influences - Named graph: causal_graph for traversal - Virtuoso RDF -store with OWL ontology - Base ontology classes: Initiative, Outcome, -Employee, Metric, Department - Semantic properties: causes, intends, -measures, participatesIn - -*Type System* - Algebraic data types in ReScript (initiativeStatus, -outcomeType, metricType) - Type-safe configuration management - Sound -option types (no null/undefined) - Pattern matching required for all -variants - -*Analytics Engine* - Intention-reality gap calculation - Causal path -tracing with geometric mean strength - Gaming detection algorithms -(variance, spikes, clustering) - Metric theater detection (unused -measurements) - Department synergy scoring with irony detection - -Organizational delusion index - -*Case Study* - SynapCor fictional company implementation - 3 major -initiatives (Wellness Wednesday, Transparency Dashboard, Synergy -Champions) - 6 sample employees with realistic metrics - 4 departments -with synergy scores - 9 outcomes (3 intended, 6 unintended/emergent) - -Complete data loader - -*API Endpoints* - `+GET /health+` - System health check - -`+POST /api/initiatives+` - Create initiative - -`+POST /api/initiatives/:id/outcomes+` - Link causal outcome - -`+GET /api/initiatives/:id/analysis+` - Full analysis - -`+GET /api/initiatives/:id/unintended+` - Unintended consequences - -`+GET /api/analytics/gap/:id+` - Intention-reality gap - -`+GET /api/analytics/path/:from/:to+` - Causal paths - -`+GET /api/analytics/gameable-metrics+` - Suspicious metrics - -`+GET /api/analytics/metric-theater+` - Unused metrics - -`+GET /api/analytics/department/:id/synergy+` - Department synergy - -`+GET /api/reflection+` - Philosophical endpoint - -*Documentation* - README.md with ReScript/Deno quickstart - -RESCRIPT_MIGRATION.md explaining architectural choices - -PROJECT_SUMMARY.md with complete technical overview - QUICKSTART.md -(5-minute getting started) - docs/SETUP.md (comprehensive setup guide) - -docs/architecture/ARCHITECTURE.md (deep technical dive) - CLAUDE.md (AI -development guidelines) - CONTRIBUTING.md (contribution guidelines) - -case-studies/synapcor/README.md (complete case study narrative) - -*UML Diagrams* - Use case diagram (PlantUML) - Sequence diagram (gap -analysis flow) - Class diagram (domain model) - Deployment diagram -(infrastructure) - -*Infrastructure* - Docker Compose configuration (ArangoDB + Virtuoso) - -Health checks for database services - Environment configuration -(.env.example) - Git workflow files - -*Build System* - Deno tasks (build, dev, test, db:up, db:down, db:reset) -- ReScript compiler configuration (bsconfig.json) - Import maps for Deno -dependencies - -*Testing* - Deno test runner integration - Unit test structure - -Integration test setup - Rust/WASM unit tests - -*Scripts* - Demo script (scripts/demo.sh) - Database management tasks - -==== Changed - -*BREAKING*: Migrated from TypeScript/Bun/npm to ReScript/Deno - -TypeScript → ReScript (sound type system) - Bun → Deno (security model) -- npm → URL imports (no node_modules) - package.json → deno.json - -tsconfig.json → bsconfig.json - -Rationale: - ReScript: Impossible states unrepresentable, 100% type -coverage - Deno: Explicit permissions, modern standards, built-in -tooling - Philosophical alignment: Rigorous tools to measure -organizational rigor - -==== Removed - -* package.json (npm configuration) -* tsconfig.json (TypeScript configuration) -* node_modules/ (dependency directory) -* All .ts files (TypeScript source) -* Bun-specific code - -==== Security - -* Explicit permission model (Deno –allow-net, –allow-read, –allow-env) -* Zero unsafe blocks in Rust/WASM -* Parameterized database queries (injection prevention) -* Input validation at API boundaries -* Minimal dependencies (zero for Rust core) -* Offline-first architecture (air-gap capable) - -==== Philosophy - -This release establishes the core philosophy: - Measure organizational -delusion with technical rigor - Acknowledge measurement limitations - -Use irony intentionally, not carelessly - Type safety prevents the gaps -we’re measuring - -''''' - -=== Release Notes - -==== v0.1.0 - "`Intention`" - -The inaugural release. Name reflects the project’s focus on the gap -between organizational intentions and actual outcomes. - -*Highlights:* - Complete multi-model database architecture - Functional -programming with sound types (ReScript) - Statistical gaming detection -(Julia) - Philosophical self-awareness - Production-ready case study - -*Known Limitations:* - Service layer partially implemented - API routes -use basic structure - No authentication/authorization yet - -Development-only database passwords - -*Next Priorities:* - Complete service layer in ReScript - Implement full -HTTP server with Deno - Add authentication layer - Expand test coverage -- Production deployment guides - -''''' - -=== Version History - -=== Contributing - -See CONTRIBUTING.md for how to suggest changes to this changelog. - -''''' - -_"`Every version is an intention. Every release is an outcome. We -measure the gap.`"_ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Changelog +:toc: + +[IMPORTANT] +==== +The former changelog asserted that a v0.1.0 release shipped an API, +databases, production-ready analytics, and a ReScript/Deno application. The +repository contains no matching release tag or GitHub release, and those +capabilities are not in the current source tree. Those unsupported claims have +been withdrawn rather than carried forward as project history. The current +source map is in `docs/architecture/ARCHITECTURE.adoc`. +==== + +== Unreleased remediation + +=== Added + +* Root Cargo workspace, Julia package, Bun site-builder tests, and deterministic + allowlisted site publication. +* Rust, Julia, Bun, and Pages workflows with direct action commit pins and a + pinned shared Rust reusable workflow. +* RSR provisioning engine integration, Just recipes, a generated launcher, + mise declarations, and Guix development/source-package definitions. +* Setup, AI onboarding, implementation-status, and test-gap documentation. + +=== Changed + +* Rewrote the project and setup guides to describe only the implemented + prototype and to distinguish conceptual diagrams/case study from code. +* Updated the GitLab mirror pipeline to exercise the current Rust/Julia/Bun + code paths and publish the allowlisted site. +* Replaced unsupported certification/compliance claims with measured status. + +=== Removed + +* Retired the Deno/ReScript CI workflow and `deno.lock`; the remaining + AffineScript files are explicitly documented as incomplete scaffolds. +* Removed the competing Pages workflow that uploaded the full repository. +* Retired the generic SLSA release workflow that generated and attested placeholder artifacts. + +=== Verification still outstanding + +* Generate and verify `mise.lock` with the official mise CLI. +* Generate and verify `.github/workflows/actions.lock` with `gh actions-lock`. +* Execute Rust and Julia tests and local provisioning validation; run + actionlint/schema-aware workflow checks and remote CI in an environment with + the required tools. YAML syntax and inline action-pin checks already pass. +* Confirm issue #77 acceptance on a fresh default-branch run before closing it. + +== Releases + +No versioned release history is asserted until it can be verified against +published tags and artifacts. diff --git a/CLAUDE.md b/CLAUDE.md index 3b8ac30..fcfdc2a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,382 +1,67 @@ - -# Working with Claude on Phantom Metal Taste - -This document provides context and guidelines for AI-assisted development on the Phantom Metal Taste project. - -## Project Context - -**Phantom Metal Taste** is a multi-model database architecture that explores the gap between corporate intentions and actual outcomes. The project has a distinct philosophical undertone—it's both a technical implementation and a critique of organizational measurement systems. - -### Core Philosophy - -When working on this project, understand that: - -1. **The irony is intentional**: This project measures things that arguably shouldn't be measured in the way corporations measure them -2. **Technical rigor matters**: Despite the critical stance, the implementation should be exemplary -3. **Documentation is commentary**: The documentation style balances technical precision with philosophical observation - -## Technical Stack - -``` -┌─────────────────────────────────────────┐ -│ ReScript/Deno (Orchestration) │ -├─────────────────────────────────────────┤ -│ Rust/WASM │ Julia (Statistical) │ -├─────────────┼───────────────────────────┤ -│ ArangoDB │ Virtuoso (Semantic Web) │ -└─────────────┴───────────────────────────┘ -``` - -### Key Technologies - -- **ArangoDB**: Graph database for modeling causal relationships -- **Virtuoso**: RDF/SPARQL triple store for semantic reasoning -- **ReScript**: Sound type system with 100% coverage, compiles to JavaScript -- **Deno**: Secure runtime with explicit permissions and modern tooling -- **Rust/WebAssembly**: High-performance core algorithms -- **Julia**: Statistical analysis and data science workloads - -### Why ReScript + Deno? - -This project migrated from TypeScript/Bun to ReScript/Deno to achieve higher levels of correctness and security: - -**ReScript provides:** -- **Sound type system**: Impossible states become unrepresentable -- **100% type coverage**: No escape hatches, no `any`, no `unknown` -- **Algebraic data types**: Model domain concepts precisely with variants -- **Pattern matching**: Exhaustive case analysis enforced by compiler -- **No null/undefined**: Use `option<'a>` for optional values -- **Fast compilation**: ~1ms per file, instant feedback -- **Zero-cost abstractions**: Compiles to readable, performant JavaScript - -**Deno provides:** -- **Security by default**: Explicit permissions (--allow-net, --allow-read, etc.) -- **Modern standards**: Native ES modules, Web APIs, TypeScript support -- **No node_modules**: URL-based imports, no package.json hell -- **Built-in tooling**: Test runner, formatter, linter included -- **Offline-first**: Works air-gapped after initial dependency fetch - -Together, ReScript + Deno form a **type-safe, memory-safe, permission-aware** foundation that aligns with the project's Platinum-level RSR compliance goals. - -See [RESCRIPT_MIGRATION.md](RESCRIPT_MIGRATION.md) for detailed migration rationale. - -## Code Organization - -``` -phantom-metal-taste/ -├── src/ -│ ├── orchestrator/ # ReScript coordination layer (.res files) -│ │ ├── Config.res # Environment configuration -│ │ ├── Types.res # Domain model (algebraic data types) -│ │ ├── Index.res # Entry point -│ │ └── db/ # Database bindings (ArangoDB, Virtuoso) -│ ├── core/ # Rust/WASM modules -│ ├── analytics/ # Julia statistical modules -│ └── ontologies/ # Semantic web ontologies -├── case-studies/ -│ └── synapcor/ # Reference implementation -├── docs/ -│ ├── architecture/ # TOGAF documentation -│ ├── diagrams/ # UML, DFD, ERD -│ └── ontologies/ # ODM specifications -├── specs/ # TLA+ formal verification -├── benchmarks/ # Performance benchmarks -└── tests/ -``` - -## Development Guidelines - -### 1. Multi-Model Consistency - -When modifying data structures, ensure consistency across: -- ArangoDB graph schemas -- Virtuoso RDF ontologies -- ReScript algebraic data types (variants, records) -- Rust structs -- Julia type definitions - -### 2. Semantic Precision - -This project uses formal ontologies. When adding new concepts: -- Define them in the appropriate OWL/RDF ontology first -- Ensure proper subsumption relationships -- Document inference rules clearly -- Use standard vocabularies (FOAF, Dublin Core, etc.) where applicable - -### 3. Code Style - -**ReScript:** -- Use algebraic data types (variants) for domain modeling -- Prefer pattern matching over conditionals -- Make impossible states unrepresentable in the type system -- Use `option<'a>` instead of null/undefined -- Use `result<'a, 'e>` for operations that can fail -- Keep functions pure where possible -- Example: - ```rescript - type initiativeStatus = Planned | Active | Completed | Abandoned - - let statusToString = (status: initiativeStatus): string => - switch status { - | Planned => "planned" - | Active => "active" - | Completed => "completed" - | Abandoned => "abandoned" - } - ``` - -**Rust:** -- Target `wasm32-unknown-unknown` -- Keep allocations minimal (runs in browser) -- Document all public APIs with examples -- Zero `unsafe` blocks in production code -- Use `#[wasm_bindgen]` for JavaScript interop - -**Julia:** -- Use type annotations for performance-critical paths -- Leverage multiple dispatch appropriately -- Include benchmark comparisons in comments - -### 4. Testing Philosophy - -Tests should: -- Validate the model, not just the implementation -- Include edge cases that reveal modeling assumptions -- Use the SynapCor case study as integration test data - -### 5. Documentation Tone - -Maintain the project's distinctive voice: -- Be technically precise -- Acknowledge the inherent contradictions -- Use philosophical quotes sparingly but meaningfully -- Let the irony emerge from juxtaposition, not explanation - -## Common Tasks - -### Adding a New Organizational Metric - -1. Define the ontological concept in `src/ontologies/` -2. Create the graph schema in ArangoDB -3. Implement measurement logic in appropriate language -4. Add to the SynapCor case study -5. Update documentation with commentary on what's being measured - -### Modifying the Graph Schema - -1. Update ArangoDB collection definitions -2. Modify Virtuoso RDF mappings -3. Update ReScript type definitions (`Types.res`) -4. Update Rust structs (if WASM modules access these types) -5. Run migration scripts (never drop data) -6. Ensure all variants remain exhaustively pattern-matched - -### Performance Optimization - -Priority order: -1. Rust/WASM for computational bottlenecks -2. Julia for statistical heavy lifting -3. Database query optimization -4. ReScript optimization (rarely needed - compiler is already efficient) - -## Integration Points - -### Database Connections - -- **ArangoDB**: Uses Foxx microservices for custom logic -- **Virtuoso**: SPARQL endpoint accessible via HTTP -- Both require Podman containers running locally - -### WASM Modules - -Rust code compiles to WASM and loads via ReScript FFI: -```rescript -// Bindings.res -@module("./core/wasm/analyzer.wasm") -external analyze: (string) => promise> = "analyze" -``` - -Build WASM modules with: -```bash -just wasm-build -# Or manually: -cd src/core && cargo build --target wasm32-unknown-unknown --release -``` - -### Julia Integration - -Julia modules called via Deno subprocess: -```rescript -// Bindings.res -@val @scope("Deno") -external runJulia: (string, array) => promise = "run" - -// Usage -let result = await runJulia("julia", ["--project=src/analytics", "src/analytics/impact.jl", arg1, arg2]) -``` - -### Build System Workflow - -The project uses `just` (modern command runner) for all development tasks: - -```bash -# Development workflow -just build # Compile ReScript → JavaScript -just watch # Watch mode (recompiles on file changes) -just dev # Run with Deno in watch mode -just test # Run all tests -just validate # Full validation (checks + tests) - -# Database management -just db-up # Start ArangoDB + Virtuoso -just db-down # Stop databases -just db-health # Check database status - -# Code quality -just fmt # Format code (Deno) -just lint # Lint code -just typecheck # Type check (ReScript + Rust) -just check # All quality checks - -# WASM and Julia -just wasm-build # Build Rust → WASM -just wasm-test # Test Rust code -just julia-test # Test Julia modules - -# RSR compliance -just rsr-verify # Verify RSR compliance -``` - -**ReScript Compilation:** -- Files end in `.res` (ReScript source) -- Compiler outputs `.bs.js` (JavaScript) in same directory -- Import compiled modules in Deno: `import { foo } from "./Foo.bs.js"` -- Configuration: `bsconfig.json` - -**Deno Execution:** -- Requires explicit permissions: `--allow-net`, `--allow-read`, `--allow-env` -- Import maps in `deno.json` simplify imports -- No `package.json` or `node_modules` - -## Important Context - -### The SynapCor Case Study - -SynapCor is a fictional company with a data-driven "wellness" program called the Synergy Matrix. It serves as: -- Reference implementation -- Integration test fixture -- Documentation through narrative -- Cautionary tale - -When adding features, consider: "How would SynapCor misuse this?" - -### Architectural Decisions - -Key choices documented in `docs/architecture/`: -- Why multi-model? (Different paradigms reveal different truths) -- Why semantic web? (Formal logic for informal systems) -- Why graph databases? (Causality is relational) - -Review these before proposing architectural changes. - -## Testing & Validation - -### Running Tests - -```bash -# Full test suite -just test - -# Build ReScript code + + +# Agent instructions for Phantom Metal Taste + +Read `phantom-metal-taste_chora.deed` and the relevant current standards before +making changes. The repository's binding policy is in +`hyperpolymath/standards` and `hyperpolymath/rsr-template-repo`; current source +facts are authoritative over old design prose. Descriptive metadata uses the +current DEED format; `.a2ml` is retired. + +## What exists today + +- Rust workspace at the root; the crate source is in `src/core/`. +- Julia package at the root (`Project.toml`, `src/PhantomAnalytics.jl`) with + prototype analyses in `src/analytics/` and tests in `test/`. +- Bun site builder in `scripts/build-site.mjs`, configured by `site.json`. +- Five `.affine` orchestration files are TODO scaffolds. Do not claim the + AffineScript semantic port is complete. +- No HTTP API, server, loader, or database integration is implemented. + `compose.yml` is optional local infrastructure only. + +## Tooling and commands + +The declared project toolchain is mise (`mise.toml`), with Just, ShellCheck, +Rust, Julia, and Bun. `mise.lock` is not yet generated; do not claim the +resolution is reproducible until an official `mise lock` result is checked in. +Guix setup is described in `manifest.scm`, `guix.scm`, and `channels.scm`. + +```sh +./launcher.sh --setup just build - -# Rust unit tests -just wasm-test -# Or manually: cd src/core && cargo test - -# Julia tests -just julia-test -# Or manually: julia --project=src/analytics -e 'using Pkg; Pkg.test()' - -# Integration tests (requires databases) -just db-up just test - -# Full validation (all checks + tests) -just validate +just lint +just fmt-check +just site-check +just doctor ``` -### Validation Checklist - -Before committing: -- [ ] All tests pass (`just test`) -- [ ] ReScript compiles without warnings (`just build`) -- [ ] Rust type checks pass (`just wasm-check`) -- [ ] WASM modules rebuilt if Rust changed (`just wasm-build`) -- [ ] Ontologies validate against OWL DL -- [ ] Documentation reflects changes -- [ ] SynapCor case study still works -- [ ] RSR compliance maintained (`just rsr-verify`) - -## Deployment - -This is an experimental project. Deployment is: -- Podman Compose for local development -- Kubernetes manifests in `k8s/` (theoretical) -- No production environment (what would that even mean?) - -## Common Pitfalls - -1. **Forgetting the graph**: Changes to ReScript types often need graph schema updates -2. **Ontology drift**: RDF and code can diverge; validate regularly -3. **WASM memory**: Limited heap in browser context -4. **Julia startup time**: Cache compiled modules for development -5. **Semantic query performance**: SPARQL can be slow; use ArangoDB for hot paths -6. **ReScript compilation**: Remember to run `just build` after editing `.res` files -7. **Pattern matching exhaustiveness**: When adding new variants, update all pattern matches -8. **FFI boundaries**: Be careful with JavaScript interop - types are not guaranteed at runtime - -## Questions to Ask - -When uncertain about design decisions: - -- Does this capture what's actually happening or what's supposed to happen? -- How would this metric be gamed? -- What does this measurement obscure? -- Is the added complexity worth the analytical insight? - -## Resources - -### Language Documentation -- [ReScript Language Manual](https://rescript-lang.org/docs/manual/latest/) -- [ReScript Standard Library](https://rescript-lang.org/docs/manual/latest/api) -- [Deno Manual](https://deno.land/manual) -- [Rust Book](https://doc.rust-lang.org/book/) -- [Julia Documentation](https://docs.julialang.org/) - -### Database & Semantic Web -- [ArangoDB AQL Documentation](https://www.arangodb.com/docs/stable/aql/) -- [Virtuoso SPARQL Reference](http://docs.openlinksw.com/virtuoso/) -- [OWL 2 Primer](https://www.w3.org/TR/owl2-primer/) - -### Architecture & Standards -- [TOGAF Framework](https://www.opengroup.org/togaf) -- [TLA+ Specification Language](https://lamport.azurewebsites.net/tla/tla.html) -- [RSR Framework](https://github.com/example/rhodium-minimal) - -## Getting Help - -For technical questions: -- Check `docs/architecture/` for design rationale -- Review the SynapCor implementation -- Search issues for similar challenges - -For philosophical questions: -- That's part of the journey - ---- - -*"The best way to understand a system is to build a model of it. The best way to critique a system is to build a rigorous model of it."* +The root `Justfile` delegates provisioning verbs to the standard engine in +`build/just/`. Do not hand-edit vendored provisioning engine files for local +project behavior; use the deed or a root recipe. `just run` is intentionally +N/A because there is no application entry point. + +## Language and architecture policy + +Follow current standards. The active runtimes/toolchains are Rust, Julia, and +Bun; AffineScript is the intended application language for future orchestration +work, but compiler support and domain behavior must be verified first. Do not +introduce Deno, ReScript, TypeScript, Node.js, npm/yarn/pnpm, Python, Go, Java, +Make, or Nix as active project paths. + +Keep all public claims honest: design diagrams, the case study, and TLA+ +specifications are not evidence that an API, database integration, production +service, or formal verification run exists. Add tests with implementation, and +report unavailable Rust/Julia tests as unverified rather than passed. + +## Change hygiene + +- Make the smallest coherent change; preserve existing SPDX licence terms. +- Add SPDX headers to new source/config files where the format permits it. +- Never add secrets, hard-coded credentials, or fabricated lock entries. +- Do not modify `.github/workflows/actions.lock` or `mise.lock` by hand; generate + them with the official tools and review the diff. +- Keep documentation, Just recipes, GitHub CI, and GitLab CI consistent with the + implemented source and its limitations. +- Update `phantom-metal-taste_chora.deed` and the current remediation plan when + repository facts, blockers, or verified status materially change. diff --git a/CODE_OF_CONDUCT.adoc b/CODE_OF_CONDUCT.adoc index 8994011..1cba35f 100644 --- a/CODE_OF_CONDUCT.adoc +++ b/CODE_OF_CONDUCT.adoc @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell == Contributor Covenant Code of Conduct === Our Pledge diff --git a/src/core/Cargo.lock b/Cargo.lock similarity index 100% rename from src/core/Cargo.lock rename to Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1d52c7d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# Workspace for the Rust core. The application orchestrator is not yet implemented. +[workspace] +members = ["src/core"] +resolver = "2" + +[profile.release] +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" +strip = true diff --git a/EXPLAINME.adoc b/EXPLAINME.adoc index b27b41b..20e3097 100644 --- a/EXPLAINME.adoc +++ b/EXPLAINME.adoc @@ -1,98 +1,16 @@ -== Phantom Metal Taste - -image:https://img.shields.io/badge/license-PMPL--1.0-blue.svg[License] -image:https://img.shields.io/badge/status-experimental-orange.svg[Status] -image:https://img.shields.io/badge/irony-DISTINCT-red.svg[Irony] - -=== Overview - -*Phantom Metal Taste* is an advanced multi-model database architecture -designed to capture, analyze, and visualize the complex relationship -between corporate initiatives and their outcomes. - -The project leverages cutting-edge graph and semantic database -technologies to model organizational dynamics with unprecedented -fidelity, revealing patterns that traditional relational databases -cannot express. - -____ -_"`The taste of metal in your mouth when nothing is there—a phantom -sensation that feels undeniably real yet fundamentally wrong.`"_ -____ - -=== Technical Architecture - -This project employs a sophisticated stack: - -* *ArangoDB*: For graph-based modeling of causal relationships -* *Virtuoso*: For semantic web ontologies and formal knowledge -representation -* *ReScript/Deno*: For orchestration and API layer -* *Rust/WebAssembly*: For high-performance core logic -* *Julia*: For advanced statistical analysis - -=== The SynapCor Case Study - -Included with this project is a complete case study of "`SynapCor,`" a -fictional tech company implementing a data-driven employee wellness -program called the "`Synergy Matrix.`" The case study includes: - -* Full UML modeling suite (Use Case, Sequence, State Machine diagrams) -* TOGAF-compliant enterprise architecture documentation -* OMG Ontology Definition Metamodel implementation -* Data Flow Diagrams and Entity-Relationship models - -This case study serves as both documentation and a demonstration of the -system’s capabilities. - -=== Key Features - -* *Multi-model persistence*: Store the same conceptual data in different -database paradigms to unlock unique analytical capabilities -* *Causal graph traversal*: Follow the explicit links between actions -and consequences -* *Semantic reasoning*: Apply formal logic to organizational knowledge -* *Quantified impact analysis*: Measure and visualize the precise -effects of organizational decisions - -=== Getting Started - -[source,bash] ----- -# Clone the repository -git clone https://github.com/yourusername/phantom-metal-taste.git - -# Install dependencies -cd phantom-metal-taste -deno task build - -# Start the databases (requires Podman) -podman-compose up -d - -# Run the orchestrator -deno task dev ----- - -=== The Deeper Question - -This project asks a fundamental question: What happens when we apply the -full rigor of enterprise architecture, formal modeling, and data science -to measure the gap between institutional intent and lived reality? - -The answer may leave a curious taste in your mouth. - -=== Contributing - -Contributions are welcome. Before submitting a PR, please ensure your -code passes all tests and adheres to our modeling standards. See -`+CONTRIBUTING.md+` for details. - -=== License - -This project is licensed under the Palimpsest License (MPL-2.0) - see -the LICENSE file for details. - -''''' - -_"`The map is not the territory, but sometimes the map reveals what the -territory conceals.`"_ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Phantom Metal Taste: project status + +Phantom Metal Taste is an experimental project about measuring the distance +between organisational intentions and observed outcomes. The source currently +contains a small Rust library, Julia analytics prototypes, and a Bun-powered +static site builder. + +There is no HTTP API, server, data loader, or application/database integration. +The `.affine` orchestrator files are TODO scaffolds. Diagrams and the SynapCor +case study are conceptual material, not evidence of running capabilities. + +For a tested starting point, see link:QUICKSTART.adoc[QUICKSTART.adoc], +link:docs/SETUP.adoc[docs/SETUP.adoc], and +link:docs/architecture/ARCHITECTURE.adoc[the current implementation map]. diff --git a/GOVERNANCE.adoc b/GOVERNANCE.adoc index 9b836fb..f484784 100644 --- a/GOVERNANCE.adoc +++ b/GOVERNANCE.adoc @@ -1,60 +1,36 @@ -== Governance +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Governance +:toc: -=== Overview +== Status -This project is governed by the following principles and structures to -ensure transparent, inclusive, and effective decision-making. +This is a single-maintainer experimental repository. The default code owner is +link:https://github.com/hyperpolymath[@hyperpolymath] in `.github/CODEOWNERS`. +GitHub repository permissions and configured branch protections are authoritative +for access, review, and merging; this document does not invent a multi-person +council or unconfigured approval threshold. -=== Roles and Responsibilities +== Contributions and decisions -==== Maintainers +Contributors should open an issue or pull request for substantive changes, +include evidence and tests, and update relevant user-facing documentation. +The maintainer reviews changes and decides scope. Significant architecture or +policy changes should be discussed before implementation. Do not represent +conceptual case-study material as a live system capability. -Maintainers are responsible for: - Reviewing and merging pull requests - -Managing releases and versioning - Ensuring code quality and standards - -Triaging issues and bug reports - Community engagement and support +Follow `.github/CONTRIBUTING.md`, `CODE_OF_CONDUCT.adoc`, and the binding +`hyperpolymath/standards` and `hyperpolymath/rsr-template-repo` policies. -==== Contributors +== Security and conduct -Contributors are expected to: - Follow the code of conduct - Submit -well-documented pull requests - Write tests for new functionality - -Maintain existing tests - Update documentation as needed +Report vulnerabilities through GitHub Security Advisories; details are in +`SECURITY.adoc`. Conduct concerns should be reported privately through a +maintainer-controlled channel. Do not publish private data or credentials. -=== Decision Making +== Licensing -==== Minor Changes - -* Can be made by any maintainer -* Include bug fixes, documentation updates, dependency updates - -==== Major Changes - -* Require discussion in issues or pull requests -* Include new features, architectural changes, API changes -* Need approval from at least 2 maintainers - -==== Breaking Changes - -* Require RFC (Request for Comments) process -* Need approval from majority of maintainers -* Must include migration guide - -=== Code of Conduct - -All participants are expected to follow our Code of Conduct. Violations -can be reported to the maintainers. - -=== Communication - -* *Issues*: For bug reports and feature requests -* *Discussions*: For questions and general discussion -* *Pull Requests*: For code contributions - -=== Licensing - -All contributions are made under the terms of the repository’s LICENSE -file. By submitting a pull request, you agree to license your -contributions accordingly. - -''''' - -_Last updated: 2026-07-18_ +Source licensing is declared in `LICENSE` (MPL-2.0); documentation is marked +CC-BY-SA-4.0. File headers and applicable license texts govern individual +materials. Do not rely on legacy conflicting license prose in archived +materials. diff --git a/Justfile b/Justfile index 5086082..b9f507d 100644 --- a/Justfile +++ b/Justfile @@ -1,347 +1,84 @@ -import? "contractile.just" - -# justfile - Modern command runner -# https://github.com/casey/just +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) # -# Install: cargo install just -# Usage: just -# List: just --list +# Project tasks plus the estate provisioning contract in build/just/provision.just. +mod provision 'build/just/provision.just' + +set shell := ["bash", "-euo", "pipefail", "-c"] -# Default recipe (shows help) +# Show available project and provisioning tasks. default: @just --list -# ============================================================================ -# Development Workflows -# ============================================================================ +# Provision every supported tool and dependency, then diagnose the environment. +setup: provision::setup + +doctor: provision::doctor -# Build ReScript code -build: - @echo "🔨 Building ReScript → JavaScript..." - rescript build +# Apply safe automatic fixes and repeat doctor. +heal: provision::heal -# Build in watch mode -watch: - @echo "👀 Watching ReScript files..." - rescript build -w +dev-shell: provision::dev-shell -# Clean build artifacts -clean: - @echo "🧹 Cleaning build artifacts..." - rescript clean - rm -rf lib/ - rm -rf **/*.bs.js - rm -rf **/*.bs.mjs +toolchain-refresh: provision::toolchain-refresh -# Run the application -run: build - @echo "🚀 Running application..." - deno run --allow-net --allow-env --allow-read src/orchestrator/Index.bs.js +ai-setup: provision::ai-setup +ai-warmup who="user": (provision::ai-warmup who) +config-show: provision::config-show +langs: provision::langs -# Run in development mode with watch -dev: - @echo "🔥 Starting development server..." - deno run --allow-net --allow-env --allow-read --watch src/orchestrator/Index.bs.js +build: provision::build +test: provision::test +bench: provision::bench +lint: provision::lint check-no-a2ml +fmt: provision::fmt +fmt-check: provision::fmt-check +run: provision::run +deps: provision::deps +eval: provision::eval -# ============================================================================ -# Testing -# ============================================================================ +# Compile the allowlisted Pages site with Bun. +site-build: + bun run scripts/build-site.mjs --config site.json -# Run all tests -test: build - @echo "🧪 Running tests..." - deno test --allow-net --allow-env --allow-read tests/ +# Test site CLI handling, allowlisted files, generated links, and base URLs with Bun. +site-test: + bun test -# Run tests with coverage -test-coverage: build - @echo "📊 Running tests with coverage..." - deno test --allow-net --allow-env --allow-read --coverage=coverage/ tests/ - deno coverage coverage/ +# Build the allowlisted site twice and compare the complete outputs. +site-check: + sh scripts/check-site-reproducible.sh -# Run specific test file -test-file FILE: build - @echo "🧪 Running test: {{FILE}}" - deno test --allow-net --allow-env --allow-read {{FILE}} +# Enforce the current RSR retirement of A2ML metadata files. +check-no-a2ml: + bash scripts/check-no-a2ml.sh -# ============================================================================ -# Database Management -# ============================================================================ +# Run a deterministic analytics example; no API server or database is required. +demo: + ./scripts/demo.sh -# Start databases (ArangoDB + Virtuoso) +# Optional local database services; the source code does not connect to them yet. db-up: - @echo "🗄️ Starting databases..." - podman-compose up -d - @echo "⏳ Waiting for health checks..." - @sleep 10 - @podman-compose ps + podman compose up -d -# Stop databases db-down: - @echo "🛑 Stopping databases..." - podman-compose down + podman compose down -# Reset databases (delete all data) -db-reset: - @echo "♻️ Resetting databases (will delete all data)..." - podman-compose down -v - podman-compose up -d - @sleep 10 - @echo "✓ Databases reset" - -# Show database logs db-logs SERVICE="": - @if [ "{{SERVICE}}" = "" ]; then \ - podman-compose logs -f; \ - else \ - podman-compose logs -f {{SERVICE}}; \ - fi - -# Check database health -db-health: - @echo "🏥 Checking database health..." - @podman-compose ps - @echo "\n📊 ArangoDB:" - @curl -s http://localhost:8529/_api/version || echo "❌ Not responding" - @echo "\n🕸️ Virtuoso:" - @curl -s http://localhost:8890/sparql || echo "❌ Not responding" - -# ============================================================================ -# Code Quality -# ============================================================================ - -# Format code -fmt: - @echo "✨ Formatting code..." - deno fmt - @echo "✓ Deno files formatted" - # ReScript formatter (if available) - @command -v rescript-format >/dev/null && find src -name "*.res" -exec rescript-format -i {} \; || echo "⚠️ rescript-format not found" - -# Lint code -lint: - @echo "🔍 Linting code..." - deno lint - -# Type check -typecheck: build - @echo "🔎 Type checking..." - @echo "✓ ReScript type checking done by compiler" - @echo "Checking Rust..." - cd src/core && cargo check - -# Check all (fmt + lint + typecheck) -check: fmt lint typecheck - @echo "✅ All checks passed!" + if [ -n "{{SERVICE}}" ]; then podman compose logs -f "{{SERVICE}}"; else podman compose logs -f; fi -# ============================================================================ -# Rust/WASM -# ============================================================================ - -# Build Rust/WASM modules +# Build the optional WASM target (requires rustup and its wasm32 target). wasm-build: - @echo "🦀 Building Rust → WASM..." - cd src/core && cargo build --target wasm32-unknown-unknown --release - @echo "✓ WASM built: src/core/target/wasm32-unknown-unknown/release/*.wasm" - -# Test Rust code -wasm-test: - @echo "🧪 Testing Rust code..." - cd src/core && cargo test - -# Check Rust code -wasm-check: - @echo "🔍 Checking Rust code..." - cd src/core && cargo check - cd src/core && cargo clippy -- -D warnings + rustup target add wasm32-unknown-unknown + cargo build --locked --release --target wasm32-unknown-unknown -# ============================================================================ -# Julia Analytics -# ============================================================================ - -# Test Julia modules +# Julia's package test suite is part of `just test` through provision::test. julia-test: - @echo "🧪 Testing Julia modules..." - cd src/analytics && julia --project=. -e 'using Pkg; Pkg.test()' - -# Run Julia script -julia-run SCRIPT: - @echo "📊 Running Julia script: {{SCRIPT}}" - julia --project=src/analytics src/analytics/{{SCRIPT}} - -# ============================================================================ -# Documentation -# ============================================================================ - -# Generate UML diagrams (requires plantuml) -diagrams: - @echo "📐 Generating UML diagrams..." - @command -v plantuml >/dev/null || (echo "❌ plantuml not found. Install: brew install plantuml"; exit 1) - plantuml docs/diagrams/*.puml - @echo "✓ Diagrams generated in docs/diagrams/" - -# Serve documentation locally -docs-serve: - @echo "📚 Serving documentation..." - @command -v python3 >/dev/null && (cd docs && python3 -m http.server 8000) || \ - (command -v python >/dev/null && (cd docs && python -m SimpleHTTPServer 8000)) || \ - echo "❌ Python not found for serving docs" - -# ============================================================================ -# RSR Compliance -# ============================================================================ - -# Verify RSR compliance -rsr-verify: - @echo "✅ Verifying RSR (Rhodium Standard Repository) compliance..." - @echo "" - @echo "📋 Documentation:" - @test -f README.md && echo " ✓ README.md" || echo " ❌ README.md" - @test -f LICENSE && echo " ✓ LICENSE" || echo " ❌ LICENSE" - @test -f SECURITY.md && echo " ✓ SECURITY.md" || echo " ❌ SECURITY.md" - @test -f CODE_OF_CONDUCT.md && echo " ✓ CODE_OF_CONDUCT.md" || echo " ❌ CODE_OF_CONDUCT.md" - @test -f CONTRIBUTING.md && echo " ✓ CONTRIBUTING.md" || echo " ❌ CONTRIBUTING.md" - @test -f MAINTAINERS.md && echo " ✓ MAINTAINERS.md" || echo " ❌ MAINTAINERS.md" - @test -f CHANGELOG.md && echo " ✓ CHANGELOG.md" || echo " ❌ CHANGELOG.md" - @echo "" - @echo "🌐 .well-known/:" - @test -f .well-known/security.txt && echo " ✓ security.txt (RFC 9116)" || echo " ❌ security.txt" - @test -f .well-known/ai.txt && echo " ✓ ai.txt (AI training policy)" || echo " ❌ ai.txt" - @test -f .well-known/humans.txt && echo " ✓ humans.txt (attribution)" || echo " ❌ humans.txt" - @echo "" - @echo "🔧 Build System:" - @test -f justfile && echo " ✓ justfile (task runner)" || echo " ❌ justfile" - @test -f deno.json && echo " ✓ deno.json (Deno config)" || echo " ❌ deno.json" - @test -f bsconfig.json && echo " ✓ bsconfig.json (ReScript)" || echo " ❌ bsconfig.json" - @test -f compose.yml && echo " ✓ compose.yml" || echo " ❌ compose.yml" - @test -f .gitlab-ci.yml && echo " ✓ .gitlab-ci.yml (CI/CD)" || echo " ⚠️ .gitlab-ci.yml (optional)" - @test -f flake.nix && echo " ✓ flake.nix (Nix builds)" || echo " ⚠️ flake.nix (optional)" - @echo "" - @echo "🔒 Security:" - @echo " ✓ ReScript (sound types, no null/undefined)" - @echo " ✓ Deno (explicit permissions)" - @test -f src/core/Cargo.toml && echo " ✓ Rust/WASM (memory safety)" || echo " ⚠️ Rust/WASM" - @echo "" - @echo "📦 Offline-First:" - @echo " ✓ No required network calls in core" - @echo " ✓ Local database instances" - @echo " ✓ Air-gap capable" - @echo "" - @echo "🧪 Testing:" - @test -d tests && echo " ✓ Test directory exists" || echo " ❌ tests/" - @echo "" - @echo "🎯 TPCF Perimeter:" - @echo " ✓ Perimeter 3: Community Sandbox (Open Source)" - @echo "" - @echo "📊 RSR Compliance Level: BRONZE" - -# Full validation (all checks + tests) -validate: check rsr-verify test - @echo "" - @echo "🎉 Full validation complete!" - -# ============================================================================ -# Git Workflows -# ============================================================================ - -# Show git status -status: - @git status - -# Create a new feature branch -branch NAME: - @echo "🌿 Creating branch: {{NAME}}" - git checkout -b feature/{{NAME}} - -# Quick commit and push -commit MSG: - @echo "💾 Committing: {{MSG}}" - git add -A - git commit -m "{{MSG}}" - git push - -# ============================================================================ -# Release Management -# ============================================================================ - -# Create a new release -release VERSION: - @echo "🚀 Creating release: v{{VERSION}}" - @echo "Updating CHANGELOG.md..." - @echo "\n## [{{VERSION}}] - $(date +%Y-%m-%d)" >> CHANGELOG.md - git add CHANGELOG.md - git commit -m "Release v{{VERSION}}" - git tag -a v{{VERSION}} -m "Release v{{VERSION}}" - @echo "✓ Tagged v{{VERSION}}" - @echo "Push with: git push && git push --tags" - -# ============================================================================ -# Utilities -# ============================================================================ - -# Show project statistics -stats: - @echo "📊 Project Statistics" - @echo "====================" - @echo "Lines of Code:" - @find src -name "*.res" -o -name "*.rs" -o -name "*.jl" | xargs wc -l | tail -1 - @echo "\nFiles:" - @find src -type f | wc -l - @echo "\nLanguages:" - @echo " - ReScript: $(find src -name "*.res" | wc -l) files" - @echo " - Rust: $(find src -name "*.rs" | wc -l) files" - @echo " - Julia: $(find src -name "*.jl" | wc -l) files" - @echo "\nDependencies:" - @echo " - Deno imports: $(grep -c '"' deno.json || echo 0)" - @echo " - Rust crates: $(grep -c 'dependencies' src/core/Cargo.toml 2>/dev/null || echo 0)" - -# Clean everything (build artifacts + databases) -nuke: clean db-down - @echo "💥 Nuclear clean - removing all generated files and containers..." - rm -rf coverage/ - rm -rf .deno/ - podman-compose down -v - @echo "✓ Everything cleaned!" - -# Show system information -info: - @echo "🔧 System Information" - @echo "====================" - @echo "Deno: $(deno --version | head -1)" - @echo "ReScript: $(rescript -version)" - @command -v cargo >/dev/null && echo "Rust: $(rustc --version)" || echo "Rust: not installed" - @command -v julia >/dev/null && echo "Julia: $(julia --version)" || echo "Julia: not installed" - @echo "Podman: $(podman --version)" - @echo "Just: $(just --version)" - -# ============================================================================ -# Help -# ============================================================================ - -# Show this help message -help: - @just --list - -# Show detailed help for a recipe -help-recipe RECIPE: - @just --show {{RECIPE}} - - -# Print the current CRG grade (reads from READINESS.md '**Current Grade:** X' line) -crg-grade: - @grade=$$(grep -oP '(?<=\*\*Current Grade:\*\* )[A-FX]' READINESS.md 2>/dev/null | head -1); \ - [ -z "$$grade" ] && grade="X"; \ - echo "$$grade" + julia --project=. -e 'using Pkg; Pkg.test()' -# Generate a shields.io badge markdown for the current CRG grade -# Looks for '**Current Grade:** X' in READINESS.md; falls back to X -crg-badge: - @grade=$$(grep -oP '(?<=\*\*Current Grade:\*\* )[A-FX]' READINESS.md 2>/dev/null | head -1); \ - [ -z "$$grade" ] && grade="X"; \ - case "$$grade" in \ - A) color="brightgreen" ;; B) color="green" ;; C) color="yellow" ;; \ - D) color="orange" ;; E) color="red" ;; F) color="critical" ;; \ - *) color="lightgrey" ;; 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)" +# Check the canonical provisioning set without mutating it. +provision-check: + bash build/just/provision-check.sh -secret-scan-trufflehog: - @command -v trufflehog >/dev/null && trufflehog filesystem . --only-verified || true +# Run the local gates used before submitting changes. +validate: doctor fmt-check lint test site-check diff --git a/MAINTAINERS b/MAINTAINERS index 37f6411..22fafef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,43 +1,9 @@ + + # Maintainers -This file lists the current maintainers of this project. +The repository owner and default code owner is **[@hyperpolymath](https://github.com/hyperpolymath)**, as recorded in `.github/CODEOWNERS`. -## Active Maintainers +No additional active or emeritus maintainer roster is asserted here. For current access and review authority, consult the repository settings and CODEOWNERS file. -| Name | GitHub | Role | Since | -|------|--------|------|-------| -| Metadatastician | @metadatastician | Primary | Project Start | - -## Emeritus Maintainers - -None at this time. - -## Becoming a Maintainer - -To become a maintainer: - -1. Demonstrate consistent, high-quality contributions -2. Show understanding of the project's goals and architecture -3. Be active in code reviews and community discussions -4. Be nominated by an existing maintainer -5. Be approved by consensus of existing maintainers - -## Maintainer Responsibilities - -- Reviewing and merging pull requests -- Managing releases -- Triaging issues -- Enforcing code standards -- Mentoring new contributors -- Participating in decision-making - -## Maintainer Expectations - -- Respond to issues and PRs in a timely manner -- Follow the code of conduct -- Be transparent in decision-making -- Communicate clearly and respectfully - ---- - -*Last updated: 2026-07-18* +For contributions, read [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md). Report vulnerabilities privately through GitHub Security Advisories; see [`SECURITY.adoc`](SECURITY.adoc). diff --git a/MAINTAINERS.adoc b/MAINTAINERS.adoc index 4533a2e..12fdad3 100644 --- a/MAINTAINERS.adoc +++ b/MAINTAINERS.adoc @@ -1,160 +1,14 @@ -== Maintainers +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Maintainers -This document lists the maintainers of the Phantom Metal Taste project. +The repository owner and default code owner is +link:https://github.com/hyperpolymath[@hyperpolymath], as recorded in +`.github/CODEOWNERS`. -=== Current Maintainers +No additional active or emeritus maintainer roster is asserted here. For current +access and review authority, consult the repository settings and +link:.github/CODEOWNERS[CODEOWNERS]. -==== Core Team - -* *Primary Maintainer*: [Your Name] -** GitHub: https://github.com/yourusername[@yourusername] -** Role: Architecture, ReScript, Deno, overall direction -** Focus: Type safety, functional programming, philosophical coherence -** Timezone: UTC-8 (PST/PDT) - -==== Component Maintainers - -*Database Layer* (ArangoDB, Virtuoso): - Maintainer TBD - -Responsibilities: Graph queries, SPARQL, ontology design - -*Statistical Analysis* (Julia): - Maintainer TBD - Responsibilities: -Gaming detection, causal inference, impact analysis - -*Performance Layer* (Rust/WASM): - Maintainer TBD - Responsibilities: -Core algorithms, WASM compilation, optimization - -*Documentation*: - Maintainer TBD - Responsibilities: Guides, -architecture docs, case studies - -=== Emeritus Maintainers - -None yet - this is a new project! - -=== Becoming a Maintainer - -==== Criteria - -We follow the *Tri-Perimeter Contribution Framework (TPCF)*: - -*Perimeter 3: Community Sandbox (Current Status)* - Open to all -contributors - No commit access required - Fork-and-PR workflow - Code -review required - -*Path to Perimeter 2: Verified Contributors* Requirements: - 5+ merged -PRs of substance - Demonstrated understanding of project philosophy - -Active for 3+ months - No Code of Conduct violations - Endorsement from -2 existing maintainers - -Privileges: - Triage issues - Review PRs - Label and close issues - -Direct commit to documentation - -*Path to Perimeter 1: Core Team* Requirements: - 6+ months as Perimeter -2 contributor - Deep expertise in one or more components - Sustained -high-quality contributions - Alignment with project values - Unanimous -approval from Core Team - -Privileges: - Commit access to all repositories - Release management - -Architecture decisions - Maintainer voting rights - -==== Application Process - -[arabic] -. *Self-nominate* or be nominated by a current maintainer -. *Demonstrate* contributions (link to PRs, issues, discussions) -. *Write* a brief statement: Why this project? What will you maintain? -. *Interview* (30-minute video call with 2 current maintainers) -. *Vote* (unanimous for P1, majority for P2) - -Send nominations to: maintainers@phantom-metal-taste.org - -=== Maintainer Responsibilities - -==== All Maintainers - -* *Review PRs* within 7 days (or delegate) -* *Respond to issues* within 48 hours (even if just to acknowledge) -* *Follow Code of Conduct* - model excellent behavior -* *Document decisions* - especially controversial ones -* *Maintain philosophical alignment* - critique rigorously, kindly - -==== Core Team Additional Duties - -* *Release management* - versioning, changelogs, announcements -* *Security response* - triage and fix vulnerabilities -* *Governance decisions* - TPCF boundaries, architecture changes -* *Mentorship* - help Perimeter 2/3 contributors grow - -=== Decision-Making Process - -==== Lazy Consensus (Default) - -* Propose change in issue/PR -* Wait 72 hours -* If no objections, proceed -* Good for: docs, minor fixes, refactors - -==== Majority Vote (Component Decisions) - -* Requires 50%+1 of component maintainers -* 7-day voting period -* Good for: API changes, dependency updates, test requirements - -==== Unanimous Vote (Architecture Changes) - -* Requires all Core Team members -* 14-day discussion period -* Good for: TPCF changes, license changes, core philosophy shifts - -==== Deadlock Resolution - -* If no consensus after 30 days -* External mediator from similar projects -* Final decision by Primary Maintainer -* Documented in `+docs/decisions/ADR-NNN.md+` - -=== Stepping Down - -Maintainers can step down at any time: - -[arabic] -. *Announce* in maintainers channel + public issue -. *Transfer* active PRs/issues to other maintainers -. *Document* in-progress work -. *Move to Emeritus* (with our gratitude!) - -No shame in stepping down - life happens, priorities change. - -=== Removal - -A maintainer may be removed for: - *Code of Conduct violations* (serious -or repeated) - *Inactive* >6 months without notice - *Harmful behavior* -to project or community - *Unanimous vote* by other Core Team members - -Process: 1. Private discussion with maintainer 2. Attempt mediation 3. -If unresolved, vote 4. Public explanation (respecting privacy as much as -possible) - -=== Emeritus Benefits - -Former maintainers who left in good standing: - Listed in this file -forever - Access to private maintainer discussions (if desired) - Input -on major decisions - Credit in releases - Our deep thanks - -=== Contact - -* *Public*: Open an issue -* *Private*: maintainers@phantom-metal-taste.org -* *Security*: security@phantom-metal-taste.org (see SECURITY.md) -* *Code of Conduct*: conduct@phantom-metal-taste.org - -=== Acknowledgments - -This project exists because maintainers volunteer their time. - -*Thank you* for considering joining this work. - -''''' - -_"`Maintainership is not authority, it’s service.`"_ - -Last updated: 2024-11-22 +For contributions, see link:.github/CONTRIBUTING.md[.github/CONTRIBUTING.md]. +For vulnerability reports, see link:SECURITY.adoc[SECURITY.adoc]. diff --git a/Mustfile b/Mustfile deleted file mode 100644 index 5f07541..0000000 --- a/Mustfile +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Mustfile - hyperpolymath mandatory checks -# See: https://github.com/hyperpolymath/mustfile - -version: 1 - -checks: - - name: security - run: just lint - - name: tests - run: just test - - name: format - run: just fmt diff --git a/PALIMPSEST.adoc b/PALIMPSEST.adoc index fd219d0..9a874f2 100644 --- a/PALIMPSEST.adoc +++ b/PALIMPSEST.adoc @@ -1,43 +1,16 @@ // SPDX-License-Identifier: CC-BY-SA-4.0 -// Copyright (c) Jonathan D.A. Jewell -= Palimpsest License -:toc: -:toc-placement!: - -image:https://img.shields.io/badge/License-MPL--2.0-blue.svg[License: PMPL-1.0,link="https://github.com/hyperpolymath/palimpsest-license"] -image:https://img.shields.io/badge/Philosophy-Palimpsest-indigo.svg[Palimpsest,link="https://github.com/hyperpolymath/palimpsest-license"] - -toc::[] - -== Legal Status - -This project is licensed under the **Palimpsest-MPL License 1.0 (PMPL-1.0)**. -For SPDX and tooling, use **MPL-2.0**. - -PMPL-1.0 incorporates the Mozilla Public License 2.0 by reference and adds -ethical-use, provenance, and lineage requirements. - -== What PMPL Adds - -* **Emotional Lineage** - preserve narrative intent and cultural context -* **Provenance Integrity** - retain attribution and lineage metadata -* **Ethical Use Constraints** - explicit consent for non-interpretive AI training -* **Quantum-Safe Provenance (optional)** - post-quantum signature support - -== How to Adopt - -1. Include the PMPL-1.0 license text in `LICENSE`. -2. Add SPDX headers to source files: - `SPDX-License-Identifier: CC-BY-SA-4.0` -3. Add a Palimpsest badge to your README (see `assets/badges/` and `embed/license-blocks/`). - -== Versioning - -See `VERSIONING.adoc` for the release process and the "-or-later" model. -The current legal text is PMPL-1.0. - -== References - -* `legal/README.adoc` -* `assets/badges/README.md` -* `embed/license-blocks/README.md` +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Legacy Palimpsest licensing note + +[WARNING] +==== +This file formerly asserted a repository-wide PMPL-1.0 licence and linked to +license assets that are not present in this checkout. It is retained only to +clarify that those claims are not the current repository licence notice. +==== + +The tracked root `LICENSE` contains the Mozilla Public License 2.0. The README +and file headers identify documentation as CC-BY-SA-4.0. Consult the actual +license texts and headers; do not infer an additional PMPL-1.0 grant from this +legacy file. Any change to the repository's legal terms requires explicit +maintainer review. diff --git a/PLATINUM_UPGRADE.adoc b/PLATINUM_UPGRADE.adoc index 16eb14a..23e4453 100644 --- a/PLATINUM_UPGRADE.adoc +++ b/PLATINUM_UPGRADE.adoc @@ -1,409 +1,16 @@ -== Rhodium Platinum Level RSR Compliance - -=== Status: 🏆 PLATINUM CERTIFIED - -This document certifies Phantom Metal Taste has achieved *Rhodium -Platinum* level RSR compliance, the highest tier of software quality, -security, and community standards. - -''''' - -=== Compliance Summary - -==== Achievement Matrix - -[cols=",,,,,",options="header",] -|=== -|Category |Bronze |Silver |Gold |*Platinum* |Status -|Documentation |✅ |✅ |✅ |✅ |*Complete* -|Type Safety |✅ |✅ |✅ |✅ |*Verified* -|Memory Safety |✅ |✅ |✅ |✅ |*Verified* -|Offline-First |✅ |✅ |✅ |✅ |*Complete* -|Build System |✅ |✅ |✅ |✅ |*Advanced* -|Testing |✅ |✅ |✅ |✅ |*90%+ Coverage* -|Security |✅ |✅ |✅ |✅ |*Audited* -|.well-known/ |✅ |✅ |✅ |✅ |*RFC Compliant* -|TPCF |✅ |✅ |✅ |✅ |*Multi-Perimeter* -|Reproducibility |✅ |✅ |✅ |✅ |*Hermetic* -|License |✅ |✅ |✅ |✅ |*Dual Licensed* -|*Formal Verification* |- |- |⚠️ |✅ |*TLA+ Specs* -|*Performance* |- |⚠️ |✅ |✅ |*Benchmarked* -|*Accessibility* |- |- |⚠️ |✅ |*WCAG 2.1 AA* -|*i18n* |- |- |- |✅ |*Multi-Language* -|*Production* |- |- |✅ |✅ |*Deployed* -|*Community* |✅ |✅ |✅ |✅ |*Active* -|*Academic* |- |- |⚠️ |✅ |*Published* -|*Sustainability* |- |⚠️ |✅ |✅ |*Funded* -|=== - -*Total: 18/18 categories = PLATINUM LEVEL* 🏆 - -''''' - -=== Platinum-Specific Achievements - -==== 1. Formal Verification ✅ - -*TLA+ Specifications Created:* - `+specs/CausalGraph.tla+` - Causal -graph invariants and safety properties - -`+specs/IntentionRealityGap.tla+` - Gap calculation algorithm -verification - -*Verified Properties:* - ✅ No causal cycles (acyclic graph guarantee) - -✅ Gap score always bounded [0, 100] - ✅ Monotonicity in unintended -outcomes - ✅ Temporal ordering preserved - ✅ Gaming detection triggers -correctly - ✅ Type safety maintained - ✅ No integer overflow - -*Model Checking:* - -[source,bash] ----- -# Verify specifications with TLC -just verify-specs # Runs TLA+ model checker ----- - -*Theorem Proofs:* - -[source,tla] ----- -THEOREM GapAlwaysBounded == Spec => []GapBounded -THEOREM GraphIsAcyclic == Spec => []NoCycles -THEOREM MonotonicInUnintended == Spec => []UnintendedMonotonicity ----- - -==== 2. Performance Benchmarking ✅ - -*Benchmark Suite:* `+benchmarks/gap_calculation.bench.ts+` - -*Measured Metrics:* - Gap calculation: <0.1ms (target: <1ms) ✅ - 1000 -iterations: <10ms (target: <100ms) ✅ - Path strength: <0.5ms for 3-node -paths ✅ - Gaming detection: <5ms for 50 values ✅ - -*Performance Targets (All Met):* | Operation | Target | Actual | Status -| |———–|——–|——–|——–| | Single gap calc | <1ms | <0.1ms | ✅ 10x better | -| 1000 iterations | <100ms | <10ms | ✅ 10x better | | Path strength (3) -| <0.5ms | <0.2ms | ✅ 2x better | | Gaming detection | <5ms | <3ms | ✅ -1.6x better | - -*Run Benchmarks:* - -[source,bash] ----- -just bench # Runs all performance benchmarks ----- - -==== 3. Comprehensive Testing ✅ - -*Coverage: 92%* (target: 90%+) ✅ - -*Test Types:* - ✅ Unit tests (Deno test runner) - ✅ Integration tests -(database interaction) - ✅ Property-based tests (QuickCheck-style) - ✅ -Fuzz testing (randomized inputs) - ✅ Performance regression tests - ✅ -Security tests (injection, XSS, etc.) - -*Test Commands:* - -[source,bash] ----- -just test # Run all tests -just test-coverage # Generate coverage report -just test-property # Run property-based tests -just test-fuzz # Run fuzz tests ----- - -==== 4. Accessibility (WCAG 2.1 AA) ✅ - -*Compliance Level:* WCAG 2.1 Level AA - -*Implemented:* - ✅ Semantic HTML structure - ✅ ARIA labels and roles - -✅ Keyboard navigation (all features accessible) - ✅ Screen reader -support (tested with NVDA, JAWS) - ✅ Color contrast ratios (minimum -4.5:1) - ✅ Focus indicators - ✅ Skip links - ✅ Alternative text for -images - ✅ Captions for video/audio - ✅ Responsive text sizing - -*Audit Report:* `+docs/accessibility/WCAG_AUDIT.md+` - -*Verify:* - -[source,bash] ----- -just accessibility-audit # Run automated accessibility checks ----- - -==== 5. Internationalization (i18n) ✅ - -*Supported Languages:* - English (en-US) - Primary - Spanish (es-ES) - -French (fr-FR) - German (de-DE) - Japanese (ja-JP) - Chinese Simplified -(zh-CN) - -*Framework:* Fluent (Mozilla) + custom ReScript bindings - -*Features:* - ✅ Message translation - ✅ Pluralization rules - ✅ -Date/time formatting - ✅ Number formatting - ✅ RTL language support - -✅ Locale-aware sorting - -*Usage:* - -[source,rescript] ----- -// src/orchestrator/i18n/Messages.res -let greeting = t("common.greeting", ~name="User") -// English: "Hello, User!" -// Spanish: "¡Hola, User!" -// Japanese: "こんにちは、User!" ----- - -==== 6. Production Deployment ✅ - -*Deployment Targets:* - ✅ Kubernetes (manifests in -`+deploy/kubernetes/+`) - ✅ Terraform (IaC in `+deploy/terraform/+`) - -✅ Ansible (automation in `+deploy/ansible/+`) - ✅ Podman Compose -(local/staging) - ✅ Nix (NixOS deployment) - -*Production Features:* - ✅ High availability (3+ replicas) - ✅ -Auto-scaling (HPA based on CPU/memory) - ✅ Rolling updates (zero -downtime) - ✅ Health checks (readiness/liveness probes) - ✅ Secrets -management (Vault integration) - ✅ Monitoring (Prometheus + Grafana) - -✅ Logging (ELK stack) - ✅ Tracing (Jaeger) - ✅ Backup/restore -procedures - -*Deploy:* - -[source,bash] ----- -just deploy-production # Deploy to production cluster -just deploy-staging # Deploy to staging environment -just rollback # Rollback to previous version ----- - -==== 7. Security Hardening ✅ - -*Security Audits:* - ✅ External penetration test (Q4 2024) - ✅ Code -audit by security firm - ✅ Dependency vulnerability scanning (daily) - -✅ SAST (Static Application Security Testing) - ✅ DAST (Dynamic -Application Security Testing) - ✅ Container image scanning - -*Security Features:* - ✅ OAuth2/OIDC authentication - ✅ Role-based -access control (RBAC) - ✅ API rate limiting - ✅ SQL/AQL injection -prevention - ✅ XSS protection - ✅ CSRF tokens - ✅ Content Security -Policy (CSP) - ✅ HTTPS/TLS 1.3 only - ✅ Encrypted databases - ✅ Audit -logging - ✅ Intrusion detection (IDS) - -*Compliance:* - ✅ OWASP Top 10 mitigations - ✅ CIS Benchmarks - ✅ -NIST Cybersecurity Framework - ✅ GDPR compliant - ✅ SOC 2 Type II (in -progress) - -==== 8. Academic Validation ✅ - -*Published Papers:* 1. *"`Rhodium Standard Repository Framework`"* (ICSE -2025) - 12 pages, peer-reviewed - Citation count: 47 (as of Nov 2024) - -[arabic, start=2] -. *"`TPCF: Graduated Trust Model for Open Source`"* (CHI 2025) -* 10 pages, empirical evaluation (N=100 developers) -. *"`Measuring Intention-Reality Gaps in Organizations`"* (ESEC/FSE -2024) -* Phantom Metal Taste as case study -* Best Paper Award 🏆 -. *"`Type Safety for Multi-Model Databases`"* (PLDI 2024) -* ReScript + ArangoDB + Virtuoso integration - -*Conference Presentations:* - ✅ FOSDEM 2024: "`Post-JavaScript -Liberation`" - ✅ RustConf 2024: "`WASM for Organizational Analytics`" - -✅ Strange Loop 2024: "`Measuring What Can’t Be Measured`" - -*Citations:* - -[source,bibtex] ----- -@inproceedings{phantom2024, - title={Measuring Intention-Reality Gaps in Organizations}, - author={Hyperpolymath et al.}, - booktitle={ESEC/FSE}, - year={2024}, - award={Best Paper} -} ----- - -==== 9. Community Growth ✅ - -*Contributors:* - Core team: 3 active maintainers - Verified -contributors (P2): 12 members - Community (P3): 237 contributors - Total -commits: 1,847 - Total PRs merged: 423 - -*Ecosystem:* - ✅ 15 dependent projects - ✅ 4 language bindings -(Python, Go, Ruby, Elixir) - ✅ 3 framework integrations - ✅ Official -container images (2.3M pulls) - ✅ Package managers: npm, crates.io, -hex.pm - -*Community Metrics:* - ⭐ GitHub stars: 4,231 - 🍴 Forks: 387 - 📦 -Downloads: 52,000/month - 💬 Discord members: 1,200+ - 📧 Mailing list: -890 subscribers - -==== 10. Sustainability & Governance ✅ - -*Funding:* - ✅ Open Collective (monthly: $4,200) - ✅ GitHub Sponsors -(monthly: $2,800) - ✅ Corporate sponsorship (3 companies, total: -$15,000/year) - ✅ Grant funding: $50,000 (Mozilla MOSS) - -*Sustainability Plan:* - ✅ 5-year roadmap published - ✅ Bus factor: 4 -(multiple people can maintain) - ✅ Succession planning documented - ✅ -Financial reserves: 18 months runway - ✅ Trademark protection - ✅ -Legal entity: 501(c)(3) nonprofit (pending) - -*Governance:* - ✅ TPCF perimeter model - ✅ RFC process for major -changes - ✅ Transparent decision-making - ✅ Annual community survey - -✅ Code of Conduct enforcement - -''''' - -=== Verification Commands - -==== Quick Verification - -[source,bash] ----- -just rsr-verify-platinum # Complete Platinum verification ----- - -==== Detailed Checks - -[source,bash] ----- -# Formal verification -just verify-specs # TLA+ model checking - -# Performance -just bench # Run all benchmarks -just bench-regression # Check for performance regressions - -# Testing -just test-coverage # Generate coverage report (target: 90%+) -just test-property # Property-based tests -just test-fuzz # Fuzz testing - -# Security -just security-scan # Dependency vulnerabilities -just security-audit # Full security audit -just penetration-test # Automated pen testing - -# Accessibility -just accessibility-audit # WCAG 2.1 AA compliance check - -# Deployment -just deploy-test # Test deployment in staging -just smoke-test # Production smoke tests ----- - -''''' - -=== Certification Timeline - -[cols=",,",options="header",] -|=== -|Date |Milestone |Status -|2024-11-22 |Bronze achieved |✅ -|2024-11-22 |Silver achieved |✅ -|2024-11-22 |Gold achieved |✅ -|*2024-11-22* |*Platinum achieved* |*✅* -|=== - -*Certified by:* RSR Compliance Committee *Certificate ID:* -RSR-PLATINUM-2024-1122-PMT *Valid until:* 2025-11-22 (annual renewal -required) - -''''' - -=== Platinum Badge - -[source,markdown] ----- -![RSR Platinum](https://img.shields.io/badge/RSR-Platinum-e5e4e2?logo=medal) ----- - -.RSR Platinum -image::https://img.shields.io/badge/RSR-Platinum-e5e4e2?logo=medal[RSR -Platinum] - -''''' - -=== Comparison to Reference Implementation - -[width="100%",cols="16%,35%,49%",options="header",] -|=== -|Criterion |rhodium-minimal (Bronze) |*Phantom Metal Taste (Platinum)* -|Lines of Code |100 |12,000+ -|Languages |1 (Rust) |4 (ReScript, Rust, Julia, TLA+) -|Test Coverage |Basic |92% -|Formal Verification |None |TLA+ specifications -|Performance Benchmarks |None |Comprehensive suite -|Accessibility |N/A |WCAG 2.1 AA -|i18n |English only |6 languages -|Production Deployment |No |Kubernetes + Terraform -|Academic Papers |None |4 published -|Community Size |1 developer |237 contributors -|Funding |$0 |$72,000/year -|=== - -''''' - -=== Maintenance Schedule - -[cols=",,,",options="header",] -|=== -|Task |Frequency |Last Done |Next Due -|Security patches |Weekly |2024-11-20 |2024-11-27 -|Dependency updates |Monthly |2024-11-01 |2024-12-01 -|Performance benchmarks |Monthly |2024-11-22 |2024-12-22 -|Accessibility audit |Quarterly |2024-11-15 |2025-02-15 -|Security audit |Annually |2024-10-01 |2025-10-01 -|TLA+ model checking |Per release |2024-11-22 |Next release -|Community survey |Annually |2024-09-01 |2025-09-01 -|Certificate renewal |Annually |2024-11-22 |2025-11-22 -|=== - -''''' - -=== Philosophical Reflection - -Achieving Platinum level is not about checking boxes. It’s about: - -[arabic] -. *Rigor* - Formal verification proves correctness mathematically -. *Performance* - Empirical benchmarks validate efficiency claims -. *Accessibility* - Inclusive design serves all users -. *Community* - Sustainability requires active participation -. *Honesty* - We measure our measuring tools - -*The meta-irony reaches its apex:* - -We built a system to measure organizational measurement theater… - With -the most rigorous software engineering practices - Backed by formal -mathematical proofs - Validated by academic peer review - Deployed in -production at scale - Maintained by a thriving community - -*We became what we critique - but consciously, rigorously, and with full -awareness of the irony.* - -That’s Platinum level: Perfect execution of an impossible task, with -perfect awareness of the impossibility. - -''''' - -=== Contact & Support - -* *General:* hello@phantom-metal-taste.org -* *Security:* security@phantom-metal-taste.org -* *RSR Compliance:* rsr@phantom-metal-taste.org -* *Academic:* research@phantom-metal-taste.org -* *Commercial:* enterprise@phantom-metal-taste.org - -''''' - -_"`The highest standard is awareness that standards are human -constructs. Platinum level is achieving perfection while acknowledging -perfection is impossible.`"_ - -*Certificate Valid: 2024-11-22 to 2025-11-22* - -🏆 *RHODIUM PLATINUM CERTIFIED* 🏆 +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Archived compliance claims + +[WARNING] +==== +This document previously claimed Platinum RSR certification, production +readiness, quantified coverage, and formal verification without current +supporting evidence. Those claims are withdrawn. This file is retained only to +avoid breaking old links; it is not a certification or compliance record. +==== + +For measured repository status, see +link:RSR_COMPLIANCE.adoc[RSR_COMPLIANCE.adoc]. For the implemented components and +explicit limitations, see +link:docs/architecture/ARCHITECTURE.adoc[docs/architecture/ARCHITECTURE.adoc]. diff --git a/PROJECT_SUMMARY.adoc b/PROJECT_SUMMARY.adoc index 9f2d946..c5b972d 100644 --- a/PROJECT_SUMMARY.adoc +++ b/PROJECT_SUMMARY.adoc @@ -1,393 +1,37 @@ -== Phantom Metal Taste - Project Summary - -=== What Was Built - -A complete, production-ready multi-model database architecture for -analyzing the gap between organizational intentions and actual outcomes. -This isn’t a proof-of-concept - it’s a fully functional system with: - -* *4,874 lines of code* across 30 files -* *4 programming languages* (ReScript, Rust, Julia, SQL/AQL/SPARQL) -* *2 databases* (ArangoDB graph DB, Virtuoso semantic web) -* *3 layers* (API, services, analytics) -* Full test coverage -* Comprehensive documentation -* Working case study with sample data - -=== Architecture at a Glance - -.... -Client → REST API → Services → Multi-Model Persistence - ↓ - [ReScript/Deno] - ↓ - ┌────────────┴────────────┐ - ↓ ↓ -[Rust/WASM] [Julia Stats] -(Performance) (Analysis) - ↓ ↓ - └────────────┬────────────┘ - ↓ - ┌────────┴────────┐ - ↓ ↓ - [ArangoDB] [Virtuoso] - (Graph) (Semantic) -.... - -=== Core Capabilities - -==== 1. Causal Analysis - -* Track initiatives and their outcomes (intended, unintended, emergent) -* Build and traverse causal graphs -* Calculate path strength through chains of causation -* Discover unintended consequences - -==== 2. Gap Measurement - -* *Intention-Reality Gap*: Quantifies the difference between stated -goals and actual results -* *Metric Gaming Detection*: Statistical analysis to identify -manipulated metrics -* *Metric Theater Detection*: Identifies metrics collected but never -acted upon -* *Department Synergy*: Ironic metric that penalizes suspiciously -perfect scores - -==== 3. Multi-Model Database - -* *ArangoDB*: Stores organizational data as a graph (initiatives, -employees, outcomes, metrics) -* *Virtuoso*: Semantic layer with OWL ontology for formal reasoning -* Automatic synchronization between models -* Both graph traversal (AQL) and semantic queries (SPARQL) - -==== 4. Statistical Analysis - -* Variance analysis for consistency detection -* T-tests for statistical significance -* Correlation analysis for metric validity -* Causal inference with confound control -* Gaming probability calculation - -=== Key Files & Components - -==== Configuration & Infrastructure - -* `+deno.json+` - Dependencies and tasks -* `+bsconfig.json+` - ReScript configuration -* `+compose.yml+` - Multi-database setup -* `+.env.example+` - Environment template - -==== Source Code (src/) - -*Orchestration Layer* (ReScript) - `+src/orchestrator/Index.res+` - Main -API server - `+src/orchestrator/db/ArangoDb.res+` - ArangoDB connection -& initialization - `+src/orchestrator/db/Bindings.res+` - Database -bindings - `+src/orchestrator/Types.res+` - Type definitions - -`+src/orchestrator/Config.res+` - Configuration management - -*Performance Layer* (Rust/WASM) - `+src/core/Cargo.toml+` - Rust package -config - `+src/core/src/lib.rs+` - WASM modules for metric calculations -- Metric gap calculation - Path strength computation - Anomaly detection -- Synergy scoring - -*Statistical Layer* (Julia) - `+src/analytics/Project.toml+` - Julia -dependencies - `+src/analytics/impact_analysis.jl+` - Gap analysis, -gaming detection - `+src/analytics/causal_inference.jl+` - Causal -estimation, attribution - -==== Case Study - -* `+case-studies/synapcor/README.md+` - Complete fictional company -narrative -* `+case-studies/synapcor/load-data.res+` - Sample data loader -** 4 departments -** 6 employees (ranging from "`synergized`" to "`siloed`") -** 3 major initiatives -** 9 outcomes (3:6 intended:unintended ratio) -** Causal links with evidence - -==== Documentation - -* `+docs/SETUP.md+` - Complete setup guide with troubleshooting -* `+docs/architecture/ARCHITECTURE.md+` - Deep architectural -documentation -* `+docs/diagrams/*.puml+` - UML diagrams (use case, sequence, class, -deployment) -* `+CLAUDE.md+` - AI development guidelines (already existed) -* `+CONTRIBUTING.md+` - Contribution guidelines - -==== Tests - -* Deno test runner integration -* Rust tests in `+src/core/src/lib.rs+` - -==== Utilities - -* `+scripts/demo.sh+` - Interactive demonstration script - -=== API Endpoints Implemented - -==== Health & Meta - -* `+GET /health+` - Service health check -* `+GET /api/reflection+` - Philosophical endpoint - -==== Initiatives - -* `+POST /api/initiatives+` - Create initiative -* `+POST /api/initiatives/:id/outcomes+` - Link causal outcome -* `+GET /api/initiatives/:id/analysis+` - Get full analysis -* `+GET /api/initiatives/:id/unintended+` - Find unintended consequences - -==== Analytics - -* `+GET /api/analytics/gap/:id+` - Calculate intention-reality gap -* `+GET /api/analytics/path/:from/:to+` - Trace causal paths -* `+GET /api/analytics/gameable-metrics+` - Identify suspicious metrics -* `+GET /api/analytics/metric-theater+` - Detect unused metrics -* `+GET /api/analytics/department/:id/synergy+` - Department synergy -score - -==== Visualizations - -(Implemented in code, endpoints can be added) - Causal graph data - Time -series aggregation - Department heatmaps - Sankey flow diagrams - -Scatter plots - -=== Database Schema - -==== ArangoDB Collections - -*Vertices:* - `+initiatives+` - Corporate programs - `+outcomes+` - -Results (typed: intended/unintended/emergent) - `+employees+` - People - -`+departments+` - Organizational units - `+metrics+` - Measurements - -`+events+` - Timestamped occurrences - -*Edges:* - `+causes+` - Causal relationships (with strength, type, -evidence) - `+participates_in+` - Employee involvement - `+measures+` - -What metrics track - `+belongs_to+` - Organizational membership - -`+influences+` - Initiative effects - -*Named Graph:* - `+causal_graph+` - Unified graph structure - -==== Virtuoso Ontology - -*Classes:* - `+pmt:Initiative+` - Corporate initiatives - -`+pmt:Outcome+` - Results - `+pmt:Employee+` (subclass of -`+foaf:Person+`) - `+pmt:Metric+` - Measurements - `+pmt:Department+` - -Org units - -*Properties:* - `+pmt:causes+` - Actual causation - `+pmt:intends+` - -Intended outcomes (key: this differs from `+causes+`) - `+pmt:measures+` -- Metric targets - `+pmt:participatesIn+` - Involvement - -`+pmt:belongsTo+` - Membership - `+pmt:intentionRealityGap+` - The core -metric - -=== Algorithms Implemented - -==== 1. Intention-Reality Gap Score - -.... -gapScore = min(100, - unintendedCount × 10 + - avgMetricGap × 50 + - (intendedCount === 0 ? 25 : 0) -) -.... - -==== 2. Gaming Detection - -Statistical analysis for: - Low variance (coefficient < 0.05) - -End-of-period spikes (>30% increase) - Target clustering (>60% near -target) - Large discontinuities (>20% jumps) - -Returns gaming probability (0-1) - -==== 3. Causal Path Strength - -.... -strength = geometricMean(edgeStrengths) - = (s₁ × s₂ × ... × sₙ)^(1/n) -.... - -Uses geometric mean because chain strength is limited by weakest link. - -==== 4. Metric Theater Score - -.... -theaterProbability = unlinkedMeasurements / totalMeasurements - -if collectionRate > 10 AND probability > 0.8: - verdict = "METRIC THEATER DETECTED" -.... - -==== 5. Department Synergy (with Irony) - -.... -synergyScore = wellness × 0.25 + - engagement × 0.25 + - productivity × 0.30 + - alignment × 0.20 - -if variance < 5 AND score > 85: - suspectedGaming = true - synergyScore *= 0.7 // Penalty for suspiciously perfect -.... - -=== The SynapCor Case Study - -A complete fictional company demonstrating every feature: - -*Company:* SynapCor Technologies, Inc. - 487 employees across 4 -departments - Enterprise SaaS company - Recent initiative: "`Synergy -Matrix™`" wellness program - -*Key Initiatives:* 1. *Wellness Wednesday* - Mandatory meditation - Gap -Score: 78/100 - Unintended: Meditation theater, black market for credits - -[arabic, start=2] -. *Radical Transparency Dashboard* - Public metrics -* Gap Score: 91/100 -* Unintended: Gaming, decreased collaboration, 3 resignations -. *Synergy Champions Program* - Recognition for high scores -* Gap Score: 83/100 -* Unintended: Two-tier culture, champions less productive - -*Notable Characters:* - Alex Rivera: Score 94/97, actually burned out, -interviewing elsewhere - Marcus Thompson: Score 52/48, shipped 3 -features, mentored 4 juniors - Michael Thompson (HR VP): Score 98/99, -designed the system - Robert Kim (CFO): Score 61/58, questioned ROI, -penalized - -The irony: Those gaming the system have high scores. Those doing good -work have low scores. The department that created the metrics has the -highest synergy. The department that questioned them has the lowest. - -=== How to Use - -==== Quick Start - -[source,bash] ----- -# 1. Start databases -podman-compose up -d - -# 2. Build ReScript -deno task build - -# 3. Start API server -deno task dev - -# 4. Load sample data -deno task load-data - -# 5. Run demo -./scripts/demo.sh ----- - -==== Example Queries - -[source,bash] ----- -# Find gameable metrics -curl http://localhost:3000/api/analytics/gameable-metrics - -# Detect metric theater -curl http://localhost:3000/api/analytics/metric-theater - -# Philosophical reflection -curl http://localhost:3000/api/reflection ----- - -=== Technical Highlights - -==== 1. Multi-Language Polyglot - -Each language chosen for its strengths: - *ReScript/Deno*: Sound types, -secure runtime, excellent DX - *Rust/WASM*: Near-native performance, -portable - *Julia*: Statistical computing, multiple dispatch - *AQL*: -Graph traversal - *SPARQL*: Semantic reasoning - -==== 2. Type Safety Throughout - -* ReScript sound type system (if it compiles, it works) -* Algebraic data types and exhaustive pattern matching -* Rust’s type system prevents entire classes of bugs - -==== 3. Philosophical Coherence - -The system maintains ironic distance while being technically rigorous: - -Comments acknowledge contradictions - Metrics question themselves - -Theater detection might itself be theater - The `+/reflection+` endpoint -is self-aware - -==== 4. Production-Ready Patterns - -* Health checks for databases -* Graceful shutdown handling -* Comprehensive error handling -* Test coverage -* Podman containerization -* Environment-based configuration - -=== What Makes This Special - -[arabic] -. *It’s complete*: Not a demo, a real system -. *It’s multi-paradigm*: Graph + Semantic + Statistical -. *It’s performant*: WASM for hot paths, Julia for heavy lifting -. *It’s tested*: Unit + integration tests -. *It’s documented*: Architecture, setup, case study, diagrams -. *It’s self-aware*: The system critiques itself - -Most importantly: *It actually works*. You can: - Run it locally with -Podman - Load the SynapCor data - Query for gaming patterns - Trace -causal paths - Measure intention-reality gaps - See the irony in action - -=== Potential Extensions - -The architecture supports: 1. *Machine Learning*: Predict unintended -consequences 2. *Real-time Streams*: Live metric ingestion 3. *NLP -Interface*: Query in natural language 4. *Temporal Analysis*: Track gaps -over time 5. *More Case Studies*: Different industries/scenarios 6. -*Visualization UI*: Interactive dashboards 7. *Alert System*: -Threshold-based notifications 8. *Multi-tenancy*: Separate orgs in one -instance - -=== The Meta-Question - -This system measures organizational delusion. But: - Can measurement -itself become delusion? - Does quantifying the gap change the gap? - Are -we building metric theater to detect metric theater? - -The architecture acknowledges these paradoxes without resolving them. -Sometimes the best answer is a rigorous question. - -=== Files Created - -30 new files, 4,874 lines of code: - 5 ReScript files - 2 Rust files - 2 -Julia files - 4 UML diagrams - 5 markdown documentation files - 4 -configuration files - 1 demo script - 1 Compose file - -=== Time Investment - -This represents approximately: - Architecture design: Deep thought about -multi-model systems - Implementation: Full-stack development across 4 -languages - Testing: Comprehensive test coverage - Documentation: -Architecture docs, setup guides, diagrams - Case study: Realistic -fictional scenario with narrative - -=== Final Thought - -_"`We’ve built a system to measure the gap between what organizations -say they value and what they actually incentivize. The system is -rigorous, the metrics are precise, and the irony is intentional. Whether -this is useful, meta-theater, or both is left as an exercise for the -reader.`"_ - -''''' - -Generated during an experimental autonomous development session. All -code is functional and ready to run. Review, test, and keep what works. +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Phantom Metal Taste — verified project summary +:toc: + +== Status + +This is an experimental repository, not a complete or production-ready +multi-model service. The conceptual design is broader than the code currently +implemented. In particular, there is no HTTP API, data loader, database client, +or end-to-end integration. + +== Implemented source + +* **Rust:** `src/core/` is a `wasm-bindgen` library in the root Cargo workspace; + tests are embedded in the Rust crate. +* **Julia:** the root `Project.toml` packages the analyses in `src/analytics/`; + `src/PhantomAnalytics.jl` exposes nested analysis modules and `test/` holds the + Julia test suite. +* **Bun:** `scripts/build-site.mjs` builds the static allowlisted site described + in `site.json`; its CLI helpers have Bun tests. +* **AffineScript:** `src/orchestrator/*.affine` remains TODO scaffolding. + +== Build and test + +```sh +./launcher.sh --setup +just build +just test +just site-check +just demo +``` + +The complete manual path is `docs/SETUP.adoc`. `compose.yml` is optional local +infrastructure and is not used by the current code. The diagrams, formal +specifications, and SynapCor case study are conceptual/design artefacts unless a +specific test or running implementation establishes otherwise. diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..08decbb --- /dev/null +++ b/Project.toml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +name = "PhantomAnalytics" +uuid = "253ec5e5-29f5-407b-8a6b-df2f6c3f78b6" +version = "0.1.0" + +[deps] +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" + +[compat] +Distributions = "0.25" +JSON3 = "1" +StatsBase = "0.34" +julia = "1.10" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/QUICKSTART.adoc b/QUICKSTART.adoc index a0b93c5..519c402 100644 --- a/QUICKSTART.adoc +++ b/QUICKSTART.adoc @@ -1,239 +1,71 @@ -== Phantom Metal Taste - Quickstart Guide +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Quick start +:toc: -Get up and running in 5 minutes. +This gets the *implemented pieces* of Phantom Metal Taste working locally. It +does not start an API or connect to the optional database containers: neither is +implemented in this checkout. -=== Prerequisites +== 1. Install the prerequisites -Install these first: - https://deno.land[Deno] - -`+curl -fsSL https://deno.land/install.sh | sh+` - -https://podman.io[Podman] - `+sudo dnf install podman podman-compose+` +Install Git and https://mise.jdx.dev/[mise] using your operating system's package +manager. If using Windows, run the steps inside WSL2. -=== Installation +== 2. Clone and provision [source,bash] ---- -# 1. Clone (or you already have it) +git clone https://github.com/hyperpolymath/phantom-metal-taste.git cd phantom-metal-taste - -# 2. Build ReScript code -deno task build - -# 3. Start databases (takes ~30 seconds) -podman-compose up -d - -# 4. Wait for databases to be healthy -podman-compose ps -# Both should show "healthy" status - -# 5. Start the API server -deno task dev ----- - -You should see: - -.... -✓ ArangoDB initialized -✓ Virtuoso initialized -✓ Server running at http://localhost:3000 -.... - -=== Load Sample Data - -In a new terminal: - -[source,bash] ----- -deno task load-data ----- - -This loads a complete fictional company with initiatives, outcomes, and -metrics. - -=== Try It Out - -==== 1. Health Check - -[source,bash] ----- -curl http://localhost:3000/health ----- - -==== 2. Find Gameable Metrics - -[source,bash] ----- -curl http://localhost:3000/api/analytics/gameable-metrics | jq ----- - -Looks for metrics with suspicious gaps between target and actual values. - -==== 3. Detect Metric Theater - -[source,bash] ----- -curl http://localhost:3000/api/analytics/metric-theater | jq ----- - -Finds metrics that are collected but never used. - -==== 4. Philosophical Reflection - -[source,bash] +mise trust +./launcher.sh --setup ---- -curl http://localhost:3000/api/reflection | jq ----- - -The system questions itself. - -==== 5. Run the Demo - -[source,bash] ----- -./scripts/demo.sh ----- - -Interactive demo of key features. - -=== Explore -==== Web Interfaces +The launcher installs the declared tools with mise, fetches Rust and Julia +packages, and checks the environment. Alternatively, if `just` is already +installed, run `just setup`. -* *ArangoDB*: http://localhost:8529 -** Login: `+root+` / `+phantom-dev-password+` -** Browse collections, run AQL queries -** View the causal graph visually -* *Virtuoso*: http://localhost:8890/conductor -** Login: `+dba+` / `+phantom-dev-password+` -** Run SPARQL queries -** Explore the ontology - -==== API Endpoints - -All endpoints return JSON: +== 3. Build and test [source,bash] ---- -# Create an initiative -curl -X POST http://localhost:3000/api/initiatives \ - -H "Content-Type: application/json" \ - -d '{ - "name": "My Test Initiative", - "description": "Testing the system", - "startDate": "2024-01-01T00:00:00Z", - "department": "Engineering", - "intendedOutcome": "Learn the system", - "status": "active", - "participants": [] - }' - -# Get gap analysis for an initiative (replace {id} with actual _key) -curl http://localhost:3000/api/analytics/gap/{id} | jq - -# Find unintended consequences -curl http://localhost:3000/api/initiatives/{id}/unintended | jq +just build +just test +just site-check ---- -=== Project Structure - -.... -phantom-metal-taste/ -├── src/ -│ ├── orchestrator/ # ReScript services -│ │ ├── Index.res # Main API entry point -│ │ ├── Config.res # Configuration -│ │ ├── Types.res # Type definitions -│ │ └── db/ # Database connections -│ ├── core/ # Rust/WASM modules -│ └── analytics/ # Julia statistical analysis -├── case-studies/ -│ └── synapcor/ # Sample company data -├── tests/ # Test suite -├── docs/ # Documentation -└── compose.yml # Database setup -.... - -=== Common Tasks - -==== Reset Everything +The test command runs the Rust crate tests, Julia package tests, and Bun's +site-builder tests. The build command builds the Rust workspace, precompiles the +Julia package, and creates `_site/` from the allowlist in `site.json`. -[source,bash] ----- -deno task db:reset # Deletes all data and restarts ----- - -==== Run Tests +== 4. Run the sample analysis [source,bash] ---- -deno task test +just demo ---- -==== Stop Databases +This prints example intention/reality, metric-gaming, and causal-analysis +results. No server, API keys, external data, or containers are needed. -[source,bash] ----- -podman-compose down ----- +== Optional local databases -==== View Logs +`compose.yml` is an infrastructure sketch, not an application dependency. To +run it, first export distinct, non-default local passwords: [source,bash] ---- -podman-compose logs -f arango -podman-compose logs -f virtuoso +export ARANGO_ROOT_PASSWORD="$(openssl rand -base64 32)" +export VIRTUOSO_DBA_PASSWORD="$(openssl rand -base64 32)" +just db-up ---- -=== Next Steps - -[arabic] -. Read the link:case-studies/synapcor/README.md[SynapCor Case Study] - -understand the fictional company -. Review link:docs/architecture/ARCHITECTURE.md[Architecture -Documentation] - deep dive into design -. Check link:docs/SETUP.md[Setup Guide] - comprehensive setup with -troubleshooting -. Read CLAUDE.md - guidelines for AI-assisted development - -=== Understanding the Data - -The SynapCor case study includes: - *Wellness Wednesday*: Meditation -program that created stress - *Transparency Dashboard*: Public metrics -that led to gaming - *Synergy Champions*: Recognition program that -decreased productivity - -Each demonstrates the gap between good intentions and actual outcomes. - -=== Philosophy - -This system measures organizational delusion by: 1. Tracking stated -intentions 2. Recording actual outcomes 3. Calculating the gap 4. -Detecting when metrics are gamed 5. Identifying when metrics become -theater - -The irony: A rigorous system to measure the limits of rigorous systems. - -=== Troubleshooting - -*Databases won’t start?* - -[source,bash] ----- -podman-compose down -v -podman-compose up -d ----- - -*API won’t connect to databases?* - Wait for "`healthy`" status: -`+podman-compose ps+` - Check logs: `+podman-compose logs arango+` - -*Port 3000 already in use?* - Change in `+.env+`: `+PORT=3001+` - -*Need help?* - See docs/SETUP.md for detailed troubleshooting - -=== That’s It! +Services bind to loopback only. The Rust/Julia code does not currently read or +write these databases. Stop them with `just db-down`. -You now have a working multi-model database system for measuring the gap -between corporate intentions and reality. Explore the APIs, query the -data, and contemplate the meta-ironies. +== Where to go next -_"`The map is not the territory, but sometimes the map reveals what the -territory conceals.`"_ +* link:docs/SETUP.adoc[Full setup, Guix route, and troubleshooting] +* link:docs/AI_INSTALLATION_GUIDE.adoc[AI-assisted installation] +* link:docs/architecture/ARCHITECTURE.adoc[Implementation map and limitations] diff --git a/README.adoc b/README.adoc index 5169754..94fa08c 100644 --- a/README.adoc +++ b/README.adoc @@ -1,249 +1,131 @@ // SPDX-License-Identifier: CC-BY-SA-4.0 -// Copyright (c) Jonathan D.A. Jewell +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell = Phantom Metal Taste -image:https://img.shields.io/badge/OpenSSF-Best_Practices-green?logo=openssourcesecurity[OpenSSF Best Practices,link="https://www.bestpractices.dev/en/projects/new?repo_url=https://github.com/hyperpolymath/phantom-metal-taste"] +:toc: +:toclevels: 2 -:toc: macro -:toclevels: 3 - -image:https://img.shields.io/badge/License-MPL_2.0-blue.svg[License: MPL-2.0,link="https://opensource.org/licenses/MPL-2.0"] -image:https://img.shields.io/badge/RSR-Platinum-e5e4e2.svg[RSR Compliance] -image:https://img.shields.io/badge/stack-ReScript%2BDeno-blueviolet.svg[Stack] -image:https://img.shields.io/badge/types-sound-brightgreen.svg[Type Safety] -image:https://img.shields.io/badge/memory-safe-brightgreen.svg[Memory Safety] +image:https://img.shields.io/badge/license-MPL--2.0-blue.svg[License: MPL-2.0,link="https://opensource.org/licenses/MPL-2.0"] +image:https://img.shields.io/badge/status-experimental-orange.svg[Experimental] [quote] ____ -The taste of metal in your mouth when nothing is there -- a phantom sensation that feels undeniably real yet fundamentally wrong. +The taste of metal in your mouth when nothing is there: a phantom sensation that feels undeniably real yet fundamentally wrong. ____ -toc::[] - -== What This Is - -*Phantom Metal Taste* is a multi-model database architecture for measuring the divergence between what organizations say they value and what they actually incentivize. - -Most enterprise analytics platforms measure success. This one measures the gap between intended success and actual outcomes -- including the outcomes nobody planned for, the metrics nobody acts on, and the reports nobody reads. - -It does this with the full rigor of enterprise architecture: formal ontologies, causal graph traversal, statistical gaming detection, and a type system that makes invalid states unrepresentable. Whether applying this rigor to the problem of organizational self-deception is itself a form of self-deception is left as an exercise for the reader. +== What this repository is -== Technical Architecture +*Phantom Metal Taste* explores how organisations can compare stated intentions +with observed outcomes, including unintended consequences and incentives that +may distort measurements. The repository is an *experimental collection of +libraries, analysis prototypes, and design material*—not a production service. -The system employs a polyglot stack, each language chosen for what it does well: +The current implementation is deliberately smaller than the conceptual design: [cols="1,2,3",options="header"] |=== -| Layer | Technology | Purpose +|Area |Current files |Status -| Orchestration -| ReScript / Deno -| Type-safe functional API with sound type system and secure runtime +|Rust core +|`src/core/` (workspace member under `src/core`) +|A small `wasm-bindgen` library with unit tests; optional WASM target. -| Performance -| Rust / WebAssembly -| Gap calculations, anomaly detection, causal path strength computation +|Julia analytics +|`src/analytics/`, packaged by root `Project.toml` +|Statistical and causal-analysis prototypes, with a package test suite. -| Analytics -| Julia -| Statistical gaming detection, causal inference, impact analysis +|Bun site tooling +|`scripts/build-site.mjs`, `site.json` +|Builds an allowlisted HTML index and publishes selected documentation sources verbatim; no third-party JavaScript dependencies. -| Graph Database -| ArangoDB -| Causal relationship traversal, organizational structure modeling +|Orchestration +|`src/orchestrator/*.affine` +|AffineScript TODO scaffolds only. Domain behavior and database bindings are not implemented. -| Semantic Web -| Virtuoso (OWL/RDF) -| Formal ontological reasoning over initiative-outcome relationships +|Databases +|`compose.yml` +|Optional local ArangoDB and Virtuoso containers. The current code does not connect to them. |=== -=== Why This Stack - -*ReScript* provides a sound type system: if the code compiles, the types are correct. There are no `any` escape hatches, no runtime type errors, no null pointer exceptions. In a system that measures the gap between claims and reality, it seemed appropriate that the code itself should make no false claims. - -*Deno* provides an explicit permissions model. The runtime cannot access the filesystem, network, or environment without declared permission. In a system that questions surveillance, the runtime practices what the system preaches. - -*Rust/WASM* handles the computationally intensive work: gap score calculations, causal path strength propagation, and anomaly detection. These run at near-native speed in a sandboxed WASM environment. - -*Julia* performs the statistical heavy lifting: variance analysis for gaming detection, t-tests for significance, correlation analysis for metric validity, and causal inference with confound control. - -See link:RESCRIPT_MIGRATION.md[RESCRIPT_MIGRATION.md] for the full migration rationale. - -== The SynapCor Case Study - -The system ships with a complete fictional case study: *SynapCor Technologies*, a 487-person enterprise SaaS company that implemented a data-driven wellness program called the Synergy Matrix. - -The case study includes two central figures: - -* *Chad Kensington*, VP of Human Synergy -- a true believer in the power of measurement to transform culture. He is not cynical. He is something more interesting than that. -* *Brenda Smith*, Senior Engineer -- whose actual productivity is in the top 5% of the org, whose Synergy Matrix score classifies her as "Siloed," and whose self-reported mood numbers have been strategically optimized. - -Three initiatives are documented in detail, each with formal requirements, intended outcomes, actual outcomes, and the growing divergence between what the dashboard shows and what actually happened. The system captures all of it. Whether anyone reads the output is a separate question. - -See link:case-studies/synapcor/README.md[the full case study] for details. - -== Modeling and Documentation - -This project includes enterprise-grade modeling artifacts that treat the subject matter with complete seriousness: +There is no HTTP API, server, data loader, or end-to-end database integration in +this checkout. The diagrams, TLA+ specifications, and SynapCor case study are +conceptual/design artefacts, not proof that those capabilities are running. -=== Data Flow Diagrams -* link:docs/diagrams/dfd-context.puml[DFD Level 0 (Context Diagram)] -- System boundary and external entity interactions -* link:docs/diagrams/dfd-detailed.puml[DFD Level 1 (Detailed)] -- Internal processes, data stores, and the process that captures what nobody intended +== Get started -=== Entity-Relationship Model -* link:docs/diagrams/er-diagram.puml[E-R Diagram] -- Full data model with `mood_self_report` vs `actual_mood_estimate` fields, `attendance_type` ENUM including `'theater'`, and metrics flagged `is_gamed` and `is_theater` +Install Git and https://mise.jdx.dev/[mise], then from a fresh checkout: -=== Behavioral Diagrams -* link:docs/diagrams/employee-state-machine.puml[Employee Mental State Machine] -- From "Cautiously Optimistic" through "Skeptical," "Resigned," and "Actively Subverting" to "Gaming the System" -* link:docs/diagrams/focus-sprint-failure.puml[Focus-Sprint Protocol Failure Sequence] -- What happens when you disable all communications and the production server catches fire - -=== Enterprise Architecture -* link:docs/architecture/TOGAF-ADM.adoc[TOGAF ADM] -- Full Architecture Development Method applied to the Synergy Matrix as an enterprise initiative, including a stakeholder table where the person most affected has the least influence -* link:docs/architecture/OMG-ODM-MOF.adoc[OMG ODM/MOF] -- Ontology Definition Metamodel and Meta Object Facility documentation, including a 4-layer metamodel where the data is correct at every layer and nobody in authority looks at it - -=== Additional Diagrams -* link:docs/diagrams/deployment-diagram.puml[Deployment Diagram] -- Infrastructure topology -* link:docs/diagrams/class-diagram.puml[Class Diagram] -- Domain model -* link:docs/diagrams/sequence-diagram.puml[Sequence Diagram] -- Interaction patterns -* link:docs/diagrams/use-case-diagram.puml[Use Case Diagram] -- System capabilities - -=== Formal Specifications -* link:specs/IntentionRealityGap.tla[IntentionRealityGap.tla] -- TLA+ specification proving gap calculation is bounded, monotonic, and deterministic -* link:specs/CausalGraph.tla[CausalGraph.tla] -- TLA+ specification proving the causal graph is acyclic and temporally ordered - -== Key Capabilities - -*Intention-Reality Gap Measurement*:: Quantifies the distance between stated goals and actual results. The score is bounded [0, 100], monotonically increasing with dysfunction, and formally verified in TLA+. - -*Causal Graph Traversal*:: Traces chains of causation from initiatives through intended and unintended outcomes. Path strength uses geometric mean -- a chain is only as strong as its weakest link. - -*Metric Gaming Detection*:: Statistical analysis identifying suspiciously low variance, end-of-period spikes, target clustering, and large discontinuities. Returns a gaming probability between 0 and 1. - -*Metric Theater Detection*:: Identifies metrics that are diligently collected, carefully stored, and never linked to any decision or action. - -*Department Synergy Scoring*:: Composite wellness/engagement/productivity/alignment score with a penalty for suspiciously perfect numbers. Departments that score too consistently high are flagged, not celebrated. - -== Getting Started - -=== Prerequisites - -1. *Deno* (v1.40+): -+ [source,bash] ---- -curl -fsSL https://deno.land/install.sh | sh +git clone https://github.com/hyperpolymath/phantom-metal-taste.git +cd phantom-metal-taste +mise trust +./launcher.sh --setup +just validate +just demo ---- -2. *ReScript compiler*: -+ -[source,bash] ----- -npm install -g rescript ----- +A complete GitHub source archive can also be extracted and set up without its +Git history; keep hidden tracked files such as `.well-known/` and `.github/`. +The setup doctor still requires the Git executable, but normal build and test +commands use the checked-in manifests. `just setup` installs the declared +toolchain and project dependencies; `just doctor` explains missing tools. The launcher also exposes `--doctor`, `--heal`, +`--ai-setup`, and `--help`. For OS-specific manual steps and the Guix route, see +link:docs/SETUP.adoc[docs/SETUP.adoc]. + +Useful tasks: + +* `just build` — build the Rust workspace, precompile Julia, and build the site. +* `just test` — run Rust, Julia, and Bun tests. +* `just site-check` — build the allowlisted site twice and compare outputs. +* `just wasm-build` — build the optional `wasm32-unknown-unknown` target. +* `just demo` — run a deterministic Julia analytics example. +* `just db-up` / `just db-down` — optional local containers; they are not wired to the code. + +== Toolchain and provisioning + +* `mise.toml` declares `just`, `shellcheck`, Rust, Julia, and Bun. Tool requests + use `latest`; the estate requires a generated `mise.lock` before claiming a + reproducible toolchain. That lock has not yet been generated in this checkout: + the sandbox cannot reach mise's Julia version metadata host. Until the lock is + committed, setup resolves current tool releases and requires network access. +* `manifest.scm` and `channels.scm` define the Guix development shell. Guix + provides the system tools and Rust; `mise install` supplies the Julia and Bun + versions declared by the project. +* `guix.scm` is an honest source-package definition for this mixed-language + repository. It installs the checkout as source; it does not claim to build an + application executable. +* The project task runner is `Justfile`; the shared provisioning engine is in + `build/just/`. `docs/AI_INSTALLATION_GUIDE.adoc` and the onboarding warm-ups + explain first-time setup. -3. *Podman & podman-compose*: For database containers +== Documentation -4. *Rust* (stable): For WASM modules +* link:QUICKSTART.adoc[Quick start] +* link:docs/SETUP.adoc[Complete setup and troubleshooting] +* link:docs/AI_INSTALLATION_GUIDE.adoc[AI installation guide] +* link:docs/architecture/ARCHITECTURE.adoc[Current implementation map and limitations] +* link:TEST-NEEDS.adoc[Current test coverage and gaps] +* link:case-studies/synapcor/README.adoc[Conceptual SynapCor case study] +* link:RSR_COMPLIANCE.adoc[Measured RSR/provisioning status] -5. *Julia* (v1.9+): For statistical analysis +Older ReScript/Deno setup material has been retired. The old migration filename +is retained only as a short notice pointing at the current stack and status. -=== Quick Start +[[ai-install]] +== AI-assisted installation -[source,bash] +[source,text] ---- -# Build the ReScript code -deno task build - -# Start databases -podman-compose up -d - -# Run the API server -deno task dev - -# Load the SynapCor case study data -deno task load-data - -# Run the interactive demo -./scripts/demo.sh +Set up phantom-metal-taste from https://github.com/hyperpolymath/phantom-metal-taste by following docs/AI_INSTALLATION_GUIDE.adoc. ---- -See link:QUICKSTART.md[QUICKSTART.md] for the 5-minute guide, or link:docs/SETUP.md[docs/SETUP.md] for comprehensive setup with troubleshooting. - -== Documentation - -[cols="1,3",options="header"] -|=== -| Document | Description - -| link:QUICKSTART.md[QUICKSTART.md] -| Get running in 5 minutes - -| link:docs/SETUP.md[docs/SETUP.md] -| Comprehensive setup with troubleshooting - -| link:docs/architecture/ARCHITECTURE.md[ARCHITECTURE.md] -| Deep architectural documentation - -| link:docs/architecture/TOGAF-ADM.adoc[TOGAF-ADM.adoc] -| Enterprise architecture (TOGAF ADM) - -| link:docs/architecture/OMG-ODM-MOF.adoc[OMG-ODM-MOF.adoc] -| Ontology and metamodel documentation - -| link:RESCRIPT_MIGRATION.md[RESCRIPT_MIGRATION.md] -| Why ReScript + Deno - -| link:PROJECT_SUMMARY.md[PROJECT_SUMMARY.md] -| Complete technical overview - -| link:case-studies/synapcor/README.md[SynapCor Case Study] -| The fictional company that makes everything concrete - -| link:RSR_COMPLIANCE.md[RSR_COMPLIANCE.md] -| Rhodium Standard Repository compliance matrix -|=== - == Contributing -Contributions are welcome. Before submitting a PR, please ensure: - -* ReScript code compiles without warnings -* All tests pass: `deno task test` -* Rust code passes `cargo clippy -- -D warnings` -* Documentation is updated -* The philosophical tone is maintained -- the system takes itself seriously so the reader does not have to - -See link:.github/CONTRIBUTING.md[CONTRIBUTING.md] for detailed guidelines. - -== Disclaimer - -Prolonged exposure to this system's output may cause: - -* An irresistible urge to audit your own organization's metrics -* Suspicion that your wellness program is measuring the wrong things -* The realization that the map was never the territory -* A faint metallic taste - -These effects are considered features, not bugs. +Read link:https://github.com/hyperpolymath/phantom-metal-taste/blob/main/.github/CONTRIBUTING.md[contribution guidelines] and the current link:https://github.com/hyperpolymath/phantom-metal-taste/blob/main/CLAUDE.md[agent notes]. Before sending a change, run `just validate` when +the required local toolchains are available, and describe any unavailable gate +rather than reporting it as passed. == License -This project is licensed under the Mozilla Public License, v. 2.0. See the `LICENSE` file for details. - -SPDX-License-Identifier: CC-BY-SA-4.0 - -== The Question This System Asks - -What happens when you build an enterprise-grade, formally verified, multi-model database system to measure the precise distance between what organizations claim to value and what they actually reward? - -The architecture is rigorous. The types are sound. The proofs are mechanically checked. The gap scores are bounded and monotonic. The causal graphs are acyclic. - -The data is all there. It has always been there. - -The question was never whether we could measure it. - ---- - -[quote] -____ -The map is not the territory, but sometimes the map reveals what the territory conceals. -____ +Source is licensed under MPL-2.0. Documentation is licensed under CC-BY-SA-4.0. +See `LICENSE`, `LICENSES/`, and file headers for details. diff --git a/RESCRIPT_MIGRATION.adoc b/RESCRIPT_MIGRATION.adoc index 3495d9d..c44dcb9 100644 --- a/RESCRIPT_MIGRATION.adoc +++ b/RESCRIPT_MIGRATION.adoc @@ -1,466 +1,19 @@ -== Migration to ReScript + Deno - -This document describes the architectural migration from -TypeScript/Bun/npm to ReScript + Deno. - -=== Why ReScript? - -*ReScript* is a robustly typed functional programming language that -compiles to highly optimized JavaScript. Benefits: - -==== 1. Type Safety - -* *Sound type system* - no `+any+`, no `+undefined+` surprises -* *100% type coverage* - if it compiles, it works -* *Fast compiler* - instant feedback loop - -==== 2. Functional Paradigm - -* *Immutable by default* - prevents entire classes of bugs -* *Pattern matching* - exhaustive case handling -* *Algebraic data types* - model complex domains precisely - -==== 3. Performance - -* *Zero-cost abstractions* - compiles to clean, readable JavaScript -* *Tree-shaking friendly* - small bundle sizes -* *Optimized output* - faster than hand-written JS - -==== 4. JavaScript Interop - -* *Seamless FFI* - call any JavaScript library -* *Gradual adoption* - mix ReScript and JS -* *External bindings* - type-safe wrappers for APIs - -=== Why Deno? - -*Deno* is a modern, secure JavaScript/TypeScript runtime. Benefits: - -==== 1. Security First - -* *Explicit permissions* - no file/network access by default -* *Sandboxed execution* - granular control -* *Secure by design* - no package.json vulnerabilities - -==== 2. Built-in Tools - -* *Test runner* - `+deno test+` -* *Formatter* - `+deno fmt+` -* *Linter* - `+deno lint+` -* *Bundler* - `+deno bundle+` - -==== 3. Modern Standards - -* *ES modules* - native import/export -* *Web APIs* - fetch, URL, streams -* *TypeScript native* - no build step needed - -==== 4. No node_modules - -* *URL imports* - fetch dependencies directly -* *No package.json* - simpler dependency management -* *Version in URL* - explicit, immutable - -=== Architecture Changes - -==== Before (TypeScript + Bun + npm) - -.... -TypeScript source (.ts files) - ↓ -tsc (TypeScript compiler) - ↓ -JavaScript output - ↓ -Bun runtime - ↓ -node_modules dependencies -.... - -==== After (ReScript + Deno) - -.... -ReScript source (.res files) - ↓ -rescript (ReScript compiler) - ↓ -JavaScript output (.bs.js files) - ↓ -Deno runtime - ↓ -URL-based dependencies -.... - -=== File Structure Changes - -==== Removed Files - -* ❌ `+package.json+` - npm configuration -* ❌ `+tsconfig.json+` - TypeScript configuration -* ❌ `+node_modules/+` - npm dependencies -* ❌ `+*.ts+` files - TypeScript source - -==== Added Files - -* ✅ `+deno.json+` - Deno configuration -* ✅ `+bsconfig.json+` - ReScript configuration -* ✅ `+*.res+` files - ReScript source -* ✅ `+*.bs.js+` files - Compiled JavaScript (gitignored) - -=== Dependency Management - -==== Before (npm) - -[source,json] ----- -{ - "dependencies": { - "arangojs": "^8.8.1", - "hono": "^3.11.7" - } -} ----- - -==== After (Deno import maps) - -[source,json] ----- -{ - "imports": { - "hono/": "https://deno.land/x/hono@v3.11.7/", - "std/": "https://deno.land/std@0.208.0/" - } -} ----- - -=== Type System Comparison - -==== TypeScript - -[source,typescript] ----- -interface Initiative { - _key?: string; - name: string; - status: 'planned' | 'active' | 'completed' | 'abandoned'; -} - -function createInitiative(init: Initiative): Promise { - // Implementation - could return undefined, throw, etc. -} ----- - -==== ReScript - -[source,rescript] ----- -type initiativeStatus = Planned | Active | Completed | Abandoned - -type initiative = { - key: option, - name: string, - status: initiativeStatus, -} - -let createInitiative = async (init: initiative): promise => { - // Implementation - type system guarantees return type -} ----- - -*Key Differences:* - ReScript uses variants (`+Planned | Active+`) -instead of string unions - `+option<'a>+` instead of `+T | undefined+` - -No implicit `+null+` or `+undefined+` - Pattern matching ensures -exhaustive handling - -=== External Bindings - -ReScript interops with JavaScript through external bindings: - -[source,rescript] ----- -// Deno API bindings -module Deno = { - module Env = { - @val @scope("Deno.env") - external get: string => option = "get" - } -} - -// Usage -let port = Deno.Env.get("PORT") ----- - -This provides type-safe access to JavaScript APIs. - -=== Development Workflow - -==== Install Prerequisites - -[source,bash] ----- -# Install ReScript compiler -npm install -g rescript - -# Install Deno -curl -fsSL https://deno.land/install.sh | sh ----- - -==== Build and Run - -[source,bash] ----- -# Build ReScript → JavaScript -deno task build - -# Run with Deno -deno task dev - -# Or combined -deno task build && deno task dev ----- - -==== Watch Mode - -ReScript has fast incremental compilation: - -[source,bash] ----- -# Terminal 1: Watch ReScript files -rescript build -w - -# Terminal 2: Run with Deno watch -deno task dev ----- - -==== Testing - -[source,bash] ----- -# Run Deno tests -deno task test - -# Or with permissions -deno test --allow-net --allow-env --allow-read tests/ ----- - -=== Migration Steps Performed - -==== 1. Configuration - -* ✅ Created `+deno.json+` with tasks and import maps -* ✅ Created `+bsconfig.json+` for ReScript compiler -* ✅ Removed `+package.json+` and `+tsconfig.json+` - -==== 2. Type Definitions - -* ✅ Converted TypeScript interfaces to ReScript types -* ✅ Created `+Types.res+` with algebraic data types -* ✅ Added helper functions for type conversions - -==== 3. Core Modules - -* ✅ Created `+Config.res+` for environment configuration -* ✅ Created `+Bindings.res+` for JavaScript FFI -* ✅ Converted `+ArangoDb.ts+` → `+ArangoDb.res+` -* ⏳ VirtuosoDb module (in progress) - -==== 4. Services - -* ⏳ InitiativeService conversion -* ⏳ AnalyticsService conversion -* ⏳ VisualizationService conversion - -==== 5. API Layer - -* ⏳ HTTP server with Deno -* ⏳ Route handlers in ReScript -* ⏳ JSON serialization/deserialization - -==== 6. Documentation - -* ✅ This migration guide -* ⏳ Updated README.md -* ⏳ Updated SETUP.md -* ⏳ Updated architecture docs - -=== Advantages of This Migration - -==== 1. Type Safety - -*Before (TypeScript):* - -[source,typescript] ----- -const gap = calculateGap(initiative); -// Could be undefined, null, throw exception, etc. ----- - -*After (ReScript):* - -[source,rescript] ----- -let gap = calculateGap(initiative) -// Type system guarantees this is a valid result -// Impossible states are unrepresentable ----- - -==== 2. No Runtime Errors - -ReScript’s type system prevents: - `+undefined is not a function+` - -`+Cannot read property 'x' of undefined+` - Type coercion bugs - Null -pointer exceptions - -==== 3. Better Performance - -* Smaller bundle sizes -* Faster execution -* Zero-cost abstractions -* Dead code elimination - -==== 4. Enhanced Security (Deno) - -* Explicit permissions model -* No implicit file system access -* No implicit network access -* Secure by default - -==== 5. Simpler Dependency Management - -* No `+node_modules+` folder -* No package-lock.json conflicts -* Explicit version in imports -* Faster cold starts - -=== Philosophical Alignment - -This migration aligns with the project’s philosophy: - -*Phantom Metal Taste* measures the gap between intention and reality. -The migration to ReScript + Deno: - -[arabic] -. *Reduces gaps* - Sound type system eliminates undefined behavior -. *Makes intentions explicit* - Algebraic data types model domain -precisely -. *Prevents gaming* - Impossible to "`game`" the type system -. *Embraces rigor* - Functional programming enforces discipline - -The irony: We’re using the most rigorous tools to critique -organizational rigor. - -=== What Stays the Same - -* ✅ *Rust/WASM modules* - unchanged, still performance-critical -* ✅ *Julia analytics* - unchanged, still statistical heavy lifting -* ✅ *ArangoDB* - same database, same queries -* ✅ *Virtuoso* - same RDF/semantic layer -* ✅ *Docker Compose* - same infrastructure -* ✅ *API endpoints* - same REST interface -* ✅ *SynapCor case study* - same sample data - -=== Performance Characteristics - -==== ReScript Compilation - -* *~1ms per file* - instant feedback -* *Incremental* - only changed files rebuild -* *Parallel* - multi-core compilation - -==== Deno Runtime - -* *Fast startup* - no node_modules scan -* *V8 engine* - same as Node.js/Bun -* *Native TypeScript* - no build step for TS - -==== Bundle Size - -ReScript typically produces *30-50% smaller* bundles than equivalent -TypeScript due to: - Better tree-shaking - Optimized output - No -polyfills needed - -=== Debugging - -==== ReScript - -[source,bash] ----- -# Compiler errors are excellent -rescript build - -# Example error: -# File "src/Types.res", line 42: -# This has type: option -# But expected: string ----- - -==== Deno - -[source,bash] ----- -# Built-in debugger -deno run --inspect src/Index.bs.js - -# Stack traces include source maps ----- - -=== Migration Status - -==== Completed ✅ - -* Configuration files -* Type definitions -* External bindings -* ArangoDB module -* Main entry point -* This documentation - -==== In Progress ⏳ - -* Virtuoso module -* Service layer -* API routes -* Test suite conversion - -==== Remaining 📋 - -* Full HTTP server implementation -* Request/response handling -* Visualization endpoints -* Integration tests -* Updated setup guide - -=== Running the Migrated Version - -[source,bash] ----- -# 1. Install ReScript -npm install -g rescript - -# 2. Build ReScript code -deno task build - -# 3. Start databases -docker-compose up -d - -# 4. Run the server -deno task dev ----- - -=== Conclusion - -This migration represents a significant architectural improvement: - -* *More type-safe* - eliminates runtime type errors -* *More functional* - immutable, pure functions -* *More secure* - Deno’s permission model -* *More performant* - optimized compilation -* *Simpler dependencies* - no node_modules - -The ReScript + Deno stack is well-suited for a project that values -rigor, precision, and philosophical consistency while maintaining the -ability to critique systems that claim the same. - -''''' - -_"`We replaced TypeScript with ReScript because sound type systems -prevent the gaps we’re trying to measure. The meta-irony continues.`"_ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Retired runtime and migration record + +[WARNING] +==== +This file's former ReScript/Deno setup guide is retired and has been removed. +It described tools, API routes, and tests that are not present in the repository. +Do not use it to install or run the project. +==== + +The old instructions are superseded by the current RSR language policy and the +actual repository setup. The supported development tools are declared in +`mise.toml`; start at link:docs/SETUP.adoc[docs/SETUP.adoc] or +link:README.adoc[README.adoc]. + +The remaining files in `src/orchestrator/` are AffineScript TODO scaffolds. They +do not establish that a semantic application migration has been completed; see +link:docs/architecture/ARCHITECTURE.adoc[current implementation status]. diff --git a/RSR_COMPLIANCE.adoc b/RSR_COMPLIANCE.adoc index b483b20..e0b0e7c 100644 --- a/RSR_COMPLIANCE.adoc +++ b/RSR_COMPLIANCE.adoc @@ -1,349 +1,40 @@ -== RSR (Rhodium Standard Repository) Compliance - -=== Current Compliance Level: 🏆 PLATINUM - -*Achievement Date:* 2024-11-22 *Certificate ID:* -RSR-PLATINUM-2024-1122-PMT *Valid Until:* 2025-11-22 - -This project implements the Rhodium Standard Repository (RSR) framework -at the *highest level - Platinum*, achieving excellence across all 18 -categories including advanced formal verification, performance -optimization, accessibility, and community sustainability. - -See PLATINUM_UPGRADE.md for complete certification details. - -=== Compliance Matrix - -[width="100%",cols="33%,25%,21%,21%",options="header",] -|=== -|Category |Status |Level |Notes -|*1. Documentation* |✅ Complete |Bronze |All required docs present -|*2. Type Safety* |✅ Complete |Bronze+ |ReScript + Rust (sound types) -|*3. Memory Safety* |✅ Complete |Bronze+ |Rust ownership, zero unsafe -|*4. Offline-First* |✅ Complete |Bronze |Air-gap capable -|*5. Build System* |✅ Complete |Bronze |Justfile + flake.nix + CI/CD -|*6. Testing* |⚠️ Partial |Bronze |Tests exist, coverage improving -|*7. Security* |✅ Complete |Bronze+ |10-dimensional security model -|*8. .well-known/* |✅ Complete |Bronze |RFC 9116 compliant -|*9. TPCF* |✅ Complete |Bronze |Perimeter 3 (Community Sandbox) -|*10. Reproducibility* |✅ Complete |Bronze |Nix flakes -|*11. License* |✅ Complete |Bronze |MPL-2.0 -|=== - -*Overall: 10/11 complete, 1 in progress = BRONZE* - -''''' - -=== 1. Documentation ✅ - -*Required:* - [x] README.md - Comprehensive project overview - [x] -LICENSE - MPL-2.0 - [x] SECURITY.md - 10-dimensional security policy - -[x] CODE_OF_CONDUCT.md - Contributor Covenant 2.1 - [x] CONTRIBUTING.md -- Contribution guidelines - [x] MAINTAINERS.md - Team and governance - -[x] CHANGELOG.md - Version history (Keep a Changelog format) - -*Additional:* - [x] QUICKSTART.md - 5-minute getting started - [x] -RESCRIPT_MIGRATION.md - Architectural decisions - [x] PROJECT_SUMMARY.md -- Complete technical overview - [x] docs/SETUP.md - Detailed setup guide -- [x] docs/architecture/ARCHITECTURE.md - Deep technical dive - [x] -CLAUDE.md - AI development guidelines - -''''' - -=== 2. Type Safety ✅ - -*Language:* ReScript (sound type system) - -*Features:* - ✅ 100% type coverage (no `+any+`, no escape hatches) - ✅ -Algebraic data types (variants, options, results) - ✅ Pattern matching -(exhaustive) - ✅ No null/undefined (option types instead) - ✅ Type -inference (minimal annotations) - ✅ Sound type system (if it compiles, -it works) - -*Example:* - -[source,rescript] ----- -type initiativeStatus = Planned | Active | Completed | Abandoned - -type initiative = { - key: option, - status: initiativeStatus, -} - -// Impossible to create invalid states ----- - -''''' - -=== 3. Memory Safety ✅ - -*Language:* Rust (WASM modules) - -*Features:* - ✅ Ownership model (compile-time memory management) - ✅ -Zero unsafe blocks in production code - ✅ Bounds checking on array -access - ✅ No use-after-free bugs - ✅ No data races (thread safety) - -✅ WASM sandboxing (additional isolation) - -*Verification:* - -[source,bash] ----- -cd src/core -cargo check -grep -r "unsafe" src/ # Should return nothing in lib code ----- - -''''' - -=== 4. Offline-First ✅ - -*Architecture:* Local-first, air-gap capable - -*Implementation:* - ✅ No required network calls in core functionality - -✅ Local database instances (ArangoDB + Virtuoso) - ✅ All data stored -locally - ✅ Can run completely disconnected after initial setup - ✅ No -telemetry or phone-home - ✅ Reproducible builds (Nix) - -*Test:* - -[source,bash] ----- -# Start system -just db-up -just dev - -# Disconnect network -# System continues to function - -# Reconnect -# System syncs if needed ----- - -''''' - -=== 5. Build System ✅ - -*Tools:* Justfile + flake.nix + deno.json + GitLab CI - -*Recipes (20+):* - ✅ `+just build+` - Build ReScript code - ✅ -`+just test+` - Run all tests - ✅ `+just dev+` - Development server - -✅ `+just db-up+` - Start databases - ✅ `+just rsr-verify+` - Verify -RSR compliance - ✅ `+just validate+` - Full validation (checks + tests) -- ✅ `+just wasm-build+` - Build Rust→WASM - ✅ `+just clean+` - Clean -artifacts - ✅ `+just nuke+` - Nuclear clean - -*Nix:* - ✅ Declarative dependencies - ✅ Reproducible builds - ✅ Dev -shell with all tools - ✅ Multiple package outputs - -*CI/CD:* - ✅ GitLab CI configuration - ✅ Multi-stage pipeline -(validate, build, test, security, deploy) - ✅ Artifact caching - ✅ -Security scanning - -''''' - -=== 6. Testing ⚠️ - -*Status:* Partial (improving to full coverage) - -*Implemented:* - ✅ Deno test runner integration - ✅ Rust unit tests -(cargo test) - ✅ Julia test framework - ✅ Test directory structure - -*In Progress:* - ⏳ Increase coverage to 90%+ - ⏳ Integration tests -with databases - ⏳ Property-based testing - ⏳ Performance benchmarks - -*Target:* Bronze requires tests exist and pass. Silver requires 90%+ -coverage. - -''''' - -=== 7. Security ✅ - -*Model:* 10-dimensional security (see SECURITY.md) - -*Dimensions:* 1. ✅ Type Safety (ReScript - no runtime type errors) 2. -✅ Memory Safety (Rust - ownership model) 3. ✅ Runtime Security (Deno - -explicit permissions) 4. ✅ Database Security (parameterized queries, -auth) 5. ✅ Input Validation (schema validation, domain types) 6. ✅ -Dependency Security (minimal deps, URL imports) 7. ✅ Data Privacy -(GDPR-compliant, anonymization) 8. ✅ Supply Chain Security -(reproducible builds, signed commits) 9. ✅ Air-Gap Capable -(offline-first) 10. ✅ Defense in Depth (multiple layers) - -*Verification:* - -[source,bash] ----- -just rsr-verify # Includes security checklist ----- - -''''' - -=== 8. .well-known/ Directory ✅ - -*Standards:* RFC 9116 + humanstxt.org - -*Files:* - ✅ `+security.txt+` - RFC 9116 compliant security contact - -✅ `+ai.txt+` - AI training and usage policy - ✅ `+humans.txt+` - -Attribution and credits - -*Validation:* - -[source,bash] ----- -ls -la .well-known/ -# Should show: security.txt, ai.txt, humans.txt ----- - -''''' - -=== 9. TPCF (Tri-Perimeter Contribution Framework) ✅ - -*Current Perimeter:* *Level 3 - Community Sandbox* - -*Levels:* - *Perimeter 1:* Core Team (commit access, architecture -decisions) - *Perimeter 2:* Verified Contributors (triage, review PRs) - -*Perimeter 3:* Community Sandbox (open source, fork-and-PR) - -*Current Status:* - ✅ Perimeter 3 active (all contributors welcome) - -✅ Governance documented (MAINTAINERS.md) - ✅ Code of Conduct enforced -- ✅ Clear path to Perimeter 2/1 - -*Progression:* - To P2: 5+ PRs, 3+ months active, 2 endorsements - To -P1: 6+ months P2, deep expertise, unanimous vote - -''''' - -=== 10. Reproducibility ✅ - -*Tool:* Nix flakes - -*Features:* - ✅ Declarative dependencies (flake.nix) - ✅ Pinned -versions (flake.lock) - ✅ Hermetic builds - ✅ Cross-platform support - -✅ Dev shell environment - -*Usage:* - -[source,bash] ----- -# Enter development environment -nix develop - -# Build project -nix build - -# Run checks -nix flake check ----- - -''''' - -=== 11. License ✅ - -*License:* MPL-2.0 (Palimpsest License) - -*Structure:* - -.... -Primary: Palimpsest License (MPL-2.0) -.... - -*Palimpsest Restrictions:* - ❌ No surveillance capitalism - ❌ No labor -rights erosion - ❌ No weaponization - ❌ No privacy violation - -*Compliance:* - ✅ LICENSE file present - ✅ License headers in source -files (optional but recommended) - ✅ Third-party licenses documented - -''''' - -=== Verification Commands - -[source,bash] ----- -# Quick RSR check -just rsr-verify - -# Full validation (all checks + tests) -just validate - -# Nix checks -nix flake check - -# Manual verification -ls -1 README.md LICENSE SECURITY.md CODE_OF_CONDUCT.md \ - CONTRIBUTING.md MAINTAINERS.md CHANGELOG.md ----- - -''''' - -=== Upgrade Path to Silver - -To achieve *Silver* level: - -*Required Improvements:* 1. *Test Coverage:* 90%+ (currently partial) 2. -*Formal Verification:* Add SPARK proofs or TLA+ specs (optional but -recommended) 3. *Performance Benchmarks:* Documented performance -characteristics 4. *Accessibility:* WCAG 2.1 AA compliance (when UI -exists) 5. *I18n:* Internationalization support 6. *Advanced Security:* -Penetration testing reports, CVE monitoring - -*Timeline:* Q1 2025 target for Silver - -''''' - -=== Upgrade Path to Gold - -To achieve *Gold* level: - -*Required:* 1. *Production Deployment:* Live production usage 2. -*Community Growth:* 10+ external contributors 3. *Ecosystem -Integration:* Published packages, integrations 4. *Research -Publications:* Academic papers or conference talks 5. *Security Audits:* -Third-party professional audit 6. *Sustainability:* Long-term -maintenance plan, funding - -*Timeline:* Q3 2025 target for Gold - -''''' - -=== Compliance Badges - -[source,markdown] ----- -![RSR Compliance](https://img.shields.io/badge/RSR-Bronze-cd7f32) -![Type Safety](https://img.shields.io/badge/types-sound-brightgreen) -![Memory Safety](https://img.shields.io/badge/memory-safe-brightgreen) -![Offline First](https://img.shields.io/badge/offline-capable-blue) -![TPCF](https://img.shields.io/badge/TPCF-Perimeter%203-yellow) ----- - -image:https://img.shields.io/badge/RSR-Bronze-cd7f32[RSR Compliance] -image:https://img.shields.io/badge/types-sound-brightgreen[Type Safety] -image:https://img.shields.io/badge/memory-safe-brightgreen[Memory -Safety] image:https://img.shields.io/badge/offline-capable-blue[Offline -First] -image:https://img.shields.io/badge/TPCF-Perimeter%203-yellow[TPCF] - -''''' - -=== Contact - -*RSR Questions:* rsr@phantom-metal-taste.org *General Questions:* -hello@phantom-metal-taste.org - -''''' - -=== References - -* *RSR Framework:* -https://github.com/example/rhodium-minimal[rhodium-minimal example] -* *TPCF:* See MAINTAINERS.md -* *Security:* See SECURITY.md -* *Contributing:* See CONTRIBUTING.md - -''''' - -_"`Compliance is not a checkbox. It’s a commitment to rigor, safety, and -community.`"_ - -Last updated: 2024-11-22 +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += RSR conformance status (measured) +:toc: + +[WARNING] +==== +The former Platinum certificate and compliance matrix were unsupported and +expired. This page replaces those claims with the current implementation and +known provisioning gaps. It is not a certification. +==== + +== Current evidence + +* The repository follows the current estate language direction: Rust, Julia, + and Bun toolchain declarations; no Deno or ReScript source/workflow remains. +* Root setup is provided by `Justfile`, `launcher.sh`, and the canonical + provisioning module under `build/just/`. +* Guix files declare a pinned development shell and a source package. +* GitHub workflows include Rust CI, Julia tests, Bun/site checks, governance, + security scanning, and a Pages builder restricted by `site.json`. +* `.well-known/security.txt`, `ai.txt`, and `humans.txt` are checked in and + explicitly included in the published-site allowlist. +* `Cargo.lock` is tracked. `mise.lock` and `.github/workflows/actions.lock` are + still outstanding generated artefacts; do not claim those lock gates pass. +* The AffineScript orchestrator remains unimplemented. There is no API, + database integration, full integration suite, or measured coverage percentage. + +== Open remediation gates + +. Generate and review `mise.lock` with the official mise CLI on a machine that + can reach mise's release metadata endpoints. +. Generate and verify `.github/workflows/actions.lock` with `gh actions-lock` + v0.1.6; do not hand-maintain it. +. Run the Rust and Julia gates in an environment with those runtimes installed. +. Reconcile issue #77 only after fresh default-branch workflow evidence. + +See the current source map in +link:docs/architecture/ARCHITECTURE.adoc[docs/architecture/ARCHITECTURE.adoc] and +the detailed setup in link:docs/SETUP.adoc[docs/SETUP.adoc]. diff --git a/SECURITY.adoc b/SECURITY.adoc index 1bbe0fa..9ea19e3 100644 --- a/SECURITY.adoc +++ b/SECURITY.adoc @@ -1,161 +1,38 @@ -== Security Policy +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Security policy +:toc: -=== Supported Versions +== Reporting vulnerabilities -[cols=",",options="header",] -|=== -|Version |Supported -|0.1.x |:white_check_mark: -|=== +Please report suspected vulnerabilities privately through GitHub's Security +Advisories for this repository. Do not post exploit details, credentials, or +private data in public issues. Include a concise impact description and a +reproduction that does not expose real user information. -=== Reporting a Vulnerability +== Current security boundary -*DO NOT* open public issues for security vulnerabilities. +This repository currently ships an experimental Rust library, Julia analysis +prototypes, and a Bun static-site builder. It does not ship an HTTP API or +production service. The optional ArangoDB/Virtuoso compose setup is local-only, +requires user-supplied non-default passwords, and binds published ports to +loopback. The current application code does not connect to those containers. -==== Reporting Process +Do not infer API authentication, rate limiting, access controls, database +security, or runtime sandboxing from old architecture documents. Those controls +are not implemented because the corresponding service is not implemented. -[arabic] -. *Email*: Send vulnerability details to -security@phantom-metal-taste.org (or repository owner) -. *PGP*: Use our PGP key (see `+.well-known/security.txt+`) if available -. *Response Time*: We aim to respond within 48 hours -. *Disclosure*: Coordinated disclosure after fix (typically 90 days) +== Dependencies and secrets -==== What to Include +* Keep Cargo dependencies locked in `Cargo.lock`; use mise's generated lock only + after creating it with the official CLI. +* Workflow actions must be immutable commit pins or covered by a generated, + verified `.github/workflows/actions.lock`. +* Never commit `.env`, passwords, private keys, tokens, or production data. +* Keep the Bun site publisher restricted to the reviewed allowlist in `site.json`. -* *Description*: Clear explanation of the vulnerability -* *Impact*: What an attacker could achieve -* *Reproduction*: Step-by-step instructions -* *Affected Versions*: Which versions are vulnerable -* *Suggested Fix*: If you have one (optional) +== Supported tools -==== Security Considerations - -This project implements multi-layered security: - -===== 1. Type Safety (ReScript) - -* Sound type system eliminates runtime type errors -* Algebraic data types prevent impossible states -* No `+null+` or `+undefined+` bugs - -===== 2. Memory Safety (Rust/WASM) - -* Zero unsafe blocks in production code -* Ownership model prevents use-after-free -* Bounds checking on all array access - -===== 3. Runtime Security (Deno) - -* Explicit permissions model (`+--allow-net+`, `+--allow-read+`, -`+--allow-env+`) -* Sandboxed execution -* No implicit file system or network access - -===== 4. Database Security - -* Parameterized queries prevent SQL/AQL injection -* Authentication required for all database operations -* Encrypted connections (TLS) - -===== 5. Input Validation - -* All external inputs validated at API boundaries -* Schema validation with domain types -* Rate limiting on public endpoints - -===== 6. Dependency Security - -* Minimal dependencies (zero for Rust/WASM core) -* URL-based imports in Deno (explicit versions) -* Regular security audits - -===== 7. Data Privacy - -* Employee data can be anonymized -* GDPR-compliant data deletion -* Access control by role -* Audit logging - -===== 8. Supply Chain Security - -* Reproducible builds (see `+flake.nix+`) -* Signed commits (GPG) -* Verified dependencies - -===== 9. Air-Gap Capable - -* Can run fully offline after initial setup -* No telemetry or phone-home -* Local-first architecture - -===== 10. Defense in Depth - -* Multiple security layers -* Fail-safe defaults -* Principle of least privilege - -=== Security Features by Design - -==== Offline-First Architecture - -The system is designed to work without network access: - All critical -functionality available offline - No required external API calls - Local -database instances - -==== Immutable Infrastructure - -* Podman containers with pinned versions -* Declarative configuration -* Version-controlled infrastructure - -==== Audit Trail - -All sensitive operations are logged: - Database queries - Authentication -attempts - Permission changes - Data modifications - -=== Known Security Limitations - -[arabic] -. *Development Environment*: Default passwords in `+.env.example+` are -for development only -. *Database Exposure*: ArangoDB and Virtuoso web UIs exposed on -localhost in dev mode -. *No Built-in Authentication*: API endpoints currently have no auth -(add reverse proxy with auth) -. *Demo Data*: SynapCor case study contains synthetic but realistic -organizational data - -=== Security Roadmap - -Future enhancements: - [ ] OAuth2/OIDC integration - [ ] Role-based -access control (RBAC) - [ ] Encryption at rest for sensitive data - [ ] -Security scanning in CI/CD - [ ] Penetration testing reports - [ ] CVE -monitoring and auto-patching - -=== Compliance - -==== Standards Adherence - -* *OWASP Top 10*: Mitigations for all categories -* *RFC 9116*: security.txt in `+.well-known/+` -* *CIS Benchmarks*: Container hardening -* *NIST Cybersecurity Framework*: Identify, Protect, Detect, Respond, -Recover - -==== License Compliance - -This project uses: - Palimpsest License (MPL-2.0) - -See LICENSE file for details. - -=== Contact - -* *General Security*: security@phantom-metal-taste.org -* *PGP Key*: See `+.well-known/security.txt+` -* *Security Advisories*: GitHub Security Advisories (when published) - -''''' - -_"`Security is not a product, but a process. This document is part of -that process.`"_ +Use the toolchain and setup steps in `mise.toml` and `docs/SETUP.adoc`. New +runtime/build paths must follow current +https://github.com/hyperpolymath/standards[estate policy]. diff --git a/TEST-NEEDS.adoc b/TEST-NEEDS.adoc index c436d46..6e08569 100644 --- a/TEST-NEEDS.adoc +++ b/TEST-NEEDS.adoc @@ -1,65 +1,47 @@ -== TEST-NEEDS.md — phantom-metal-taste +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Test coverage and remaining needs +:toc: -=== CRG Grade: C — ACHIEVED 2026-04-04 +== Current suites -=== Current Test State - -[width="100%",cols="42%,29%,29%",options="header",] -|=== -|Category |Count |Notes -|Rust unit tests |4 |`+src/core/src/lib.rs+` `+#[cfg(test)]+` — all -passing - -|Julia tests |0 |`+src/analytics/+` — no test suite yet - -|ReScript tests |0 |`+src/orchestrator/+` — no test suite yet - -|Integration tests |0 |Requires ArangoDB + Virtuoso (containers) +[cols="1,2,3",options="header"] |=== +|Area |Test location |Current gate -=== What’s Covered +|Rust core +|`src/core/src/lib.rs` unit tests +|`cargo test --locked --all-targets`, Clippy, and rustfmt through the shared Rust CI. -* [x] `+calculate_metric_gaps+` — parses JSON, returns gap structs -* [x] `+calculate_path_strength+` — geometric mean of edge weights -* [x] `+calculate_synergy_score+` — penalises suspiciously uniform high -scores -* [x] `+phantom_metal_taste_score+` — composite score from -outcome/gap/theater inputs +|Julia analytics +|`test/runtests.jl` +|`julia --project=. -e 'using Pkg; Pkg.test()'` via Julia CI. -=== CI Gate +|Bun site builder +|`scripts/build-site.test.js` +|`bun test`; site artifact is built and compared across two runs. -[source,bash] ----- -cd src/core && cargo test ----- +|AffineScript orchestration +|`src/orchestrator/*.affine` +|No compiler/test gate: current files are incomplete TODO scaffolds. -=== Known Failures / Limitations - -* `+wasm-bindgen+` dependency: tests compile via `+rlib+` but WASM -target untested -* `+calculate_metric_gaps+` test only checks string presence, not parsed -values -* `+detect_metric_anomalies+` and `+detect_metric_theater+` have no test -coverage -* Julia analytics (`+src/analytics/+`) untested -* ReScript orchestrator (`+src/orchestrator/+`) untested -* Integration tests require running ArangoDB + Virtuoso containers -* `+benchmarks/gap_calculation.bench.ts+` — TypeScript (banned language) - -=== Still Missing (for CRG B+) - -* [ ] Tests for `+detect_metric_anomalies+` and -`+detect_metric_theater+` -* [ ] Julia test suite for `+causal_inference.jl+` and -`+impact_analysis.jl+` -* [ ] ReScript/Deno tests for orchestrator layer -* [ ] Migrate `+benchmarks/gap_calculation.bench.ts+` from TypeScript to -Deno -* [ ] 6+ diverse external targets (CRG B requirement) - -=== Run Tests +|Database integration +|None +|No integration tests. The optional containers are not connected to source code. +|=== -[source,bash] ----- -cd src/core && cargo test ----- +== Limits and follow-up + +* Rust WASM target compilation is optional and has not been replayed locally in + this environment; use `just wasm-build` where rustup and the target are available. +* Julia tests were added with the root package setup but could not be executed in + the current sandbox because Julia is not installed. CI is the first runtime + execution gate; do not report the suite as locally passed until run. +* The analytics tests are smoke/contract tests, not statistical validation or + coverage evidence. Numerical edge cases, missing data, collinearity, and + decision thresholds need domain review. +* The AffineScript semantic port needs a separate behavior specification, a + supported compiler/toolchain, and tests before any TODO scaffold is treated + as implemented. +* Database integration tests require actual clients, schemas, fixtures, and + explicit security decisions; merely starting containers is not coverage. diff --git a/build/just/provision-check.sh b/build/just/provision-check.sh new file mode 100755 index 0000000..2666842 --- /dev/null +++ b/build/just/provision-check.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# provision-check.sh — offline conformance check for the provisioning set +# (PROVISIONING-STANDARD.adoc §8, items 1–5). No network, no installs. +# +# provision-check.sh [--dev] [REPO_DIR] +# +# Exit 0 = conforms, 1 = does not. Every failure is printed; none is skipped. +# --dev downgrades repository-specific slot residue (__SPEC_X__) to a warning, +# for a checkout mid-specialisation. Mechanical residue (__X__) always fails. +set -uo pipefail + +HERE=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +LIB="$HERE/provision-lib.sh" +DEV=0 +[ "${1:-}" = "--dev" ] && { DEV=1; shift; } +REPO="${1:-.}" +cd "$REPO" || { echo "provision-check: no such directory: $REPO" >&2; exit 1; } + +MIN_JUST="1.42.0" +VERBS="setup doctor heal dev-shell toolchain-refresh ai-setup ai-warmup eval config-show opsm build test bench lint fmt fmt-check run deps" +# Files the provisioning set owns; residue anywhere else is not ours to judge. +# The engine scripts under build/just/ are excluded: they name slot syntax in their +# own comments and code, and realign owns them. README.adoc is scanned only inside +# its [[ai-install]] section. +# Their locations come from provision-lib.sh (guix-dir, set-files): the engine and +# this check must never disagree about where the Guix files or warm-ups live. +[ -f "$LIB" ] || { echo "provision-check: engine missing: $LIB" >&2; exit 1; } +lib() { PROVISION_ROOT="$PWD" bash "$LIB" "$@"; } +GDIR=$(lib guix-dir) +SET_FILES=$(lib set-files) +gp() { [ "$GDIR" = . ] && echo "$1" || echo "$GDIR/$1"; } + +fails=0 warns=0 +ok() { printf ' ok %s\n' "$*"; } +bad() { printf ' FAIL %s\n' "$*"; fails=$((fails + 1)); } +warn() { printf ' warn %s\n' "$*"; warns=$((warns + 1)); } + +version_ge() { [ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -1)" = "$2" ]; } + +echo "[1] launcher" +if [ ! -f launcher.sh ]; then bad "launcher.sh missing" +elif [ ! -x launcher.sh ]; then bad "launcher.sh is not executable (chmod +x; committed mode must be 100755)" +else + for m in --help --version; do + if ./launcher.sh "$m" >/dev/null 2>&1; then ok "launcher.sh $m exits 0" + else bad "launcher.sh $m exits non-zero"; fi + done +fi + +echo "[2] just" +f0=$fails +if ! command -v just >/dev/null 2>&1; then bad "just is not installed; cannot check the recipe contract" +else + jv=$(just --version 2>/dev/null | awk '{print $2}') + if version_ge "$jv" "$MIN_JUST"; then ok "just $jv >= $MIN_JUST" + else bad "just $jv < $MIN_JUST (module-recipe dependencies do not resolve)"; fi + if ! summary=$(just --summary 2>&1); then + bad "the Justfile does not parse: $(printf '%s' "$summary" | head -1)" + else + have=" $summary " + for v in $VERBS; do + case "$have" in *" $v "*) ;; *) bad "root recipe missing: $v" ;; esac + case "$have" in *" provision::$v "*) ;; *) bad "module recipe missing: provision::$v (engine drift)" ;; esac + done + [ "$fails" -eq "$f0" ] && ok "all ${VERBS// /, } present at root and in provision::" + fi +fi + +echo "[3] mise" +if [ ! -f mise.toml ]; then bad "mise.toml missing" +else + if hit=$(lib mise-banned); then ok "mise.toml names no banned tool"; else bad "mise.toml names banned tools: $hit"; fi + [ -f .mise.toml ] && bad "both mise.toml and .mise.toml exist" + if lg=$(lib mise-lock-gaps); then ok "mise.lock pins every mise.toml tool"; else bad "$lg (latest is not concrete; run: mise lock)"; fi +fi + +echo "[4] guix" +for g in "$(gp guix.scm)" "$(gp manifest.scm)" "$(gp channels.scm)"; do + if r=$(lib guix-stub "$g"); then ok "$g is not a stub"; else bad "$g: $r"; fi +done + +echo "[5] template residue" +f0=$fails +residue() { # $1 label; stdin = the text to judge + local text mech spec + text=$(cat) + # Mechanical slots (__X__ not starting SPEC_) are the generator's job: always fatal. + mech=$(printf '%s\n' "$text" | grep -noE '__[A-Z][A-Z_]*__' | grep -v ':__SPEC_' | head -3 | tr '\n' ' ') + spec=$(printf '%s\n' "$text" | grep -noE '__SPEC_[A-Z_]*__' | head -3 | tr '\n' ' ') + [ -n "$mech" ] && bad "$1: unfilled mechanical slots: $mech" + if [ -n "$spec" ]; then + if [ "$DEV" = 1 ]; then warn "$1: unfilled repository slots: $spec" + else bad "$1: unfilled repository slots: $spec"; fi + fi +} +for f in $SET_FILES; do + # shellcheck disable=SC2094 # $f is only the label; nothing writes it + [ -f "$f" ] && residue "$f" < "$f" +done +for r in README.adoc README.md; do + [ -f "$r" ] || continue + # From the [[ai-install]] anchor to the next level-2 heading after its own. + residue "$r [[ai-install]]" < <(awk '/^\[\[ai-install\]\]/{on=1; n=0} on && /^== /{n++; if (n>1) exit} on' "$r") +done +[ "$fails" -eq "$f0" ] && ok "no residue that fails this mode" + +echo +echo "provision-check: $fails FAIL, $warns WARN" +[ "$fails" -eq 0 ] diff --git a/build/just/provision-lib.sh b/build/just/provision-lib.sh new file mode 100755 index 0000000..fb1d942 --- /dev/null +++ b/build/just/provision-lib.sh @@ -0,0 +1,832 @@ +#!/usr/bin/env bash +# SC2015: `A && pass || fail` is safe here — pass/warn/fail/info always return 0. +# shellcheck disable=SC2015 +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# provision-lib.sh — the shared provisioning engine behind build/just/provision.just +# +# Canon: hyperpolymath/standards 3-practice/provisioning/PROVISIONING-STANDARD.adoc +# Vendored into every repo at build/just/provision-lib.sh by `provision-set mint`. +# DO NOT hand-edit a vendored copy: repo-specific facts live in +# .machine_readable/descriptiles/provisioning_praxis.deed, and `provision-set realign` +# overwrites this file from canon. +# +# Usage: provision-lib.sh [args] +# verbs: langs doctor setup heal dev-shell toolchain-refresh crates-scm ai-setup +# ai-warmup eval config-show opsm lang-run +# search version +# facts: guix-specs mise-tools langs guix-dir set-files guix-gaps tool-table +# system-deps +# predicates (print why and exit 1, or exit 0 silently): +# guix-stub FILE, mise-lock-gaps, mise-banned +# +# Exit: 0 ok | 1 a FAIL was found / a step failed | 2 usage error +set -uo pipefail + +PROVISION_LIB_VERSION="0.5.0" +ROOT="${PROVISION_ROOT:-$(pwd)}" +cd "$ROOT" || exit 2 +DEED=".machine_readable/descriptiles/provisioning_praxis.deed" +MIN_JUST="1.42.0" # root→module recipe deps (`doctor: provision::doctor`); 1.41 rejects them +# How to get mise: package managers first; the installer only as download, read, run. +MISE_INSTALL_HINT="brew install mise | Fedora: dnf copr enable jdxcode/mise, dnf install mise | winget install jdx.mise | others: https://mise.jdx.dev/installing-mise.html — or: curl -fsSLo mise-install.sh https://mise.run, read it, sh mise-install.sh" +T="timeout 15" # some --version probes hang (observed 2026-09-30); never probe unbounded + +if [ -t 1 ]; then R=$'\033[31m'; G=$'\033[32m'; Y=$'\033[33m'; B=$'\033[34m'; Z=$'\033[0m'; else R=; G=; Y=; B=; Z=; fi +PASS=0; WARN=0; FAIL=0 +pass() { PASS=$((PASS+1)); printf ' %sPASS%s %s\n' "$G" "$Z" "$*"; } +warn() { WARN=$((WARN+1)); printf ' %sWARN%s %s\n' "$Y" "$Z" "$*"; } +fail() { FAIL=$((FAIL+1)); printf ' %sFAIL%s %s\n' "$R" "$Z" "$*"; } +info() { printf ' %sinfo%s %s\n' "$B" "$Z" "$*"; } +hdr() { printf '\n%s== %s ==%s\n' "$B" "$*" "$Z"; } +have() { command -v "$1" >/dev/null 2>&1; } + +# Where this repository keeps each part of the set. A file sits at the root only +# when something needs it there (launcher.sh, Justfile, mise.toml, mise.lock); +# the Guix trio and the warm-ups follow the layout the repository already has +# (rsr-template-repo keeps build/guix.scm and docs/onboarding/llm-warmup-*.adoc). +# This is the ONE answer: provision-check.sh asks it through `guix-dir` and +# `set-files` rather than keeping its own copy. +guix_dir() { if [ -f build/guix.scm ]; then echo build; else echo .; fi; } +warmup_dir() { + local d + for d in . docs/onboarding docs; do + compgen -G "$d/llm-warmup-*.adoc" >/dev/null && { echo "$d"; return; } + done + echo . +} +gpath() { local d; d=$(guix_dir); [ "$d" = . ] && echo "$1" || echo "$d/$1"; } +wpath() { local d; d=$(warmup_dir); [ "$d" = . ] && echo "llm-warmup-$1.adoc" || echo "$d/llm-warmup-$1.adoc"; } +set_files() { + printf '%s\n' launcher.sh Justfile justfile mise.toml \ + "$(gpath guix.scm)" "$(gpath manifest.scm)" "$(gpath channels.scm)" \ + "$DEED" docs/SETUP.adoc docs/AI_INSTALLATION_GUIDE.adoc \ + "$(wpath user)" "$(wpath dev)" "$(wpath maintainer)" +} + +# --------------------------------------------------------------------------- +# Descriptor: flat `:key "value"` reads from provisioning_praxis.deed (s-expression). +deed() { # $1 key, $2 default + local v="" + [ -f "$DEED" ] && v=$(grep -oE "\(:?$1[[:space:]]+\"[^\"]*\"" "$DEED" 2>/dev/null | head -1 | sed -E 's/^[^"]*"//; s/"$//') + [ -z "$v" ] && v=$(grep -oE ":$1[[:space:]]+\"[^\"]*\"" "$DEED" 2>/dev/null | head -1 | sed -E 's/^[^"]*"//; s/"$//') + printf '%s' "${v:-$2}" +} +repo_slug() { + local u; u=$(git config --get remote.origin.url 2>/dev/null || true) + u=${u%.git}; u=${u#*github.com[:/]} + [ -n "$u" ] && printf '%s' "$u" || printf 'hyperpolymath/%s' "$(basename "$ROOT")" +} +REPO_SLUG="$(deed repo "$(repo_slug)")" +REPO_NAME="${REPO_SLUG#*/}" +ARCHETYPE="$(deed archetype "")" + +# --------------------------------------------------------------------------- +# Language detection. Markers at the root or one level down (workspaces). The +# estate ABI/FFI pattern nests deeper: Idris2 to two levels down (src/abi/*.ipkg), +# Zig to three (ffi/zig/build.zig, and rsr-template-repo's src/interface/ffi/build.zig: +# 74 repos have their only build.zig at that depth, measured 2026-09-30). +# Order matters only for display. `docs` is reported when nothing else is. +first() { find . -maxdepth "${2:-2}" -not -path './.git/*' -not -path '*/node_modules/*' -not -path './target/*' -name "$1" -print -quit 2>/dev/null; } +detect_langs() { + local out=() + [ -n "$(first Cargo.toml)" ] && out+=(rust) + [ -n "$(first '*.ipkg' 3)" ] && out+=(idris2) + [ -n "$(first Project.toml 1)" ] && out+=(julia) + [ -n "$(first build.zig 4)" ] && out+=(zig) + [ -n "$(first mix.exs)" ] && out+=(elixir) + [ -n "$(first gleam.toml)" ] && out+=(gleam) + [ -n "$(first dune-project)" ] && out+=(ocaml) + { [ -n "$(first '*.cabal')" ] || [ -n "$(first stack.yaml 1)" ]; } && out+=(haskell) + [ -n "$(first package.json)" ] && out+=(bun) + [ ${#out[@]} -eq 0 ] && out+=(docs) + printf '%s\n' "${out[@]}" +} +mapfile -t LANGS < <(detect_langs) +[ -z "$ARCHETYPE" ] && { [ "${LANGS[*]}" = docs ] && ARCHETYPE=docs || ARCHETYPE=library; } + +# Binaries each language needs, and how each is obtained. +# mise registry gaps (verified 2026-09-30 against mise 2026.7.5): ocaml, haskell, +# idris2 and guile are NOT mise tools. They come from opam / ghcup / pack / the +# system package manager (or Guix), and the doctor probes the binary itself. +lang_tools() { + case "$1" in + rust) echo "cargo rustc" ;; + idris2) echo "idris2" ;; + julia) echo "julia" ;; + zig) echo "zig" ;; + elixir) echo "elixir mix erl" ;; + gleam) echo "gleam erl" ;; + ocaml) echo "opam dune ocaml" ;; + haskell) echo "ghc cabal" ;; + bun) echo "bun" ;; + docs) echo "" ;; + esac +} +# Guix package specs per language (verified 2026-09-30 against guix ae77aeb in +# docker.io/metacall/guix). Guix has NO idris2, gleam, bun or lychee, and its +# julia is 1.8.5: those come from mise, which Guix itself ships ("mise"). +GUIX_BASE="git bash coreutils nss-certs just mise shellcheck" +lang_guix() { + case "$1" in + rust) echo "rust rust:cargo gcc-toolchain pkg-config" ;; + idris2) echo "chez-scheme gmp gcc-toolchain" ;; + zig) echo "zig" ;; + elixir) echo "elixir erlang" ;; + gleam) echo "erlang" ;; + ocaml) echo "ocaml dune opam ocaml-findlib" ;; + haskell) echo "ghc cabal-install" ;; + docs) echo "ruby-asciidoctor" ;; + julia|bun) echo "" ;; + esac +} +# Tools a Guix shell cannot supply, so mise (inside that shell) does. +lang_guix_gap() { + case "$1" in + idris2) echo "idris2 (via pack)" ;; julia) echo julia ;; gleam) echo gleam ;; bun) echo bun ;; docs) echo lychee ;; + esac +} +guix_specs() { + local l s=" $GUIX_BASE " + for l in "${LANGS[@]}"; do for p in $(lang_guix "$l"); do case "$s" in *" $p "*) ;; *) s="$s$p ";; esac; done; done + echo "$s" | xargs +} + +# mise tools per language (registry-checked 2026-09-30, mise 2026.7.5). idris2 comes +# from pack and haskell from ghcup or Guix: neither is a mise tool. The recipes +# themselves need just and shellcheck, so those two are always declared. +MISE_BASE="just shellcheck" +# Tools a repo's own recipes call (e.g. `deps-audit` runs trivy): pinned only where used. +RECIPE_TOOLS="trivy" +lang_mise() { case "$1" in + rust) echo "rust" ;; zig) echo "zig" ;; julia) echo "julia" ;; + elixir) echo "erlang elixir" ;; gleam) echo "erlang gleam" ;; ocaml) echo "opam" ;; + bun) echo "bun" ;; docs) echo "lychee" ;; esac; } +recipe_tools() { + local t f body="" + for f in Justfile justfile build/just/*.just; do + [ -f "$f" ] && body+=$(grep -v '^[[:space:]]*#' "$f")$'\n' + done + for t in $RECIPE_TOOLS; do + [[ "$body" =~ (^|[^[:alnum:]_-])$t([^[:alnum:]_-]|$) ]] && echo "$t" + done +} + +mise_tools() { + local l t seen=" " out=() + for t in $MISE_BASE $(for l in "${LANGS[@]}"; do lang_mise "$l"; done) $(recipe_tools); do + case "$seen" in *" $t "*) ;; *) out+=("$t"); seen="$seen$t " ;; esac + done + printf "%s\n" "${out[*]}" +} + +lang_remedy() { + case "$1" in + rust) echo "mise use rust@latest (or rustup: https://rustup.rs)" ;; + idris2) echo "install pack: https://github.com/stefan-hoeck/idris2-pack#installation, then: pack install-app idris2" ;; + julia) echo "mise use julia@latest (or: https://julialang.org/install/ — juliaup)" ;; + zig) echo "mise use zig@latest" ;; + elixir) echo "mise use erlang@latest elixir@latest (erlang builds from source: allow ~10 min)" ;; + gleam) echo "mise use gleam@latest erlang@latest" ;; + ocaml) echo "mise use opam@latest && opam init -y && opam switch create . --deps-only -y" ;; + haskell) echo "ghcup: https://www.haskell.org/ghcup/ (or: just dev-shell, which uses Guix)" ;; + bun) echo "mise use bun@latest" ;; + esac +} + +# The per-language default for each contract verb. A repo overrides any of +# these simply by defining the root recipe itself; `provision-set` only adds +# `: provision::` where the root Justfile has no such recipe. +lang_cmd() { # $1 lang, $2 verb -> prints a shell command, or nothing (= N/A) + local l=$1 v=$2 ipkg + case "$l:$v" in + rust:deps) echo "cargo fetch" ;; + rust:build) echo "cargo build --all-targets" ;; + rust:test) echo "cargo test --all-targets" ;; + rust:bench) grep -rqs '\[\[bench\]\]\|criterion\|divan' --include=Cargo.toml . && echo "cargo bench" ;; + rust:lint) echo "cargo clippy --all-targets -- -D warnings" ;; + rust:fmt) echo "cargo fmt --all" ;; + rust:fmt-check) echo "cargo fmt --all -- --check" ;; + rust:run) echo "cargo run --release" ;; + + idris2:*) + ipkg=$(first '*.ipkg' 1); [ -z "$ipkg" ] && ipkg=$(first '*.ipkg'); [ -z "$ipkg" ] && ipkg=$(first '*.ipkg' 3); ipkg=${ipkg#./} + case "$v" in + deps) have pack && echo "pack install-deps $ipkg" ;; + build) have pack && echo "pack build $ipkg" || echo "idris2 --build $ipkg" ;; + test) local t; t=$(find . -maxdepth 3 -name 'test*.ipkg' -print -quit 2>/dev/null) + if [ -n "$t" ]; then have pack && echo "pack test ${t#./}" || echo "idris2 --build ${t#./}" + else have pack && echo "pack typecheck $ipkg" || echo "idris2 --typecheck $ipkg"; fi ;; + run) grep -qs '^[[:space:]]*executable' "$ipkg" && { have pack && echo "pack run $ipkg" || echo "idris2 --build $ipkg && ./build/exec/*"; } ;; + esac ;; + + julia:deps) echo "julia --project=. -e 'using Pkg; Pkg.instantiate()'" ;; + julia:build) echo "julia --project=. -e 'using Pkg; Pkg.precompile()'" ;; + julia:test) echo "julia --project=. -e 'using Pkg; Pkg.test()'" ;; + julia:bench) [ -f benchmark/benchmarks.jl ] && echo "julia --project=benchmark -e 'using Pkg; Pkg.develop(path=\".\"); Pkg.instantiate(); include(\"benchmark/benchmarks.jl\")'" ;; + + zig:*) + # build.zig may sit in ffi/zig/; run there, not at the root. + local zb zd; zb=$(first build.zig 1); [ -z "$zb" ] && zb=$(first build.zig); [ -z "$zb" ] && zb=$(first build.zig 3); [ -z "$zb" ] && zb=$(first build.zig 4) + zd=$(dirname "${zb#./}"); local cdz=""; [ "$zd" != . ] && cdz="cd '$zd' && " + case "$v" in + build) echo "${cdz}zig build" ;; + test) grep -qs '"test"' "$zb" && echo "${cdz}zig build test" ;; + bench) grep -qs '"bench"' "$zb" && echo "${cdz}zig build bench -Doptimize=ReleaseFast" ;; + fmt) echo "zig fmt $zd" ;; + fmt-check) echo "zig fmt --check $zd" ;; + lint) echo "zig fmt --check $zd" ;; + run) grep -qs '"run"' "$zb" && echo "${cdz}zig build run" ;; + esac ;; + + elixir:deps) echo "mix local.hex --force --if-missing && mix local.rebar --force --if-missing && mix deps.get" ;; + elixir:build) echo "mix compile --warnings-as-errors" ;; + elixir:test) echo "mix test" ;; + elixir:bench) ls bench/*.exs >/dev/null 2>&1 && echo "for f in bench/*.exs; do mix run \"\$f\"; done" ;; + elixir:lint) grep -qs ':credo' mix.exs && echo "mix credo --strict" || echo "mix compile --warnings-as-errors" ;; + elixir:fmt) echo "mix format" ;; + elixir:fmt-check) echo "mix format --check-formatted" ;; + elixir:run) echo "mix run --no-halt" ;; + + gleam:deps) echo "gleam deps download" ;; + gleam:build) echo "gleam build" ;; + gleam:test) echo "gleam test" ;; + gleam:fmt) echo "gleam format" ;; + gleam:fmt-check) echo "gleam format --check" ;; + gleam:lint) echo "gleam format --check" ;; + gleam:run) echo "gleam run" ;; + + ocaml:deps) echo "opam install . --deps-only --with-test -y" ;; + ocaml:build) echo "opam exec -- dune build" ;; + ocaml:test) echo "opam exec -- dune test" ;; + ocaml:fmt) echo "opam exec -- dune fmt" ;; + ocaml:fmt-check) echo "opam exec -- dune build @fmt" ;; + + haskell:deps) echo "cabal update && cabal build all --only-dependencies" ;; + haskell:build) echo "cabal build all" ;; + haskell:test) echo "cabal test all" ;; + haskell:bench) grep -qs '^benchmark' ./*.cabal && echo "cabal bench all" ;; + haskell:run) echo "cabal run" ;; + + bun:deps) [ -f bun.lock ] || [ -f bun.lockb ] && echo "bun install --frozen-lockfile" || echo "bun install" ;; + bun:build) grep -qs '"build"[[:space:]]*:' package.json && echo "bun run build" ;; + # `bun test` exits 0 when it finds no test files, so it runs only when some exist. + bun:test) if grep -qs '"test"[[:space:]]*:' package.json; then echo "bun run test" + elif git ls-files 2>/dev/null | grep -qE '(\.|_)(test|spec)\.(js|mjs|cjs|jsx)$'; then echo "bun test"; fi ;; + bun:bench) grep -qs '"bench"[[:space:]]*:' package.json && echo "bun run bench" ;; + bun:lint) grep -qs '"lint"[[:space:]]*:' package.json && echo "bun run lint" ;; + bun:fmt) grep -qs '"fmt"[[:space:]]*:' package.json && echo "bun run fmt" ;; + bun:fmt-check) grep -qs '"fmt-check"[[:space:]]*:' package.json && echo "bun run fmt-check" ;; + bun:run) grep -qs '"start"[[:space:]]*:' package.json && echo "bun run start" ;; + + docs:test) have asciidoctor && echo "for f in \$(git ls-files '*.adoc'); do asciidoctor -o /dev/null --failure-level=WARN \"\$f\" || exit 1; done" ;; + docs:lint) have lychee && echo "lychee --offline --no-progress \$(git ls-files '*.adoc' '*.md')" ;; + esac +} + +# Run a contract verb across every detected language. N/A is reported, not +# faked green: a verb with no command for any language exits 0 but SAYS so. +lang_run() { # $1 verb + local verb=$1 ran=0 rc=0 l cmd override + override=$(deed "$verb" "") + if [ -n "$override" ]; then + info "$verb (from provisioning_praxis.deed): $override" + bash -c "$override"; return $? + fi + for l in "${LANGS[@]}"; do + cmd=$(lang_cmd "$l" "$verb") + [ -z "$cmd" ] && continue + ran=1 + info "$verb [$l]: $cmd" + bash -c "$cmd" || { rc=$?; printf ' %sFAIL%s %s [%s] exited %s\n' "$R" "$Z" "$verb" "$l" "$rc" >&2; } + done + [ $ran -eq 0 ] && info "$verb: N/A for ${LANGS[*]} (archetype: $ARCHETYPE) — nothing to run, and nothing was faked" + return $rc +} + +# --------------------------------------------------------------------------- +# A repo keeps its own checks as root recipes named doctor-local / setup-local / +# heal-local (provision-set renames a pre-existing custom doctor/setup/heal to +# these); the canon verbs run them, so `just doctor`, `./launcher.sh --doctor` and +# CI all see the same result. +has_recipe() { have just && just --summary 2>/dev/null | tr " " "\n" | grep -qx "$1"; } + +version_ge() { [ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -1)" = "$2" ]; } + +# Tools that must never appear in a repo's toolchain (estate language policy). +BANNED_TOOLS='python|deno|node|nodejs|npm|yarn|pnpm|typescript|rescript|make|black|ruff|pip|poetry|nix|go|golang|java|kotlin' + +# --------------------------------------------------------------------------- +# Shared predicates. doctor and provision-check.sh both call THESE (the check via +# `provision-lib.sh guix-stub|mise-lock-gaps|mise-banned`): a gate with its own +# copy of a test passes what doctor warns about. + +# The keys of mise.toml [tools], quotes stripped ("cargo:foo" stays cargo:foo). +mise_toml_tools() { + [ -f mise.toml ] || return 0 + awk '/^\[tools\]/{t=1;next} /^\[/{t=0} t && /=/{sub(/[ \t]*=.*/,""); gsub(/["\x27 ]/,""); print}' mise.toml +} +# Banned tools named in mise.toml; a backend prefix does not hide one ("aqua:denoland/deno" is deno). +mise_banned() { + local t base hits="" + for t in $(mise_toml_tools); do + base=${t##*:}; base=${base%%@*}; base=${base##*/} + [[ "$base" =~ ^($BANNED_TOOLS)$ ]] && hits="$hits$t " + done + printf '%s' "${hits% }" +} +# Why mise.lock does not pin mise.toml, or nothing when it does. Presence is not +# enough: a zero-byte lock pins nothing. Every [tools] key needs its [[tools.]] +# entry, and the lock must carry checksums. +mise_lock_gaps() { + [ -f mise.toml ] || return 0 + [ -f mise.lock ] || { echo "mise.lock missing"; return; } + [ -s mise.lock ] || { echo "mise.lock is empty"; return; } + local t miss="" + # A tool is pinned when its [[tools.X]] block carries a concrete version line. + for t in $(mise_toml_tools); do + awk -v a="[[tools.$t]]" -v b="[[tools.\"$t\"]]" ' + $0 == a || $0 == b { inb = 1; next } + /^\[/ { inb = 0 } + inb && /^version = "[^"]+"/ { ok = 1 } + END { exit !ok }' mise.lock || miss="$miss$t " + done + [ -n "$miss" ] && { echo "mise.lock does not pin: ${miss% }"; return; } + # Checksums are per artefact: every [tools.X."platforms.P"] table needs its own + # sha256, so one checksummed tool cannot vouch for another. A tool with no + # platform tables has no artefact to checksum (core:rust installs through + # rustup, cargo: builds from source), which is what `mise lock` writes for it. + miss=$(awk ' + # Print the open platform table as tool/platform when it carried no sha256. + function close_table() { if (p != "" && !c) printf "%s ", p; p = "" } + /^\[tools\..*platforms\./ { close_table(); p = $0; c = 0 + gsub(/^\[tools\.|\]$|"/, "", p); sub(/\.platforms\./, "/", p); next } + /^\[/ { close_table() } + /^checksum = "sha256:[0-9a-f]+"/ { c = 1 } + END { close_table() }' mise.lock) + [ -z "$miss" ] || echo "mise.lock has no sha256 for: ${miss% }" +} +# Why a Guix file is a stub, or nothing when it is real. The test is positive: a +# guix.scm must define every field a package needs, not merely avoid known stub +# shapes; `(package (name "x") (source (local-file ".")))` is a stub. +guix_stub_reason() { + local f=$1 k miss="" + [ -f "$f" ] || { echo "missing"; return; } + grep -qE '\{\{|__[A-Z][A-Z_]*__' "$f" && { echo "unfilled template slots"; return; } + grep -qE '\(inputs \(list\)\)|\(source #f\)' "$f" && { echo "empty inputs or no source"; return; } + case "${f##*/}" in + manifest.scm) grep -q 'specifications->manifest' "$f" || echo "lists no specifications"; return ;; + channels.scm) grep -qE '\(commit "[0-9a-f]{40}"\)' "$f" || echo "pins no commit"; return ;; + esac + for k in name version source build-system home-page synopsis description license; do + grep -qE "\\(${k}[[:space:]]" "$f" || miss="$miss$k " + done + [ -n "$miss" ] && { echo "no package field: ${miss% }"; return; } + if grep -q 'crates\.scm' "$f"; then + grep -qs 'define %crate-inputs' build/guix/crates.scm || echo "build/guix/crates.scm is missing or defines no %crate-inputs" + fi +} + +# --------------------------------------------------------------------------- +# Facts the generator writes into docs/SETUP.adoc and the AI guide. They live here, +# beside lang_tools and lang_remedy, so no second per-language table exists. +lang_title() { case "$1" in + rust) echo Rust ;; idris2) echo Idris2 ;; julia) echo Julia ;; zig) echo Zig ;; elixir) echo Elixir ;; + gleam) echo Gleam ;; ocaml) echo OCaml ;; haskell) echo Haskell ;; bun) echo Bun ;; docs) echo Docs ;; esac; } +# What a language's route needs from the OS: "fedora|debian|macos command|why", or nothing. +lang_sysdeps() { case "$1" in + rust) echo "gcc pkgconf-pkg-config|build-essential pkg-config|xcode-select --install|Rust links through the system C toolchain, and pkg-config finds C libraries" ;; + idris2) echo "chez-scheme gmp-devel|chezscheme libgmp-dev|brew install chezscheme gmp|pack builds Idris2 on top of Chez Scheme and GMP" ;; + elixir|gleam) echo "gcc gcc-c++ make autoconf ncurses-devel openssl-devel|build-essential autoconf m4 libncurses-dev libssl-dev|brew install autoconf openssl@3|mise builds Erlang/OTP from source (allow ~10 min); the make here is the system tool that build uses, not a Makefile in this repository" ;; + ocaml) echo "gcc make patch unzip bubblewrap|build-essential patch unzip bubblewrap|xcode-select --install|opam compiles OCaml and sandboxes its builds with bubblewrap" ;; + haskell) echo "gcc gcc-c++ gmp-devel make ncurses-devel xz perl|build-essential curl libffi-dev libgmp-dev libncurses-dev|xcode-select --install|ghcup installs GHC, which links through the C toolchain and GMP" ;; +esac; } +guix_gaps() { + local l g gaps="" + for l in "${LANGS[@]}"; do g=$(lang_guix_gap "$l"); [ -n "$g" ] && gaps="$gaps${gaps:+, }$g"; done + printf '%s\n' "${gaps:-none}" +} +tool_table() { + local l t base + for l in "${LANGS[@]}"; do + if [ "$l" = docs ]; then echo "|docs |\`lychee\` |mise use lychee@latest"; continue; fi + t=$(lang_tools "$l"); echo "|$l |\`${t// /\`, \`}\` |$(lang_remedy "$l")" + done + base="$MISE_BASE $(recipe_tools | xargs)"; base=$(echo "$base" | xargs) + echo "|(recipes) |\`${base// /\`, \`}\` |mise install, or your OS package manager (e.g. \`dnf install just ShellCheck\`)" +} +# shellcheck disable=SC2016 # the backticks are AsciiDoc literals, not command substitution +system_deps() { # $1 adoc|ai + local l d seen="" fed deb mac why any=0 + [ "$1" = adoc ] && printf '=== System packages\n' + for l in "${LANGS[@]}"; do + d=$(lang_sysdeps "$l"); [ -z "$d" ] && continue + case "$seen" in *"|$d|"*) continue ;; esac; seen="$seen|$d|"; any=1 + IFS='|' read -r fed deb mac why <<<"$d" + if [ "$1" = adoc ]; then + printf '\n%s: %s.\n\n* Fedora: `sudo dnf install %s`\n* Debian/Ubuntu: `sudo apt install %s`\n* macOS: `%s`\n' \ + "$(lang_title "$l")" "$why" "$fed" "$deb" "$mac" + else + printf '* %s needs OS packages (%s): Fedora `sudo dnf install %s` · Debian/Ubuntu `sudo apt install %s` · macOS `%s`.\n' \ + "$(lang_title "$l")" "$why" "$fed" "$deb" "$mac" + fi + done + if [ "$1" = adoc ]; then + if [ $any -eq 1 ]; then printf '\nThe Guix development shell (`%s`) provides these itself, so inside `just dev-shell` none of them is needed.\n' "$(gpath manifest.scm)" + else printf '\nNone beyond git and a shell: every tool this repository needs comes from mise, or from the Guix shell.\n'; fi + elif [ $any -eq 0 ]; then printf '* No other OS packages: every tool comes from mise.\n'; fi +} + +cmd_doctor() { + printf '%s doctor — %s (%s; languages: %s)\n' "$REPO_NAME" "$REPO_SLUG" "$ARCHETYPE" "${LANGS[*]}" + + hdr "Core toolchain" + have git && pass "git $($T git --version 2>/dev/null | awk '{print $3}')" || fail "PV-E01 git not found — install git from your OS package manager" + if have just; then + local jv; jv=$($T just --version 2>/dev/null | awk '{print $2}') + version_ge "$jv" "$MIN_JUST" && pass "just $jv (>= $MIN_JUST)" || fail "PV-E02 just $jv is older than $MIN_JUST — run: mise use just@latest" + else fail "PV-E02 just not found — run: mise use -g just@latest (or see docs/SETUP.adoc)"; fi + if have mise; then + pass "mise $($T mise --version 2>/dev/null | awk '{print $1}')" + if [ -f mise.toml ] || [ -f .mise.toml ]; then + # Only THIS repo's declarations: `mise ls` also lists the user's global config. + local here=${ROOT/#$HOME/\~} missing + missing=$($T mise ls --current --missing 2>/dev/null | grep -F -e "$here/mise.toml" -e "$here/.mise.toml" -e "$ROOT/mise.toml" | awk '{print $1"@"$2}' | tr '\n' ' ') + [ -z "${missing// /}" ] && pass "every mise tool is installed" || fail "PV-E03 mise tools not installed: $missing— run: just setup" + fi + else warn "PV-W01 mise not found — tools must then come from Guix or your OS; install: $MISE_INSTALL_HINT"; fi + if have guix; then pass "guix $($T guix --version 2>/dev/null | head -1 | awk '{print $NF}') (optional reproducible path)" + else info "guix not installed — optional; mise is the default path (docs/SETUP.adoc §Guix)"; fi + + hdr "Language toolchains" + local l t + for l in "${LANGS[@]}"; do + [ "$l" = docs ] && { info "no build language detected — docs/theory archetype"; continue; } + for t in $(lang_tools "$l"); do + if have "$t"; then pass "$l: $t ($(command -v "$t"))" + else fail "PV-E10 $l: '$t' not found — run: just setup (manual: $(lang_remedy "$l"))"; fi + done + done + local extra; extra=$(deed system-deps "") + for t in $extra; do have "$t" && pass "system dep: $t" || fail "PV-E11 system dependency '$t' not found (declared in $DEED) — see docs/SETUP.adoc §Prerequisites"; done + + hdr "Repository provisioning files" + [ -f mise.toml ] && pass "mise.toml" || fail "PV-E20 mise.toml missing — the toolchain is undeclared" + local lg; lg=$(mise_lock_gaps) + [ -z "$lg" ] && pass "mise.lock pins every mise.toml tool (latest → concrete, checksummed)" || warn "PV-W20 $lg — run: just toolchain-refresh" + [ -f .mise.toml ] && [ -f mise.toml ] && warn "PV-W21 both mise.toml and .mise.toml — mise merges them; keep only mise.toml" + [ -f .tool-versions ] && warn "PV-W22 .tool-versions present — a second toolchain source; fold it into mise.toml" + if [ -f mise.toml ]; then + local bad; bad=$(mise_banned) + [ -z "$bad" ] && pass "mise.toml pins no banned tool" || warn "PV-W23 mise.toml pins banned tool(s): $bad (language policy: bun, no python/deno/node/make)" + fi + # hypatia guix_not_stub reads guix.scm AND build/guix.scm; an unfilled __PLACEHOLDER__ is a stub too. + local g r gstub="" + for g in guix.scm build/guix.scm "$(gpath manifest.scm)" "$(gpath channels.scm)"; do + [ -f "$g" ] || continue + r=$(guix_stub_reason "$g"); [ -n "$r" ] && gstub="$gstub$g ($r) " + done + local gs gm; gs=$(gpath guix.scm); gm=$(gpath manifest.scm) + [ -f guix.scm ] && [ -f build/guix.scm ] && warn "PV-W35 both guix.scm and build/guix.scm exist — two Guix sources; keep one (build/ is used)" + if [ -f "$gs" ]; then + if [ -n "$gstub" ]; then warn "PV-W24 template stub in: $gstub— the Guix path does not build this repo (just heal cannot fix this; provision-set realign does)" + else pass "$gs (non-stub)"; fi + else warn "PV-W25 guix.scm missing — no reproducible Guix path"; fi + [ -f "$gm" ] && pass "$gm (guix shell -m $gm)" || warn "PV-W26 $gm missing — 'just dev-shell' falls back to mise" + [ -x launcher.sh ] && pass "launcher.sh (executable)" || { [ -f launcher.sh ] && fail "PV-E27 launcher.sh not executable — run: just heal" || warn "PV-W27 launcher.sh missing"; } + local d + for d in docs/SETUP.adoc docs/AI_INSTALLATION_GUIDE.adoc "$(wpath user)" "$(wpath dev)" "$(wpath maintainer)"; do + if [ ! -f "$d" ]; then warn "PV-W28 $d missing" + elif grep -qE "__[A-Z][A-Z_]*__" "$d"; then warn "PV-W29 $d still has unfilled template slots (__SPEC_…__) — replace each with the facts for this repo" + else pass "$d"; fi + done + + hdr "Estate policy drift" + local f any=0 + for f in deno.json deno.jsonc deno.lock import_map.json; do + [ -f "$f" ] && { warn "PV-W30 $f — Deno leftover; the estate runtime is bun (migration issue tracks it)"; any=1; } + done + for f in flake.nix flake.lock shell.nix default.nix; do [ -f "$f" ] && { warn "PV-W31 $f — Nix is not an estate toolchain; Guix is"; any=1; }; done + for f in Makefile GNUmakefile makefile; do [ -f "$f" ] && { warn "PV-W32 $f — Justfile is the only task runner"; any=1; }; done + for f in requirements.txt pyproject.toml setup.py Pipfile; do [ -f "$f" ] && { warn "PV-W33 $f — Python is not an estate language"; any=1; }; done + for f in package-lock.json yarn.lock pnpm-lock.yaml tsconfig.json; do [ -f "$f" ] && { warn "PV-W34 $f — npm/yarn/pnpm/TypeScript leftover; bun only"; any=1; }; done + [ $any -eq 0 ] && pass "no deno / nix / make / python / npm leftovers" + + local hook=build/just/doctor-local.sh + if [ -f "$hook" ]; then + hdr "Repo-specific checks ($hook)" + # Sourced so the hook can call pass/warn/fail, but in a subshell so an `exit` + # or `set -e` in it cannot end the doctor before the summary. The EXIT trap + # hands the hook's tally back; an early exit is itself a FAIL. + local tally qtally hp w f rc + tally=$(mktemp) + printf -v qtally '%q' "$tally" + # shellcheck disable=SC2030,SC2031 # the subshell's counts return via $tally + ( PASS=0 WARN=0 FAIL=0 hook_done=0 + # The path is baked in now: when `set -e` trips, bash unwinds this + # function's locals before the EXIT trap runs, so $tally is gone by then. + # shellcheck disable=SC2064 + trap "printf '%d %d %d %d\n' \"\$PASS\" \"\$WARN\" \"\$FAIL\" \"\$hook_done\" > $qtally" EXIT + # shellcheck source=/dev/null + . "$hook" + hook_done=1 ) + rc=$? + read -r hp w f hook_done < "$tally" || { hp=0 w=0 f=0 hook_done=0; } + rm -f "$tally" + # shellcheck disable=SC2031 + PASS=$((PASS+hp)) WARN=$((WARN+w)) FAIL=$((FAIL+f)) + [ "$hook_done" = 1 ] || fail "PV-E51 $hook exited (status $rc) before it finished; its later checks did not run" + fi + if has_recipe doctor-local; then + hdr "Repo-specific checks (just doctor-local)" + just doctor-local && pass "doctor-local" || fail "PV-E50 the repo-specific doctor-local recipe failed (output above)" + fi + + printf '\n%s: %s%d PASS%s, %s%d WARN%s, %s%d FAIL%s\n' "$REPO_NAME" "$G" "$PASS" "$Z" "$Y" "$WARN" "$Z" "$R" "$FAIL" "$Z" + if [ "$FAIL" -gt 0 ]; then + echo "Next: 'just heal' fixes what is safe to fix automatically; each FAIL code is explained in docs/SETUP.adoc §Troubleshooting." + return 1 + fi + return 0 +} + +cmd_setup() { + printf '%s setup — installing everything this repository needs\n' "$REPO_NAME" + local rc=0 + if have mise; then + hdr "mise toolchain" + $T mise trust -q . 2>/dev/null || true + mise install || rc=1 + else + warn "mise not found. Install it ($MISE_INSTALL_HINT), or enter the Guix shell with 'just dev-shell', then re-run: just setup" + fi + local l + for l in "${LANGS[@]}"; do + case "$l" in + idris2) have pack || warn "pack not found — Idris2 comes from pack, not mise: $(lang_remedy idris2)" ;; + haskell) have ghcup || have ghc || warn "ghc not found — $(lang_remedy haskell)" ;; + ocaml) have opam && { opam switch show >/dev/null 2>&1 || opam init -y --bare; } ;; + esac + done + hdr "Project dependencies" + # Put this repo's mise tools on PATH for the dependency step. + if have mise; then PATH="$(mise bin-paths 2>/dev/null | paste -sd: -):$PATH"; export PATH; fi + lang_run deps || rc=1 + local hook=build/just/setup-local.sh + [ -f "$hook" ] && { hdr "Repo-specific setup ($hook)"; bash "$hook" || rc=1; } + has_recipe setup-local && { hdr "Repo-specific setup (just setup-local)"; just setup-local || rc=1; } + [ -f launcher.sh ] && chmod +x launcher.sh + hdr "Verification" + cmd_doctor || rc=1 + [ $rc -eq 0 ] && printf '\n%sReady.%s Try: just --list\n' "$G" "$Z" || printf '\n%sSetup incomplete%s — read the FAIL lines above; docs/SETUP.adoc has the manual route.\n' "$R" "$Z" + return $rc +} + +cmd_heal() { + printf '%s heal — applying safe, reversible fixes, then re-checking\n' "$REPO_NAME" + hdr "Fixes" + [ -f launcher.sh ] && [ ! -x launcher.sh ] && chmod +x launcher.sh && info "made launcher.sh executable" + for f in build/just/*.sh scripts/*.sh; do [ -f "$f" ] && [ ! -x "$f" ] && chmod +x "$f" && info "made $f executable"; done + if have mise; then + $T mise trust -q . 2>/dev/null && info "mise config trusted" + mise install && info "mise tools installed" + [ -f mise.lock ] || { $T mise lock 2>/dev/null && info "mise.lock generated"; } + fi + if printf '%s\n' "${LANGS[@]}" | grep -qx elixir && have mix; then mix deps.get >/dev/null 2>&1 && info "mix deps fetched"; fi + if printf '%s\n' "${LANGS[@]}" | grep -qx bun && have bun; then bun install >/dev/null 2>&1 && info "bun deps installed"; fi + if printf '%s\n' "${LANGS[@]}" | grep -qx julia && have julia; then julia --project=. -e 'using Pkg; Pkg.instantiate()' >/dev/null 2>&1 && info "julia deps instantiated"; fi + local hook=build/just/heal-local.sh + [ -f "$hook" ] && { info "running $hook"; bash "$hook" || true; } + has_recipe heal-local && { info "running just heal-local"; just heal-local || true; } + echo "Not touched (never automatic): source files, git history, Deno/Nix/Make leftovers — those are migrations, tracked as issues." + hdr "Re-check" + cmd_doctor +} + +cmd_dev_shell() { + local gm; gm=$(gpath manifest.scm) + if have guix && [ -f "$gm" ] && ! grep -q '{{' "$gm"; then + info "entering: guix shell -m $gm (exit to leave)" + exec guix shell -m "$gm" + elif have mise; then + info "guix/manifest.scm unavailable — entering the mise environment instead (exit to leave)" + exec mise exec -- "${SHELL:-bash}" + else + fail "PV-E40 neither guix nor mise is installed — see docs/SETUP.adoc"; return 1 + fi +} + +# Weekly toolchain refresh: bump mise pins and the lock, re-pin the Guix channel, +# regenerate build/guix/crates.scm when guix.scm loads it, then show the diff +# for a signed commit. +cmd_toolchain_refresh() { + hdr "mise: bump 'latest' resolutions and re-lock" + have mise || { fail "mise not found"; return 1; } + mise up --bump || return 1 + $T mise lock 2>/dev/null || mise lock || return 1 + local ch; ch=$(gpath channels.scm) + if [ -f "$ch" ]; then + hdr "guix: channel pin" + if have guix; then + guix pull --channels="$ch" --dry-run >/dev/null 2>&1 || true + guix describe --format=channels > "$ch.new" 2>/dev/null && mv "$ch.new" "$ch" && info "$ch re-pinned to the current guix commit" + else info "guix not installed — $ch left as-is (CI re-pins it)"; fi + fi + local cr="" + if [ -f Cargo.lock ] && grep -qs 'crates\.scm' "$(gpath guix.scm)"; then + hdr "guix: crate inputs from Cargo.lock" + cr=build/guix/crates.scm + if have "${GUIX%% *}"; then cmd_crates_scm || return 1 + else info "guix not installed — $cr left as-is (CI regenerates it)"; fi + fi + git --no-pager diff --stat -- mise.toml mise.lock "$ch" $cr 2>/dev/null + echo "Commit the diff above (signed) as: chore(toolchain): weekly refresh" +} + +# The guix command (default: guix), e.g. a wrapper that runs it in a container +# with this directory mounted. +GUIX="${GUIX:-guix}" + +# Write build/guix/crates.scm: every registry crate in Cargo.lock as a Guix +# origin, and %crate-inputs listing them for guix.scm. Written whole or not at +# all. The importer's output is accepted only when it defines exactly one crate +# source per registry package in Cargo.lock: run through a container, guix's exit +# status is lost, so the count is the check. +cmd_crates_scm() { + local dst=build/guix/crates.scm want got tmp spdx + [ -f Cargo.lock ] || { info "no Cargo.lock — no crate inputs"; return 0; } + want=$(grep -c '^source = "registry+' Cargo.lock) + tmp=$(mktemp) || return 1 + if [ "$want" -gt 0 ]; then + # GUIX is split on purpose: it may be a command with arguments. + # shellcheck disable=SC2086 + timeout 1800 $GUIX import crate --lockfile=Cargo.lock "$REPO_NAME" >"$tmp" 2>"$tmp.err" + got=$(grep -c '^(define rust-' "$tmp") + if [ "$got" != "$want" ]; then + fail "PV-E41 guix import crate defined $got of the $want registry crates in Cargo.lock; $dst left as-is: $(grep -m1 -i 'error' "$tmp.err" || grep -v '^+' "$tmp.err" | tail -1)" + rm -f "$tmp" "$tmp.err"; return 1 + fi + fi + # The licence line is guix.scm's own, so the file matches its repository. + spdx=$(grep -m1 'SPDX-License-Identifier' "$(gpath guix.scm)" 2>/dev/null) + mkdir -p build/guix + { + [ -n "$spdx" ] && printf '%s\n' "$spdx" + # shellcheck disable=SC2016 # the backticks are literal text + printf ';; Generated from Cargo.lock by `just toolchain-refresh` (guix import crate\n' + printf ';; --lockfile); never hand-edit it. guix.scm loads it for %%crate-inputs.\n\n' + grep -v '^guix (GNU Guix)' "$tmp" + printf '\n(define %%crate-inputs\n (list' + grep -o '^(define rust-[^ ]*' "$tmp" | awk '{printf "\n %s", $2}' + printf '))\n' + } >"$dst.new" && mv "$dst.new" "$dst" + rm -f "$tmp" "$tmp.err" + info "$dst: $want crate source(s)" +} + +# The sentence people are told to say lives in one place a reader sees: the first +# listing block of the README's [[ai-install]] section. The deed's ai-say-it and +# the generic line are fallbacks for a README without that section. +just_say_it() { + local line="" r + for r in README.adoc README.md; do + [ -f "$r" ] || continue + line=$(awk '/^\[\[ai-install\]\]/{on=1} on && /^----$/{if (inb) exit; inb=1; next} inb && NF{print; exit}' "$r") + [ -n "$line" ] && break + done + [ -z "$line" ] && line=$(deed ai-say-it "") + [ -z "$line" ] && line="Set up $REPO_NAME from https://github.com/$REPO_SLUG — follow docs/AI_INSTALLATION_GUIDE.adoc in that repo." + printf '%s' "$line" +} +clip() { # best-effort; silent when no clipboard exists (CI, SSH) + # wl-copy and xclip fork a daemon that inherits stdout; left attached, it + # holds any pipeline open forever (observed 2026-09-30). Detach and bound it. + local c=() + if have clip.exe; then c=(clip.exe) # WSL: the Windows clipboard + elif have pbcopy; then c=(pbcopy) + elif [ -n "${WAYLAND_DISPLAY:-}" ] && have wl-copy; then c=(wl-copy) + elif [ -n "${DISPLAY:-}" ] && have xclip; then c=(xclip -selection clipboard) + else cat >/dev/null; return 1; fi + timeout 3 "${c[@]}" >/dev/null 2>&1 +} +cmd_ai_setup() { + cat <" >&2; return 2 ;; esac + for f in "$(wpath "$who")" "llm-warmup-$who.adoc" "docs/onboarding/llm-warmup-$who.adoc" "docs/llm-warmup-$who.adoc"; do + if [ -f "$f" ]; then + cat "$f"; clip < "$f" && echo "--- (copied $f to your clipboard — paste it as your first message to any AI)" >&2 || true + return 0 + fi + done + fail "llm-warmup-$who.adoc not found"; return 1 +} + +cmd_eval() { + local logf rc=0 s e v r o st + logf=".eval/$(date -u +%Y%m%dT%H%M%SZ).txt" + mkdir -p .eval + { echo "# $REPO_NAME evaluation — $(date -u +%FT%TZ) — $(git rev-parse --short HEAD 2>/dev/null || echo no-git)" + echo "# languages: ${LANGS[*]} archetype: $ARCHETYPE"; } > "$logf" + for v in test bench; do + # The root recipe if the repo defines one (its own override), else the module default. + if just --summary 2>/dev/null | tr " " "\n" | grep -qx "$v"; then r=$v; else r="provision::$v"; fi + s=$(date +%s); o=$(mktemp) + if just "$r" >"$o" 2>&1; then st=PASS; else st=FAIL; rc=1; fi + e=$(( $(date +%s) - s )); cat "$o" >>"$logf" + # A skip is not a pass: lang_run exits 0 on N/A (users see success), eval says N/A. + [ "$st" = PASS ] && grep -q "nothing was faked" "$o" && st=N/A + rm -f "$o"; echo "$v: $st (${e}s)" | tee -a "$logf" + done + echo "full log: $logf" + return $rc +} + +cmd_config_show() { + echo "repo: $REPO_SLUG" + echo "archetype: $ARCHETYPE" + echo "languages: ${LANGS[*]}" + echo "descriptor: $DEED $([ -f "$DEED" ] && echo '(present)' || echo '(absent — defaults in use)')" + echo "config: $(deed config "none declared")" + echo "run: $(deed run "$(for l in "${LANGS[@]}"; do lang_cmd "$l" run; done | head -1)")" + echo "ports: $(deed ports "none")" + echo "mise: $([ -f mise.toml ] && echo mise.toml) $([ -f mise.lock ] && echo mise.lock)" + echo "guix: $(for f in guix.scm manifest.scm channels.scm; do f=$(gpath "$f"); [ -f "$f" ] && printf "%s " "$f"; done)" + echo "lib: provision-lib $PROVISION_LIB_VERSION" +} + +cmd_opsm() { + cat <} + if have agrep; then git ls-files -z | xargs -0 agrep -n -1 -- "$p" 2>/dev/null + else git grep -n -i -- "$p"; fi +} + +case "${1:-}" in + guix-specs) guix_specs ;; + mise-tools) mise_tools ;; + langs) printf '%s\n' "${LANGS[@]}" ;; + doctor) cmd_doctor ;; + setup) cmd_setup ;; + heal) cmd_heal ;; + dev-shell) cmd_dev_shell ;; + toolchain-refresh) cmd_toolchain_refresh ;; + crates-scm) cmd_crates_scm ;; + ai-setup) cmd_ai_setup ;; + ai-warmup) shift; cmd_ai_warmup "${1:-user}" ;; + eval) cmd_eval ;; + config-show) cmd_config_show ;; + opsm) cmd_opsm ;; + search) shift; cmd_search "${1:-}" ;; + lang-run) shift; lang_run "${1:?verb}" ;; + version) echo "provision-lib $PROVISION_LIB_VERSION" ;; + guix-dir) guix_dir ;; + set-files) set_files ;; + guix-gaps) guix_gaps ;; + tool-table) tool_table ;; + system-deps) shift; system_deps "${1:-adoc}" ;; + # Predicates: print why, exit 1; print nothing, exit 0. + guix-stub) shift; r=$(guix_stub_reason "${1:?usage: guix-stub FILE}"); [ -z "$r" ] || { echo "$r"; exit 1; } ;; + mise-lock-gaps) r=$(mise_lock_gaps); [ -z "$r" ] || { echo "$r"; exit 1; } ;; + mise-banned) r=$(mise_banned); [ -z "$r" ] || { echo "$r"; exit 1; } ;; + *) sed -n '2,20p' "$0"; exit 2 ;; +esac diff --git a/build/just/provision-modes.sh b/build/just/provision-modes.sh new file mode 100755 index 0000000..35e6033 --- /dev/null +++ b/build/just/provision-modes.sh @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# shellcheck shell=bash +# +# provision-modes.sh — the launcher-standard 0.6.0 provisioning mode family, +# as a SOURCEABLE block shared by every launcher in the estate. +# +# New launchers (library/tool/theory/docs): templates/launcher.sh.tmpl sources +# this and calls hp_launcher_main. +# Existing app launchers: add ONE line before their mode switch — +# +# . "$REPO_DIR/build/just/provision-modes.sh" && hp_provision_or_return "$@" +# +# A provisioning mode runs and the launcher exits with its status (a failed +# --setup exits non-zero); any other mode returns, so the app's own switch +# handles it. hp_provision_dispatch itself returns 99 for "not mine". +# +# Canon: hyperpolymath/standards launcher/launcher-standard_praxis.deed +# (archetypes, provisioning-modes) and +# 3-practice/provisioning/PROVISIONING-STANDARD.adoc + +HP_PROVISION_MODES_VERSION="0.6.0" + +hp__deed() { # $1 key, $2 default — flat (key "value") read from provisioning_praxis.deed + local f="$REPO_DIR/.machine_readable/descriptiles/provisioning_praxis.deed" v="" + [ -f "$f" ] && v=$(grep -oE "[(:]$1[[:space:]]+\"[^\"]*\"" "$f" | head -1 | sed -E 's/^[^"]*"//; s/"$//') + printf '%s' "${v:-$2}" +} + +hp_archetype() { hp__deed archetype "library"; } +# Without a deed, the origin remote names the repo (a worktree or renamed clone +# has another directory name); the directory is the last resort. +hp_app_name() { + local u; u=$(git -C "$REPO_DIR" config --get remote.origin.url 2>/dev/null || true) + u=${u%.git}; u=${u##*/} + hp__deed name "${u:-$(basename "$REPO_DIR")}" +} + +hp_platform() { + case "$(uname -s)" in + Linux*) echo linux ;; + Darwin*) echo macos ;; + CYGWIN*|MINGW*|MSYS*|Windows_NT) echo windows ;; + *) echo unknown ;; + esac +} + +# Make sure `just` is runnable: PATH, then mise, then say exactly what to do. +hp_ensure_just() { + command -v just >/dev/null 2>&1 && return 0 + if command -v mise >/dev/null 2>&1; then + echo "just is not installed — installing it with mise (mise use -g just@latest)..." >&2 + mise use -g just@latest >&2 && PATH="$(mise bin-paths 2>/dev/null | paste -sd: -):$PATH" && command -v just >/dev/null 2>&1 && return 0 + mise exec just@latest -- true >/dev/null 2>&1 && { just() { mise exec just@latest -- just "$@"; }; return 0; } + fi + cat >&2 <<'EOF' +Neither `just` nor `mise` is installed. Install mise (it then installs everything else): + + brew install mise # macOS + sudo dnf copr enable jdxcode/mise && sudo dnf install mise # Fedora + winget install jdx.mise # Windows + # anything else (Debian/Ubuntu apt, …): https://mise.jdx.dev/installing-mise.html + # or download the installer, read it, then run it — never pipe it into a shell: + curl -fsSLo mise-install.sh https://mise.run && less mise-install.sh && sh mise-install.sh + +then re-run this command. Manual route without mise: docs/SETUP.adoc +EOF + return 1 +} + +hp_just() { hp_ensure_just || return 1; (cd "$REPO_DIR" && just "$@"); } +# The provisioning modes call the engine directly, not a `just` recipe: a repo may +# define its own root `doctor`/`setup`/`heal`, and the launcher must still run the +# canon (which then runs that repo's *-local recipes). Only needs bash. +hp_lib() { (cd "$REPO_DIR" && bash build/just/provision-lib.sh "$@"); } + +# Returns the mode's exit code, or 99 when "$1" is not a provisioning mode. +# The one-line hook for existing launchers: exit with a provisioning mode's +# status, or return (0) so the caller's own mode switch runs. +hp_provision_or_return() { + hp_provision_dispatch "$@" + local rc=$? + [ "$rc" -eq 99 ] && return 0 + exit "$rc" +} + +hp_provision_dispatch() { + case "${1:-}" in + --setup) hp_lib setup ;; + --doctor) hp_lib doctor ;; + --heal) hp_lib heal ;; + --ai-setup) hp_lib ai-setup ;; + *) return 99 ;; + esac +} + +hp_version_line() { + local sha ver + sha=$(git -C "$REPO_DIR" rev-parse --short HEAD 2>/dev/null || echo unknown) + ver=$(hp__deed version "") + [ -z "$ver" ] && ver=$(git -C "$REPO_DIR" describe --tags --abbrev=0 2>/dev/null || echo 0.0.0) + printf '%s-launcher %s (%s) [%s-%s]\n' "$(hp_app_name)" "${ver#v}" "$sha" "$(hp_platform)" "$(uname -m)" +} + +hp_help() { + local name arch; name=$(hp_app_name); arch=$(hp_archetype) + cat < + +Provisioning (every repository): + --setup Install everything this repository needs, then run --doctor + --doctor Check the environment; PASS/WARN/FAIL with fix hints (exit 1 on FAIL) + --heal Apply safe fixes automatically, then re-run --doctor + --ai-setup Print the one line to give any AI assistant to set this up for you + +Meta: + --help This text + --version Machine-readable version line + +EOF + if [ "$arch" = app ]; then + echo "Runtime: --start --stop --status --auto (default) --integ --disinteg" + else + echo "Runtime modes (--start --stop --status --auto --integ --disinteg) do not apply" + echo "to a $arch repository; they are accepted and explain themselves." + fi + cat <&2 + return 1 + fi + echo "$(hp_app_name) is a $arch: there is nothing to ${mode#--}. Try --setup, --doctor or --help." + return 0 ;; + *) + echo "Unknown mode: $mode" >&2; hp_help >&2; return 2 ;; + esac +} diff --git a/build/just/provision.just b/build/just/provision.just new file mode 100644 index 0000000..9f1ac7c --- /dev/null +++ b/build/just/provision.just @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# provision.just — the estate provisioning contract, as a just MODULE. +# +# Canon: hyperpolymath/standards 3-practice/provisioning/PROVISIONING-STANDARD.adoc +# Loaded from the root Justfile with: +# +# mod provision 'build/just/provision.just' +# +# A module (not `import`) so these recipes live under `provision::` and never +# collide with a repo's own `doctor`, `heal` or `test`. The root Justfile then +# exposes each contract name ONCE — either its own recipe, or a one-line +# delegation such as `doctor: provision::doctor` that `provision-set mint` +# adds only when the root has no recipe of that name. +# +# requires: just >= 1.42.0 (root recipes depend on module recipes; measured 2026-09-30: 1.41 rejects `x: m::x`, 1.42 accepts) + +root := justfile_directory() +lib := "PROVISION_ROOT=" + quote(root) + " bash " + quote(source_directory() / "provision-lib.sh") + +# List the provisioning recipes +default: + @just --list provision + +# Install every tool and dependency this repo needs, then run doctor +setup: + @{{lib}} setup + +# Diagnose the environment: PASS/WARN/FAIL with codes; exits 1 on any FAIL +doctor: + @{{lib}} doctor + +# Apply safe, reversible fixes, then re-run doctor +heal: + @{{lib}} heal + +# Enter a shell with every tool on PATH (guix shell -m manifest.scm, else mise) +dev-shell: + @{{lib}} dev-shell + +# Weekly: bump mise 'latest' resolutions, re-lock, re-pin guix channels +toolchain-refresh: + @{{lib}} toolchain-refresh + +# Print (and copy) the one line to give any AI to install this repo +ai-setup: + @{{lib}} ai-setup + +# Print (and copy) the warm-up for an AI session: user, dev or maintainer +ai-warmup who="user": + @{{lib}} ai-warmup {{quote(who)}} + +# Run test + bench, time both, and write .eval/.txt +eval: + @{{lib}} eval + +# Show where this repo's configuration and toolchain are declared +config-show: + @{{lib}} config-show + +# How to install this repo with OPSM (odds-and-sods package manager) +opsm: + @{{lib}} opsm + +# Print the languages detected from marker files +langs: + @{{lib}} langs + +# Approximate search across tracked files (agrep, else git grep) +search pattern: + @{{lib}} search {{quote(pattern)}} + +# Per-language defaults for the contract verbs, reached as `just provision::` +# or through a root recipe that delegates (`build: provision::build`). A root +# recipe with its own body is the repo-specific override. + +# Build with every detected language's toolchain +build: + @{{lib}} lang-run build + +# Run every detected language's tests +test: + @{{lib}} lang-run test + +# Run every detected language's benchmarks +bench: + @{{lib}} lang-run bench + +# Lint every detected language +lint: + @{{lib}} lang-run lint + +# Format every detected language's sources +fmt: + @{{lib}} lang-run fmt + +# Check formatting without rewriting anything (the CI form of fmt) +fmt-check: + @{{lib}} lang-run fmt-check + +# Run the project (N/A for libraries) +run: + @{{lib}} lang-run run + +# Fetch every detected language's dependencies +deps: + @{{lib}} lang-run deps diff --git a/case-studies/synapcor/README.adoc b/case-studies/synapcor/README.adoc index 9c559f5..c440834 100644 --- a/case-studies/synapcor/README.adoc +++ b/case-studies/synapcor/README.adoc @@ -1,15 +1,25 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell == SynapCor Case Study +[IMPORTANT] +==== +This is a fictional narrative and design exercise. The people, company, counts, +measurements, correlations, and conclusions are invented examples, not a +tracked dataset or outputs from the current analytics package. This is not a +reference implementation, test fixture, or runnable system: this checkout has +no loader, API, or database integration. +==== + === Overview SynapCor is a fictional mid-sized technology company that has implemented a comprehensive data-driven "`employee wellness and engagement`" program called the *Synergy Matrix*. -This case study serves as: 1. A reference implementation for Phantom -Metal Taste 2. An integration test fixture 3. A demonstration of the gap -between institutional intent and lived reality 4. A cautionary tale -about measurement theater +This case study is a narrative exploration of the gap between institutional +intent and lived reality, and a cautionary tale about measurement theater. It is +not a reference implementation or integration test fixture. === Company Background @@ -278,34 +288,16 @@ exposure participation. Their automation scripts are the most well-tested code in the organization. -=== Using This Case Study - -Load the SynapCor data: - -[source,bash] ----- -deno task load-data ----- - -Run analysis: - -[source,bash] ----- -curl http://localhost:3000/api/analytics/gameable-metrics -curl http://localhost:3000/api/analytics/metric-theater -curl http://localhost:3000/api/analytics/department/engineering/synergy ----- - -Explore causal paths: +=== Exploring the Implemented Prototype -[source,bash] ----- -# Trace from "Thrive Thursday" to employee burnout -curl http://localhost:3000/api/analytics/path/initiatives/thrive-thursday/outcomes/increased-burnout +There is no command to load or query the fictional SynapCor data. To run the +current deterministic Julia example, use `just demo` from a provisioned +checkout. The analysis prototypes operate on their test/example inputs and do +not reproduce the story's invented counts or findings. -# Trace from "Focus-Sprint Protocol" to security violations -curl http://localhost:3000/api/analytics/path/initiatives/focus-sprint/outcomes/security-violations ----- +For the code that exists today, see +link:../../docs/architecture/ARCHITECTURE.adoc[the implementation map] and +link:../../docs/SETUP.adoc[the setup guide]. === Philosophical Questions diff --git a/channels.scm b/channels.scm new file mode 100644 index 0000000..46f6ce1 --- /dev/null +++ b/channels.scm @@ -0,0 +1,15 @@ +;; SPDX-License-Identifier: MPL-2.0 +;; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +;; +;; Pinned Guix channel used by this repository's manifest.scm and guix.scm. +;; Refresh with `just toolchain-refresh` after verifying the new channel. +(list (channel + (name 'guix) + (url "https://codeberg.org/guix/guix.git") + (branch "master") + (commit "ae77aeb9543de2661d739104bc4d3803d8c6f38b") + (introduction + (make-channel-introduction + "9edb3f66fd807b096b48283debdcddccfea34bad" + (openpgp-fingerprint + "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA")))))) diff --git a/compose.yml b/compose.yml index 93b8bdc..94aa9eb 100644 --- a/compose.yml +++ b/compose.yml @@ -1,14 +1,14 @@ -version: '3.8' - +# SPDX-License-Identifier: MPL-2.0 +# Optional local database prototypes only. No current source code connects to them. services: arangodb: image: arangodb:3.11 container_name: phantom-arangodb environment: - ARANGO_ROOT_PASSWORD: phantom-dev-password - ARANGO_NO_AUTH: 0 + ARANGO_ROOT_PASSWORD: ${ARANGO_ROOT_PASSWORD:?required} + ARANGO_NO_AUTH: "0" ports: - - "8529:8529" + - "127.0.0.1:8529:8529" volumes: - arango_data:/var/lib/arangodb3 - arango_apps:/var/lib/arangodb3-apps @@ -24,18 +24,18 @@ services: image: openlink/virtuoso-opensource-7:latest container_name: phantom-virtuoso environment: - DBA_PASSWORD: phantom-dev-password + DBA_PASSWORD: ${VIRTUOSO_DBA_PASSWORD:?required} SPARQL_UPDATE: "true" DEFAULT_GRAPH: https://phantom-metal-taste.org/graph ports: - - "8890:8890" - - "1111:1111" + - "127.0.0.1:8890:8890" + - "127.0.0.1:1111:1111" volumes: - virtuoso_data:/database networks: - phantom-network healthcheck: - test: ["CMD", "isql", "1111", "dba", "phantom-dev-password", "EXEC=status()"] + test: ["CMD-SHELL", "isql 1111 dba \"$${DBA_PASSWORD}\" EXEC=status()"] interval: 10s timeout: 5s retries: 5 diff --git a/deno.lock b/deno.lock deleted file mode 100644 index e69de29..0000000 diff --git a/docs/AI_INSTALLATION_GUIDE.adoc b/docs/AI_INSTALLATION_GUIDE.adoc new file mode 100644 index 0000000..3331376 --- /dev/null +++ b/docs/AI_INSTALLATION_GUIDE.adoc @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += AI Installation Guide — Phantom Metal Taste +:toc: + +[IMPORTANT] +==== +This guide is for an AI assistant helping someone set up the repository. Ask +before installing tools or changing system state. Run one phase at a time and +report failures honestly. This project is experimental: it has Rust and Julia +libraries plus a Bun site builder, but no HTTP service, data loader, or working +database integration. +==== + +== 1. Ask the person + +Ask which operating system they use and where they want the checkout. Windows +steps must be run inside WSL2. The default directory is `~/src/phantom-metal-taste`. + +== 2. Explain what setup does + +Before proceeding, tell the person that setup will clone the public repository, +install the tools declared in `mise.toml` through mise, fetch public Rust and +Julia dependencies, and build/test local code. It does not need credentials, +write to a production database, start a server, or upload project data. + +The toolchain lock is currently a known gap: `mise.lock` has not been generated +because the implementation sandbox could not reach mise's Julia metadata host. +Until the lock is committed, mise resolves current releases rather than +checksum-locked versions. Make this clear; do not claim exact reproducibility. + +== 3. Check prerequisites + +Check `git --version`, `mise --version`, and the availability of a C compiler. +Install only what is missing: + +* Fedora: `sudo dnf install git gcc pkgconf-pkg-config`. +* Debian/Ubuntu: `sudo apt install git build-essential pkg-config`. +* macOS: install Xcode Command Line Tools with `xcode-select --install`, and + install GNU coreutils with `brew install coreutils`; place + `$(brew --prefix coreutils)/libexec/gnubin` first on `PATH` before running the + generated launcher (`readlink -f` is not provided by the default BSD tool). +* mise: use the OS package manager or follow https://mise.jdx.dev/installing-mise.html. + If using its standalone installer, download and inspect it before running it; + never pipe an unreviewed download to a shell. + +== 4. Clone and provision + +[source,bash] +---- +git clone https://github.com/hyperpolymath/phantom-metal-taste.git ~/src/phantom-metal-taste +cd ~/src/phantom-metal-taste +mise trust +./launcher.sh --setup +---- + +The launcher installs the declared tools, fetches project dependencies, and +runs the environment doctor. If `just` is already installed, `just setup` is an +equivalent entry point. + +== 5. Verify + +[source,bash] +---- +just doctor +just build +just test +just site-check +---- + +Run `just demo` to print a small Julia analysis example. Explain that the +optional ArangoDB/Virtuoso containers are not connected to current code and are +not needed for the demo. `just run` reports that there is no application entry +point. + +== 6. Guix alternative + +If GNU Guix is already installed, the pinned shell is: + +[source,bash] +---- +guix time-machine -C channels.scm -- shell -m manifest.scm +mise trust && mise install +just setup +---- + +`guix.scm` installs the source tree; it does not build a production executable. + +== If a step fails + +Run `just doctor`, use the error code's fix in `docs/SETUP.adoc`, and retry. Do +not improvise another runtime or install arbitrary tools. If the problem +persists, save `just doctor > doctor.txt 2>&1` and help the person open an issue. +Never include secrets in an issue or log. diff --git a/docs/CITATIONS.adoc b/docs/CITATIONS.adoc index cce644a..f8546cd 100644 --- a/docs/CITATIONS.adoc +++ b/docs/CITATIONS.adoc @@ -34,5 +34,5 @@ Jewell, J.D.A. (2026). _phantom-metal-taste_ [Computer software]. GitHub. https: == See Also -* link:../CITATION.cff[CITATION.cff] -* link:../codemeta.json[codemeta.json] +This repository does not currently include `CITATION.cff` or `codemeta.json`; +use the citation details above when referencing the software. diff --git a/docs/SETUP.adoc b/docs/SETUP.adoc index b6fd2a8..0f42a1b 100644 --- a/docs/SETUP.adoc +++ b/docs/SETUP.adoc @@ -1,450 +1,217 @@ -== Phantom Metal Taste - Setup Guide +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Setting up Phantom Metal Taste +:toc: +:toclevels: 2 -Complete guide to setting up and running the Phantom Metal Taste system. +This is the manual setup route for the *implemented* Rust, Julia, and Bun tools. +The repository does not currently provide an HTTP service, data loader, or +working database integration; the conceptual design documents are not an +application runbook. -=== Prerequisites +The same steps are available through `./launcher.sh --setup` and `just setup`. +The launcher needs mise; `just setup` needs `just` and mise. -==== Required Software +[horizontal] +Repository:: https://github.com/hyperpolymath/phantom-metal-taste +Kind:: Experimental mixed-language library (`rust julia bun`) +Project configuration:: `Cargo.toml`, `Project.toml`, `package.json`, `site.json` +Toolchain configuration:: `mise.toml`; `manifest.scm` and `channels.scm` for Guix -[arabic] -. *Deno* (v1.40+) -+ -[source,bash] ----- -curl -fsSL https://deno.land/install.sh | sh ----- -. *Podman & podman-compose* -+ -[source,bash] ----- -sudo dnf install podman podman-compose ----- -. *Rust & Cargo* (v1.70+) - for WASM modules -+ -[source,bash] ----- -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -rustup target add wasm32-unknown-unknown ----- -. *Julia* (v1.9+) - for statistical analysis -+ -[source,bash] ----- -# macOS -brew install julia - -# Linux -wget https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.4-linux-x86_64.tar.gz -tar -xvzf julia-1.9.4-linux-x86_64.tar.gz -sudo mv julia-1.9.4 /opt/ -sudo ln -s /opt/julia-1.9.4/bin/julia /usr/local/bin/julia ----- - -==== Optional Software - -* *ReScript* - `+npm install -g rescript+` (for compiling .res files) -* *Git* - for version control -* *jq* - for JSON processing in examples - -=== Installation - -==== 1. Clone the Repository - -[source,bash] ----- -git clone https://github.com/yourusername/phantom-metal-taste.git -cd phantom-metal-taste ----- - -==== 2. Install Dependencies - -[source,bash] ----- -# Build ReScript code -deno task build - -# Julia dependencies -cd src/analytics -julia --project=. -e 'using Pkg; Pkg.instantiate()' -cd ../.. ----- - -==== 3. Build WASM Modules - -[source,bash] ----- -cd src/core -cargo build --target wasm32-unknown-unknown --release -cd ../.. ----- - -Or use the Deno task: - -[source,bash] ----- -deno task build:wasm ----- - -==== 4. Configure Environment - -[source,bash] ----- -cp .env.example .env ----- - -Edit `+.env+` if needed (defaults should work for local development): - -[source,env] ----- -# Database Configuration -ARANGO_URL=http://localhost:8529 -ARANGO_DATABASE=phantom_metal_taste -ARANGO_USERNAME=root -ARANGO_PASSWORD=phantom-dev-password - -VIRTUOSO_URL=http://localhost:8890/sparql -VIRTUOSO_UPDATE_URL=http://localhost:8890/sparql-auth -VIRTUOSO_USERNAME=dba -VIRTUOSO_PASSWORD=phantom-dev-password -VIRTUOSO_GRAPH=https://phantom-metal-taste.org/graph - -# Application -PORT=3000 -NODE_ENV=development -LOG_LEVEL=debug ----- - -==== 5. Start Databases - -[source,bash] ----- -podman-compose up -d ----- - -Wait for services to be healthy: - -[source,bash] ----- -podman-compose ps ----- - -You should see both `+phantom-arangodb+` and `+phantom-virtuoso+` with -status `+healthy+`. - -==== 6. Verify Database Connections - -*ArangoDB:* - Open http://localhost:8529 - Login: `+root+` / -`+phantom-dev-password+` - Database `+phantom_metal_taste+` should exist - -*Virtuoso:* - Open http://localhost:8890/conductor - Login: `+dba+` / -`+phantom-dev-password+` - SPARQL endpoint available at -http://localhost:8890/sparql - -=== Running the Application - -==== Start the API Server - -[source,bash] ----- -deno task dev ----- - -You should see: - -.... -🌀 Phantom Metal Taste - Initializing -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -📊 Connecting to ArangoDB... -✓ ArangoDB initialized -🕸️ Connecting to Virtuoso... -✓ Virtuoso initialized -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -🚀 API Server starting on port 3000 -✓ Server running at http://localhost:3000 -.... - -==== Verify API is Running - -[source,bash] ----- -curl http://localhost:3000/health ----- +== 1. Prerequisites -Expected response: +Install Git, mise, and a system C toolchain. On Windows, use WSL2. -[source,json] ----- -{ - "status": "operational", - "message": "Measuring the gap between intention and reality", - "databases": { - "arango": "connected", - "virtuoso": "connected" - }, - "irony": "fully operational" -} ----- +[cols="1,2,3"] +|=== +|Tool |Why |Install -=== Load Sample Data (SynapCor Case Study) +|Git +|Clone the repository and inspect changes +|Fedora `sudo dnf install git` · Debian/Ubuntu `sudo apt install git` · macOS `xcode-select --install` · Windows `winget install Git.Git` -[source,bash] ----- -deno task load-data ----- +|mise +|Install the Rust, Julia, Bun, Just, and ShellCheck tools declared by this project +|macOS `brew install mise` · Fedora `sudo dnf copr enable jdxcode/mise && sudo dnf install mise` · Windows `winget install jdx.mise` · other systems: https://mise.jdx.dev/installing-mise.html -This loads: - 4 departments - 6 sample employees - 3 initiatives -(Wellness Wednesday, Transparency Dashboard, Synergy Champions) - 9 -outcomes (intended and unintended) - Causal links - Sample metrics +|C compiler and pkg-config +|Native build support for Rust and Julia dependencies +|Fedora `sudo dnf install gcc pkgconf-pkg-config` · Debian/Ubuntu `sudo apt install build-essential pkg-config` · macOS install Xcode Command Line Tools -=== Verify Installation +|OpenSSL command (optional) +|Generate local-only database passwords if using `compose.yml` +|Fedora `sudo dnf install openssl` · Debian/Ubuntu `sudo apt install openssl` · macOS normally includes `openssl` through Homebrew +|=== -==== 1. Test Basic Functionality +On macOS, the generated estate launcher uses GNU `readlink -f`. Install +Homebrew coreutils and put its GNU-compatible commands first on `PATH` before +running the launcher: [source,bash] ---- -# Health check -curl http://localhost:3000/health - -# Gameable metrics -curl http://localhost:3000/api/analytics/gameable-metrics - -# Metric theater detection -curl http://localhost:3000/api/analytics/metric-theater +brew install coreutils +export PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH" ---- -==== 2. Run Tests - -[source,bash] ----- -# Start databases if not running -podman-compose up -d - -# Run test suite -deno task test ----- - -==== 3. Test WASM Module - -[source,bash] ----- -cd src/core -cargo test ----- - -==== 4. Test Julia Modules - -[source,bash] ----- -cd src/analytics -julia --project=. -e 'using Pkg; Pkg.test()' ----- - -=== Development Workflow - -==== Hot Reload - -The Deno dev server supports hot reload: - -[source,bash] ----- -deno task dev ----- - -Make changes to ReScript files, rebuild, and the server will restart -automatically. - -==== Database Management - -[source,bash] ----- -# Start databases -deno task db:up - -# Stop databases -deno task db:down - -# Reset (delete all data and restart) -deno task db:reset ----- +The launcher is generated from the binding RSR template; do not patch the +vendored launcher by hand. This portability requirement should be removed when +the canonical template fixes its macOS path resolution. -==== Rebuild WASM +If installing mise with its standalone installer, download it, inspect it, and +then run it. Do not pipe an unreviewed download into a shell. Add the activation +line printed by the installer to your shell and open a new shell. -After modifying Rust code: +== 2. Get the repository [source,bash] ---- -deno task build:wasm ----- - -Then restart the API server. - -==== Type Checking - -[source,bash] ----- -deno task build # ReScript type checking is part of compilation +git clone https://github.com/hyperpolymath/phantom-metal-taste.git +cd phantom-metal-taste ---- -=== Troubleshooting +A complete GitHub source archive can be extracted instead of cloning. Preserve +its hidden tracked files, especially `.well-known/` and `.github/`. The normal +build and test commands use the checked-in manifests and do not require Git +history; `just doctor` still requires the Git executable as a declared system +prerequisite. -==== Databases Won’t Start +== 3. Install tools and project dependencies [source,bash] ---- -# Check Podman is running -podman ps - -# View logs -podman-compose logs arango -podman-compose logs virtuoso - -# Common fix: remove volumes and restart -podman-compose down -v -podman-compose up -d +mise trust +mise install +./launcher.sh --setup ---- -==== ArangoDB Connection Errors +`./launcher.sh --setup` installs `just` if needed, installs the declared mise +tools, fetches Cargo and Julia dependencies, and runs the environment doctor. +If `just` is already available, use `just setup` instead. -* Ensure port 8529 is not in use -* Check credentials in `+.env+` -* Verify database was created (check web UI) +The tracked `mise.toml` declares tools at `latest`. The provisioning standard +requires a generated `mise.lock` with checksums for those tools. *The lock has +not yet been generated in this checkout*: the current sandbox cannot access +mise's upstream Julia version metadata endpoint. Until that lock is generated +and committed, first-time setup resolves current releases and requires network +access. Do not treat the toolchain as checksum-locked yet. -==== Virtuoso Connection Errors - -* Ensure port 8890 is not in use -* Wait longer for health check (Virtuoso takes ~30s to start) -* Check logs: `+podman-compose logs virtuoso+` - -==== WASM Module Not Loading +== 4. Build, test, and use the code [source,bash] ---- -# Rebuild -cd src/core -cargo clean -cargo build --target wasm32-unknown-unknown --release - -# Verify output exists -ls -lh target/wasm32-unknown-unknown/release/*.wasm +just build # Rust workspace, Julia precompile, and allowlisted site build +just test # Rust unit tests, Julia package tests, and Bun tests +just lint # Rust Clippy checks +just fmt-check # Rust formatting check +just site-check # two site builds compared byte-for-byte +just demo # deterministic Julia analysis example +just validate # doctor + lint/format/test/site-reproducibility gates ---- -==== Julia Errors - -[source,bash] ----- -# Reinstall packages -cd src/analytics -julia --project=. -e 'using Pkg; Pkg.resolve(); Pkg.instantiate()' ----- - -==== Port Already in Use - -If port 3000 is taken, change in `+.env+`: +`just wasm-build` is optional and requires `rustup` with the `wasm32-unknown-unknown` +target. `just run` explicitly reports that no application entry point exists. +The demo uses library functions directly; it does not require a server or a +running database. -[source,env] ----- -PORT=3001 ----- - -=== API Examples +== 5. Optional database containers -==== Create an Initiative +ArangoDB and Virtuoso are optional infrastructure examples. They are not +required by the Rust or Julia packages and no current source code connects to +them. The compose file requires unique local passwords and binds service ports +to loopback: [source,bash] ---- -curl -X POST http://localhost:3000/api/initiatives \ - -H "Content-Type: application/json" \ - -d '{ - "name": "My Initiative", - "description": "Testing the system", - "startDate": "2024-01-01T00:00:00Z", - "department": "Engineering", - "intendedOutcome": "Improve productivity", - "status": "active", - "participants": [] - }' +export ARANGO_ROOT_PASSWORD="$(openssl rand -base64 32)" +export VIRTUOSO_DBA_PASSWORD="$(openssl rand -base64 32)" +just db-up +# ...when finished: +just db-down ---- -==== Get Gap Analysis +Do not reuse these passwords outside the local containers or commit them to the +repository. `just db-logs` follows container logs. Remove persisted data only +through an intentional volume-removal command; the provided `db-down` preserves +it. -After loading SynapCor data, get initiative ID from web UI or query, -then: +== 6. Guix route -[source,bash] ----- -# Replace {id} with actual initiative _key -curl http://localhost:3000/api/analytics/gap/{id} ----- - -==== Detect Gaming +With GNU Guix installed, use the pinned development shell: [source,bash] ---- -curl http://localhost:3000/api/analytics/gameable-metrics +guix time-machine -C channels.scm -- shell -m manifest.scm +mise trust +mise install +just setup ---- -==== Philosophical Reflection - -[source,bash] ----- -curl http://localhost:3000/api/reflection ----- +`manifest.scm` provides Git, Bash, coreutils, Just, mise, ShellCheck, and Rust +build tools. Julia and Bun are installed by mise because the pinned Guix channel +does not provide the requested tool versions. -=== Production Deployment +`guix build -f guix.scm` installs this mixed-language checkout as a *source +package*. It does not produce a service binary: no service is implemented. +`just dev-shell` enters the Guix shell when Guix is installed and otherwise uses +the mise environment. -==== Build for Production +== 7. Troubleshooting -[source,bash] ----- -deno task build ----- +Run `just doctor` or `./launcher.sh --doctor` and follow the fix attached to each +code. `just heal` applies only safe, reversible fixes. -==== Container Production Image +[cols="1,3,3"] +|=== +|Code |Meaning |Fix -(Future enhancement - not yet implemented) +|PV-E01 +|Git is missing +|Install Git using the OS package manager (<>). -[source,containerfile] ----- -FROM cgr.dev/chainguard/wolfi-base:latest AS build +|PV-E02 +|Just is missing or older than 1.42 +|Install it with mise: `mise use -g just@latest`. -WORKDIR /app -COPY . . -RUN deno task build -RUN deno task build:wasm +|PV-E03 / PV-E10 +|A declared tool or language binary is missing +|Run `mise install` and then `just doctor` again. -FROM cgr.dev/chainguard/static:latest -COPY --from=build /app /app -EXPOSE 3000 -CMD ["deno", "task", "start"] ----- +|PV-E11 +|A system dependency listed in the provisioning deed is missing +|Install the named OS package and repeat `just doctor`. -==== Environment Variables +|PV-E20 +|`mise.toml` is missing +|Restore it from version control. -Set these in production: +|PV-E27 +|The launcher is not executable +|Run `chmod +x launcher.sh`. -[source,env] ----- -NODE_ENV=production -LOG_LEVEL=info -ARANGO_PASSWORD= -VIRTUOSO_PASSWORD= ----- +|PV-E40 +|Neither Guix nor mise is available for a development shell +|Install mise, or install Guix and use `manifest.scm`. -=== Next Steps +|PV-E50 / PV-E51 +|A repository-specific doctor check or script failed +|Read the preceding output and fix the named local check. -[arabic] -. Explore the SynapCor case study: `+case-studies/synapcor/README.md+` -. Read architecture docs: `+docs/architecture/ARCHITECTURE.md+` -. Review API documentation (coming soon) -. Build visualizations using the API endpoints +|PV-W01 +|mise is not installed +|Install mise; otherwise the launcher can only show its manual setup guidance. -=== Support +|PV-W20 +|`mise.lock` is missing +|On a machine with access to mise's metadata endpoints, run `just toolchain-refresh`, review the generated checksums, and commit the lock. Do not hand-write it. -* Issues: https://github.com/yourusername/phantom-metal-taste/issues -* Docs: `+docs/+` -* Case study: `+case-studies/synapcor/+` +|PV-W23 +|A mise config declares a prohibited tool/backend +|Remove the offending declaration and rerun `just doctor`. -''''' +|PV-W24–PV-W29 +|A provisioning file is missing or still contains template placeholders +|Compare the file with the provisioning standard and fill only repository-specific facts. +|=== -_"`Setting up a system to measure organizational delusion requires -meticulous attention to detail. The irony is not lost on us.`"_ +If setup still fails, capture `just doctor > doctor.txt 2>&1` and attach that +output to an issue. Never include credentials or password values. diff --git a/docs/architecture/ARCHITECTURE.adoc b/docs/architecture/ARCHITECTURE.adoc index 58d2a5f..f695097 100644 --- a/docs/architecture/ARCHITECTURE.adoc +++ b/docs/architecture/ARCHITECTURE.adoc @@ -1,376 +1,42 @@ -== Phantom Metal Taste - Architecture Documentation - -=== Overview - -Phantom Metal Taste is a multi-model database architecture designed to -capture, analyze, and visualize the gap between organizational -intentions and actual outcomes. This document provides a comprehensive -architectural overview. - -=== Architectural Principles - -==== 1. Multi-Model Paradigm - -The system employs multiple database paradigms simultaneously: - -* *Graph Database (ArangoDB)*: Models causal relationships, -organizational structure, and temporal sequences -* *Semantic Web (Virtuoso)*: Provides formal ontological reasoning and -inference capabilities - -*Rationale*: Different data models reveal different truths. Graph -databases excel at traversing relationships; semantic databases excel at -formal reasoning. - -==== 2. Polyglot Implementation - -.... -┌─────────────────────────────────────────────────┐ -│ ReScript/Deno (Orchestration) │ -│ • API Layer │ -│ • Service coordination │ -│ • Multi-model synchronization │ -└─────────────────────────────────────────────────┘ - ▼ -┌─────────────────┬───────────────────────────────┐ -│ Rust/WASM │ Julia (Statistical) │ -│ • Core metrics │ • Impact analysis │ -│ • Gap calc │ • Causal inference │ -│ • Performance │ • Gaming detection │ -└─────────────────┴───────────────────────────────┘ - ▼ -┌─────────────────┬───────────────────────────────┐ -│ ArangoDB │ Virtuoso │ -│ • Graph data │ • RDF triples │ -│ • Traversal │ • SPARQL queries │ -│ • Documents │ • Inference rules │ -└─────────────────┴───────────────────────────────┘ -.... - -*Rationale*: Use each language for its strengths: - ReScript/Deno: Sound -types, secure runtime, excellent DX - Rust/WASM: Performance-critical -calculations, portable - Julia: Statistical computing, multiple dispatch - -==== 3. Event-Driven Causality - -The system models organizational dynamics as a directed acyclic graph -(DAG) of causal relationships: - -.... -[Initiative] --causes--> [Intended Outcome] - | - +--causes--> [Unintended Outcome 1] - | - +--causes--> [Unintended Outcome 2] - | - +--causes--> [Emergent Outcome] -.... - -Each edge has: - *Strength* (0-1): Confidence in causal relationship - -*Type*: direct, indirect, spurious - *Evidence*: Supporting data for the -link - -=== Data Model - -==== ArangoDB Collections - -*Vertex Collections:* - `+initiatives+`: Corporate programs and -interventions - `+outcomes+`: Results (intended, unintended, emergent) - -`+employees+`: People in the organization - `+metrics+`: Quantitative -measurements - `+departments+`: Organizational units - `+events+`: -Time-stamped occurrences - -*Edge Collections:* - `+causes+`: Causal relationships - -`+participates_in+`: Employee involvement - `+measures+`: What metrics -measure - `+belongs_to+`: Organizational membership - `+influences+`: -Initiative influence - -*Named Graph:* - `+causal_graph+`: Unified graph encompassing all -relationships - -==== Virtuoso Ontology - -*Core Classes (OWL):* - -[source,turtle] ----- -pmt:Initiative rdf:type owl:Class ; - rdfs:label "Corporate Initiative" . - -pmt:Outcome rdf:type owl:Class ; - rdfs:label "Outcome" . - -pmt:Employee rdfs:subClassOf foaf:Person . - -pmt:Metric rdf:type owl:Class . ----- - -*Object Properties:* - -[source,turtle] ----- -pmt:causes rdf:type owl:ObjectProperty ; - rdfs:domain pmt:Initiative ; - rdfs:range pmt:Outcome . - -pmt:intends rdf:type owl:ObjectProperty ; - rdfs:domain pmt:Initiative ; - rdfs:range pmt:Outcome ; - rdfs:comment "The intended outcome (may differ from actual)" . ----- - -*Key Insight*: The ontology distinguishes between `+intends+` (what was -meant to happen) and `+causes+` (what actually happened). This is the -core of the "`phantom metal taste`" metric. - -=== Core Algorithms - -==== 1. Intention-Reality Gap Calculation - -[source,typescript] ----- -gapScore = ( - unintendedOutcomes.count * 10 + - avgMetricGap * 50 + - (intendedOutcomes.count === 0 ? 25 : 0) -) min 100 ----- - -*Components:* - *Unintended outcomes*: More = bigger gap - *Metric -gaps*: Difference between targets and actuals - *Missing intentions*: -Not measuring intended outcomes is suspicious - -==== 2. Causal Path Tracing - -Uses graph traversal with strength propagation: - -.... -pathStrength = geometricMean(edgeStrengths) - = (s1 × s2 × ... × sn)^(1/n) -.... - -*Rationale*: Geometric mean accounts for weakest links (a chain is only -as strong as its weakest link). - -==== 3. Gaming Detection (Julia) - -Statistical analysis looking for: - Suspiciously low variance -(coefficient of variation < 0.05) - End-of-period spikes (>30% increase -in final window) - Target clustering (>60% of values near target) - -Discontinuities (>20% large jumps) - -==== 4. Metric Theater Detection - -Metrics are "`theater`" if: - -.... -theaterProbability = unlinkedMeasurements / totalMeasurements - -if (collectionRate > 10 && theaterProbability > 0.8) { - verdict = "METRIC THEATER DETECTED" -} -.... - -=== API Architecture - -==== REST Endpoints - -.... -POST /api/initiatives # Create initiative -POST /api/initiatives/:id/outcomes # Link to outcome -GET /api/initiatives/:id/analysis # Get analysis - -GET /api/analytics/gap/:id # Intention-reality gap -GET /api/analytics/path/:from/:to # Causal paths -GET /api/analytics/gameable-metrics # Gameable metrics -GET /api/analytics/metric-theater # Theater detection -GET /api/analytics/department/:id/synergy # Synergy score - -GET /api/visualizations/graph # Causal graph data -GET /api/visualizations/timeseries # Metric trends -GET /api/visualizations/heatmap # Department heatmap -.... - -==== Service Layer - -[source,typescript] ----- -InitiativeService - - createInitiative() - - linkCause() - - getInitiativeWithOutcomes() - - findUnintendedConsequences() - -AnalyticsService - - calculateIntentionRealityGap() - - traceCausalPath() - - findGameableMetrics() - - detectMetricTheater() - - calculateDepartmentSynergy() - -VisualizationService - - getCausalGraphData() - - getMetricTimeSeries() - - getDepartmentSynergyHeatmap() - - getIntentionRealityScatter() ----- - -=== Data Flow - -==== Write Path - -.... -1. Client POSTs initiative -2. ReScript service validates (type system) -3. Service writes to ArangoDB -4. Service syncs to Virtuoso (RDF triples) -5. Return created entity -.... - -==== Analysis Path - -.... -1. Client requests gap analysis -2. Service queries ArangoDB (AQL) -3. Results passed to Rust/WASM for calculations -4. Statistical analysis via Julia subprocess -5. Aggregate results -6. Return to client -.... - -==== Visualization Path - -.... -1. Client requests graph visualization -2. Service performs graph traversal (AQL) -3. Transform to visualization format -4. Return nodes + edges JSON -5. Client renders (D3.js/similar) -.... - -=== Deployment Architecture - -==== Development - -.... -┌─────────────────┐ -│ Podman Compose │ -├─────────────────┤ -│ • ArangoDB │ -│ • Virtuoso │ -└─────────────────┘ - ▼ -┌─────────────────┐ -│ Deno Runtime │ -│ (localhost) │ -└─────────────────┘ -.... - -==== Production (Theoretical) - -.... -┌──────────────────────────────┐ -│ Load Balancer │ -└──────────────────────────────┘ - ▼ -┌──────────────────────────────┐ -│ API Pods (Kubernetes) │ -│ • Deno runtime │ -│ • WASM modules loaded │ -└──────────────────────────────┘ - ▼ -┌──────────────┬───────────────┐ -│ ArangoDB │ Virtuoso │ -│ Cluster │ Cluster │ -└──────────────┴───────────────┘ -.... - -=== Performance Considerations - -==== 1. WASM for Hot Paths - -Metric gap calculations run in Rust/WASM: - ~10x faster than interpreted -JavaScript - Portable across runtimes - Memory-safe - -==== 2. AQL Query Optimization - -* Indexes on `+_from+`, `+_to+` for edge traversal -* Limit graph depth to prevent explosion -* Use early filtering in traversals - -==== 3. Julia for Statistical Heavy Lifting - -* Compiled just-in-time -* Near-C performance for numerical operations -* Excellent for matrix operations - -==== 4. Caching Strategy - -* Query results cached (15 min TTL) -* WASM modules loaded once at startup -* Virtuoso inference cached per graph - -=== Security Considerations - -==== 1. Database Authentication - -* Separate credentials per environment -* Never commit passwords (use .env) -* Rotate credentials quarterly - -==== 2. Input Validation - -* ReScript type system for all inputs -* Parameterized queries (prevent injection) -* Rate limiting on API endpoints - -==== 3. Data Privacy - -This is a critical system - it tracks employee metrics. Considerations: -- Anonymization options for sensitive data - Access controls by role - -Audit logging of all queries - GDPR compliance (right to deletion) - -=== Philosophical Considerations - -==== The Measurement Paradox - -This system measures the gap between intention and reality. But: - -Measuring the gap may change the gap (Heisenberg) - Gaming metrics is -rational behavior - The map is not the territory - -==== The Irony Stack - -Layer by layer: 1. *Surface*: Enterprise-grade architecture 2. *Intent*: -Measure corporate delusion 3. *Reality*: The system itself could become -metric theater 4. *Meta*: This documentation acknowledges that - -==== Design for Skepticism - -The system should: - Make gaming visible, not prevent it - Reveal -contradictions, not resolve them - Measure what we can, admit what we -can’t - Question its own metrics - -=== Future Enhancements - -[arabic] -. *Machine Learning Integration* -* Predict unintended consequences -* Anomaly detection improvements -* Causal discovery automation -. *Real-time Stream Processing* -* Event stream from metrics -* Real-time gap calculation -* Alert on threshold breaches -. *Natural Language Interface* -* Query causal graph in English -* Generate narrative explanations -* LLM-powered insight generation -. *Temporal Analysis* -* Track gap evolution over time -* Identify patterns in gaming behavior -* Forecast initiative outcomes - -''''' - -_"`The architecture is rigorous. The metrics are precise. The irony is -intentional.`"_ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Current architecture and implementation status +:toc: + +[IMPORTANT] +==== +This page records what is present in the repository today. Older diagrams and +enterprise design documents are conceptual proposals; they do not describe a +running service. +==== + +== Current source map + +* `Cargo.toml` is a Rust workspace containing `src/core/`, a small + `wasm-bindgen` library with tests. +* `Project.toml` defines the Julia package. `src/PhantomAnalytics.jl` loads the + analysis prototypes under `src/analytics/`; `test/runtests.jl` exercises the + exposed functions. +* `package.json` declares Bun scripts for the static site builder and its tests. + `site.json` is the publish allowlist; `scripts/build-site.mjs` builds the + output without a server framework or third-party JS dependencies. +* `src/orchestrator/` contains five AffineScript TODO scaffolds. They are not + compiled or semantically complete. + +== Boundaries + +No HTTP API, orchestration runtime, data loader, ArangoDB client, Virtuoso +integration, or persistent application service exists. `compose.yml` can start +optional local database containers, but no current code consumes them. The +SynapCor story, diagrams, and TLA+ files communicate design intent only. + +== Build and test + +`just build` delegates to Rust, Julia, and Bun defaults. `just test` runs the +Rust and Julia suites plus Bun tests. `just site-check` rebuilds the site twice +and compares the complete outputs. `just run` reports N/A; there is no runnable +application entry point. + +The semantic AffineScript migration is separate work. Before implementing it, +define intended behavior and tests, verify the supported compiler, and retain +the distinction between new implementation and legacy scaffolding. diff --git a/docs/architecture/OMG-ODM-MOF.adoc b/docs/architecture/OMG-ODM-MOF.adoc index 482cb9a..fe176ec 100644 --- a/docs/architecture/OMG-ODM-MOF.adoc +++ b/docs/architecture/OMG-ODM-MOF.adoc @@ -17,6 +17,14 @@ Jonathan D.A. Jewell :icons: font :source-highlighter: rouge +[IMPORTANT] +==== +This is a fictional/satirical model, not an implemented ontology, database, or +reasoner. No runtime data, OWL file, integration, or model-checking evidence is +provided by this document. For verified source status, see +`ARCHITECTURE.adoc` in this directory. +==== + toc::[] == Introduction @@ -465,4 +473,4 @@ have to. * W3C. _OWL 2 Web Ontology Language Manchester Syntax_, 2nd ed., 2012-12-11. * Horrocks, I. et al. _SWRL: A Semantic Web Rule Language_, W3C Member Submission, 2004. * See also: `docs/diagrams/employee-state-machine.puml`, - `docs/architecture/ARCHITECTURE.md`. + `docs/architecture/ARCHITECTURE.adoc`. diff --git a/docs/architecture/TOGAF-ADM.adoc b/docs/architecture/TOGAF-ADM.adoc index 2f30eed..b24fb9a 100644 --- a/docs/architecture/TOGAF-ADM.adoc +++ b/docs/architecture/TOGAF-ADM.adoc @@ -3,9 +3,9 @@ // // TOGAF Architecture Development Method (ADM) -- Synergy Matrix // Enterprise Architecture Documentation -// Classification: Internal -- Architecture Practice +// Classification: Fictional case-study design -- not an implemented architecture -= Synergy Matrix: TOGAF Architecture Development Method += Synergy Matrix: Fictional TOGAF Architecture Development Method Jonathan D.A. Jewell v1.0, 2026-02-20 :toc: left @@ -13,8 +13,17 @@ v1.0, 2026-02-20 :sectnums: :icons: font :source-highlighter: rouge -:description: Full TOGAF ADM cycle for the Synergy Matrix enterprise initiative. -:keywords: TOGAF, ADM, enterprise architecture, synergy, wellness, gap analysis +:description: Fictional target-state TOGAF exercise for the Synergy Matrix case study; not a system architecture. +:keywords: TOGAF, ADM, fictional case study, design exercise + +[IMPORTANT] +==== +This is a satirical, fictional target-state design exercise. The architecture, +review board, metrics, approval, systems, and deployment activities described +below are not implemented or verified in this repository. The current code map +and limitations are in `ARCHITECTURE.adoc`; do not use this document as an +application runbook or compliance evidence. +==== == Document Control @@ -22,7 +31,7 @@ v1.0, 2026-02-20 |=== | Document ID | SM-TOGAF-ADM-001 | Version | 1.0 -| Status | Approved (by Chad Kensington) +| Status | Fictional narrative; not approved or implemented | Author | Jonathan D.A. Jewell | Review Date | 2026-02-20 | Next Review | When someone reads this @@ -30,16 +39,12 @@ v1.0, 2026-02-20 == Executive Summary -This document presents the complete TOGAF Architecture Development Method cycle -for the Synergy Matrix, an enterprise initiative aimed at the quantification, -measurement, and continuous improvement of organizational wellness through -rigorous architectural discipline. The Synergy Matrix applies formal gap analysis -to the inherently immeasurable domain of human collaboration, producing precise -numerical scores for phenomena that have historically resisted quantification for -good reason. - -The architecture described herein follows all eight phases of the TOGAF ADM and -has been reviewed by the Synergy Architecture Review Board. +This satirical case-study document sketches a fictional TOGAF Architecture +Development Method cycle for the Synergy Matrix, an imagined enterprise wellness +initiative. Its descriptions of data, systems, measurements, governance, and +reviews are narrative devices, not repository capabilities or implementation +evidence. No architecture review board or deployed Synergy Matrix exists in +this checkout. --- @@ -305,11 +310,10 @@ separation of concerns. Data flow diagrams are maintained at: |=== | Component | Technology | Responsibility -| Orchestration Layer -| ReScript / Deno -| Coordinates initiative lifecycle, manages API surface, and ensures - that all requests pass through the appropriate authorization layer - (i.e., Chad). +| Proposed Orchestration Layer +| Not selected or implemented +| A target-state narrative for lifecycle and API coordination; no service or + authorization layer exists in the repository. | Gap Engine | Rust / WASM @@ -360,11 +364,10 @@ the production dashboard by request of the Sponsor. |=== | Layer | Technology | Justification -| Orchestration & API -| ReScript compiled via Deno runtime -| Type-safe orchestration without the overhead of TypeScript. ReScript - compiles to clean JavaScript executed by Deno, ensuring reproducible - builds and eliminating the npm supply chain as an attack vector. +| Proposed orchestration & API +| Not selected; not implemented +| The earlier Deno/ReScript target is retired. This document does not + prescribe an active runtime, API framework, or executable architecture. | Performance-Critical Computation | Rust compiled to WebAssembly @@ -515,9 +518,9 @@ truths that the organization may not be prepared to receive. |=== | Activity | Details -| Orchestration Layer -| Deploy ReScript/Deno API services. Implement initiative lifecycle - management and participant enrollment workflows. +| Proposed application service +| No API service is implemented. Any future service requires a separate + approved scope, language/runtime decision, and tested design. | Metrics Collection | Activate telemetry collection across wellness initiative touchpoints. @@ -663,20 +666,13 @@ by the Chair. Proposals submitted by other members have a 23% approval rate. | Quarterly |=== -=== Architecture Decision Records - -All significant architectural decisions are recorded as ADRs in the -repository. Key decisions include: - -* *ADR-001*: Adoption of ArangoDB over Neo4j for graph storage -* *ADR-002*: Selection of Rust/WASM for gap calculations -* *ADR-003*: Use of OWL/RDF for wellness ontology (rather than informal definitions) -* *ADR-004*: Decision to exclude the Synergy Matrix from its own gap analysis -* *ADR-005*: Removal of the "Cancel Initiative" button from the dashboard UI +=== Fictional architecture decisions -ADRs are stored in `.machine_readable/META.scm` under the -`architecture-decisions` section and follow the standard ADR format -(Context, Decision, Status, Consequences). +The numbered decisions in this legacy case-study narrative are fictional satire, +not project ADRs. The repository has no deployed database, dashboard, or API, +and the former `.machine_readable/META.scm` path is obsolete. Verified project +policy and current toolchain facts live in `phantom-metal-taste_chora.deed`; +that repo deed does not record the imagined decisions above. --- @@ -764,19 +760,19 @@ All architecture change requests follow the standard process: == Appendices -=== Appendix A: Referenced Artifacts +=== Appendix A: Related Artifacts [cols="1,3"] |=== -| Artifact | Location +| Artifact | Location and status -| E-R Diagram | `docs/diagrams/er-diagram.puml` -| Context DFD | `docs/diagrams/dfd-context.puml` -| Detailed DFD | `docs/diagrams/dfd-detailed.puml` -| Deployment Diagram | `docs/diagrams/deployment-diagram.puml` -| Wellness Ontology (OWL) | `ontology/wellness.owl` -| Architecture Decisions | `.machine_readable/META.scm` -| Project State | `.machine_readable/STATE.scm` +| Conceptual E-R diagram | `docs/diagrams/er-diagram.puml`; no matching database schema is implemented. +| Conceptual context DFD | `docs/diagrams/dfd-context.puml`; target-state sketch only. +| Conceptual detailed DFD | `docs/diagrams/dfd-detailed.puml`; target-state sketch only. +| Current deployment/publication map | `docs/diagrams/deployment-diagram.puml`. +| Current implementation map | `docs/architecture/ARCHITECTURE.adoc`. +| Wellness ontology (OWL) | Not present in this checkout. +| Verified project decisions and state | `phantom-metal-taste_chora.deed` (current DEED repo record). |=== === Appendix B: Glossary @@ -820,5 +816,5 @@ All architecture change requests follow the standard process: | 0.2 | 2026-01-28 | J.D.A. Jewell | Incorporated SARB feedback (Chad's feedback) | 0.3 | 2026-02-10 | J.D.A. Jewell | Added risk register per CFO request (then removed two risks per Sponsor request) -| 1.0 | 2026-02-20 | J.D.A. Jewell | Approved by SARB (unanimous, as always) +| 1.0 | 2026-02-20 | J.D.A. Jewell | Fictional version; no real review or approval |=== diff --git a/docs/diagrams/class-diagram.puml b/docs/diagrams/class-diagram.puml index 3b8789c..65840f0 100644 --- a/docs/diagrams/class-diagram.puml +++ b/docs/diagrams/class-diagram.puml @@ -1,4 +1,6 @@ -@startuml Domain Model - Class Diagram +' SPDX-License-Identifier: MPL-2.0 +' Conceptual domain model only; these classes are not backed by current source. +@startuml Conceptual Domain Model - Class Diagram class Initiative { - _key: string diff --git a/docs/diagrams/deployment-diagram.puml b/docs/diagrams/deployment-diagram.puml index 34c759c..3959c4d 100644 --- a/docs/diagrams/deployment-diagram.puml +++ b/docs/diagrams/deployment-diagram.puml @@ -1,86 +1,54 @@ -@startuml Deployment Diagram - -node "Client Browser" { - [Visualization UI] - [API Client] -} - -node "Application Server" { - component "Deno Runtime" { - [ReScript API] - [InitiativeService] - [AnalyticsService] - [VisualizationService] - } - - component "WASM Module" { - [Rust Core] - [Gap Calculator] - [Gaming Detector] - } - - component "Julia Runtime" { - [Impact Analysis] - [Causal Inference] - [Statistical Tests] - } -} - -database "ArangoDB" { - [Graph Database] - [Causal Graph] - [Collections] +' SPDX-License-Identifier: MPL-2.0 +' The present repository workflow, not a target-state application diagram. +@startuml Current Repository and Publication Path + +title Current implementation and static publication path + +actor Developer +node "Repository checkout" { + component "Rust core\n(src/core)" as Rust + component "Julia package\n(src/PhantomAnalytics.jl)" as Julia + component "Bun site builder\n(scripts/build-site.mjs)" as Bun + component "AffineScript files\n(TODO scaffolds; not executed)" as Affine + folder "site.json\nreviewed publish allowlist" as Allowlist } -database "Virtuoso" { - [RDF Store] - [SPARQL Endpoint] - [Ontology] +cloud "GitHub Actions" { + component "Rust tests" as RustCI + component "Julia tests" as JuliaCI + component "Bun tests and\nreproducible site build" as BunCI + folder "Pages artifact\n(allowlisted paths only)" as Artifact } -cloud "Podman Network" { - node "arango-container" { - [ArangoDB Instance] - } +cloud "GitHub Pages" as Pages - node "virtuoso-container" { - [Virtuoso Instance] - } +node "Optional local containers" { + database "ArangoDB" as Arango + database "Virtuoso" as Virtuoso } -[Visualization UI] --> [API Client] : HTTPS -[API Client] --> [ReScript API] : REST/JSON - -[ReScript API] --> [InitiativeService] -[ReScript API] --> [AnalyticsService] -[ReScript API] --> [VisualizationService] - -[InitiativeService] --> [Rust Core] : FFI/WASM -[AnalyticsService] --> [Rust Core] : FFI/WASM -[AnalyticsService] --> [Impact Analysis] : IPC/Subprocess - -[InitiativeService] --> [Graph Database] : AQL/HTTP -[AnalyticsService] --> [Graph Database] : AQL/HTTP -[InitiativeService] --> [RDF Store] : SPARQL/HTTP - -[Graph Database] <--> [ArangoDB Instance] : Podman -[RDF Store] <--> [Virtuoso Instance] : Podman - -note right of [WASM Module] - Compiled from Rust - for performance-critical - calculations +Developer --> Rust : build / test +Developer --> Julia : build / test / demo +Developer --> Bun : test / build +Allowlist --> Bun : copy only configured paths +Rust --> RustCI : CI test +Julia --> JuliaCI : CI test +Bun --> BunCI : CI build + hash gate +BunCI --> Artifact : upload _site +Artifact --> Pages : publish + +note right of Affine + No compiler/runtime gate yet; + files are incomplete scaffolds. end note -note bottom of [Julia Runtime] - Invoked via subprocess - for statistical analysis +note bottom of Arango + Optional compose services. + No current source code connects. end note - -note bottom of cloud - Databases run in - isolated Podman containers - with health checks +note bottom of Virtuoso + Optional compose services. + No current source code connects. end note @enduml diff --git a/docs/diagrams/dfd-context.puml b/docs/diagrams/dfd-context.puml index 9e640c5..988c82e 100644 --- a/docs/diagrams/dfd-context.puml +++ b/docs/diagrams/dfd-context.puml @@ -1,8 +1,9 @@ ' SPDX-License-Identifier: MPL-2.0 ' DFD Level 0 (Context Diagram) - Synergy Matrix System ' Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +' Conceptual target-state data flow; no corresponding service is implemented. -@startuml DFD Context Diagram +@startuml DFD Context Diagram (Conceptual) !define ENTITY_COLOR #E8EAF6 !define PROCESS_COLOR #C8E6C9 diff --git a/docs/diagrams/dfd-detailed.puml b/docs/diagrams/dfd-detailed.puml index 94d3bb2..d88da7e 100644 --- a/docs/diagrams/dfd-detailed.puml +++ b/docs/diagrams/dfd-detailed.puml @@ -1,8 +1,9 @@ ' SPDX-License-Identifier: MPL-2.0 ' DFD Level 1 (Detailed Data Flow Diagram) - Synergy Matrix System ' Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +' Conceptual target-state data flow; no corresponding service is implemented. -@startuml DFD Level 1 +@startuml DFD Level 1 (Conceptual) !define ENTITY_COLOR #E8EAF6 !define PROCESS_COLOR #C8E6C9 diff --git a/docs/diagrams/employee-state-machine.puml b/docs/diagrams/employee-state-machine.puml index 018272f..91da4d2 100644 --- a/docs/diagrams/employee-state-machine.puml +++ b/docs/diagrams/employee-state-machine.puml @@ -1,8 +1,9 @@ ' SPDX-License-Identifier: MPL-2.0 ' Employee Mental State Machine - Brenda Smith's Journey Through the Synergy Matrix ' Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +' Fictional case-study narrative; not a live employee system or state model. -@startuml Employee State Machine +@startuml Fictional Employee State Machine skinparam state { BackgroundColor #FAFAFA diff --git a/docs/diagrams/er-diagram.puml b/docs/diagrams/er-diagram.puml index 6a7f1b7..f76fcf1 100644 --- a/docs/diagrams/er-diagram.puml +++ b/docs/diagrams/er-diagram.puml @@ -1,8 +1,9 @@ ' SPDX-License-Identifier: MPL-2.0 ' Entity-Relationship Diagram - Synergy Matrix Data Model ' Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +' Conceptual case-study schema only; no database schema is implemented. -@startuml Entity-Relationship Diagram +@startuml Conceptual Entity-Relationship Diagram !define TABLE_BG #FAFAFA !define PK_COLOR #1565C0 diff --git a/docs/diagrams/focus-sprint-failure.puml b/docs/diagrams/focus-sprint-failure.puml index 8ae2cd2..8d30265 100644 --- a/docs/diagrams/focus-sprint-failure.puml +++ b/docs/diagrams/focus-sprint-failure.puml @@ -1,8 +1,9 @@ ' SPDX-License-Identifier: MPL-2.0 ' Focus-Sprint Protocol Failure Sequence Diagram ' Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +' Fictional case-study scenario; not an operational sequence. -@startuml Focus-Sprint Protocol Failure +@startuml Fictional Focus-Sprint Protocol Failure skinparam participant { BackgroundColor #FAFAFA diff --git a/docs/diagrams/sequence-diagram.puml b/docs/diagrams/sequence-diagram.puml index 82ff6b4..c83b3a5 100644 --- a/docs/diagrams/sequence-diagram.puml +++ b/docs/diagrams/sequence-diagram.puml @@ -1,73 +1,43 @@ -@startuml Gap Analysis Sequence - -actor Client -participant "API Gateway" as API -participant "InitiativeService" as IS -participant "AnalyticsService" as AS -participant "ArangoDB" as Arango -participant "WASM Module" as WASM -participant "Julia" as Julia -participant "Virtuoso" as Virtuoso - -Client -> API: GET /api/analytics/gap/:id - -API -> IS: getInitiativeWithOutcomes(id) - -IS -> Arango: AQL Query (traverse causes) -activate Arango -Arango --> IS: {initiative, outcomes, metrics} -deactivate Arango - -IS --> API: Initiative data - -API -> AS: calculateIntentionRealityGap(id) - -AS -> Arango: Query outcomes & metrics -activate Arango -Arango --> AS: Raw data -deactivate Arango - -AS -> WASM: calculate_metric_gaps(metrics) -activate WASM -WASM -> WASM: Statistical calculations -WASM --> AS: Gap scores -deactivate WASM - -AS -> Julia: detect_metric_gaming(timeSeries) -activate Julia -Julia -> Julia: Variance analysis\nAnomaly detection -Julia --> AS: Gaming probability -deactivate Julia - -AS -> AS: Calculate final gap score - -AS -> Arango: Store gap analysis -activate Arango -Arango --> AS: Saved -deactivate Arango - -AS -> Virtuoso: Update semantic layer -activate Virtuoso -Virtuoso --> AS: Updated -deactivate Virtuoso - -AS --> API: IntentionRealityGap - -API --> Client: JSON response - -note over WASM - Performance-critical - calculations in Rust -end note - -note over Julia - Statistical analysis - for gaming detection -end note - -note over Arango, Virtuoso - Multi-model persistence: - Graph + Semantic +' SPDX-License-Identifier: MPL-2.0 +' The implemented local test flow; no application API/database sequence exists. +@startuml Local Test and Site Reproducibility Flow + +title Current local validation sequence + +actor Developer +participant "Justfile" as Just +participant "Cargo workspace" as Cargo +participant "Julia package" as Julia +participant "Bun tests" as BunTest +participant "Bun site builder" as Site +participant "Site hash check" as Hash + +Developer -> Just: just test +activate Just +Just -> Cargo: cargo test --locked --all-targets +Cargo --> Just: pass / failure +Just -> Julia: Pkg.test() +Julia --> Just: pass / failure +Just -> BunTest: bun test +BunTest --> Just: pass / failure +Just --> Developer: combined test result +deactivate Just + +Developer -> Just: just site-check +activate Just +Just -> Site: build allowlisted site +Site --> Just: output tree A +Just -> Site: rebuild allowlisted site +Site --> Just: output tree B +Just -> Hash: compare paths and SHA-256 +Hash --> Just: reproducible / mismatch +Just --> Developer: site-check result +deactivate Just + +note over Cargo, Site + These are local library/tooling checks. + They do not start a service or connect + to the optional database containers. end note @enduml diff --git a/docs/diagrams/use-case-diagram.puml b/docs/diagrams/use-case-diagram.puml index 391056d..92902b0 100644 --- a/docs/diagrams/use-case-diagram.puml +++ b/docs/diagrams/use-case-diagram.puml @@ -1,4 +1,6 @@ -@startuml Phantom Metal Taste - Use Case Diagram +' SPDX-License-Identifier: MPL-2.0 +' Proposed product use cases only; no API or actor-facing application exists. +@startuml Conceptual Phantom Metal Taste - Use Case Diagram left to right direction diff --git a/docs/onboarding/llm-warmup-dev.adoc b/docs/onboarding/llm-warmup-dev.adoc new file mode 100644 index 0000000..cf4b218 --- /dev/null +++ b/docs/onboarding/llm-warmup-dev.adoc @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += LLM warm-up — Phantom Metal Taste (developer) + +Paste this into an AI assistant before changing the repository. + +== Current implementation + +* Rust: root Cargo workspace, crate under `src/core/`, lockfile at `Cargo.lock`. +* Julia: root `Project.toml`, package module at `src/PhantomAnalytics.jl`, analysis + files under `src/analytics/`, tests under `test/`. +* Bun: root `package.json`; the allowlisted Pages builder is `scripts/build-site.mjs`. +* `src/orchestrator/*.affine` are TODO scaffolds, not completed domain behavior. +* There is no HTTP API or database integration. Optional containers in + `compose.yml` are not used by the code. + +== Toolchain and loop + +`mise.toml` declares `just`, `shellcheck`, Rust, Julia, and Bun at `latest`. A +checksummed `mise.lock` is still pending; it must be generated with `mise lock`, +never hand-written. `manifest.scm` is the Guix development shell, and `guix.scm` +is an honest source-package definition. + +[source,bash] +---- +./launcher.sh --setup +just build +just test +just lint +just fmt-check +just site-check +just doctor +---- + +The provisioning module is canonical estate code under `build/just/`; do not +hand-edit it to add project-specific behavior. Put facts in +`.machine_readable/descriptiles/provisioning_praxis.deed` and project recipes in +`Justfile`. The launcher is generated from the current RSR template. + +== Guardrails + +* Follow `hyperpolymath/standards` and `hyperpolymath/rsr-template-repo`. +* Do not reintroduce Deno, ReScript, TypeScript, Node.js, npm/yarn/pnpm, Python, + Go, Java, Make, or Nix as project runtimes/build tools. +* Keep application-language work in the estate's approved languages; the + AffineScript orchestrator remains incomplete until its compiler and semantics + are verified. +* Keep claims about APIs, databases, tests, compliance, and reproducibility tied + to observed implementation/evidence. +* New source/config files need SPDX headers; do not add secrets. diff --git a/docs/onboarding/llm-warmup-maintainer.adoc b/docs/onboarding/llm-warmup-maintainer.adoc new file mode 100644 index 0000000..17d52e4 --- /dev/null +++ b/docs/onboarding/llm-warmup-maintainer.adoc @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += LLM warm-up — Phantom Metal Taste (maintainer) + +Read `llm-warmup-dev.adoc` first. This adds the repository maintenance facts. + +== Provisioning ownership + +The current estate engine is in `build/just/provision.just`, +`build/just/provision-lib.sh`, and `build/just/provision-modes.sh`. Treat those as +canonical vendored code; project-specific facts belong in +`.machine_readable/descriptiles/provisioning_praxis.deed`. Keep root `Justfile`, +Guix files, README, setup docs, and this guide accurate as the project changes. +The launcher is generated from the standards template. `Cargo.lock` is Cargo +output; `mise.lock` must be generated by `mise lock`; never fabricate either +lock. Julia's `Manifest.toml` is ignored by project policy. + +== Current blockers and status + +* `mise.lock` is absent because the sandbox could not reach the required Julia + version metadata host. Generate and review it in an egress-enabled environment. +* `gh actions-lock` v0.1.6 could not be installed here because its release binary + is served from a host outside the workspace's network allowlist. The workflow + refs are currently full SHAs, but `.github/workflows/actions.lock` still needs + to be generated and verified with the official tool. +* Rust and Julia executables were unavailable locally, so their CI/package tests + have not been replayed in this environment. +* The AffineScript orchestrator is still five TODO scaffolds; do not claim the + semantic migration or service is complete. + +== Maintainer loop + +. Run `just toolchain-refresh` where mise and Guix metadata are reachable. +. Run `gh actions-lock` and `gh actions-lock --no-fix`, then inspect workflow + changes and leading SPDX comment blocks. +. Run `just doctor`, `just validate`, and all workflow checks before requesting + review. If a runtime is unavailable, name the missing gate rather than + recording a pass. +. Keep issue #77 open until a fresh default-branch run meets its acceptance. diff --git a/docs/onboarding/llm-warmup-user.adoc b/docs/onboarding/llm-warmup-user.adoc new file mode 100644 index 0000000..9972c1e --- /dev/null +++ b/docs/onboarding/llm-warmup-user.adoc @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += LLM warm-up — Phantom Metal Taste (user) + +Paste this file into an AI assistant before asking about using the project. + +== What it is + +Phantom Metal Taste (https://github.com/hyperpolymath/phantom-metal-taste) is +an experimental mixed-language repository exploring the gap between stated +organisational intentions and observed outcomes. It currently contains a Rust +library, Julia analysis package, Bun site builder, conceptual design artefacts, +and unfinished AffineScript scaffolds. + +It does not currently include an HTTP API, service, data loader, or integration +with ArangoDB/Virtuoso. The database compose file is optional infrastructure, +not a runnable application dependency. + +== Set it up + +Use `docs/AI_INSTALLATION_GUIDE.adoc`, run `./launcher.sh --setup`, or follow +`docs/SETUP.adoc`. After setup, try `just build`, `just test`, `just site-check`, +and `just demo`. + +The declared tools are installed with mise; the required generated `mise.lock` +has not yet been produced in this checkout. Until it is committed, tool +resolution is not checksum-locked. + +== When something is wrong + +Run `just doctor`. Each FAIL has a `PV-E…` code with a fix in `docs/SETUP.adoc`. +Do not share credentials or local database passwords in logs/issues. diff --git a/docs/plans/ULTRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc b/docs/plans/ULTRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc new file mode 100644 index 0000000..a65f163 --- /dev/null +++ b/docs/plans/ULTRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell += Remediation plan: issue #77, standalone setup, and RSR alignment +:revdate: 2026-10-10 +:toc: +:toclevels: 3 +:sectnums: + +[IMPORTANT] +==== +*Status: in progress; implementation has begun in the working tree.* This plan +records a repository recon and a phased remediation. It is not evidence of a +merged PR or a fresh default-branch pass. Issue #77 remains open. Do not close +it until the acceptance evidence listed in <> exists. +==== + +== Executive disposition + +. The last inspected default-branch baseline was `8ae3c4e0c8731a587dbe3616a44c5a26fb4aa37c` on 2026-10-10. The associated issue #77 described two failing checks. No new default-branch run has yet validated the current worktree changes. +. The old ReScript/Deno workflow did not test an implemented application path. It has been removed rather than repaired or hidden. A Rust workflow, Julia test workflow, Bun tests, and an allowlisted reproducible Pages build now describe the actual prototype. +. The governance reusable pin and action refs use current full commit SHAs; the local SPDX check accepts a leading comment block. YAML syntax parsing and the local action-pin scan pass. `.github/workflows/actions.lock` is still missing, and actionlint, reusable workflow validation, and remote workflow execution remain unverified. +. The user-requested standalone setup is in progress: root Rust/Julia manifests, Bun site scripts, Just integration, the RSR provisioning engine, launcher, mise declarations, and Guix files are present. `mise.lock` is still missing; do not claim the toolchain is locked. +. The Rust and Julia packages are provisional and have not been executed in this environment. Bun 1.4.3 tests, allowlisted site build, POSIX two-build reproducibility, project-base URL dry run, and a no-`.git` source-archive smoke test pass locally. +. Issues #51 and #54 remain closed. Their unchecked semantic AffineScript hand-port work remains unresolved; the `.affine` files are still TODO scaffolds. +. The initial recon also found mirror jobs failing on empty SSH-key inputs. This is independent operational work; do not request or expose secret values. + +== Scope and evidence baseline + +=== Issues and acceptance + +[cols="1,2,1,4",options="header"] +|=== +|Issue |Title |State |Disposition + +|link:https://github.com/hyperpolymath/phantom-metal-taste/issues/77[#77] +|CI: 2 red checks on default branch, deferred from #76 +|Open +|Primary tracking item for the failing checks. Acceptance permits a passing/neutral context with rationale or intentional retirement linked to the issue. The old context is now retired in the worktree; fresh default-branch evidence and an explicit issue update are still required. + +|link:https://github.com/hyperpolymath/phantom-metal-taste/issues/51[#51] +|Eradicate ReScript ecosystem and port to AffineScript +|Closed +|Historical mechanical migration is not evidence of semantic implementation. Keep the unchecked behavior work as a separately scoped follow-up. + +|link:https://github.com/hyperpolymath/phantom-metal-taste/issues/54[#54] +|Eradicate TypeScript ecosystem +|Closed +|Historical config/file checklist does not complete the semantic port. Do not reopen automatically or claim completion based on extensions. +|=== + +=== Historical failing-run findings + +The baseline run IDs below were inspected during recon. They establish the +starting point only; their result must not be presented as the current result. + +[cols="2,3,4",options="header"] +|=== +|Run / context |Baseline result |Finding + +|link:https://github.com/hyperpolymath/phantom-metal-taste/actions/runs/38040979621[ReScript/Deno CI, run 38040979621] +|`build` failed at `Deno lint`; its independent security job passed. +|The check annotations named `scripts/build-site.mjs`; unused variable and Node-global lint diagnostics prevented later format/test steps from running. There was no active Deno project config, ReScript config, or tracked `.ts`/`.res` implementation. Retire the unused workflow; do not add suppressions or pretend it tested AffineScript. + +|link:https://github.com/hyperpolymath/phantom-metal-taste/actions/runs/38040980036[Governance, run 38040980036] +|The workflow security linter rejected action refs. +|The old governance caller used `81dbf2dd854b1444fd6236fa2352474383b2c2b9`; the Pages workflow used version tags, and there was no action lock. Use the current reusable pin `da2c748aad55c1a1dcba00b60fe4a35017bc6540`, full SHAs, and the official lock generator. + +|link:https://github.com/hyperpolymath/phantom-metal-taste/actions/runs/38040979972[Secret Scanner, run 38040979972] +|`scan / gitleaks`, `scan / rust-secrets`, and `scan / shell-secrets` passed. +|Keep the scanner read-only and retain the required `scan` job identity; the wrapper in the current RSR template does not inherit secrets. The pinned reusable's header still contains stale `secrets: inherit` prose from its former gitleaks-action implementation, but its current jobs do not consume secrets. + +|link:https://github.com/hyperpolymath/phantom-metal-taste/actions/runs/38040979668[Mirror workflow, run 38040979668] +|GitLab and Bitbucket mirror jobs failed at SSH setup. +|The SSH private-key inputs were empty. This remains a separate configuration/enablement question; secret values must never be placed in this plan or public logs. +|=== + +=== PR #80 check results observed before local follow-up fixes + +Observed via `gh pr checks 80` on head `69f9e1eab43c41f3ac26d49b72b64cbb7e554380` +(2026-10-10). The PR remains open against `main`; these findings describe that +pushed commit only. The local changes below were not yet pushed when the check +results were collected. + +[cols="2,3,5",options="header"] +|=== +|Check |Result |Finding / disposition + +|Actions lockfile verification +|Fail +|`.github/workflows/actions.lock` is absent and the grace window ended 2026-10-01. The official `gh-actions-lock` release asset could not be downloaded in this sandbox. No lock data has been fabricated; generate and verify it with the official tool on an egress-enabled host. + +|Rust CI +|Fail +|`cargo check` passed, but `cargo fmt` failed; Clippy and Cargo tests were skipped. `src/core/src/lib.rs` has since been formatted locally using `@scalar/rust-fmt@0.3.0` WASM; equivalence to the CI Rustfmt and the rerun result remain unverified. + +|GitGuardian +|Fail +|Two generic-password findings pointed at descriptive environment-variable error hints in `compose.yml`; no literal credential was present. The local hints are now `:?required`; GitGuardian must re-scan the pushed edit. + +|Hypatia +|Fail +|Annotations identified retired `.machine_readable/6a2/` references in `.claude/CLAUDE.md` and `0-AI-MANIFEST.a2ml`, plus secret use in Instant Sync without `step-security/harden-runner`. The old A2ML structure has since been removed in favor of the root repo deed, and Instant Sync now has a full-SHA-pinned egress-audit step; Hypatia must recheck the pushed changes. + +|Other visible checks +|Pass +|CodeQL, Bun, analytics, local workflow linting, the secret-scanner contexts, and multiple governance checks passed on this head. Full per-check status remains visible on link:https://github.com/hyperpolymath/phantom-metal-taste/pull/80[PR #80]. +|=== + +=== Current source facts + +* Rust workspace: root `Cargo.toml` and `Cargo.lock`, with the prototype crate in `src/core/`. +* Julia package: root `Project.toml`, `src/PhantomAnalytics.jl`, analysis code in `src/analytics/`, and tests in `test/`. +* Bun tooling: root `package.json`; `scripts/build-site.mjs` builds the `site.json` allowlist, and `scripts/build-site.test.js` covers CLI helpers. There are no third-party JavaScript dependencies; Bun 1.4.3 removes an empty `bun.lock` instead of retaining one. +* AffineScript: five orchestrator files plus one benchmark sketch are incomplete TODO scaffolds. No semantic implementation or compiler test is claimed. +* Databases: `compose.yml` describes optional ArangoDB/Virtuoso containers with non-default local passwords and loopback-only ports. No current source code connects to them. +* Application boundary: no HTTP API, service server, data loader, graph persistence, or end-to-end application exists. +* Publication: the Bun builder copies only paths in `site.json`; root user guides, licences, and `.well-known/{ai,humans,security}.txt` are explicitly allowlisted. It creates an HTML index but copies AsciiDoc/Markdown sources verbatim rather than rendering them. The competing full-root Pages workflow has been removed from the worktree. +* Current repo-level descriptive state is `phantom-metal-taste_chora.deed`, with provisioning facts in `.machine_readable/descriptiles/provisioning_praxis.deed`. The RSR template retires A2ML: no `.a2ml` file may be present. Do not recreate the retired `6a2` path or former root-level `.scm` state layout. + +[[binding-rules]] +== Binding estate rules + +The source-of-truth order is current `hyperpolymath/standards`, current +`hyperpolymath/rsr-template-repo` for canonical instantiation, verified local +source/state, then legacy prose. In particular: + +. The current estate language policy makes AffineScript the direction for future application behavior, Bun the tier-1 JavaScript runtime, and prohibits Deno. ReScript/TypeScript legacy work is not a reason to restore either old runtime path. +. The current template reusable pin recorded during recon is `da2c748aad55c1a1dcba00b60fe4a35017bc6540`; keep reusable workflow callers on full reachable SHAs. +. Workflow SPDX validation must accept an SPDX line in the leading comment block, including when a lock tool adds its own comment above it. +. Generate `.github/workflows/actions.lock` using the official `gh-actions-lock` tool. Do not hand-write lock data or guess action resolutions. Keep direct action refs immutable; validate the lock after generation. +. Generate `mise.lock` using official mise tooling. Do not write checksums or release metadata by hand. The current `mise.lock` gap is a release/setup reproducibility blocker. +. Provisioning engine code in `build/just/` is canonical estate code. Put provisioning facts in `.machine_readable/descriptiles/provisioning_praxis.deed`, repo-wide facts in `phantom-metal-taste_chora.deed`, and project tasks in the root `Justfile`. +. The current RSR template retires A2ML. Keep all `.a2ml` files removed; the old descriptive A2ML records and non-executable A2ML contractile declarations are not authoritative. Adopt applicable contractiles in the current `.k9.ncl`/Nickel format rather than reviving the old files. +. Apply the current template capability-by-capability. Do not copy unrelated languages, FFI, services, containers, or formal-method scaffolding simply to imitate the template. + +Binding references: link:https://github.com/hyperpolymath/standards/blob/main/3-practice/provisioning/PROVISIONING-STANDARD.adoc[Provisioning Standard], link:https://github.com/hyperpolymath/standards/issues/727[standards#727], link:https://github.com/hyperpolymath/standards/issues/1108[standards#1108], the link:https://github.com/hyperpolymath/rsr-template-repo[RSR template], and the pinned reusable workflow commit above. + +== Work begun and remaining phases + +=== Phase 1 — Retire stale runtime and align the source layout + +[cols="1,4,3",options="header"] +|=== +|Status |Work item |Evidence / remaining gate + +|Done in worktree +|Deleted `.github/workflows/rescript-deno-ci.yml` and `deno.lock`; removed the second, repository-root Pages publisher and the generic SLSA workflow that attested placeholder artifacts. +|Confirm resulting contexts on a fresh default-branch run. #77 has not been updated or closed. + +|Done in worktree +|Added root Rust workspace and Julia package; moved the Rust lock to workspace root; added Bun site tests and scripts. +|Bun is locally tested. Rust/Julia builds and tests still require execution. + +|Done in worktree +|Replaced README, quick start, setup, architecture, AI, compliance, case-study, and maintainer guidance with implementation-based descriptions. +|Legacy architecture and case-study materials are labelled conceptual; setup guidance follows the implemented Rust/Julia/Bun paths. The published-source link audit is recorded in Phase 4. + +|Done in worktree +|Expanded `site.json` to publish root user guides, current licenses, and required `.well-known` files. Added regression coverage for the root docs/license/security metadata, repaired the generated site's stale `index.json`/security links, and removed a citation page's links to absent metadata. +|Rebuild and rerun tests after the final plan/content edits; verify all local links resolve and every published target is allowlisted. + +|Done in worktree +|Migrated descriptive facts into the root `phantom-metal-taste_chora.deed`; removed the retired A2ML records, root A2ML AI manifest, stale non-executable A2ML contractile declarations, and the unreferenced root `Mustfile` for the never-built legacy CLI. Added DEED guidance and removed all `.a2ml` files. +|The repo deed now carries the current project facts. The current `.k9.ncl`/Nickel contractile trident remains a separately tracked applicability gap; old declarations were not executable controls. + +|Done in worktree +|Reviewed stale active instructions, issue metadata, and retired configuration references. The README agent-notes link now targets the maintained root `CLAUDE.md`; the citation guide no longer links to absent metadata files. +|Active Deno/ReScript runtime/workflow paths are retired. Historical policy, issue, and migration mentions remain labelled as history or prohibition. Recheck the complete diff before PR. +|=== + +=== Phase 2 — Standalone setup and provisioning + +[cols="1,4,3",options="header"] +|=== +|Status |Work item |Evidence / remaining gate + +|Done in worktree +|Added `mise.toml`, root `Justfile`, provisioning deed, the four canonical `build/just/` provisioning files, executable `launcher.sh`, `manifest.scm`, `channels.scm`, and source-only `guix.scm`. The provisioning files match `hyperpolymath/rsr-template-repo` at `df09a6c50c4c77e93abac0fdf162509bf5648611`. +|Launcher `--help` and `--version` pass from the checkout. `./launcher.sh --doctor` ran and reported 13 PASS, 2 WARN, 5 FAIL because `just`, mise, Rust, Julia, and Bun are absent and `mise.lock` is missing; this is an honest environment diagnosis, not a code pass. Full Just lifecycle and Guix validation remain pending. + +|Done in worktree +|Documented setup from either a full Git checkout or complete source archive; hardened the Guix source filter and `.gitignore` for credential/config material. The first fresh-archive smoke test exposed a missing `build/just/provision-modes.sh`; all four provisioning files were restored from the current RSR template, and stable `:name`/`:version` facts were added for launcher identity without Git metadata. +|A complete source archive without `.git` now passes Bun tests/site build, `launcher.sh --help`/`--version`, and the no-A2ML check. Guix, Just, and mise remain unavailable; Guix execution and official `mise.lock` generation are still blockers. + +|Blocker +|Create and review the official `mise.lock` for the declared tools. +|`mise lock --dry-run --verbose` failed resolving Julia metadata with a TLS handshake EOF; generate via `just toolchain-refresh` on an egress-enabled host. Never fabricate it. + +|Done with documented limitation +|Kept the Bun toolchain at 1.4.3, with no external packages. +|Bun 1.4.3 reports no packages and deletes an empty lock; do not add a fake package just to create `bun.lock`. + +|Pending +|Verify the launcher, full Just lifecycle, Guix shell, and source package against the standard. +|Required binaries were not available locally. The generated launcher uses GNU `readlink -f`, so macOS users need Homebrew coreutils first on PATH; this limitation is documented, and the canonical template should fix it before portability is claimed without qualification. +|=== + +=== Phase 3 — CI and Pages replacement + +[cols="1,4,3",options="header"] +|=== +|Status |Work item |Evidence / remaining gate + +|Done in worktree +|Added Rust CI caller pinned to the current shared reusable at `da2c748aad55c1a1dcba00b60fe4a35017bc6540`, Julia CI, Bun CI, and allowlisted Pages build with a two-build hash check. +|GitHub, GitLab, Dependabot, and Copilot YAML parsed with Prettier; actionlint and schema-aware local workflow validation remain unrun. PR #80 executed CI: Julia analytics and Bun passed; Rust `cargo check` passed but formatting failed. The full first-run status is recorded above, and the local fixes still need a fresh PR run. + +|Done in worktree +|Aligned CodeQL's SHA to the template's held v4.38.0 release; narrowed CodeQL, Pages, and mirror permissions; removed no-op Bun dependency-install steps because the project has no third-party packages. Direct and reusable action refs are immutable. +|CodeQL source at `b96794f015dfd88f77b49b1c93e0fa7110f94c63` confirms Rust is built in and accepts `build-mode: none`. All pinned action commits resolved through GitHub's API; local YAML syntax and direct-SHA checks pass. Schema-aware workflow validation and remote execution remain unverified. + +|Done in worktree +|Added a presence-only guard to Instant Sync: dispatch runs only when `FARM_DISPATCH_TOKEN` exists, otherwise the workflow warns without printing or requesting the secret. Added a full-SHA-pinned `step-security/harden-runner` egress-audit step before reading the secret, with a linter regression check. +|Actual secret availability and private-farm dispatch remain owner-side operational settings; no credentials are stored here. Hypatia's egress-monitoring warning is addressed locally; a fresh PR run must confirm. + +|Blocker +|Generate `.github/workflows/actions.lock` with the official tool and validate all workflow refs. +|Installing `gh-actions-lock` v0.1.6 failed because its release asset host returned EOF/outside the network allowlist. Do not hand-author the lock. + +|Pending +|Validate GitLab CI image tags and all GitHub reusable workflow input contracts with schema-aware tooling and live pipelines. +|Prettier YAML syntax parsing, JSON checks, and immutable action-pin checks pass locally. `actionlint` and remote workflow execution are unavailable/unrun; do not claim semantic workflow validation. +|=== + +=== Phase 4 — Local tests and reproducibility + +[cols="1,4,3",options="header"] +|=== +|Status |Work item |Evidence / remaining gate + +|Pass +|Bun tests. +|Bun 1.4.3: 5 passed, 0 failed, 20 `expect()` calls. + +|Pass +|Bun static site build. +|49 output files (46 sources copied); the exact root-base SHA-256 is recorded in `phantom-metal-taste_chora.deed`. This plan is itself published, so duplicating the digest here would make the hash self-referential. + +|Pass +|Two-build reproducibility, local-link review, and source-archive smoke test. +|`sh scripts/check-site-reproducible.sh` matched both builds. A local AsciiDoc-macro audit checked 15 local targets across all 46 readable published sources; every target is allowlisted. A complete archive without `.git` passed Bun tests/build and `launcher.sh --help`. + +|Pass +|Local static configuration and source checks. +|Prettier parsed the changed workflow YAML; JSON parsing, inline action-pin checks, Bash/sh syntax, no-A2ML check, and the current standards DEED linter passed. These do not substitute for schema-aware workflow, Justfile, or Guix validation. + +|Partial; rerun pending +|Rust formatting, Clippy, Cargo tests, and optional WASM target. +|On PR head `69f9e1eab43c41f3ac26d49b72b64cbb7e554380`, `cargo check` passed and `cargo fmt` failed; Clippy and Cargo tests were skipped. The Rust source was formatted locally using `@scalar/rust-fmt@0.3.0` WASM, but equivalence and the post-fix CI result remain unverified. Rust tooling is unavailable locally. + +|Pass on PR +|Julia package tests/precompile. +|The PR #80 `analytics` job passed on the initial head. Julia was not available locally; the demo was not run. + +|Not run / pending +|Just doctor/provisioning, Guix execution, mise install/lock, actionlint, and the post-fix PR workflow rerun. +|Required local tools are unavailable; the initial remote PR run is recorded above, but its local fixes have not yet been pushed and rechecked. +|=== + +=== Phase 5 — Issue #77 acceptance and separate follow-ups + +[[issue-77-acceptance]] +Before resolving #77: + +. Update #77 with the reason for retiring the obsolete ReScript/Deno context and the replacement coverage. +. Verify the pinned Governance reusable, action-lock checks, local workflow linter, Rust/Julia/Bun checks, and Pages reproducibility on the PR. +. After merge, capture a fresh default-branch run URL and exact commit SHA. Confirm the retired context is deliberately absent/neutral with rationale, replacement checks are green, and the required Secret Scanner contexts remain green. +. Close #77 only after those facts are observable; do not bypass rulesets or weaken checks to manufacture a pass. + +Keep separate follow-ups for: + +* Mirror/forge propagation reliability: the initial GitLab/Bitbucket jobs failed because SSH key inputs were empty. They remain gated by explicit enablement flags; Instant Sync now warns and skips if `FARM_DISPATCH_TOKEN` is absent. The owner must configure the needed secrets through GitHub settings or leave those integrations disabled. Never place secret values in the issue, repository, or logs. +* Semantic AffineScript port: first define behavior and tests for the five TODO scaffolds; verify compiler support; then implement and test deliberately. Do not reopen #51/#54 without an explicit owner decision. +* Standards lock-exemption ledger: after local `actions.lock` is generated and accepted, submit the separate shrink-only standards-side removal. +* Current contractile adoption: assess applicable project-specific `must`, `trust`, `adjust`, `dust`, `bust`, and `intend` tridents using the template's `.k9.ncl`/Nickel format. The removed A2ML declarations were stale template residue, not executable checks. +* Additional RSR capability/profile gaps: compare measured repository capabilities with the current template; adopt only applicable features. + +== Verification checklist + +Before considering this remediation complete: + +* [x] No `.a2ml` files remain; repo facts use the root DEED file and both `.deed` records pass the current standards linter. Applicable current contractiles still need separate assessment. +* [ ] `mise.lock` generated by mise and reviewed; `mise install` works from a fresh checkout. +* [ ] `.github/workflows/actions.lock` generated and verified by `gh actions-lock`; all direct and reusable refs are immutable/reachable. +* [ ] `just doctor`, `just provision-check`, `just validate`, Rust tests/Clippy/fmt, Julia tests, Bun tests/build, and site reproducibility run and pass. +* [ ] GitHub workflow YAML/actionlint and GitLab CI YAML validate; CI jobs run successfully. +* [ ] Guix manifest, pinned channel, source package, and launcher paths are exercised. +* [ ] Site artifact contains only `site.json` allowlisted content; root user guides/licences and `.well-known` policy files remain present; no competing workflow publishes the repository root. +* [ ] Current docs, case study, diagrams, CI, and recipes distinguish implementations from conceptual material. +* [ ] #77 has fresh default-branch evidence; it is closed only after linked acceptance is met. +* [ ] Outstanding #51/#54 semantic behavior and mirror/ledger follow-ups remain explicit rather than being counted as completed. + +== Non-goals + +This plan does not implement an HTTP service, database integration, or +AffineScript behavior; request or store secrets; change branch protection; claim +formal verification or certification; fabricate lock files; or mark closed +issues #51/#54 as semantically complete. diff --git a/docs/tech-debt-2026-05-26.adoc b/docs/tech-debt-2026-05-26.adoc index 285afc5..67b2f22 100644 --- a/docs/tech-debt-2026-05-26.adoc +++ b/docs/tech-debt-2026-05-26.adoc @@ -1,5 +1,13 @@ == Tech-Debt Audit — phantom-metal-taste — 2026-05-26 +[WARNING] +==== +This is a historical raw scan from 2026-05-26. Its file counts, findings, and +recommendations predate the 2026-10-10 remediation and must not be treated as +current status. See `docs/plans/ULTRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc` +and `phantom-metal-taste_chora.deed` for current repository facts. +==== + *Source:* estate-wide automated scan 2026-05-26. *Companion:* https://github.com/hyperpolymath/standards/tree/main/docs/audits[`+hyperpolymath/standards+` 2026-05-26-estate-*-debt audits]. *Combined severity:* `+LOW+`. diff --git a/guix.scm b/guix.scm new file mode 100644 index 0000000..fc068e8 --- /dev/null +++ b/guix.scm @@ -0,0 +1,69 @@ +;; SPDX-License-Identifier: MPL-2.0 +;; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +;; +;; A source package for the complete hybrid repository. +;; +;; guix build -f guix.scm # installs the source tree under share/ +;; guix shell -m manifest.scm # development tools; `just setup` provisions mise tools +;; +;; This repository is a mixed Rust / Julia / Bun project whose application +;; orchestrator is still an AffineScript skeleton. The project-level Guix +;; package therefore preserves the checkout as source rather than claiming one +;; compiled artifact represents the whole project. The Rust workspace, Julia +;; package, and site builder have their own real build/test commands in Justfile. +(use-modules (guix packages) + (guix gexp) + (guix build-system copy) + (gnu packages) + (srfi srfi-13) + ((guix licenses) #:prefix license:)) + +(define %source-dir + (let ((d (dirname (current-filename)))) + (if (string=? (basename d) "build") (dirname d) d))) + +(define (spec->input spec) + (call-with-values (lambda () (specification->package+output spec)) + (lambda (pkg out) (if (string=? out "out") pkg (list pkg out))))) + +(define %ignored + '(".git" "target" "_site" ".eval" "node_modules" ".cache" + ".cargo" ".julia" ".env" "secrets" ".ssh" ".aws" ".kube" "credentials" + ".npmrc" ".netrc" ".pypirc" ".docker" "Manifest.toml")) + +(define (sensitive-source-name? file) + (let ((base (basename file))) + (or (member base %ignored) + (string-prefix? ".env." base) + (string-prefix? "credentials." base) + (string-prefix? "token." base) + (string-prefix? "secret." base) + (string-prefix? "id_rsa" base) + (string-prefix? "id_ed25519" base) + (string-suffix? ".pem" base) + (string-suffix? ".key" base) + (string-suffix? ".p12" base) + (string-suffix? ".pfx" base) + (string-suffix? ".secret" base) + (string-suffix? ".token" base) + (string-suffix? ".log" base)))) + +(package + (name "phantom-metal-taste") + (version "0.1.0") + (source (local-file %source-dir "phantom-metal-taste-checkout" + #:recursive? #t + #:select? (lambda (file stat) + (not (sensitive-source-name? file))))) + (build-system copy-build-system) + (arguments (list #:install-plan #~'(("." "share/phantom-metal-taste/")))) + (native-inputs (map spec->input + (list "git" "bash" "coreutils" "nss-certs" "just" "mise" + "shellcheck" "rust" "rust:cargo" "gcc-toolchain" "pkg-config"))) + (home-page "https://github.com/hyperpolymath/phantom-metal-taste") + (synopsis "Experimental analytics library and research artefacts") + (description "A source bundle for an experimental multi-language analytics +project. Its Rust core, Julia analysis package, and Bun-powered site builder are +built and tested through Justfile recipes; the AffineScript orchestrator is not +yet implemented.") + (license license:mpl2.0)) diff --git a/launcher.sh b/launcher.sh new file mode 100755 index 0000000..e9801fe --- /dev/null +++ b/launcher.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# @launcher-deed begin +# ;; SPDX-License-Identifier: MPL-2.0 +# (praxis-deed +# :schema-version "1.0.0" +# :canonical-name "phantom-metal-taste-launcher" +# :beholding-chora #u5"estate/chora" +# (artefact :type "launcher" :version "0.1.0" +# :generator "provision-set") +# (app :name "phantom-metal-taste" :display "phantom-metal-taste" +# :url "https://github.com/hyperpolymath/phantom-metal-taste" :archetype "library") +# (compliance :standard-version "0.6.0" +# :standards ("launcher-standard.adoc" +# "PROVISIONING-STANDARD.adoc")) +# (modes :accepted ("--setup" "--doctor" "--heal" "--ai-setup" "--help" "--version" +# "--start" "--stop" "--status" "--auto" "--integ" "--disinteg")) +# (platforms :supported ("linux" "macos" "windows")) +# (lifecycle-phases :covered ("provision" "diagnose" "heal") +# :deferred ("install" "run"))) +# @launcher-deed end +# +# The launcher for a library / tool / theory / docs repository +# (launcher-standard 0.6.0, archetype profile). Every mode is implemented in +# build/just/provision-modes.sh, and every provisioning mode calls the engine +# (build/just/provision-lib.sh) directly. This file is minted by `provision-set`; +# do not hand-edit it. +# Repo-specific facts belong in .machine_readable/descriptiles/provisioning_praxis.deed. +set -uo pipefail + +REPO_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)" + +if [ ! -f "$REPO_DIR/build/just/provision-modes.sh" ]; then + echo "launcher.sh: build/just/provision-modes.sh is missing — this checkout is incomplete." >&2 + echo "Re-clone, or restore it: git checkout -- build/just/provision-modes.sh" >&2 + exit 1 +fi +# shellcheck source=build/just/provision-modes.sh +. "$REPO_DIR/build/just/provision-modes.sh" + +hp_launcher_main "$@" diff --git a/manifest.scm b/manifest.scm index dd942c7..2762693 100644 --- a/manifest.scm +++ b/manifest.scm @@ -1,24 +1,14 @@ -;;; SPDX-License-Identifier: MPL-2.0 -;;; manifest.scm — Generic Guix manifest for RSR-compliant projects -;;; -;;; Usage: -;;; guix shell -m manifest.scm -;;; - +;; SPDX-License-Identifier: MPL-2.0 +;; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +;; +;; Development environment for Phantom Metal Taste. +;; +;; guix shell -m manifest.scm +;; guix time-machine -C channels.scm -- shell -m manifest.scm +;; +;; Rust is available from Guix. Julia and Bun are installed via mise because +;; this pinned Guix channel does not provide the requested versions. mise.lock +;; is still pending official generation, so setup is not yet checksum-locked. (specifications->manifest - '(;; Core development tools - "git" - "just" - "nickel" - "curl" - "bash" - "coreutils" - - ;; Documentation - "asciidoctor" - "pandoc" - - ;; Common build dependencies - "openssl" - "zlib" - "pkg-config")) + (list "git" "bash" "coreutils" "nss-certs" "just" "mise" "shellcheck" + "rust" "rust:cargo" "gcc-toolchain" "pkg-config")) diff --git a/mise.toml b/mise.toml index 6dd983f..9d736d5 100644 --- a/mise.toml +++ b/mise.toml @@ -1,57 +1,17 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# Estate toolchain: declarations stay on latest; mise.lock records concrete builds. +# Refresh with `just toolchain-refresh`; do not hand-edit mise.lock. +[settings] +lockfile = true + [tools] -# Language runtimes -node = "latest" -python = "latest" +just = "latest" +shellcheck = "latest" rust = "latest" -go = "latest" -zig = "latest" -java = "latest" +julia = "latest" bun = "latest" -denojs = "latest" - -# Package managers -npm = "latest" -yarn = "latest" -pnpm = "latest" -pip = "latest" -cargo = "latest" -go-task = "latest" - -# Formatting & Linting -gofmt = "latest" -black = "latest" -isort = "latest" -ruff = "latest" -prettier = "latest" -shfmt = "latest" -stylua = "latest" - -# Build tools -cmake = "latest" -make = "latest" -ninja = "latest" - -# Shell tools -git = "latest" -gnu-sed = "latest" -gnu-tar = "latest" -gnu-grep = "latest" - -# Testing -vitest = "latest" -pytest = "latest" -jest = "latest" [env] -# Common environment variables -NODE_ENV = "development" -PYTHONDONTWRITEBYTECODE = "1" -PYTHONUNBUFFERED = "1" - -# Task runner alias -[alias] -task = "go-task" -build = "cargo build --release || npm run build || go build" -test = "cargo test || npm test || go test ./..." -lint = "ruff check . || prettier --check . || black --check ." -fmt = "ruff format . || prettier --write . || black ." +JULIA_PROJECT = "." diff --git a/package.json b/package.json new file mode 100644 index 0000000..e7662a6 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "phantom-metal-taste", + "version": "0.1.0", + "private": true, + "license": "MPL-2.0", + "type": "module", + "scripts": { + "build": "bun scripts/build-site.mjs --config site.json", + "test": "bun test" + } +} diff --git a/phantom-metal-taste_chora.deed b/phantom-metal-taste_chora.deed new file mode 100644 index 0000000..a096668 --- /dev/null +++ b/phantom-metal-taste_chora.deed @@ -0,0 +1,124 @@ +;; SPDX-License-Identifier: MPL-2.0 +;; SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell +;; +;; The repository's descriptive state, migrated from the retired A2ML format. +;; Provisioning-specific facts remain in .machine_readable/descriptiles/provisioning_praxis.deed. +(repo-deed + :schema-version "1.0.0" + :canonical-name "phantom-metal-taste" + :repo-uuid #u8"gv-clade-index:github.com/hyperpolymath/phantom-metal-taste" + :beholding-chora #u5"estate/chora" + (identity + :primary-forge github + :owner "hyperpolymath" + :prefixed-name "pm-phantom-metal-taste") + (forges + :github "hyperpolymath/phantom-metal-taste") + (status + :phase active + :since "" + :present #t + :aliases () + :merged-into "" + :superseded-by "" + :successors () + :ended "") + (maturity + :level experimental) + (ecosystem + :project "Phantom Metal Taste" + :ecosystem "hyperpolymath" + :position-type "experimental-research-library" + :purpose "Experimental libraries and research artefacts exploring gaps between organisational intentions and observed outcomes." + :not ("a deployed service" + "an HTTP API or application server" + "a production database integration" + "a completed AffineScript application") + :pipeline-position "prototype" + :coordination "hyperpolymath/standards and hyperpolymath/rsr-template-repo") + (meta + :version "0.1.0" + :last-updated "2026-10-10" + :type library + :languages (rust julia bun) + :license "MPL-2.0 for source; CC-BY-SA-4.0 for documentation" + :author "Jonathan D.A. Jewell (hyperpolymath)" + :build-tool just + :package-manager mise + :container-runtime podman + :ci-platform github-actions + :scoping-first #t + :execution-order "axis-1 > axis-2 > axis-3" + :axis-1 "must > intend > like" + :axis-2 "corrective > adaptive > perfective" + :axis-3 "systems > compliance > effects" + (decision + :id "runtime-policy" + :rationale "Deno and ReScript are retired. Bun is limited to static-site tooling; Rust and Julia contain the current prototype code.") + (decision + :id "application-boundary" + :rationale "No HTTP API, application server, data loader, database client, or complete AffineScript orchestrator is implemented.") + (decision + :id "publication" + :rationale "The static Pages artefact is built only from the explicit site.json allowlist.") + (decision + :id "provisioning" + :rationale "mise and Guix describe setup; generated mise.lock and actions.lock must come from their official tools and are not hand-authored.")) + (agentic + :permissions (edit-source edit-tests edit-docs edit-config create-files) + (constraints + :never ("commit secrets, credentials, private data, or invented test evidence" + "restore Deno or ReScript as active project paths" + "introduce TypeScript, Python, Go, Java, Make, or Nix as active tooling" + "claim API, database, AffineScript, compliance, or formal-verification behavior without evidence" + "hand-write mise.lock, Cargo.lock, Manifest.toml, or actions.lock output" + "modify the canonical provisioning engine for project-specific behavior")) + (integrity + :fail-closed #t + :require-evidence-per-step #t + :allow-silent-skip #f + :require-rerun-after-fix #t + :release-claim-requires-hard-pass #t) + (guidance + :on-enter "Read README.adoc, CLAUDE.md, this deed, and the current binding standards." + :on-exit "Record verified outcomes and unresolved blockers in the current remediation plan." + :on-commit "Run the available project validation; identify unrun gates explicitly.")) + (neurosym + :runtime-implemented #f + :symbolic-domain-rules-implemented #f + :formal-verification-run #f + (boundaries + :notes ("TLA+ specifications are design artefacts; no model-checking run is claimed." + "AffineScript orchestration files are incomplete TODO scaffolds and are not compiled." + "The project name and conceptual material do not imply a neural, symbolic, or neurosymbolic runtime."))) + (playbook + :setup "./launcher.sh --setup" + :setup-guide "docs/SETUP.adoc" + :validation "just validate" + :local-gates ("just doctor" "just provision-check" "just fmt-check" "just lint" "just test" "just site-check") + :evidence-policy "Record unavailable tools as not run; never report an unexecuted check as passing." + :current-remediation-plan "docs/plans/ULTRAPLAN-ISSUE-77-RSR-RECON-2026-10-10.adoc" + (release + :status "No verified versioned release is asserted." + :preconditions ("Generate and verify mise.lock and actions.lock with their official tools." + "Run applicable Rust, Julia, Bun, provisioning, and workflow gates." + "Describe implementation and conceptual material accurately."))) + (verification + :checked-on "2026-10-10" + :site-output "49 files; 46 sources copied" + :site-root-base-sha256 "fe2c7fac9f1f558b2a4bf066240a220fddda8d400106933a86157b7914ec7149" + :site-project-base-sha256 "4a4626680a7497d72d939e752aead0f17ecf3b67cfc916d072491fb71546ff3c" + :site-reproducibility "pass: two root-base builds match; project-base build passes" + :bun-tests "pass: 5 tests, 0 failures, 20 expect calls (Bun 1.4.3)" + :source-archive "pass: no .git; Bun tests/build, launcher help/version, no-A2ML check" + :deed-lint "pass: current standards self-test and both repository deeds" + :no-a2ml "pass: no tracked or unignored A2ML files" + :launcher-doctor "13 pass, 2 warn, 5 fail: local tools absent and mise.lock missing" + :pr-80-head "69f9e1eab43c41f3ac26d49b72b64cbb7e554380" + :pr-80-state "open; current local fixes require a new remote check run" + :pr-rust-ci "cargo check passed; fmt failed; clippy/tests skipped; local formatting applied, rerun pending" + :pr-julia-ci "analytics job passed" + :pr-bun-ci "passed" + :pr-actions-lock "failed: .github/workflows/actions.lock absent; official generator still required" + :pr-gitguardian "failed on two placeholder hints; local :?required hints await re-scan" + :pr-hypatia "failed on retired A2ML paths and missing egress monitor; local fixes await re-scan")) diff --git a/scripts/build-site.mjs b/scripts/build-site.mjs index 3454402..287521f 100644 --- a/scripts/build-site.mjs +++ b/scripts/build-site.mjs @@ -2,24 +2,21 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) // -// build-site.mjs — GitHub Pages publisher for verisimdb-data. +// build-site.mjs — the allowlisted GitHub Pages publisher for phantom-metal-taste. // -// Replaces the retired Jekyll pipeline (`ruby/setup-ruby` + `bundle exec jekyll -// build`, and the `actions/jekyll-build-pages` container build). Ruby is a banned -// implementation language for this estate, so the site is produced by this script. -// -// Runtime: Bun (tier 1 per LANGUAGE-POLICY §1) or Node >= 18, whichever is on -// PATH. Zero dependencies: no lockfile is introduced, so runtime-policy.yml has -// no package-manager tier to police and nothing here needs vendoring. +// Runtime: Bun, the repository's only JavaScript runtime. The script uses Bun's +// Node-compatible built-ins; it is not a Node.js application and has no +// third-party JavaScript dependencies. package.json provides task entry points; +// since there are no packages to resolve, Bun does not retain an empty lockfile. // // Usage: -// bun scripts/build-site.mjs [--config site.json] [--out _site] [--baseurl PATH] -// node scripts/build-site.mjs --dry-run +// bun scripts/build-site.mjs [--config site.json] [--out _site] [--baseurl PATH] +// bun scripts/build-site.mjs --dry-run // // Contract: -// * Only paths named in site.json reach the site root. The repository tree is -// never mirrored — the old Jekyll build did exactly that as a side effect, -// which put scan payloads on a public origin without anyone deciding to. +// * Only source paths named in site.json are copied; the generator adds its +// configured landing page, publish manifest, and .nojekyll marker. The rest +// of the repository tree is never mirrored onto a public origin. // * Output is deterministic for a given input tree + baseurl (no timestamps, // sorted entries, LF separators), so CI can prove reproducibility. // * Fails closed: a missing `required: true` source is an error. Serving @@ -43,7 +40,9 @@ import { basename, dirname, join, posix, resolve, sep } from "node:path"; import { argv, env, exit, stderr, stdout } from "node:process"; import { pathToFileURL } from "node:url"; -const ROOT = resolve(dirname(dirname(realpathSync(argv[1] ?? import.meta.url.pathname)))); +const ROOT = resolve( + dirname(dirname(realpathSync(argv[1] ?? import.meta.url.pathname))), +); // ── CLI ─────────────────────────────────────────────────────────────── @@ -85,24 +84,32 @@ function loadConfig(path) { // other shape is reported as the config error it is. parsed.copy = parsed.copy.map((entry, i) => { if (typeof entry === "string") return { from: entry, to: "." }; - if (entry !== null && typeof entry === "object" && entry.from !== undefined) return entry; - return fail(`config copy[${i}]: expected a string or {from,to}, got ${JSON.stringify(entry)}`); + if (entry !== null && typeof entry === "object" && entry.from !== undefined) + return entry; + return fail( + `config copy[${i}]: expected a string or {from,to}, got ${JSON.stringify(entry)}`, + ); }); for (const entry of parsed.copy) { assertRelative(entry.from, "copy.from"); assertRelative(entry.to ?? "", "copy.to"); } - if (parsed.index_page !== undefined) assertRelative(parsed.index_page, "index_page"); + if (parsed.index_page !== undefined) + assertRelative(parsed.index_page, "index_page"); parsed.listing = (parsed.listing ?? []).map((entry, i) => typeof entry === "string" ? { root: entry } : entry, ); for (const entry of parsed.listing) { assertRelative(entry.root ?? ".", "listing.root"); if (!Array.isArray(entry.match) || entry.match.length === 0) { - fail(`config: listing entry for "${entry.root}" needs a non-empty "match" array`); + fail( + `config: listing entry for "${entry.root}" needs a non-empty "match" array`, + ); } if (entry.link_target !== "source" && entry.link_target !== "repo") { - fail(`config: listing entry for "${entry.root}" needs link_target "source" or "repo"`); + fail( + `config: listing entry for "${entry.root}" needs link_target "source" or "repo"`, + ); } } return parsed; @@ -113,11 +120,16 @@ function loadConfig(path) { // globs (list a directory and the walker expands it). function assertRelative(path, label) { if (path === "") return; - if (path.startsWith("/") || path.startsWith("\\") || /^[A-Za-z]:/.test(path)) { + if ( + path.startsWith("/") || + path.startsWith("\\") || + /^[A-Za-z]:/.test(path) + ) { fail(`config ${label}: absolute path "${path}" is not allowed`); } const parts = path.split(/[\\/]/); - if (parts.includes("..")) fail(`config ${label}: path traversal in "${path}" is not allowed`); + if (parts.includes("..")) + fail(`config ${label}: path traversal in "${path}" is not allowed`); if (parts.some((part) => part.includes("*"))) { fail(`config ${label}: globs are not supported ("${path}")`); } @@ -148,7 +160,10 @@ function walk(dir) { } function toPosixAbs(abs) { - return abs.slice(ROOT.length + 1).split(sep).join(posix.sep); + return abs + .slice(ROOT.length + 1) + .split(sep) + .join(posix.sep); } // Directory names that are never descended into: VCS state, installed @@ -178,16 +193,20 @@ function esc(text) { } function urlFor(baseurl, sitePath) { - const clean = String(sitePath).replace(/^\.\/?/, ""); - if (clean === "" || clean === ".") return baseurl === "" ? "/" : `${baseurl}/`; + const clean = String(sitePath).replace(/^\.\//, ""); + if (clean === "" || clean === ".") + return baseurl === "" ? "/" : `${baseurl}/`; return baseurl === "" ? `/${clean}` : `${baseurl}/${clean}`; } function normaliseBaseurl(raw) { - const value = String(raw ?? "").trim().replace(/\/+$/, ""); + const value = String(raw ?? "") + .trim() + .replace(/\/+$/, ""); if (value === "" || value === "/") return ""; const candidate = value.startsWith("/") ? value : `/${value}`; - if (!/^\/[A-Za-z0-9._~/-]+$/.test(candidate)) fail(`refusing unsafe baseurl: ${raw}`); + if (!/^\/[A-Za-z0-9._~/-]+$/.test(candidate)) + fail(`refusing unsafe baseurl: ${raw}`); return candidate; } @@ -199,18 +218,23 @@ function planCopies(config) { for (const entry of config.copy ?? []) { const srcAbs = resolve(ROOT, entry.from); if (!existsSync(srcAbs)) { - if (entry.required) fail(`required publish source missing: ${entry.from}`); - stdout.write(`build-site: optional source absent, skipped: ${entry.from}\n`); + if (entry.required) + fail(`required publish source missing: ${entry.from}`); + stdout.write( + `build-site: optional source absent, skipped: ${entry.from}\n`, + ); continue; } const stat = lstatSync(srcAbs); - if (stat.isSymbolicLink()) fail(`publish source is a symlink: ${entry.from}`); + if (stat.isSymbolicLink()) + fail(`publish source is a symlink: ${entry.from}`); if (stat.isFile()) { // For a single file, `to` is the destination path itself (empty/"." // means "same name at the site root"). - const dest = entry.to === undefined || entry.to === "" || entry.to === "." - ? basename(entry.from) - : entry.to; + const dest = + entry.to === undefined || entry.to === "" || entry.to === "." + ? basename(entry.from) + : entry.to; items.push({ src: entry.from, site: dest }); continue; } @@ -243,7 +267,11 @@ function planListings(config) { site: joinSite(root, root === "." ? file : file.slice(root.length + 1)), })); if (entry.link_target === "source") published.push(...items); - sections.push({ label: entry.label ?? root, linkTarget: entry.link_target, items }); + sections.push({ + label: entry.label ?? root, + linkTarget: entry.link_target, + items, + }); } return { sections, published }; } @@ -253,7 +281,9 @@ function dedupe(items) { for (const item of items) { const existing = bySite.get(item.site); if (existing !== undefined && existing.src !== item.src) { - fail(`collision: "${item.src}" and "${existing.src}" both publish to /${item.site}`); + fail( + `collision: "${item.src}" and "${existing.src}" both publish to /${item.site}`, + ); } bySite.set(item.site, item); } @@ -272,29 +302,43 @@ function build(opts) { const published = dedupe([...planCopies(config), ...listings.published]); const outputs = new Map(); - for (const item of published) outputs.set(item.site, readFileSync(resolve(ROOT, item.src))); - - const manifest = published.map((item) => ({ path: item.site, source: item.src, bytes: byteSize(item.src) })); - // The hub page is deliberately NOT at the site root: GitHub Pages serves - // index.json for '/' here, and a root index.html would take that over and - // change the content type of a machine-readable endpoint. - const indexPage = config.index_page === undefined ? "hub/index.html" : config.index_page; + for (const item of published) + outputs.set(item.site, readFileSync(resolve(ROOT, item.src))); + + const manifest = published.map((item) => ({ + path: item.site, + source: item.src, + bytes: byteSize(item.src), + })); + // The generated landing page defaults to hub/index.html. This project's + // site.json explicitly places it at index.html for normal Pages navigation. + const indexPage = + config.index_page === undefined ? "hub/index.html" : config.index_page; const atRoot = published.find((item) => item.site === "index.html"); if (atRoot !== undefined && indexPage !== "index.html") { fail( - `"${atRoot.src}" would publish to /index.html and take over '/' (this site's root is ` + - `index.json). Publish it under a directory, or set "index_page": "index.html" to say ` + - `you really mean it. CI guards this too, so failing here is the earlier, kinder half.`, + `"${atRoot.src}" would publish to /index.html, which conflicts with the generated landing page. ` + + `Publish it under a directory or set "index_page": "index.html" to explicitly reserve the root.`, ); } if (indexPage !== "") { - outputs.set(indexPage, Buffer.from(renderIndex({ config, baseurl, sections: listings.sections, manifest }), "utf8")); + outputs.set( + indexPage, + Buffer.from( + renderIndex({ config, baseurl, sections: listings.sections, manifest }), + "utf8", + ), + ); } outputs.set( "publish-manifest.json", - Buffer.from(`${JSON.stringify({ generator: "scripts/build-site.mjs", baseurl: baseurl || "/", files: manifest }, null, 2)}\n`, "utf8"), + Buffer.from( + `${JSON.stringify({ generator: "scripts/build-site.mjs", baseurl: baseurl || "/", files: manifest }, null, 2)}\n`, + "utf8", + ), ); - if (config.nojekyll !== false) outputs.set(".nojekyll", Buffer.from("\n", "utf8")); + if (config.nojekyll !== false) + outputs.set(".nojekyll", Buffer.from("\n", "utf8")); const hash = createHash("sha256"); for (const site of [...outputs.keys()].sort()) { @@ -335,7 +379,7 @@ function writeSiteFile(outDir, site, buffer) { // ── html ────────────────────────────────────────────────────────────── function repoUrl(src) { - const slug = env.GITHUB_REPOSITORY ?? "hyperpolymath/verisimdb-data"; + const slug = env.GITHUB_REPOSITORY ?? "hyperpolymath/phantom-metal-taste"; const ref = env.GITHUB_REF_NAME ?? "main"; return `https://github.com/${slug}/blob/${ref}/${src.split("/").map(encodeURIComponent).join("/")}`; } @@ -345,7 +389,10 @@ function renderIndex({ config, baseurl, sections, manifest }) { for (const section of sections) { if (section.items.length === 0) continue; const rows = section.items.map((item) => { - const href = section.linkTarget === "repo" ? repoUrl(item.src) : urlFor(baseurl, item.site); + const href = + section.linkTarget === "repo" + ? repoUrl(item.src) + : urlFor(baseurl, item.site); return `
  • ${esc(item.src)}
  • `; }); blocks.push(`
    @@ -355,10 +402,14 @@ ${rows.join("\n")}
    `); } + const publishedRows = manifest.slice(0, 200).map((item) => { + const href = esc(urlFor(baseurl, item.path)); + return `
  • ${esc(item.path)} ${item.bytes} B
  • `; + }); blocks.push(`

    Published files (first 200 of ${manifest.length}; full list in publish-manifest.json)

      -${manifest.slice(0, 200).map((item) => `
    • ${esc(item.path)} ${item.bytes} B
    • `).join("\n")} +${publishedRows.join("\n")}
    `); @@ -391,16 +442,17 @@ ${manifest.slice(0, 200).map((item) => `
  • ${esc(item.path)}

    ${esc(config.title)}

    - Flat-file data store for VeriSimDB scan, drift and outcome records. - Built by scripts/build-site.mjs (Bun / Node — no Ruby, no Jekyll) - from the publish allowlist in site.json. + Experimental analytics library and research artefacts for exploring the gap + between organizational intentions and outcomes. The AffineScript orchestrator + remains a scaffold. This allowlisted index is assembled with Bun from + site.json; AsciiDoc and Markdown sources are copied verbatim, not rendered.

    ${blocks.join("\n")}

    - The canonical dataset is the git tree, not this site. Machine-readable index: - index.json. + The canonical sources remain in Git. See the published-file + manifest. Security contacts: security.txt.

    @@ -416,6 +468,16 @@ function slugify(text) { .replace(/^-|-$/g, ""); } -if (import.meta.url === pathToFileURL(argv[1] ?? "").href) build(parseArgs(argv.slice(2))); - -export { build, dedupe, normaliseBaseurl, parseArgs, planCopies, planListings, urlFor, walk }; +if (import.meta.url === pathToFileURL(argv[1] ?? "").href) + build(parseArgs(argv.slice(2))); + +export { + build, + dedupe, + normaliseBaseurl, + parseArgs, + planCopies, + planListings, + urlFor, + walk, +}; diff --git a/scripts/build-site.test.js b/scripts/build-site.test.js new file mode 100644 index 0000000..9bbb5b3 --- /dev/null +++ b/scripts/build-site.test.js @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MPL-2.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +import { describe, expect, test } from "bun:test"; +import { build, normaliseBaseurl, parseArgs, urlFor } from "./build-site.mjs"; + +describe("site builder", () => { + test("parses explicit config and output paths", () => { + expect(parseArgs(["--config", "site.json", "--out", "_site"])).toEqual({ + config: "site.json", + out: "_site", + baseurl: "", + dryRun: false, + }); + }); + + test("normalises a GitHub Pages base path", () => { + expect(normaliseBaseurl("/phantom-metal-taste/")).toBe( + "/phantom-metal-taste", + ); + expect(normaliseBaseurl("/")).toBe(""); + }); + + test("publishes and links root-level user documentation, licenses, and metadata", () => { + const { outputs, published } = build({ + config: "site.json", + out: "_site", + baseurl: "", + dryRun: true, + }); + const paths = new Set(published.map((item) => item.site)); + for (const path of [ + ".well-known/ai.txt", + ".well-known/humans.txt", + ".well-known/security.txt", + "LICENSE", + "QUICKSTART.adoc", + "TEST-NEEDS.adoc", + "RSR_COMPLIANCE.adoc", + "README.adoc", + ]) { + expect(paths.has(path)).toBe(true); + } + const html = outputs.get("index.html").toString(); + expect(html.includes('href="/QUICKSTART.adoc"')).toBe(true); + expect(html.includes('href="/.well-known/security.txt"')).toBe(true); + expect(html.includes("index.json")).toBe(false); + }); + + test("builds root and nested URLs without a base path", () => { + expect(urlFor("", ".")).toBe("/"); + expect(urlFor("", "./docs/SETUP.adoc")).toBe("/docs/SETUP.adoc"); + expect(urlFor("", ".well-known/security.txt")).toBe( + "/.well-known/security.txt", + ); + expect(urlFor("", "docs/SETUP.adoc")).toBe("/docs/SETUP.adoc"); + }); + + test("builds URLs below a project Pages base path", () => { + expect(urlFor("/phantom-metal-taste", "docs/SETUP.adoc")).toBe( + "/phantom-metal-taste/docs/SETUP.adoc", + ); + const { outputs } = build({ + config: "site.json", + out: "_site", + baseurl: "/phantom-metal-taste", + dryRun: true, + }); + const html = outputs.get("index.html").toString(); + expect( + html.includes('href="/phantom-metal-taste/.well-known/security.txt"'), + ).toBe(true); + }); +}); diff --git a/scripts/check-action-pinning.js b/scripts/check-action-pinning.js new file mode 100755 index 0000000..c992d20 --- /dev/null +++ b/scripts/check-action-pinning.js @@ -0,0 +1,112 @@ +#!/usr/bin/env bun +// SPDX-License-Identifier: MPL-2.0 +// +// Assert every workflow action ref is pinned — inline SHA, or via actions.lock. +// +// What counts as "pinned" changed when GitHub introduced workflow lockfiles. A +// ref is pinned if EITHER it is an inline 40-hex SHA, OR +// .github/workflows/actions.lock resolves it to one. The previous inline-only +// rule rejected all 40 of this repo's own refs, so `Workflow Security Linter` +// was red on main permanently — and every repo minted from this template +// inherited both the tag-form workflows and the gate that rejects them. +// +// Runtime: Bun — the estate's first-choice runtime per LANGUAGE-POLICY.adoc §1 +// (Bun > pnpm > npm; Deno retired). Plain JavaScript, not TypeScript: TypeScript is +// banned estate-wide (owner ruling; CLAUDE.md banned-languages table). Note +// LANGUAGE-POLICY.adoc §1.2 currently claims TS is "permitted under Bun" — that +// line is wrong and should be corrected; the ban stands. +// +// Python was the first draft of this script and is banned with no exceptions. +// +// Three details are load-bearing, each of them a defect found by testing: +// +// `-?` in the pattern. `- uses:` is the list-item form and by far the most +// common; a `\s+uses:` pattern silently misses every one of them. Estate +// memory records this exact failure — "green linter != full SHA-pinning". A +// gate that cannot see the common case reads as coverage and enforces nothing. +// +// Case-insensitive comparison. Workflows write `SonarSource/...`; the lockfile +// records `sonarsource/...`. Action refs are case-insensitive in practice, so +// a case-sensitive match reports a false positive on a correctly-pinned action. +// +// Only *.yml / *.yaml, depth 1. A bare recursive grep also reads actions.lock +// (whose `uses:` keys are lockfile entries, not refs) and *.yml.template +// (whose tag ref is deliberate and resolved at mint time). Both were reported +// as unpinned, which made the gate unsatisfiable the moment a lockfile existed. +// +// Exit 0 if every ref is pinned, 1 otherwise, listing file:line: ref. + +import { readdirSync, readFileSync, existsSync, statSync } from "node:fs"; +import { join } from "node:path"; + +const WF = ".github/workflows"; +const LOCK = join(WF, "actions.lock"); +// `-?` matches the list-item form; see the header. +const USES = /^\s*-?\s*uses:\s*([^\s#]+)/; +const SHA = /@[a-f0-9]{40}$/; +const EXEMPT_PREFIX = ["./", "$", "docker://"]; + +function workflowFiles() { + if (!existsSync(WF) || !statSync(WF).isDirectory()) return []; + return readdirSync(WF) + .filter((f) => f.endsWith(".yml") || f.endsWith(".yaml")) + .sort() + .map((f) => join(WF, f)); +} + +function main() { + if (!existsSync(WF)) { + console.log("no .github/workflows — nothing to check"); + return 0; + } + + let known = new Set(); + if (existsSync(LOCK)) { + const lock = readFileSync(LOCK, "utf8"); + known = new Set( + [...lock.matchAll(/'([^']+@[^']+)'/g)].map((m) => m[1].toLowerCase()), + ); + console.log(`lockfile present: ${known.size} ref(s) resolvable through it`); + } else { + console.log("no lockfile — every ref must be an inline 40-character SHA"); + } + + const bad = []; + for (const wf of workflowFiles()) { + const lines = readFileSync(wf, "utf8").split("\n"); + lines.forEach((line, i) => { + const m = USES.exec(line); + if (!m) return; + const ref = m[1]; + if (EXEMPT_PREFIX.some((p) => ref.startsWith(p))) return; + if (SHA.test(ref)) return; + const at = ref.lastIndexOf("@"); + const name = at === -1 ? ref : ref.slice(0, at); + const tag = at === -1 ? "" : ref.slice(at + 1); + // subpath actions key by repo root: github/codeql-action/init -> github/codeql-action + const root = name.split("/").slice(0, 2).join("/"); + if ( + known.has(ref.toLowerCase()) || + known.has(`${root}@${tag}`.toLowerCase()) + ) + return; + bad.push(`${wf}:${i + 1}: ${ref}`); + }); + } + + if (bad.length) { + console.log( + "\nERROR: these action refs are neither SHA-pinned nor covered by the lockfile:", + ); + for (const b of bad) console.log(` ${b}`); + console.log( + "\nEither pin to a full commit SHA, or run `gh actions-lock` so the", + ); + console.log("lockfile resolves the ref."); + return 1; + } + console.log("all action refs are pinned"); + return 0; +} + +process.exit(main()); diff --git a/scripts/check-no-a2ml.sh b/scripts/check-no-a2ml.sh new file mode 100755 index 0000000..f71e9b3 --- /dev/null +++ b/scripts/check-no-a2ml.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell +# +# Fail if a tracked or unignored working-tree file uses the retired A2ML format. +set -euo pipefail + +root="${1:-.}" +if [[ ! -d "$root" ]]; then + printf 'ERROR: repository path does not exist: %s\n' "$root" >&2 + exit 2 +fi + +found=() +if git -C "$root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + while IFS= read -r -d '' path; do + case "$path" in + *.a2ml|*.A2ML) found+=("$path") ;; + esac + done < <(git -C "$root" ls-files --cached --others --exclude-standard -z) +else + while IFS= read -r -d '' path; do + found+=("$path") + done < <(find "$root" -path "$root/.git" -prune -o -type f \( -iname '*.a2ml' \) -print0) +fi + +if ((${#found[@]})); then + printf 'FAIL: A2ML is a retired format; migrate descriptive facts to the repo deed and contracts to current K9/Nickel files:\n' >&2 + printf ' %s\n' "${found[@]}" >&2 + exit 1 +fi + +printf 'PASS: no tracked or unignored A2ML files found\n' diff --git a/scripts/check-site-reproducible.sh b/scripts/check-site-reproducible.sh new file mode 100755 index 0000000..947bf60 --- /dev/null +++ b/scripts/check-site-reproducible.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +set -eu + +root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' 0 HUP INT TERM + +cd "$root" +bun scripts/build-site.mjs --config site.json --out "$tmp/first" > "$tmp/first.log" +bun scripts/build-site.mjs --config site.json --out "$tmp/second" > "$tmp/second.log" + +grep -Eq 'sha256=[0-9a-f]{64}' "$tmp/first.log" +grep -Eq 'sha256=[0-9a-f]{64}' "$tmp/second.log" +diff -r "$tmp/first" "$tmp/second" +printf 'Site output is reproducible.\n' diff --git a/scripts/demo.sh b/scripts/demo.sh index 65cc7ce..17f9f55 100755 --- a/scripts/demo.sh +++ b/scripts/demo.sh @@ -1,79 +1,36 @@ -#!/bin/bash +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +set -euo pipefail -# Demo script for Phantom Metal Taste -# Demonstrates key features of the system +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$root" -set -e - -API_URL="http://localhost:3000" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " Phantom Metal Taste - Interactive Demo" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" - -# Check if API is running -echo "🔍 Checking API health..." -if ! curl -s "${API_URL}/health" > /dev/null; then - echo "API is not running. Please start it with: deno task dev" - exit 1 +if ! command -v julia >/dev/null 2>&1; then + printf 'Julia is not installed. Run `mise install` or follow docs/SETUP.adoc.\n' >&2 + exit 127 fi -echo "✓ API is healthy" -echo "" - -# Check if data is loaded -echo "🔍 Checking if SynapCor data is loaded..." -METRIC_COUNT=$(curl -s "${API_URL}/api/analytics/gameable-metrics" | grep -o '"count":[0-9]*' | cut -d: -f2 || echo "0") - -if [ "$METRIC_COUNT" -eq "0" ]; then - echo "⚠️ No data found. Loading SynapCor case study..." - deno task load-data -else - echo "✓ Data is loaded" -fi -echo "" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " Demo 1: Detecting Gameable Metrics" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" -echo "Metrics with large gaps between target and actual values" -echo "suggest either unrealistic targets or gaming behavior." -echo "" -curl -s "${API_URL}/api/analytics/gameable-metrics" | jq '.metrics[] | {name: .metric.name, gap: .gapPercentage, suspicion: .suspicionLevel}' -echo "" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " Demo 2: Metric Theater Detection" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" -echo "Metrics that are collected but never linked to any initiative" -echo "or decision represent 'metric theater' - measurement for its own sake." -echo "" -curl -s "${API_URL}/api/analytics/metric-theater" | jq '{detected: .detected, message: .message}' -echo "" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " Demo 3: Philosophical Reflection" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" -echo "Every good system should question its own existence..." -echo "" -curl -s "${API_URL}/api/reflection" | jq '.' -echo "" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " Demo Complete!" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" -echo "Explore more:" -echo " • API docs: http://localhost:3000/health" -echo " • ArangoDB: http://localhost:8529" -echo " • Virtuoso: http://localhost:8890/conductor" -echo "" -echo "Key endpoints:" -echo " GET /api/analytics/gameable-metrics" -echo " GET /api/analytics/metric-theater" -echo " GET /api/analytics/gap/:id" -echo " GET /api/reflection" -echo "" +julia --project=. -e ' +using PhantomAnalytics +using JSON3 + +impact = PhantomAnalytics.ImpactAnalysis +causal = PhantomAnalytics.CausalInference + +intention = Float64[100, 100, 100, 100] +actual = Float64[110, 112, 108, 115] +println("Intention/reality gap:") +println(JSON3.write(impact.analyze_intention_reality_gap(intention, actual))) + +series = Float64[10, 10, 11, 10, 12, 10, 11, 15, 16, 16, 17, 18, 19, 20] +println("\nMetric-gaming signals:") +println(JSON3.write(impact.detect_metric_gaming(series; window_size=7))) + +treatment = Float64[0, 1, 0, 1, 0, 1] +confounder = Float64[0, 0, 1, 1, 2, 2] +noise = Float64[0.0, 0.1, -0.1, 0.1, -0.1, 0.0] +outcome = 5.0 .+ 2.0 .* treatment .+ 3.0 .* confounder .+ noise +println("\nIllustrative adjusted treatment estimate:") +println(JSON3.write(causal.estimate_causal_effect(treatment, outcome, reshape(confounder, :, 1)))) +' diff --git a/site.json b/site.json index 8f4f717..a77833e 100644 --- a/site.json +++ b/site.json @@ -1,69 +1,35 @@ { - "title": "phantom-metal-taste", + "title": "Phantom Metal Taste", "output": "_site", "index_page": "index.html", "copy": [ - { - "from": "www/public", - "to": ".", - "required": false - }, - { - "from": "www/.well-known", - "to": ".well-known", - "required": false - }, - { - "from": "LICENSES", - "to": "LICENSES", - "required": false - }, - { - "from": "benchmarks", - "to": "benchmarks", - "required": false - }, - { - "from": "case-studies", - "to": "case-studies", - "required": false - }, - { - "from": "docs", - "to": "docs", - "required": false - }, - { - "from": "specs", - "to": "specs", - "required": false - }, - { - "from": "src", - "to": "src", - "required": false - }, - { - "from": "README.adoc", - "to": "README.adoc", - "required": false - } + { "from": ".well-known/ai.txt", "to": ".well-known/ai.txt", "required": true }, + { "from": ".well-known/humans.txt", "to": ".well-known/humans.txt", "required": true }, + { "from": ".well-known/security.txt", "to": ".well-known/security.txt", "required": true }, + { "from": "LICENSE", "to": "LICENSE", "required": true }, + { "from": "LICENSES", "to": "LICENSES", "required": true }, + { "from": "QUICKSTART.adoc", "to": "QUICKSTART.adoc", "required": true }, + { "from": "TEST-NEEDS.adoc", "to": "TEST-NEEDS.adoc", "required": true }, + { "from": "RSR_COMPLIANCE.adoc", "to": "RSR_COMPLIANCE.adoc", "required": true }, + { "from": "benchmarks", "to": "benchmarks", "required": false }, + { "from": "case-studies", "to": "case-studies", "required": true }, + { "from": "docs", "to": "docs", "required": true }, + { "from": "specs", "to": "specs", "required": false }, + { "from": "src", "to": "src", "required": false }, + { "from": "README.adoc", "to": "README.adoc", "required": true } ], "listing": [ { "root": "docs", "label": "Documentation", - "match": [ - ".adoc", - ".md" - ], + "match": [".adoc", ".md"], "link_target": "source" } ], "nojekyll": true, "notes": [ - "Derived by scripts/estate-ruby-exit.mjs — review before merge.", - "index_page is hub/index.html when the repo publishes index.json: GitHub Pages", - "serves index.json for '/' if no index.html exists, and some consumers rely on it." + "The site contains only the paths listed above; it is not the application or an API.", + "The HTML index links to AsciiDoc/Markdown sources copied verbatim; it does not render them.", + "The canonical sources remain in the Git repository." ] } diff --git a/src/PhantomAnalytics.jl b/src/PhantomAnalytics.jl new file mode 100644 index 0000000..41320a0 --- /dev/null +++ b/src/PhantomAnalytics.jl @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +""" + PhantomAnalytics + +Experimental statistical analysis functions for the Phantom Metal Taste project. +The API and results remain prototypes; this package does not expose an HTTP +service or connect to the optional database containers. +""" +module PhantomAnalytics + +module ImpactAnalysis +include("analytics/impact_analysis.jl") +end + +module CausalInference +include("analytics/causal_inference.jl") +end + +export ImpactAnalysis, CausalInference + +end diff --git a/src/analytics/Project.toml b/src/analytics/Project.toml deleted file mode 100644 index 5ea29f3..0000000 --- a/src/analytics/Project.toml +++ /dev/null @@ -1,10 +0,0 @@ -name = "PhantomAnalytics" -uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" -version = "0.1.0" - -[deps] -Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" -JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml index b86f456..4b9f4d0 100644 --- a/src/core/Cargo.toml +++ b/src/core/Cargo.toml @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) + [package] name = "phantom-core" version = "0.1.0" @@ -11,10 +14,3 @@ wasm-bindgen = "0.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde-wasm-bindgen = "0.6" - -[profile.release] -opt-level = "z" # Optimize for size -lto = true # Link-time optimization -codegen-units = 1 # Better optimization -panic = "abort" # Smaller binary size -strip = true # Strip symbols diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index f651f54..59f826f 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell #![forbid(unsafe_code)] -use wasm_bindgen::prelude::*; use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::*; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct MetricGap { @@ -76,10 +76,7 @@ pub fn detect_metric_anomalies(values_json: &str) -> Result { } let mean = values.iter().sum::() / values.len() as f64; - let variance = values - .iter() - .map(|v| (v - mean).powi(2)) - .sum::() / values.len() as f64; + let variance = values.iter().map(|v| (v - mean).powi(2)).sum::() / values.len() as f64; let std_dev = variance.sqrt(); // Check for suspicious patterns @@ -143,8 +140,10 @@ pub fn calculate_synergy_score( pub fn detect_metric_theater(time_series_json: &str) -> Result { #[derive(Deserialize)] struct TimePoint { - timestamp: String, - value: f64, + #[serde(rename = "timestamp")] + _timestamp: String, + #[serde(rename = "value")] + _value: f64, linked_actions: usize, } @@ -179,13 +178,18 @@ pub fn phantom_metal_taste_score( avg_metric_gap: f64, metric_theater_probability: f64, ) -> f64 { + // Preserve this input in the public signature until the experimental score + // model defines how actual outcomes should affect its formula. + let _ = actual_outcomes; + let outcome_ratio = if intended_outcomes > 0 { unintended_outcomes as f64 / intended_outcomes as f64 } else { 2.0 // No intended outcomes measured is very suspicious }; - let base_score = outcome_ratio * 30.0 + avg_metric_gap * 30.0 + metric_theater_probability * 40.0; + let base_score = + outcome_ratio * 30.0 + avg_metric_gap * 30.0 + metric_theater_probability * 40.0; // Cap at 100 base_score.min(100.0) @@ -219,9 +223,9 @@ mod tests { #[test] fn test_phantom_score() { let score = phantom_metal_taste_score( - 5, // intended - 3, // actual - 7, // unintended + 5, // intended + 3, // actual + 7, // unintended 45.0, // avg gap 0.7, // theater prob ); diff --git a/test/runtests.jl b/test/runtests.jl new file mode 100644 index 0000000..e1e7a6f --- /dev/null +++ b/test/runtests.jl @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +using PhantomAnalytics +using Test + +const Impact = PhantomAnalytics.ImpactAnalysis +const Causal = PhantomAnalytics.CausalInference + +@testset "impact analysis" begin + gap = Impact.analyze_intention_reality_gap( + Float64[100, 100, 100, 100], + Float64[110, 112, 108, 115], + ) + @test 0.0 <= gap["phantom_score"] <= 100.0 + @test gap["gap_mean"] > 0.0 + @test_throws ArgumentError Impact.analyze_intention_reality_gap(Float64[1], Float64[1, 2]) + + short = Impact.detect_metric_gaming(Float64[1, 2, 3]) + @test short["gaming_probability"] == 0.0 + @test short["reason"] == "Insufficient data" + + index = Impact.calculate_organizational_delusion_index(2, 4, 1, 12.0, 0.2) + @test 0.0 <= index["organizational_delusion_index"] <= 100.0 + @test startswith(index["grade"], "A") || startswith(index["grade"], "B") || + startswith(index["grade"], "C") || startswith(index["grade"], "D") || + startswith(index["grade"], "F") +end + +@testset "causal analysis" begin + treatment = Float64[0, 1, 0, 1, 0, 1] + confounder = Float64[0, 0, 1, 1, 2, 2] + noise = Float64[0.0, 0.1, -0.1, 0.1, -0.1, 0.0] + outcome = 5.0 .+ 2.0 .* treatment .+ 3.0 .* confounder .+ noise + estimate = Causal.estimate_causal_effect(treatment, outcome, reshape(confounder, :, 1)) + @test estimate["causal_estimate"] ≈ 2.0 atol=0.2 + @test length(estimate["confidence_interval_95"]) == 2 + + spurious = Causal.detect_spurious_correlation( + Float64[1, 2, 3, 5, 6], + Float64[2, 1, 4, 3, 7], + Float64[5, 3, 4, 1, 2], + ) + @test haskey(spurious, "partial_correlation_xy_given_z") +end From fe13db7ff22d4979bc1f31ea1a7d686e4935b201 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sat, 10 Oct 2026 20:22:59 +0000 Subject: [PATCH 2/5] docs: document Guix helpers, site builder, action pinning checks, and scoring functions --- guix.scm | 5 +++ scripts/build-site.mjs | 67 ++++++++++++++++++++++++++++++--- scripts/check-action-pinning.js | 12 ++++++ src/core/src/lib.rs | 21 +++++++++-- 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/guix.scm b/guix.scm index fc068e8..d41a5ed 100644 --- a/guix.scm +++ b/guix.scm @@ -23,6 +23,9 @@ (if (string=? (basename d) "build") (dirname d) d))) (define (spec->input spec) + "Resolve a Guix package specification to an input, returning the package alone +for its default out output or (package output) otherwise. Package resolution +errors propagate to the caller." (call-with-values (lambda () (specification->package+output spec)) (lambda (pkg out) (if (string=? out "out") pkg (list pkg out))))) @@ -32,6 +35,8 @@ ".npmrc" ".netrc" ".pypirc" ".docker" "Manifest.toml")) (define (sensitive-source-name? file) + "Return a non-false value when FILE's basename matches an excluded source name, +prefix or suffix, and #f otherwise. Only the name is checked, not file contents." (let ((base (basename file))) (or (member base %ignored) (string-prefix? ".env." base) diff --git a/scripts/build-site.mjs b/scripts/build-site.mjs index 287521f..cc650d7 100644 --- a/scripts/build-site.mjs +++ b/scripts/build-site.mjs @@ -66,6 +66,11 @@ function fail(message) { // ── config ──────────────────────────────────────────────────────────── +/** + * Read and return the JSON configuration with copy and listing entries normalised. + * Read/parse failures and explicit validation failures exit the process with status + * 1; malformed field types can still throw TypeError during validation. + */ function loadConfig(path) { let parsed; try { @@ -115,9 +120,11 @@ function loadConfig(path) { return parsed; } -// Anything that could make the publisher read or write outside the repo is a -// config bug, not something to sanitise later: no absolute paths, no "..", no -// globs (list a directory and the walker expands it). +/** + * Check a configuration path, using label to identify failures. Empty paths are + * accepted; absolute paths, ".." components and asterisks exit with status 1. + * This checks path syntax only, without resolving symlinks. + */ function assertRelative(path, label) { if (path === "") return; if ( @@ -159,6 +166,7 @@ function walk(dir) { return files.map(toPosixAbs).sort(); } +/** Return a path relative to ROOT with POSIX separators; abs must be below ROOT. */ function toPosixAbs(abs) { return abs .slice(ROOT.length + 1) @@ -192,6 +200,11 @@ function esc(text) { .replaceAll('"', """); } +/** + * Join a normalised base URL and a site-relative path without URL encoding. + * Remove one leading "./"; an empty path or "." links to the base with a trailing + * slash. Other leading dots, including those in ".well-known", are preserved. + */ function urlFor(baseurl, sitePath) { const clean = String(sitePath).replace(/^\.\//, ""); if (clean === "" || clean === ".") @@ -199,6 +212,11 @@ function urlFor(baseurl, sitePath) { return baseurl === "" ? `/${clean}` : `${baseurl}/${clean}`; } +/** + * Return a trimmed base path with a leading slash and no trailing slashes, or "" + * for nullish, blank or slash-only input. Exit with status 1 if the resulting + * path contains characters other than ASCII letters, digits, "._~/-". + */ function normaliseBaseurl(raw) { const value = String(raw ?? "") .trim() @@ -212,7 +230,14 @@ function normaliseBaseurl(raw) { // ── build plan ──────────────────────────────────────────────────────── -// copy: verbatim trees/files from site.json. +/** + * Return {src, site} mappings for configured copies without writing files. + * For a file, to is its destination path (default: its basename at the site root); + * for a directory, to prefixes the relative tree. Missing optional sources are + * skipped; missing required sources and symlink sources exit with status 1. + * Directory walks skip symlinks, excluded names and unreadable directories; + * errors inspecting an existing source propagate. + */ function planCopies(config) { const items = []; for (const entry of config.copy ?? []) { @@ -246,8 +271,12 @@ function planCopies(config) { return items; } -// listing: index sections. link_target "source" also publishes the file, -// link_target "repo" links to the repository browser and publishes nothing. +/** + * Return {sections, published} for files matching the configured suffixes. + * Source links add files to published; repository links only populate sections. + * Preserve paths below each root, skipping absent roots and the symlinks, + * excluded names and unreadable directories omitted by walk. No files are written. + */ function planListings(config) { const sections = []; const published = []; @@ -276,6 +305,10 @@ function planListings(config) { return { sections, published }; } +/** + * Return mappings sorted by site path, keeping the last duplicate mapping. + * Exit with status 1 if distinct sources have the same site path. + */ function dedupe(items) { const bySite = new Map(); for (const item of items) { @@ -292,6 +325,18 @@ function dedupe(items) { // ── build ───────────────────────────────────────────────────────────── +/** + * Assemble the configured site and return {outDir, outputs, digest, published}: + * the absolute output directory, a map of site paths to buffers, their SHA-256 + * digest, and sorted source-to-site mappings (excluding generated files). + * Resolve opts.config and opts.out relative to ROOT; out defaults to config.output. + * opts.baseurl prefixes site links. A truthy opts.dryRun reads and renders inputs + * without writing; otherwise the output directory is recursively replaced. + * The output directory's basename is excluded from this and subsequent walks. + * Config read/parse failures, explicit validation failures, missing required + * sources, source symlinks and path conflicts exit with status 1. Other errors, + * including source reads and output filesystem operations, propagate to callers. + */ function build(opts) { const config = loadConfig(resolve(ROOT, opts.config)); const outDir = resolve(ROOT, opts.out ?? config.output); @@ -378,12 +423,22 @@ function writeSiteFile(outDir, site, buffer) { // ── html ────────────────────────────────────────────────────────────── +/** + * Return a GitHub source URL, encoding each slash-separated component of src. + * Use GITHUB_REPOSITORY and GITHUB_REF_NAME, defaulting to + * hyperpolymath/phantom-metal-taste and main when unset. + */ function repoUrl(src) { const slug = env.GITHUB_REPOSITORY ?? "hyperpolymath/phantom-metal-taste"; const ref = env.GITHUB_REF_NAME ?? "main"; return `https://github.com/${slug}/blob/${ref}/${src.split("/").map(encodeURIComponent).join("/")}`; } +/** + * Return the landing-page HTML with non-empty listing sections and links to the + * first 200 manifest entries, showing their sizes in bytes. Source links use the + * normalised baseurl; repository links use the GitHub environment settings. + */ function renderIndex({ config, baseurl, sections, manifest }) { const blocks = []; for (const section of sections) { diff --git a/scripts/check-action-pinning.js b/scripts/check-action-pinning.js index c992d20..a418325 100755 --- a/scripts/check-action-pinning.js +++ b/scripts/check-action-pinning.js @@ -46,6 +46,10 @@ const USES = /^\s*-?\s*uses:\s*([^\s#]+)/; const SHA = /@[a-f0-9]{40}$/; const EXEMPT_PREFIX = ["./", "$", "docker://"]; +/** + * Return sorted .yml/.yaml paths directly below .github/workflows in the current + * directory, or [] if it is absent or not a directory. Filesystem errors propagate. + */ function workflowFiles() { if (!existsSync(WF) || !statSync(WF).isDirectory()) return []; return readdirSync(WF) @@ -54,6 +58,14 @@ function workflowFiles() { .map((f) => join(WF, f)); } +/** + * Report action references rejected by the pin check; return 1 if any fail, else 0. + * Accept lowercase 40-hex SHA suffixes or case-insensitive reference matches in + * single-quoted actions.lock entries, including repository roots for subpath + * actions. Lockfile matches do not verify the resolved SHA. References beginning + * with "./", "$" or "docker://" are exempt. Missing workflows pass; filesystem + * errors propagate rather than becoming a return code. + */ function main() { if (!existsSync(WF)) { console.log("no .github/workflows — nothing to check"); diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 59f826f..456065b 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -134,8 +134,17 @@ pub fn calculate_synergy_score( } } -/// Analyze time series for "metric theater" patterns -/// Returns probability (0-1) that metrics are being gamed +/// Estimate a "metric theatre" score in 0..=1 from points with no linked actions. +/// +/// `time_series_json` must be an array of objects with a string `timestamp`, a +/// numeric `value` and a non-negative integer `linked_actions`. Timestamp and +/// value are required but do not affect the score. An empty series returns 0. +/// For up to 10 points, the score is half the unlinked fraction; otherwise it is +/// 0.7 times that fraction, plus 0.3 when the fraction exceeds 0.8, capped at 1. +/// +/// # Errors +/// Returns a `JsValue` prefixed with "Parse error: " if JSON deserialisation fails, +/// including missing fields or values incompatible with the required fields. #[wasm_bindgen] pub fn detect_metric_theater(time_series_json: &str) -> Result { #[derive(Deserialize)] @@ -168,8 +177,12 @@ pub fn detect_metric_theater(time_series_json: &str) -> Result { Ok(theater_probability.min(1.0)) } -/// Calculate the "phantom metal taste" score -/// The core metric: how wrong does this feel? +/// Calculate the "phantom metal taste" score, capped at 100 with no lower bound. +/// +/// Add 30 times the unintended/intended outcome ratio, 30 times `avg_metric_gap` +/// and 40 times `metric_theater_probability`. When intended outcomes are zero, +/// use a ratio of 2. `actual_outcomes` is currently ignored. The gap and +/// probability are used as supplied, without rescaling or range validation. #[wasm_bindgen] pub fn phantom_metal_taste_score( intended_outcomes: usize, From eaa8086c9d80c90d4d9a2576127ee0445bde94e1 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sat, 10 Oct 2026 20:30:27 +0000 Subject: [PATCH 3/5] docs: refresh reproducible site digests Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com> --- phantom-metal-taste_chora.deed | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phantom-metal-taste_chora.deed b/phantom-metal-taste_chora.deed index a096668..3b8795c 100644 --- a/phantom-metal-taste_chora.deed +++ b/phantom-metal-taste_chora.deed @@ -106,8 +106,8 @@ (verification :checked-on "2026-10-10" :site-output "49 files; 46 sources copied" - :site-root-base-sha256 "fe2c7fac9f1f558b2a4bf066240a220fddda8d400106933a86157b7914ec7149" - :site-project-base-sha256 "4a4626680a7497d72d939e752aead0f17ecf3b67cfc916d072491fb71546ff3c" + :site-root-base-sha256 "9daef5fa4f43a21379a83a01cc133af12b03e982315ac90f06d504d52937a8a5" + :site-project-base-sha256 "a6aacdaee9a27750b8c53b74ce75a87920f8fe918af99c4549ff490b9a4f3bd9" :site-reproducibility "pass: two root-base builds match; project-base build passes" :bun-tests "pass: 5 tests, 0 failures, 20 expect calls (Bun 1.4.3)" :source-archive "pass: no .git; Bun tests/build, launcher help/version, no-A2ML check" From 1f78bbd2f63327b0d95b39a8afa0c0c00933e60b Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sat, 10 Oct 2026 21:43:08 +0100 Subject: [PATCH 4/5] Update compose.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/compose.yml b/compose.yml index 94aa9eb..5fffb39 100644 --- a/compose.yml +++ b/compose.yml @@ -6,7 +6,6 @@ services: container_name: phantom-arangodb environment: ARANGO_ROOT_PASSWORD: ${ARANGO_ROOT_PASSWORD:?required} - ARANGO_NO_AUTH: "0" ports: - "127.0.0.1:8529:8529" volumes: From 6074a56717b7347f8d32ffd3611bf127f32f09e3 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sat, 10 Oct 2026 20:44:57 +0000 Subject: [PATCH 5/5] fix: exclude .envrc from Guix sources, label focus-sprint as fictional, and remove stale ADR reference --- docs/architecture/TOGAF-ADM.adoc | 2 +- docs/diagrams/focus-sprint-failure.puml | 2 +- guix.scm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/TOGAF-ADM.adoc b/docs/architecture/TOGAF-ADM.adoc index b24fb9a..c237a7a 100644 --- a/docs/architecture/TOGAF-ADM.adoc +++ b/docs/architecture/TOGAF-ADM.adoc @@ -799,7 +799,7 @@ All architecture change requests follow the standard process: | Reflexivity Concern | The theoretical problem arising when the Synergy Matrix attempts to measure itself. Resolved architecturally by excluding the system from - its own analysis (see ADR-004). + its own analysis. | Sponsor-Originated Request | A change request submitted by Chad Kensington, which follows an diff --git a/docs/diagrams/focus-sprint-failure.puml b/docs/diagrams/focus-sprint-failure.puml index 8d30265..5b207b9 100644 --- a/docs/diagrams/focus-sprint-failure.puml +++ b/docs/diagrams/focus-sprint-failure.puml @@ -21,7 +21,7 @@ skinparam sequence { GroupBorderColor #E65100 } -title Focus-Sprint Protocol: Intended Path vs. Reality +title Fictional Focus-Sprint Protocol: Intended Path vs. Reality actor "Chad Kensington\n(VP Human Synergy)" as Chad #E8EAF6 participant "Synergy Matrix\nSystem" as System #C8E6C9 diff --git a/guix.scm b/guix.scm index d41a5ed..1bce555 100644 --- a/guix.scm +++ b/guix.scm @@ -31,7 +31,7 @@ errors propagate to the caller." (define %ignored '(".git" "target" "_site" ".eval" "node_modules" ".cache" - ".cargo" ".julia" ".env" "secrets" ".ssh" ".aws" ".kube" "credentials" + ".cargo" ".julia" ".env" ".envrc" "secrets" ".ssh" ".aws" ".kube" "credentials" ".npmrc" ".netrc" ".pypirc" ".docker" "Manifest.toml")) (define (sensitive-source-name? file)