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.2.0"
version = "0.4.0"
last-updated = "2026-07-02"
status = "active"

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

## [Unreleased]

## [0.4.0] - 2026-07-16

### Added

- feat(engine): `diff(before, after) -> FactsDiff` — pure, deterministic
comparison of two fact snapshots: files added/removed, SPDX header
transitions, metadata changes, git state (`plasma-engine/src/diff.rs`)
- feat(cli): `plasma diff before.json after.json` with diff(1) exit
semantics (0 identical, 1 differ, 2 error) — the before/after
verification protocol for agent claims
- docs: `docs/interchange-contracts.adoc` — pins the four wire contracts
(facts snapshot, facts diff, findings JSON, SARIF namespace) that
sibling tools build against; additive-only evolution within a major

## [0.3.0] - 2026-07-16

### Added

- feat(engine): action planner — pure `plan(policy, evaluation, ctx)` maps
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.2.0
version: 0.4.0
date-released: 2026-07-02
license: "MPL-2.0"
repository-code: "https://github.com/hyperpolymath/palimpsest-plasma"
Expand Down
6 changes: 3 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.2.0"
version = "0.4.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.2.0"
version := "0.4.0"
tier := "infrastructure"
state := ".machine_readable/6a2/STATE.a2ml"

Expand Down
8 changes: 5 additions & 3 deletions ROADMAP.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ future project; the earlier union-policy-parser sub-project was removed
* [ ] Overlay `modify-rules` / `override-rules` semantics
* [ ] Content facts + `file-matches-pattern` condition semantics

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

* [x] Sibling-tool contracts pinned: facts snapshot, facts diff, findings,
SARIF namespace (docs/interchange-contracts.adoc)
* [x] `plasma diff before.json after.json` — deterministic facts diff with
diff(1) exit semantics (0 identical / 1 differ / 2 error)
* [ ] Git hooks (pre-commit, pre-push) via `plasma check --quiet`
* [ ] Reference GitHub Action / GitLab CI job
* [ ] `.plasma.toml` policy references (project-pinned policies)
* [ ] Sibling-tool contracts: stable facts-diff format for
did-you-actually-do-that, finding-provenance for somethings-fishy
* [ ] Release facts (`release` subjects/resources gain semantics)

== Future Directions
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.2.0",
"version": "0.4.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
15 changes: 15 additions & 0 deletions docs/cli-design.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ plasma check [PATH] [--policy FILE] [--format human|json|sarif]
plasma fix [PATH] [--policy FILE] [--license SPDX-ID] [--author NAME]
[--apply] [--no-backup] [--format human|json] # v0.3
plasma facts [PATH]
plasma diff BEFORE.json AFTER.json [--format human|json] # v0.4
plasma policy validate FILE
plasma audit [PATH] [--license SPDX-EXPR] [--fix]
plasma init [--path PATH] [--license SPDX-ID] [--author NAME]
Expand Down Expand Up @@ -80,6 +81,20 @@ 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.

=== `plasma diff`

Compare two fact snapshots produced by `plasma facts`. This is the
verification protocol for agent claims: snapshot before the agent runs,
snapshot after, diff the two — the result is exactly what changed as far
as policy evaluation is concerned (files added/removed, SPDX header
transitions, metadata changes, git state).

* **Exit semantics follow `diff(1)`:** 0 = identical, 1 = differ,
2 = error — scriptable without parsing output.
* Output is deterministic: identical snapshot pairs give byte-identical
JSON. The format is pinned in
link:interchange-contracts.adoc[interchange-contracts.adoc].

=== `plasma policy validate`

Parse and schema-check a policy file; print rule counts on success. Fails
Expand Down
143 changes: 143 additions & 0 deletions docs/interchange-contracts.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
// Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
= Plasma Interchange Contracts (v0.4)
:toc:
:toc-placement!:
:sectnums:

toc::[]

== Purpose

This document pins the wire formats sibling tools consume. Once published,
these contracts change only additively within a major version: new fields
may appear, existing fields keep their name, type, and meaning.

The consumers:

* **did-you-actually-do-that** (planned) — verifies agents did what they
claimed. Consumes *facts snapshots* (contract 1) and *facts diffs*
(contract 2), plus pass-findings as positive evidence (contract 3).
* **somethings-fishy** (planned) — forensic investigation of bot-inflicted
damage. Consumes *findings* (contract 3) and *SARIF* (contract 4).

