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
4 changes: 2 additions & 2 deletions .machine_readable/6a2/STATE.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ status = "active"

[project-context]
name = "palimpsest-plasma"
completion-percentage = 50
phase = "Engine v0 shipped (Rust); action planner and integration surfaces next"
completion-percentage = 55
phase = "v0.3 in progress: action planner (plasma fix) landed; more action types + integration surfaces next"

[identity]
summary = "Deterministic, typed policy engine for the agentic era"
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- feat(engine): action planner — pure `plan(policy, evaluation, ctx)` maps
violations to corrective actions or a manual list with reasons; IO
boundary `apply(plan, root, opts)` executes them with `.bak` backups and
idempotent skips (`plasma-engine/src/action.rs`, `apply.rs`)
- feat(cli): `plasma fix` — dry-run by default, `--apply` to make changes,
`--license`/`--author`/`--no-backup`/`--format human|json`. First
auto-action: AddSpdxHeader; missing files / unparsable headers → manual
- docs: "Action planner" section in `docs/engine-v0-design.adoc`;
`plasma fix` documented in `docs/cli-design.adoc`
- test: `tests/fix_selftest.rs` (dry-run, apply+backup, idempotency, json)

## [0.2.0] - 2026-07-02

Identity pivot: palimpsest-plasma is a deterministic, typed policy engine
Expand Down
4 changes: 4 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ facts:
audit:
cargo run -- audit .

# Show the remediation plan for this repository (dry-run; add --apply to fix)
fix *args:
cargo run -- fix . {{args}}

# Validate the bundled policy file
policy-check:
cargo run -- policy validate plasma-engine/policies/repo-hygiene.plasma.toml
Expand Down
9 changes: 5 additions & 4 deletions ROADMAP.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ future project; the earlier union-policy-parser sub-project was removed

== Active Milestones

=== v0.3.0 — Action Planner
=== v0.3.0 — Action Planner [IN PROGRESS]

* [ ] Action types (AddSpdxHeader, CreateFile, UpdateField, …)
* [ ] `plasma fix` — plan (dry-run) and apply modes, with backups
* [ ] Findings → planned actions mapping
* [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, …)
* [ ] Overlay `modify-rules` / `override-rules` semantics
* [ ] Content facts + `file-matches-pattern` condition semantics

Expand Down
41 changes: 37 additions & 4 deletions docs/cli-design.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ toc::[]
One binary (`plasma`), narratively clear subcommands, machine-readable
output where useful.

=== Implemented (v0.2)
=== Implemented

[source]
----
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 policy validate FILE
plasma audit [--path PATH] [--license SPDX-EXPR] [--fix]
plasma audit [PATH] [--license SPDX-EXPR] [--fix]
plasma init [--path PATH] [--license SPDX-ID] [--author NAME]
plasma badge [--license SPDX-ID] [--style STYLE]
plasma migrate [--path PATH] [--from SPDX-ID] [--to SPDX-ID]
Expand All @@ -42,6 +44,37 @@ Evaluate a repository against a policy.
- `--quiet` — exit code only
- `--verbose` — include satisfied (pass) findings

=== `plasma fix`

Plan or apply corrective actions for policy violations. **Dry-run by
default** — it prints the plan and touches nothing; `--apply` makes the
changes, writing a `<file>.bak` backup before modifying each file (unless
`--no-backup`).

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:

* **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.

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.

* **Flags:** `--policy FILE`, `--license SPDX-ID`, `--author NAME`,
`--apply`, `--no-backup`, `--format human|json`
* **Exit:** dry-run returns 1 when actions are pending (so CI can gate on a
clean tree), 0 when there is nothing to do; `--apply` returns 0 unless an
action errored.

Relationship to `plasma audit --fix`: `audit --fix` is the license-specific
tool (zone-expected headers from `.plasma.toml`); `plasma fix` is the
general policy-remediation surface driven by engine findings — headers are
simply its first supported action class.

=== `plasma facts`

Dump the deterministic fact snapshot the evaluator sees, as JSON. This is
Expand Down Expand Up @@ -70,8 +103,8 @@ proper `-`→`--` escaping.

== Roadmap surfaces (not yet implemented)

* `plasma fix` — findings → planned corrective actions, dry-run and
`--apply` modes with backups (v0.3)
* More `plasma fix` actions — CreateFile / UpdateField (beyond the v0.3
AddSpdxHeader action)
* 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
31 changes: 31 additions & 0 deletions docs/engine-v0-design.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,37 @@ this evaluator against a formal semantics:
interchange contract with sibling tooling (`somethings-fishy`,
`did-you-actually-do-that`).

== Action planner (v0.3)

The action planner turns an `Evaluation` into a remediation `Plan`, keeping
the same purity split as evaluation:

* **`plan(policy, evaluation, ctx) -> Plan`** is **pure** (`action.rs`). For
each violation it looks up the rule by id and either synthesises a
mechanical `Action` or records a `ManualItem` with a reason — nothing is
silently dropped. `FixContext` carries the injected `license`, `author`,
and `year` (never clock-derived, so planning stays deterministic).
* **`apply(plan, root, opts) -> ApplyOutcome`** is the **IO boundary**
(`apply.rs`, the counterpart to `facts.rs`). It executes actions, writing
`<file>.bak` backups first unless disabled, and is idempotent — an action
whose effect already holds is skipped, not repeated.

=== Action vocabulary (v0.3)

|===
| Action | Fires for | Effect

| `AddSpdxHeader` | violated `obligation + present` on a `header` resource | prepend `SPDX-License-Identifier` + copyright comment using the file's comment prefix
|===

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.

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`,
Expand Down
Loading
Loading