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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .machine_readable/6a2/STATE.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[metadata]
project = "palimpsest-plasma"
version = "0.5.0"
version = "0.6.0"
last-updated = "2026-07-02"
status = "active"

Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.6.0] - 2026-07-17

### Added

- feat(engine): content facts + `file-matches-pattern` — opt-in
`FactSet.file_contents` (`collect_opts`, valid-UTF-8 files ≤ 1 MiB),
omitted from the default snapshot so the v0.4 wire contract stays
byte-identical. The condition's regex is validated at load
(`InvalidRegex`) so evaluation stays total; false when a file's content
was not collected. `plasma check`/`fix` collect content automatically iff
the policy needs it; `plasma facts --with-contents` forces it
(`plasma-engine/src/{facts,eval,schema,ast}.rs`)
- feat(engine): `CreateFile` fix action — a required file at a *concrete*
path (not a glob) that is missing is created with obvious placeholder
content, never overwriting an existing file; glob-named required files
stay manual (`plasma-engine/src/{action,apply}.rs`)
- docs: content-facts + overlay/action updates across
`engine-v0-design.adoc`, `interchange-contracts.adoc`, `cli-design.adoc`

## [0.5.0] - 2026-07-16

### Added
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authors:
family-names: "Jewell"
email: "j.d.a.jewell@open.ac.uk"
affiliation: "hyperpolymath"
version: 0.5.0
version: 0.6.0
date-released: 2026-07-02
license: "MPL-2.0"
repository-code: "https://github.com/hyperpolymath/palimpsest-plasma"
Expand Down
45 changes: 42 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ members = [".", "plasma-parser", "plasma-engine"]

[package]
name = "palimpsest-plasma"
version = "0.5.0"
version = "0.6.0"
edition = "2021"
rust-version = "1.74"
authors = ["Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"]
Expand Down
2 changes: 1 addition & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ set positional-arguments := true
import? "contractile.just"

project := "palimpsest-plasma"
version := "0.5.0"
version := "0.6.0"
tier := "infrastructure"
state := ".machine_readable/6a2/STATE.a2ml"

Expand Down
6 changes: 4 additions & 2 deletions ROADMAP.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ future project; the earlier union-policy-parser sub-project was removed
* [x] `plasma fix` — plan (dry-run) and apply modes, with `.bak` backups
* [x] Findings → planned actions mapping (pure `plan`; IO `apply`)
* [x] First action type: `AddSpdxHeader` (+ manual partition with reasons)
* [ ] More action types (CreateFile, UpdateField, …)
* [x] Action type `CreateFile` (v0.6) — create a missing required file at a
concrete path; `UpdateField` and others still to come
* [x] Overlay `override-rules` semantics (v0.5) — remove/replace base rules
per context; `modify-rules` remains reserved
* [ ] Content facts + `file-matches-pattern` condition semantics
* [x] Content facts + `file-matches-pattern` condition semantics (v0.6) —
opt-in `file_contents`, regex validated at load

=== v0.4.0 — Interchange Contracts & Integration Surfaces [IN PROGRESS]

