Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
33 changes: 17 additions & 16 deletions .clinerules
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (c) {{CURRENT_YEAR}} {{AUTHOR}} ({{OWNER}}) <{{AUTHOR_EMAIL}}>
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
# Authoritative source: docs/practice/AI-CONVENTIONS.adoc

# STARTUP: Read the repo deed (*_chora.deed at the repo root) first, then .machine_readable/descriptiles/STATE.a2ml.
# STARTUP: Read the repo deed (*_chora.deed at the repo root) first, then docs/status/ROADMAP.adoc.

# LICENSE
# All original code: MPL-2.0.
# Never AGPL-3.0. MPL-2.0 only as platform-required fallback.
# SPDX header required on every source file.
# Copyright: {{AUTHOR}} ({{OWNER}}) <{{AUTHOR_EMAIL}}>
# Copyright: Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>

# STATE FILES (.machine_readable/ ONLY)
# Never create in repo root: STATE.a2ml, META.a2ml, ECOSYSTEM.a2ml,
# AGENTIC.a2ml, NEUROSYM.a2ml, PLAYBOOK.a2ml.
# The .machine_readable/ directory is the single source of truth.
# STATE FILES
# No .a2ml file may exist anywhere: the format is retired. State, metadata,
# (neurosym) and (playbook) are clauses of the repo deed (*_chora.deed);
# the journal is docs/status/ROADMAP.adoc. Never recreate them as files.
# The repo deed and .machine_readable/ are the single source of truth.

# BANNED PATTERNS
# Idris2: believe_me, assert_total, assert_smaller, unsafePerformIO
Expand All @@ -23,15 +24,15 @@
# Lean: sorry
# Rust: transmute (unless FFI with // SAFETY: comment)

# JS/TS RUNTIMES — ordered preference, reach for the first that can do the job
# (standards/3-practice/LANGUAGE-POLICY.adoc section 1, ruled 2026-07-29)
# 1. Bun default for all new work; runs .ts directly, no build step
# 2. Deno existing Deno projects are grandfathered; prefer over pnpm/npm
# 3. pnpm only where an upstream toolchain needs a node_modules layout
# 4. npm last resort; permitted, never preferred — a noted decision
# TypeScript IS PERMITTED under Bun. The old "use ReScript instead" rule is
# RETIRED: ReScript is no longer used in this estate, so that rule named a dead
# alternative. Do NOT migrate Bun to Deno — that inverts the current ruling.
# JS RUNTIME — Bun first (standards/3-practice/LANGUAGE-POLICY.adoc sections 1.3-1.4)
# 1. Bun tier 1: package.json + bun.lock, run with bun / bunx
# 2. Deno tier 2: permitted; runs the same package.json scripts (deno task)
# 3. pnpm tier 3
# 4. npm last resort; permitted, never preferred; keeps no lock
# One package.json carries every runtime's lock (bun.lock, deno.lock,
# pnpm-lock.yaml); `js-runtimes regen` writes all three (owner ruling
# 2026-10-14). TypeScript and ReScript are banned; they migrate to
# AffineScript. Use plain JavaScript where JS is needed.

# BANNED LANGUAGES
# Go -> Rust
Expand Down
33 changes: 33 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# SPDX-License-Identifier: MPL-2.0
# CodeRabbit reviews changes; humans and authorised agents own changes.
# Canonical estate language policy:
# https://github.com/metadatastician/standards/blob/main/3-practice/LANGUAGE-POLICY.adoc
# This template must never permit unsolicited AI-generated fixes/commits.
reviews:
path_instructions:
- path: "**/*"
instructions: >-
Enforce the canonical estate language policy: Python is prohibited
for all NEW work, without exceptions. Do not suggest Python
implementations or tests, and flag newly added/modified Python
files or dependency manifests as policy violations. Use the owning
project's approved language and runtime. Pre-existing third-party
code is not permission to author new Python. Do not demand language
migrations of unrelated upstream dependencies as cosmetic PR work.
pre_merge_checks:
docstrings:
mode: warning
threshold: 80
finishing_touches:
docstrings:
enabled: false
unit_tests:
enabled: false
simplify:
enabled: false
autofix:
enabled: false
fix_ci:
enabled: false
resolve_merge_conflict:
enabled: false
54 changes: 0 additions & 54 deletions .cursorrules

