From 27f56240c3e5aef4ae24988da2238704eca6eaf4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 15 Jun 2026 16:07:26 +0000 Subject: [PATCH] docs: document final artifact sealing Co-authored-by: Sara Loera --- docs/docs.json | 3 +- docs/explanation/artifacts.mdx | 62 +++++++++++-- docs/explanation/core-concepts.mdx | 7 +- docs/guides/adopting-noesis.mdx | 3 +- docs/index.mdx | 1 + docs/quickstart.mdx | 1 + docs/reference/final.mdx | 144 +++++++++++++++++++++++++++++ 7 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 docs/reference/final.mdx diff --git a/docs/docs.json b/docs/docs.json index 955c7ba..df6db55 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -95,7 +95,8 @@ "pages": [ "reference/events", "reference/state", - "reference/summary" + "reference/summary", + "reference/final" ] }, { diff --git a/docs/explanation/artifacts.mdx b/docs/explanation/artifacts.mdx index e27739f..dd98ffc 100644 --- a/docs/explanation/artifacts.mdx +++ b/docs/explanation/artifacts.mdx @@ -14,6 +14,7 @@ Every Noēsis episode produces a set of structured artifacts that capture the co events.jsonl # cognitive event timeline with lineage summary.json # metrics and KPIs (insight.metrics) state.json # plan, beliefs, memory, outcomes + final.json # terminal seal marker manifest.json # SHA-256 catalog + optional HMAC learn.jsonl # learning signals (optional) prompts.jsonl # prompt provenance (opt-in, ADR-005) @@ -334,6 +335,49 @@ noesis events ep_abc123 --phase act noesis events ep_abc123 -j | jq '.[] | select(.phase == "plan")' ``` +## final.json + +`final.json` is the terminal seal marker for an episode. If it exists, Noēsis treats the run as finalized and blocks lifecycle mutations such as checkpoint or resume. + +### Schema + +Current final schema version: `final/2.0.0` ([JSON schema](/schema/final/2.0.0.json)). + +```json +{ + "schema_version": "final/2.0.0", + "episode_id": "ep_2024_abc123_s0", + "process_id": "proc_abc123", + "run_index": 1, + "finalized_at": "2024-01-15T10:30:05Z", + "outcome": "success", + "verification_status": "unverified" +} +``` + +| Field | Description | +| --- | --- | +| `schema_version` | Final marker schema (`final/2.0.0`) | +| `episode_id` | Episode/run ID being sealed | +| `process_id` | Process lineage ID for the run | +| `run_index` | 1-based run number within the process | +| `finalized_at` | ISO 8601 timestamp for finalization | +| `outcome` | One of `success`, `failed`, `vetoed`, `cancelled`, `interrupted`, `error` | +| `verification_status` | One of `verified`, `unverified`, `not_applicable` | + +### Sealing contract + +Terminal runs seal in a fixed order: + +1. Write `final.json`. +2. Write `manifest.json` with a checksum entry for `final.json`. + +If manifest writing fails, Noēsis removes `final.json` so the run is not left in a falsely sealed state. A second seal attempt raises an immutability error and leaves existing artifacts unchanged. + + +Pause-on-veto runs (`governance_pause_on_veto=true`) stay unsealed: they emit lifecycle evidence such as `run.interrupt` and `run.checkpoint`, but do not write `final.json` or `manifest.json` until continuation or explicit termination. + + ## manifest.json The manifest provides integrity verification for all artifacts with SHA-256 hashes and optional signatures. @@ -348,7 +392,8 @@ The manifest provides integrity verification for all artifacts with SHA-256 hash "files": [ {"name": "summary.json", "sha256": "sha256:abc123...", "size_bytes": 1234, "kind": "summary"}, {"name": "state.json", "sha256": "sha256:def456...", "size_bytes": 5678, "kind": "state"}, - {"name": "events.jsonl", "sha256": "sha256:ghi789...", "size_bytes": 9012, "kind": "events"} + {"name": "events.jsonl", "sha256": "sha256:ghi789...", "size_bytes": 9012, "kind": "events"}, + {"name": "final.json", "sha256": "sha256:jkl012...", "size_bytes": 234, "kind": "attachment"} ], "signature": { "alg": "hs256", @@ -365,6 +410,8 @@ The manifest provides integrity verification for all artifacts with SHA-256 hash | `files` | Array of files with `name`, `sha256`, `size_bytes`, `kind` (`summary`, `state`, `events`, `learn`, `attachment`, `custom`) | | `signature` | Optional signature block with algorithm, key ID, value, timestamp | +For sealed terminal runs, verifiers should expect both `final.json` and `manifest.json`. `manifest.json` is not the seal marker by itself; `final.json` is. + ### Artifact immutability guarantees All artifacts are written atomically using this pattern: @@ -389,16 +436,16 @@ def verify_manifest(episode_dir: Path) -> bool: with open(manifest_path) as f: manifest = json.load(f) - for filename, info in manifest["files"].items(): - file_path = episode_dir / filename + for info in manifest["files"]: + file_path = episode_dir / info["name"] # Check size - if file_path.stat().st_size != info["size"]: + if file_path.stat().st_size != info["size_bytes"]: return False # Check hash with open(file_path, "rb") as f: - actual_hash = hashlib.sha256(f.read()).hexdigest() + actual_hash = "sha256:" + hashlib.sha256(f.read()).hexdigest() if actual_hash != info["sha256"]: return False @@ -517,7 +564,7 @@ store.vacuum() # Remove episodes older than 14 days -**Use manifests for compliance.** The SHA-256 checksums in manifest.json provide tamper evidence for audits. +**Use manifests with final markers for compliance.** `final.json` marks a terminal seal; the SHA-256 checksums in `manifest.json` provide tamper evidence for the sealed bundle. ## Next steps @@ -535,4 +582,7 @@ store.vacuum() # Remove episodes older than 14 days Complete summary schema documentation. + + Final marker schema and sealing semantics. + diff --git a/docs/explanation/core-concepts.mdx b/docs/explanation/core-concepts.mdx index 87b40e9..f2bbd05 100644 --- a/docs/explanation/core-concepts.mdx +++ b/docs/explanation/core-concepts.mdx @@ -151,6 +151,7 @@ Every episode produces structured **artifacts** that capture the full cognitive summary.json # metrics and outcomes state.json # cognitive state events.jsonl # timeline + final.json # terminal seal marker manifest.json # integrity checksums learn.jsonl # learning signals (optional) ``` @@ -256,11 +257,14 @@ The manifest provides integrity verification: "created_at": "2024-01-15T10:30:05Z", "files": [ {"name": "summary.json", "sha256": "sha256:abc123...", "size_bytes": 1234, "kind": "summary"}, - {"name": "events.jsonl", "sha256": "sha256:def456...", "size_bytes": 5678, "kind": "events"} + {"name": "events.jsonl", "sha256": "sha256:def456...", "size_bytes": 5678, "kind": "events"}, + {"name": "final.json", "sha256": "sha256:ghi789...", "size_bytes": 234, "kind": "attachment"} ] } ``` +Terminal runs also write `final.json` before `manifest.json`. The final marker is the seal; the manifest records checksums for the sealed bundle, including `final.json`. + ## Adapters **Adapters** connect Noēsis to your existing agent runtimes. They're simply callables that Noēsis wraps with cognition: @@ -344,6 +348,7 @@ flowchart TD A --> SUM[summary.json] A --> ST[state.json] A --> EV[events.jsonl] + A --> FIN[final.json] ``` 1. A **task** creates an **episode** diff --git a/docs/guides/adopting-noesis.mdx b/docs/guides/adopting-noesis.mdx index 36c5dab..d6f2e4f 100644 --- a/docs/guides/adopting-noesis.mdx +++ b/docs/guides/adopting-noesis.mdx @@ -12,7 +12,7 @@ It's practical and opinionated: what to do, what to avoid, and how to fit Noēsi ## 1) What Noēsis actually adds - **Episodes**: every run is a cognitive episode with a stable ID. -- **Artifacts**: `events.jsonl`, `summary.json`, `state.json`, `manifest.json`, optional `prompts.jsonl`. +- **Artifacts**: `events.jsonl`, `summary.json`, `state.json`, `final.json`, `manifest.json`, optional `prompts.jsonl`. - **Cognitive phases**: `observe → intuition → interpret → plan → direction → governance → act → reflect → learn → terminate → insight → memory`. - **Governance & direction**: policies that hint, intervene, or veto, with explicit flags in summary + events. - **Determinism controls**: seeds, deterministic clocks/IDs, replay support. @@ -46,6 +46,7 @@ You don’t need a perfect “episode store” on day one—pick **one** place t events.jsonl summary.json state.json + final.json manifest.json ``` diff --git a/docs/index.mdx b/docs/index.mdx index 32ea5be..212182f 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -94,6 +94,7 @@ Every run produces a clean artifact structure: summary.json # metrics and outcomes state.json # current plan and episode state events.jsonl # timeline with causal IDs + final.json # terminal seal marker manifest.json # SHA-256 + size ledger for tamper evidence learn.jsonl # optional learning payloads ``` diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx index b48ed36..b73b1b4 100644 --- a/docs/quickstart.mdx +++ b/docs/quickstart.mdx @@ -106,6 +106,7 @@ Every episode creates a structured artifact directory (written under `.noesis/ep summary.json # metrics + rollups state.json # final state snapshot events.jsonl # append-only timeline + final.json # terminal seal marker manifest.json # SHA-256 + size ledger learn.jsonl # optional learning payloads _episodes/ # optional episode index (best-effort) diff --git a/docs/reference/final.mdx b/docs/reference/final.mdx new file mode 100644 index 0000000..f38ed53 --- /dev/null +++ b/docs/reference/final.mdx @@ -0,0 +1,144 @@ +--- +title: "Final schema" +description: "Complete reference for the Noesis final.json seal marker." +--- + +The `final.json` artifact marks an episode run as terminal and sealed. It is small by design: consumers can check one file to decide whether a run may accept lifecycle mutations, then use `manifest.json` to verify the sealed bundle. + +Current final schema version: `final/2.0.0` ([JSON schema](/schema/final/2.0.0.json)). + +## Schema overview + +```json +{ + "schema_version": "final/2.0.0", + "episode_id": "ep_2024_abc123_s0", + "process_id": "proc_abc123", + "run_index": 1, + "finalized_at": "2024-01-15T10:30:05Z", + "outcome": "success", + "verification_status": "unverified" +} +``` + +## Root fields + + +Final marker schema. Currently `"final/2.0.0"`. + + + +Episode/run ID being finalized. + + + +Stable process lineage ID for the run. + + + +1-based run number within the process lineage. + + + +ISO 8601 timestamp when the final marker was written. + + + +Terminal outcome class. + +| Value | Meaning | +| --- | --- | +| `success` | The run reached a successful terminal state | +| `failed` | Verification completed and the goal was not achieved | +| `vetoed` | Governance enforced a veto before side effects completed | +| `cancelled` | The run was cancelled | +| `interrupted` | The run ended as interrupted | +| `error` | The run ended due to an execution or runtime error | + + + +Verification result class. + +| Value | Meaning | +| --- | --- | +| `verified` | Verification assertions ran and passed or failed deterministically | +| `unverified` | The run succeeded without verification assertions | +| `not_applicable` | Verification does not apply, such as veto or error outcomes | + + +## Sealing contract + +Noesis treats `final.json` as the canonical seal marker. Once it exists, lifecycle writes and resume attempts fail with `RunSealedError`. The artifact immutability guard also blocks later writes, except for the single `manifest.json` seal write that completes finalization. + +Terminal sealing is ordered: + +1. Write `final.json`. +2. Write `manifest.json`, including a checksum entry for `final.json`. + +If manifest writing fails, Noesis removes `final.json` so the episode is not left in a falsely sealed state. Double-seal attempts raise `ImmutabilityError` and do not mutate the existing final marker or manifest. + +## Lifecycle constraints + +Terminal runs include both `final.json` and `manifest.json`. This covers successful runs, failed verification, errors, and enforced vetoes that terminate the episode. + +Paused runs are intentionally unsealed. For example, `governance_pause_on_veto=true` emits `run.interrupt` and `run.checkpoint` lifecycle events, but does not write `final.json` or `manifest.json` until the run continues or terminates. + +## Examples + +### Successful unverified run + +```json +{ + "schema_version": "final/2.0.0", + "episode_id": "ep_2024_success_s0", + "process_id": "proc_success", + "run_index": 1, + "finalized_at": "2024-01-15T10:30:05Z", + "outcome": "success", + "verification_status": "unverified" +} +``` + +### Enforced veto + +```json +{ + "schema_version": "final/2.0.0", + "episode_id": "ep_2024_veto_s0", + "process_id": "proc_veto", + "run_index": 1, + "finalized_at": "2024-01-15T10:30:05Z", + "outcome": "vetoed", + "verification_status": "not_applicable" +} +``` + +## Reading final markers + +### File access + +```bash +EP_DIR=$(noesis view ep_abc123 --json | jq -r '.episode_dir') +jq '.outcome, .verification_status' "$EP_DIR/final.json" +``` + +### Sealed check + +```python +from pathlib import Path + + +def is_sealed(episode_dir: Path) -> bool: + return (episode_dir / "final.json").exists() +``` + +## Next steps + + + + Learn how final markers and manifests seal evidence bundles. + + + See lifecycle links for terminal and non-terminal runs. + +