All four contracts share plasma's determinism guarantee: identical inputs
produce byte-identical output (BTree ordering, no timestamps, no ambient
state). Consumers may therefore hash, cache, and compare outputs directly.

== Contract 1 — Facts snapshot (`plasma facts`)

The serialized `FactSet` (`plasma-engine/src/facts.rs`): the complete,
deterministic view of repository state the evaluator sees.

[source,json]
----
{
"root": "/path/given/by/caller",
"files": ["Cargo.toml", "src/main.rs", "..."],
"spdx_headers": { "src/main.rs": "MPL-2.0", "src/stub.rs": null },
"metadata": { "version": "0.4.0" },
"git": { "is_repo": true, "head_ref": "refs/heads/main" }
}
----

* `files` — every regular file, relative, `/`-separated, sorted. The walk
skip list is pinned in link:engine-v0-design.adoc[engine-v0-design.adoc].
* `spdx_headers` — raw `SPDX-License-Identifier:` value per auditable file;
`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.

**Verification protocol:** snapshot before an agent runs
(`plasma facts . > before.json`), snapshot after, then apply contract 2.
`root` is informational; snapshots are comparable across checkouts.

== Contract 2 — Facts diff (`plasma diff before.json after.json`)

The serialized `FactsDiff` (`plasma-engine/src/diff.rs`): exactly what
changed between two snapshots, deterministically ordered.

[source,json]
----
{
"root_before": "...", "root_after": "...",
"files_added": ["new.rs"],
"files_removed": ["gone.rs"],
"headers_changed": [
{ "file": "src/main.rs", "before": null, "after": "MPL-2.0" }
],
"metadata_changed": [
{ "key": "version", "before": "0.3.0", "after": "0.4.0" }
],
"git_changed": { "before": { "...": "..." }, "after": { "...": "..." } }
}
----

* `headers_changed` covers files present in **both** snapshots; header
state of added/removed files is implied by the file lists.
* `git_changed` is omitted (not `null`) when git state is unchanged.
* Exit semantics follow `diff(1)`: **0** identical, **1** differ,
**2** error — scriptable without parsing output.

An agent's claim "I only added SPDX headers" verifies as: `files_added`,
`files_removed`, `metadata_changed`, `git_changed` all empty, and every
entry in `headers_changed` has `before: null`.

== Contract 3 — Findings (`plasma check --format json`)

The serialized `Evaluation` (`plasma-engine/src/finding.rs`): ordered
findings plus a summary.

[source,json]
----
{
"root": "...",
"policy_id": "repo-hygiene",
"policy_version": { "major": 0, "minor": 1 },
"schema_version": { "major": 0, "minor": 1 },
"findings": [
{
"rule_id": "spdx-header-required",
"modality": "obligation",
"severity": "warning",
"subject": "src/main.rs",
"message": "SPDX header present for src/main.rs",
"rationale": "...",
"source": "...",
"status": "pass"
}
],
"summary": { "errors": 0, "warnings": 0, "info": 0, "passes": 96 }
}
----

* `rule_id` values are **stable identifiers**: forensic tooling keys on
them across runs and versions.
* `status: "pass"` findings are positive evidence — a satisfied obligation
is an attestation, not merely the absence of a complaint.
* `subject` is `"repo"`, a relative path, or `"metadata:<key>"`.

== Contract 4 — SARIF 2.1.0 (`plasma check --format sarif`)

Standard SARIF for GitHub Code Scanning and any SARIF-native tool
(`plasma-engine/src/report/sarif.rs`):

* `ruleId` = `plasma/<rule_id>` — the namespace is reserved and stable.
* `level` ∈ `error` | `warning` | `note` (never `info`).
* Pass findings appear only with `--verbose`, as `kind: "pass"`.
* Repo- and metadata-scoped results carry no artifact location.

== Remediation plan (informative, stabilising)

`plasma fix --format json` emits `{ "plan": Plan, "outcome": ApplyOutcome? }`
(`plasma-engine/src/action.rs`, `apply.rs`). This shape is expected to
stabilise in v0.5 once more action types exist; treat it as informative
until then.

== Versioning

Each contract inherits the crate version. Additive evolution only within a
major version; a field removal or meaning change requires a major bump and
an entry in link:release-notes.adoc[release-notes.adoc]. The policy
*schema* version (`schema_version`) is independent — see
link:engine-v0-design.adoc[engine-v0-design.adoc].
2 changes: 1 addition & 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.2.0"
version = "0.4.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 Down
Loading
Loading