This file was deleted.

34 changes: 26 additions & 8 deletions .devcontainer/Containerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (c) {{CURRENT_YEAR}} {{AUTHOR}} ({{OWNER}}) <{{AUTHOR_EMAIL}}>
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
#
# Dev Container image for {{PROJECT_NAME}}
# Dev Container image for occupancy-types
# Base: Chainguard Wolfi (minimal, supply-chain-secure)
# Build: podman build -t {{PROJECT_NAME}}-dev -f .devcontainer/Containerfile .
# Build: podman build -t occupancy-types-dev -f .devcontainer/Containerfile .
# `:latest` suits a dev container (rebuilt daily); pin by digest
# (...@sha256:<digest>) if you need a reproducible dev environment.
#
# Every tool comes from Wolfi or from a sha256-checked release binary, so the
# image builds with no dev-container features (registry-hosted features can
# vanish or turn private, and then nobody can start the container).

FROM cgr.dev/chainguard/wolfi-base:latest

Expand All @@ -14,19 +18,33 @@ RUN apk update && apk add --no-cache \
bash \
curl \
git \
just \
openssh-client \
ca-certificates \
build-base \
posix-libc-utils \
shadow \
&& rm -rf /var/cache/apk/*

# Create non-root dev user (matches devcontainer.json remoteUser)
RUN groupadd -g 1000 nonroot || true \
&& useradd -m -u 1000 -g 1000 -s /bin/bash nonroot || true
# Nickel (the .machine_readable contracts): the same verified release CI uses
# (.github/workflows/estate-rules.yml). Bump the version and both digests together.
ARG NICKEL_VERSION=1.17.0
RUN set -eu; \
case "$(uname -m)" in \
x86_64) asset=nickel-x86_64-linux; sum=afcdfa6e0fff31760cf229e85997456c02c00b8b3b84ff38f897ac7b3f39ae34 ;; \
aarch64) asset=nickel-arm64-linux; sum=9d7e027fde829b5788c92231c27fcfc926ee841d0716d655cee202c9f582e0c0 ;; \
*) echo "no Nickel release binary for $(uname -m)" >&2; exit 1 ;; \
esac; \
curl --proto '=https' --proto-redir '=https' -fsSL \
"https://github.com/nickel-lang/nickel/releases/download/${NICKEL_VERSION}/${asset}" \
-o /usr/local/bin/nickel; \
echo "${sum} /usr/local/bin/nickel" | sha256sum -c -; \
chmod 0755 /usr/local/bin/nickel

# Dev user: wolfi-base already ships `nonroot` (uid/gid 65532, home /home/nonroot);
# devcontainer.json maps your host user onto it with --userns=keep-id.

# Set workspace directory
WORKDIR /workspaces/{{PROJECT_NAME}}
WORKDIR /workspaces/occupancy-types

# Default shell
ENV SHELL=/bin/bash
Expand Down
49 changes: 41 additions & 8 deletions .devcontainer/README.adoc
Original file line number Diff line number Diff line change
@@ -1,28 +1,61 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
// Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
= Dev Container Usage
:author: {{AUTHOR}} <{{AUTHOR_EMAIL}}>
:author: Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>

== Overview

This dev container uses `cgr.dev/chainguard/wolfi-base` with git, curl, bash, and just pre-installed. Dev container features add git, just, and nickel automatically.
The image (`Containerfile`) is `cgr.dev/chainguard/wolfi-base` with bash, curl,
git, just, openssh-client and a C toolchain from Wolfi packages, plus the Nickel
release binary (SHA-256 checked). It uses no dev container *features*: the
feature images are pulled from ghcr.io and can fail anonymously, which would stop
anyone from opening the container.

== VS Code (Local)
You work as `nonroot`, the user built into wolfi-base (uid/gid 65532).

There are two configurations for the same image:

[cols="1,2,3"]
|===
| Config | Engine | Why

| `devcontainer.json`
| rootless Podman (estate default)
| Maps your host user onto `nonroot` with `--userns=keep-id:uid=65532,gid=65532`,
so the bind-mounted workspace is writable. `--security-opt=label=disable`
lets the mount work on SELinux-enforcing hosts.

| `docker/devcontainer.json`
| Docker, GitHub Codespaces, Gitpod
| Docker rejects `--userns=keep-id`, so this one has no `runArgs`.
|===

== VS Code (local, Podman)

. Install the *Dev Containers* extension (`ms-vscode-remote.remote-containers`).
. Set `dev.containers.dockerPath` to `podman` in VS Code settings.
. Open the repo folder, then choose **Reopen in Container** from the command palette.
. Open the repo folder, then choose **Reopen in Container** and pick
**occupancy-types (Podman)**.

== devcontainer CLI (Podman)

[source,sh]
----
bunx @devcontainers/cli up --workspace-folder . --docker-path podman
----

== GitHub Codespaces

. From the repository on GitHub, click **Code > Codespaces > New codespace**.
. The container builds automatically from this configuration.
. From the repository on GitHub, click **Code > Codespaces > ... > New with options**.
. Choose the **occupancy-types (Docker / Codespaces)** configuration.

== Gitpod

. Prefix the repo URL with `https://gitpod.io/#` to launch a workspace.
. Gitpod reads `devcontainer.json` and builds the environment.
. Point Gitpod at `.devcontainer/docker/devcontainer.json`.

== Customization

Replace `{{PROJECT_NAME}}` placeholders in both `devcontainer.json` and `Containerfile` with your actual project name. Run `just deps` to verify the environment after first launch.
Replace the `occupancy-types` placeholders in both `devcontainer.json` files and
the `Containerfile` with your actual project name. `just deps` runs automatically
after the container is created. Run it again to check the environment.
63 changes: 27 additions & 36 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,22 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) {{CURRENT_YEAR}} {{AUTHOR}} ({{OWNER}}) <{{AUTHOR_EMAIL}}>
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
//
// Dev Container configuration for {{PROJECT_NAME}}
// Works with: VS Code Dev Containers, GitHub Codespaces, Gitpod
// Container runtime: Podman (recommended) or any OCI-compliant runtime
// Dev Container configuration for occupancy-types — rootless Podman (default).
// Works with: VS Code Dev Containers with `dev.containers.dockerPath` = podman,
// and the devcontainer CLI (`devcontainer up --docker-path podman`).
// Docker, GitHub Codespaces and Gitpod: use .devcontainer/docker/devcontainer.json
// instead — Docker rejects the Podman-only `--userns=keep-id` below.
{
"name": "{{PROJECT_NAME}}",

"build": {
"dockerfile": "Containerfile",
"context": ".."
"context": "..",
"dockerfile": "Containerfile"
},

"features": {
"ghcr.io/devcontainers/features/git:1": {
"ppa": false,
"version": "latest"
},
"ghcr.io/jdx/devcontainer-features/just:1": {},
"ghcr.io/nickel-lang/devcontainer-feature:0": {}
},

"postCreateCommand": "just deps",

"remoteUser": "nonroot",

"containerEnv": {
"EDITOR": "code --wait",
"HOME": "/home/nonroot",
"LANG": "C.UTF-8"
},

"containerUser": "nonroot",
"customizations": {
"vscode": {
"extensions": [
Expand All @@ -45,25 +32,29 @@
"usernamehw.errorlens"
],
"settings": {
"[makefile]": {
"editor.insertSpaces": false
},
"editor.formatOnSave": true,
"editor.insertSpaces": true,
"editor.tabSize": 2,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"[makefile]": {
"editor.insertSpaces": false
}
"files.trimTrailingWhitespace": true
}
},
"codespaces": {
"openFiles": [
"README.adoc"
]
}
},

"forwardPorts": [],

"shutdownAction": "stopContainer"
"name": "occupancy-types (Podman)",
"postCreateCommand": "just deps",
"remoteUser": "nonroot",
// Rootless Podman maps your host user to root inside the container, so the
// bind-mounted workspace would be owned by root and unwritable for `nonroot`.
// keep-id maps your host user to uid/gid 65532 (`nonroot`, built into wolfi-base) instead.
// label=disable lets the workspace mount work on SELinux-enforcing hosts.
"runArgs": [
"--userns=keep-id:uid=65532,gid=65532",
"--security-opt=label=disable"
],
"shutdownAction": "stopContainer",
"updateRemoteUserUID": false
}
Loading
Loading