Expand Down
2 changes: 1 addition & 1 deletion codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"programmingLanguage": [
"Rust"
],
"version": "0.5.0",
"version": "0.6.0",
"url": "https://github.com/hyperpolymath/palimpsest-plasma",
"readme": "https://github.com/hyperpolymath/palimpsest-plasma/blob/main/README.adoc",
"issueTracker": "https://github.com/hyperpolymath/palimpsest-plasma/issues",
Expand Down
22 changes: 15 additions & 7 deletions docs/cli-design.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ plasma check [PATH] [--policy FILE] [--format human|json|sarif]
[--severity error|warning|info] [--quiet] [--verbose]
plasma fix [PATH] [--policy FILE] [--license SPDX-ID] [--author NAME]
[--apply] [--no-backup] [--format human|json] # v0.3
plasma facts [PATH]
plasma facts [PATH] [--with-contents]
plasma diff BEFORE.json AFTER.json [--format human|json] # v0.4
plasma policy validate FILE
plasma audit [PATH] [--license SPDX-EXPR] [--fix]
Expand Down Expand Up @@ -55,15 +55,18 @@ changes, writing a `<file>.bak` backup before modifying each file (unless
The planner is pure (`plasma_engine::plan`); applying is the IO boundary
(`plasma_engine::apply`). Every violation is either turned into a
mechanical action or listed under *Manual* with a reason — nothing is
silently unfixable. The v0.3 auto-action set is:
silently unfixable. The auto-action set is:

* **AddSpdxHeader** — a source file that must carry an SPDX header but does
not gets one prepended, using `--license` (default MPL-2.0), `--author`,
and the correct comment prefix for the file type.
* **CreateFile** (v0.5) — a required file at a *concrete* path (not a glob)
that is missing is created with obvious placeholder content. Never
overwrites an existing file.

Missing required files (LICENSE, README) and unparsable headers are
reported as manual (they need human-authored content). Applying is
idempotent: a file that already has a header is skipped.
A required file named by a *glob* (e.g. `LICENSE*` — no single filename to
create) and unparsable headers are reported as manual. Applying is
idempotent: a file that already has a header, or already exists, is skipped.

* **Flags:** `--policy FILE`, `--license SPDX-ID`, `--author NAME`,
`--apply`, `--no-backup`, `--format human|json`
Expand All @@ -81,6 +84,11 @@ simply its first supported action class.
Dump the deterministic fact snapshot the evaluator sees, as JSON. This is
the diffable before/after artifact for agent-verification tooling.

* `--with-contents` — also include text-file contents (`file_contents`),
needed for content-aware policies. Off by default so the snapshot stays
lean; `plasma check`/`fix` enable it automatically when the policy uses a
`file-matches-pattern` condition.

=== `plasma diff`

Compare two fact snapshots produced by `plasma facts`. This is the
Expand Down Expand Up @@ -118,8 +126,8 @@ proper `-`→`--` escaping.

== Roadmap surfaces (not yet implemented)

* More `plasma fix` actions — CreateFile / UpdateField (beyond the v0.3
AddSpdxHeader action)
* More `plasma fix` actions — `UpdateField` (beyond the v0.3 `AddSpdxHeader`
and v0.5 `CreateFile` actions)
* Git hooks (pre-commit/pre-push wrapping `plasma check --quiet`) and a
reference GitHub Action / GitLab job (v0.4)
* `plasma governance` / decision registries — awaits `consistent-with`
Expand Down
29 changes: 20 additions & 9 deletions docs/engine-v0-design.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ at **load**, never mid-evaluation (`plasma-engine/src/schema.rs`):
replacement of an overridden rule is legal
* `override-rules` targeting an id that names no base rule →
`OverrideUnknownRule`
* a `file-matches-pattern` regex that does not compile → `InvalidRegex`
(so evaluation never compiles-and-fails mid-run)
* reserved constructs: subject `release`, resource `release`, action
`consistent-with`, condition `file-matches-pattern` (v0 facts carry no
file contents), overlay effect `modify-rules` (diff semantics
`consistent-with`, overlay effect `modify-rules` (diff semantics
underspecified)

Consequence: **any policy that loads, evaluates** — `evaluate` is total.
Expand Down Expand Up @@ -131,6 +132,14 @@ reproduce identical facts:
`[package]` table when present.
* **Git**: `is_repo` and `head_ref` read directly from `.git/HEAD` — no
subprocess, no clock.
* **File contents** (opt-in): `collect_opts(root, { contents: true })` also
reads each valid-UTF-8 file up to `MAX_CONTENT_BYTES` (1 MiB) into
`file_contents`. Binary and oversized files are simply absent. This layer
is **off by default** — `collect` and a plain `plasma facts` omit it, and
`file_contents` is skipped from serialized output when empty, so the
default snapshot is byte-identical to before (an additive wire change).
`plasma check`/`fix` turn it on automatically iff the policy uses
`file-matches-pattern`; `plasma facts --with-contents` forces it.
* All collections are `BTreeMap`/`BTreeSet`: iteration order, and therefore
finding order, is deterministic. The fact set contains **no timestamps**.

Expand Down Expand Up @@ -161,6 +170,7 @@ reproduce identical facts:
| `spdx-license-is e` | header of instance parses ∧ parse(header) = parse(e); if either side fails to parse, exact-text comparison
| `governance-flag-set k v` | metadata[k] = v (absent key ⇒ false)
| `version-at-least v` | numeric dotted comparison of metadata["version"] against v; absent or non-numeric ⇒ false
| `file-matches-pattern p re` | regex `re` matches file_contents[p]; ⇒ false when content for `p` was not collected (binary, oversized, or contents off). `re` compiles at load, so a bad regex is a load error, not a mid-run panic.
| `not / all / any` | strict boolean composition
|===

Expand Down Expand Up @@ -247,21 +257,22 @@ the same purity split as evaluation:
| Action | Fires for | Effect

| `AddSpdxHeader` | violated `obligation + present` on a `header` resource | prepend `SPDX-License-Identifier` + copyright comment using the file's comment prefix
| `CreateFile` | violated `obligation + present` on a `file`/`manifest` resource with a *concrete* path | create the missing file with obvious placeholder content (never overwrites an existing file)
|===

Everything else is `manual`: missing required files (need human-authored
content), unparsable headers (need hand correction), prohibitions (removal
is not auto-applied). Future increments add `CreateFile`, `UpdateField`,
etc.; the enum and `Plan` shape are the stable contract.
Everything else is `manual`: a required file named by a *glob* (no single
filename to create), unparsable headers (need hand correction), prohibitions
(removal is not auto-applied). Future increments add `UpdateField`, etc.;
the enum and `Plan` shape are the stable contract.

Determinism/totality carry over: `plan` is pure and total; `apply` never
panics and reports per-action `applied` / `skipped` / `errors`.

== Roadmap interaction

Reserved constructs (`release` subjects/resources, `consistent-with`,
`file-matches-pattern`, `modify-rules`/`override-rules`) parse today and
gain semantics in later minor versions alongside their fact sources
(release facts, content facts, decision registries). The schema version
`modify-rules`) parse today and gain semantics in later minor versions
alongside their fact sources (release facts, decision registries). The
schema version
gates all of it: a policy using future semantics will not load on an engine
that cannot honour it.
5 changes: 5 additions & 0 deletions docs/interchange-contracts.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ deterministic view of repository state the evaluator sees.
`null` = auditable but header-less. Non-auditable files do not appear.
* `metadata` — governance keys (v0: `version` from Cargo.toml).
* `git` — read from `.git/HEAD` directly; no subprocess.
* `file_contents` — an **opt-in, additive** map (`plasma facts
--with-contents`, or auto when a policy uses `file-matches-pattern`).
Omitted from output when empty, so the default snapshot above is
byte-identical to before this field existed. Only valid-UTF-8 files up to
1 MiB are included.

**Verification protocol:** snapshot before an agent runs
(`plasma facts . > before.json`), snapshot after, then apply contract 2.
Expand Down
3 changes: 2 additions & 1 deletion plasma-engine/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: MPL-2.0
[package]
name = "plasma-engine"
version = "0.5.0"
version = "0.6.0"
edition = "2021"
authors = ["Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"]
description = "Deterministic, typed policy evaluation — policy AST, fact collection, and a pure evaluator producing findings"
Expand All @@ -17,6 +17,7 @@ serde_json = "1"
toml = "0.8"
walkdir = "2"
glob = "0.3"
regex = "1"
thiserror = "2"

[dev-dependencies]
Expand Down
Loading
Loading