diff --git a/CHANGELOG.md b/CHANGELOG.md index f66d1685..f6429d85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), `npm run check:changelog` holds this file's shape; the CI step "CHANGELOG per-PR entry check" holds each PR's diff. Details and known costs: CONTRIBUTING.md, "CHANGELOG entries". --> +## [6.28.4] - 2026-09-27 + +### Changed + +- **Document the floor's Node 24.2 requirement, the 6.28.2 product-command budget for contributors, and the 6.24.0 write-guard posture in user-facing docs.** README states that `@pharn-dev/pharn` still requires Node 20+ while `pharn/floor/*.mjs` needs Node 24.2+ (`import.meta.main`). CONTRIBUTING adds the `command-hygiene.test.mjs` ceilings and the rule for raising them. SECURITY names `run-marker.mjs` and clarifies that an installed project's permissive default outside an open run is intentional, not a write-guard bypass. +- **Release housekeeping:** remove one-shot patch/apply helpers after merge; align CHANGELOG with `main` (this section). `SKILLS_VERSION` 6.28.3 → 6.28.4 (PATCH: root documentation only — README, CONTRIBUTING, SECURITY — not the installable `pharn/` product surface). `MIN_CLI` stays 0.5.0. +- **CHANGELOG section order:** put `[Unreleased]` above released version sections (Keep a Changelog) so `check-skills-version-recorded` and CI pass. + ## [6.28.3] - 2026-09-27 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d2c91ed..f88095e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,6 +44,18 @@ Three doc regions are **generated, never hand-edited**: `docs/capabilities/**`, What that buys is **byte-equality** — the committed output equals a fresh regeneration — never that the generated content is _right_: a wrong enumerator regenerates cleanly and stays GREEN. See [`CLAUDE.md`](./CLAUDE.md) ("Three doc regions are GENERATED") for the full rule, including the one case (`ENUM_ERROR` — a duplicate lesson id, an unsafe title) where regenerating cannot help and the canon file has to be fixed instead. +### Editing product commands (`.claude/commands/pharn-*.md`) + +Since 6.28.2, [`.dev/floor/command-hygiene.test.mjs`](./.dev/floor/command-hygiene.test.mjs) enforces a **command budget** on every shipped `pharn-*` command (not `pharn-dev-*`): + +- **Size** — each command's bytes must stay at or below its row in the test's `COMMAND_BYTE_CEILINGS` table (closed over the product commands on disk, both ways). +- **Frontmatter `description:`** — at most 250 bytes and must not match the test's claim-vocabulary regex. +- **Claims block** — exactly one `## What you may claim` heading per command. + +The test checks presence and limits, not whether a claim is true. If an increment genuinely needs a larger command, **raise the ceiling in the same PR** by editing `COMMAND_BYTE_CEILINGS`: take the command's measured byte size, add 10%, round up to the next multiple of 512 — never a quiet edit to turn a red test green. Rationale and bounds live in [`CLAUDE.md`](./CLAUDE.md) ("A product command keeps what a run executes…"). + +`AGENTS.md` at the repo root is **gitignored** (a local Codex copy). It does not ship; if you use Codex here, regenerate it from `CLAUDE.md` when the latter moves. + ### CHANGELOG entries `pharn-cli` installs the tip of `main`, and `pharn update` points users at [`CHANGELOG.md`](./CHANGELOG.md). So every merge to `main` is a release, and the CHANGELOG is the only record a user reads of what reached them. Four rules: diff --git a/README.md b/README.md index 8264be45..b0daf057 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ model or human judgment remains advisory. npx @pharn-dev/pharn@latest init ``` -[![pharn](https://img.shields.io/badge/pharn-6.28.3-blue)](./CHANGELOG.md) +[![pharn](https://img.shields.io/badge/pharn-6.28.4-blue)](./CHANGELOG.md) [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE) [![CI](https://github.com/pharn-dev/pharn-oss/actions/workflows/ci.yml/badge.svg)](https://github.com/pharn-dev/pharn-oss/actions/workflows/ci.yml) [![CodeQL](https://github.com/pharn-dev/pharn-oss/actions/workflows/codeql.yml/badge.svg)](https://github.com/pharn-dev/pharn-oss/actions/workflows/codeql.yml) @@ -109,8 +109,11 @@ them. The goal is not to make AI development look clean. The goal is to make it ## Quick start -PHARN runs on [Claude Code](https://claude.com/claude-code). The installer requires Node 20 or newer. In -your project root: +PHARN runs on [Claude Code](https://claude.com/claude-code). The `@pharn-dev/pharn` installer requires +Node 20 or newer. The deterministic floor checkers this repo ships (`pharn/floor/*.mjs`, invoked by the +`/pharn-*` stages) require **Node 24.2 or newer**: their CLI entry points gate on `import.meta.main`, which +Node added in 22.18 / 24.2. On an older Node a guarded tool can exit `0` without running its checks — a +silent false green for several gates. CI and local contributor gates use Node 24. In your project root: ```bash npx @pharn-dev/pharn@latest init diff --git a/SECURITY.md b/SECURITY.md index 36cd425f..f4b2514d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ PHARN is an audit-grade methodology — taking security seriously is part of the ## What this repo is, and its security surface -This repository **is PHARN-OSS** — the audit-grade methodology itself. It is ready to install and use with Claude Code today; active development continues, and functionality that has not shipped yet is explicitly labeled. Its security surface is small by design: four trusted markdown spec docs, the `pharn-dev-*` build and `pharn-*` product commands, the hooks under `.claude/hooks/` — the two `PreToolUse` write guards (`protect-trusted-paths.cjs`, the protected-path guard, and `enforce-writes-scope.cjs`, the writes-scope guard), the scope setter they read (`set-writes-scope.cjs`), and the `/pharn-loop` `Stop` guard (`require-loop-record.cjs`, which fails open by design) — and the deterministic floor (`pharn/floor/`). No transpile step, no bundled runtime dependencies, no network egress, no secrets — stdlib-only Node (`.cjs`/`.mjs`) plus markdown. +This repository **is PHARN-OSS** — the audit-grade methodology itself. It is ready to install and use with Claude Code today; active development continues, and functionality that has not shipped yet is explicitly labeled. Its security surface is small by design: four trusted markdown spec docs, the `pharn-dev-*` build and `pharn-*` product commands, the hooks under `.claude/hooks/` — the two `PreToolUse` write guards (`protect-trusted-paths.cjs`, the protected-path guard, and `enforce-writes-scope.cjs`, the writes-scope guard), the scope setter they read (`set-writes-scope.cjs`), the run markers `/pharn-ship`, `/pharn-loop` and `/pharn-review` open and close via `pharn/floor/run-marker.mjs` (presence under `.pharn/pharn-{ship,loop,review}//active.json` — the guard reads only path and age, never contents), and the `/pharn-loop` `Stop` guard (`require-loop-record.cjs`, which fails open by design) — and the deterministic floor (`pharn/floor/`). No transpile step, no bundled runtime dependencies, no network egress, no secrets — stdlib-only Node (`.cjs`/`.mjs`) plus markdown. PHARN's security model (`THREAT-MODEL.md`, threat model B) starts from one axiom: **prompt injection is not solved.** An agent that must read hostile context — code under review, fetched docs, accumulated memory, another model's output — cannot be made to reliably ignore instructions embedded in that content. Defense therefore rests on the **deterministic floor** (hooks, content-hashes, enum/regex checks that do not depend on model judgment), not on "the model will notice the attack." The security-relevant surfaces of this repo follow from that shape. @@ -48,7 +48,7 @@ We will keep you informed throughout, coordinate disclosure timing with you, and ### In scope - **Prompt injection** in the trusted spec docs, the `pharn-dev-*` / `pharn-*` commands, or a capability — content that bypasses the constitution, or launders untrusted data into a guaranteed decision (the trust-fence; `THREAT-MODEL.md §5`). -- **Write-guard bypass** — any input that makes `protect-trusted-paths.cjs` _allow_ a Write/Edit it should deny to a path it protects — a trusted doc, `CODEOWNERS`, the guards' own settings files and hook scripts, `.pharn/writes-scope.json`, the project SPEC template (`pharn.spec-template.md`), git metadata, or memory-bank canon outside a promotion scope — or makes `enforce-writes-scope.cjs` allow a write outside the active scope (e.g. a path-normalization or path-traversal gap; fix #2 / fix #7, `THREAT-MODEL.md §4`). Writes through the Bash tool are outside both hooks by design (`LIMITS.md §6`), so a Bash write on its own is not a bypass. +- **Write-guard bypass** — any input that makes `protect-trusted-paths.cjs` _allow_ a Write/Edit it should deny to a path it protects — a trusted doc, `CODEOWNERS`, the guards' own settings files and hook scripts, `.pharn/writes-scope.json`, the project SPEC template (`pharn.spec-template.md`), git metadata, or memory-bank canon outside a promotion scope — or makes `enforce-writes-scope.cjs` _allow_ a Write/Edit the guard would deny under the posture and scope that should apply (dev checkout, installed project with an open PHARN run, installed project outside a run, explicit `writes-scope.json`, etc.; fix #2 / fix #7, `THREAT-MODEL.md §4`, CHANGELOG [6.24.0]). **Not a bypass:** since 6.24.0, an installed project with no active scope and no open `/pharn-ship`, `/pharn-loop`, or `/pharn-review` run intentionally uses a permissive default that allows most in-project writes — that is documented product behavior, not a guard failure. A bypass is a normalization, traversal, symlink-resolution, or logic flaw that reaches a path the guard should still deny given the correct posture. Writes through the Bash tool are outside both hooks by design (`LIMITS.md §6`), so a Bash write on its own is not a bypass (fix #7 detects some Bash writes at verify time, but does not prevent them). - **Floor false-negative** — a logic flaw in `pharn/floor/validate.mjs` (or any `pharn/floor/*.mjs` checker) that reports GREEN for input violating an invariant it claims to enforce (a false guarantee — the exact P0 failure mode). - Any other defect in the executable floor (a `.claude/hooks/*.cjs` hook or a `pharn/floor/*.mjs` checker) that undermines a guarantee the docs claim. diff --git a/SKILLS_VERSION b/SKILLS_VERSION index 3b4b6fd2..3290bcf4 100644 --- a/SKILLS_VERSION +++ b/SKILLS_VERSION @@ -1 +1 @@ -6.28.3 +6.28.4