Skip to content

Releases: koliha/ewp

EWP 0.2.0

Choose a tag to compare

@koliha koliha released this 24 Sep 19:06

EWP-0.2.0

Protocol EWP-0.2.0, policy reference-v2. The development iterations previously listed as 0.2.0, 0.2.0-docs, 0.2.1, and 0.2.2 are folded into this entry; none of them was a release. The 26 golden axes are unchanged from 0.1.0 (only their identity fields changed); the hardening pack grew to 26 fixtures, a 35-view invalid pack was added, and all of it is locked.

Identity

  • The Python package is ewp (was protocol, a generic top-level name that could collide in a tester's environment): from ewp.warrant import warrant_now, python -m ewp.mcp_server. The ewp-mcp and ewp-ingest commands are unchanged.
  • Policy is reference-v2. Subject binding, supersession scope, availability, and input validation changed, so reference-v1 no longer names this evaluator's judgments. warrant_now refuses reference-v1 and any other identity it does not implement.
  • WarrantView carries protocol_version (EWP-0.2.0). Reproducibility is stated over protocol version + view + policy + evaluated_at.
  • WarrantView.normative() is protocol_version, proposition_id, view_id, policy_id, policy_version, evaluated_at, and the five axes. rationale_codes and strength are diagnostic, not part of the equality contract. docs/PROTOCOL.md, docs/implementer/SCHEMA.md, and the code now agree on this.

Evaluator (reference-v2)

  • Subject binding uses declared subjects[] as exact ids. scope is never scraped. There is no family inference: a check about invoice-999 or printer-7 no longer verifies a customer-42 or server01 proposition. A check that omits subjects cannot verify a view that declares them.
  • A superseded_by edge supersedes the proposition only if its from_id is the proposition_id or a variant proposition_id:<suffix>. Unrelated edges in the bounded view no longer mark it SUPERSEDED.
  • Records whose instant is after evaluated_at, missing, or unparsable are not available at T. This covers assertions, evidence, and checks. Naive timestamps are UTC; instants are compared, not strings.
  • Selecting freshest_check no longer crashes on an unparsable timestamp; it considers only checks available at T.
  • Closed enums fail closed: polarity, result, conflict status, and lineage kind outside their enums make the view invalid (InvalidEvidenceView). Previously result: "pending" verified like supports, status: "Open" read as no conflict, and polarity: "oppose" was silently dropped.
  • Origin trust: only tool|document|human|api|vendor|sensor may raise EXTERNAL/HUMAN; endogenous and unknown origins cap at INDIRECT. result=opposes opens conflict and blocks ACCEPTED; result=inconclusive cannot raise the class.
  • Views are bounded: an assertion or evidence item about another proposition, or a conflict row that does not name the proposition, makes the view invalid. Previously a P-win view whose records were all about another proposition evaluated to ACCEPTED.
  • Field types are enforced: subjects must be lists of strings (a bare string was iterated as characters, so customer-99 could verify customer-42 on shared letters); freshness_policy_seconds must be a non-negative int, not bool; degraded a bool; retrieval_scope a string.
  • Checks whose subjects do not bind still count toward implied conflict (stated explicitly in POLICY.md).
  • Identity is unambiguous: repeated assertion/evidence/check/conflict ids in one view are refused (even identical repeats), and one source_id must carry one SourceRef. Previously one source with two lineage_ids counted as two independent lineages in memory while SQLite refused the same view.
  • omitted_sources and conflict proposition_ids must be lists of strings (a string was iterated as characters); lineage endpoints must be non-empty strings (a missing endpoint was stored as "None").
  • A missing or null required field, a record that is not an object, or a non-numeric or non-finite (nan, inf) confidence is refused as an invalid view with a clear message (the codec used to raise a bare KeyError/TypeError, and turned a null id into the string "None"); the third evaluator checks the same required fields.
  • An unparsable evaluated_at is refused with a clear message by both reference evaluators and the third evaluator (the third evaluator used to return UNACCEPTED).

Action gate

  • may_act returns DENY for a SUPERSEDED proposition at high risk and at least REQUIRE_CONFIRMATION otherwise (low risk used to return MAY_ACT).
  • may_act refuses an unknown risk level instead of treating it as medium.
  • high_requires_no_open_conflict and reversible are live.

Store and adapters

  • SQLite partitions every record by proposition_id. Previously two propositions sharing a view_id (e.g. mcp), or sharing record ids like a1/k1/s1, could overwrite each other's completeness, subjects, freshness, or records.
  • SQLite is append-only for sources, assertions, evidence, and checks: rewriting an existing id with different content raises ImmutableRecordError. Conflict participants are fixed across views; status and note belong to each snapshot. Writes are transactional. Databases from earlier development schemas are refused with a clear message.
  • SQLite persists view completeness (omitted_sources, retrieval_scope, degraded, freshness, subjects).
  • Mem0 and Graphiti (fake ingest and live client) park and restore the view's subjects[] and each check's subjects[]. A Mem0 round trip used to turn a customer-42/customer-99 mismatch into EXTERNAL/ACCEPTED.
  • Mem0 ingest writes each assertion and each evidence item as its own memory with its own polarity and original timestamp. Previously it kept one memory per source, forced polarity=supports, and used Mem0's created_at (ingest time) as observation time, which dropped opposition and could make evidence look future-dated.
  • Graphiti ingest emits an edge for evidence whose text is not already an assertion, so opposing evidence-only lineages survive raw_view. Edges may carry polarity=opposes. Parked sidecars need a matching proposition_id and are found by kind/content/name, not by Graphiti's assigned UUID.
  • Mem0 memories without metadata.ewp.proposition_id do not enter a proposition view.
  • The JSON codec keeps falsy values: freshness_policy_seconds: 0 used to become 30 days and an empty retrieval_scope used to read as complete. A missing view_id is derived from the content.
  • SQLite views are immutable (proposition_id, view_id) snapshots with explicit membership over the append-only ledger. get_view(pid, id) returns exactly that snapshot; get_view(pid) the latest; extend_view appends atomically. Previously a second view for a proposition replaced the first's metadata and merged its evidence under the old view_id. Unknown propositions raise MissingViewError. Older development databases are refused. SQLiteAdapter closes as a context manager.
  • JSON store writes are serialized per proposition with an OS file lock (released by the OS if a writer dies), and latest.json is replaced atomically. Two concurrent writers used to both pass the identity check, and one view_id vanished from the history; readers could also hit a half-written latest.json. On Windows a replace fails while any process has the file open (another EWP reader, a virus scanner), and an open can fail mid-replace; reads and replaces now retry that sharing conflict briefly instead of failing (4 readers against 4 writers failed about 60 times per run). Snapshot files are written atomically too, and a snapshot is committed once its view_id is in the history: only committed snapshots are immutable. A file whose view_id is not in the history is an orphan of an interrupted write (partial, identical, or corrected), and a retry replaces it after the same cross-snapshot record-id check as any other commit. A partial file used to make every retry fail with JSONDecodeError, and a complete one made the retry a no-op that left the snapshot out of the history. An explicit read returns only committed snapshots; a damaged committed file is an error.
  • JSON store: files are named by hashes of the ids (a proposition id could previously escape the store root, and a/b collided with a_b), writes and reads are validated (a status: "Open" conflict used to be stored as resolved), and views are immutable snapshots like SQLite.
  • Mem0 keeps every SourceRef field (source_id, observed_at, extractor_id), assertion_confidence: 0, and the view_id.
  • Graphiti edges carry roles, so an evidence-only record no longer comes back as an assertion (which could lift UNACCEPTED to TENTATIVE) and an assertion-only record no longer gains supporting evidence. Ingest stores snapshot_id/extractor_id; parked subjects and view_id are decoded safely.
  • Live Graphiti (experimental): search_view applies the parked sidecar (it used to drop checks, conflicts, lineage, subjects, and freshness); ingest writes evidence-only sources and sets reference_time from the source's observed_at.
  • New ewp-ingest command loads EvidenceViews from JSON into a ledger; trusted origins require --attest-trusted-origins.
  • All ids are proposition-local, including conflict_id (it was ledger-global in SQLite, so unrelated propositions could not both use c1). Schema version 4.
  • One canonical, record-order-independent form of a view (codec.canonical_dict) drives content-derived ids, SQLite and JSON snapshot comparison, and adapter conformance. Reordered but identical snapshots were refused as mutations and got different ids.
  • SQLite writes run in BEGIN IMMEDIATE transactions, so extend_view is atomic across processes sharing a ledger: concurrent appends from separate processes used to drop records from the latest snapshot. SQLiteAdapter(path, read_only=True) opens...
Read more

v0.1.0

Choose a tag to compare

@koliha koliha released this 22 Sep 15:20

EWP 0.1.0

Epistemic Warrant Protocol. First frozen reference.

EWP is a store-neutral contract for one question: given this bounded evidence view, what is an agent entitled to treat as warranted, and under which policy?

It answers with five axes — acceptance, conflict, verification, currency, sufficiency — plus a named policy. It does not retrieve, remember, authorize action, or decide what is true in the world. Graphiti, Mem0, Dreaming, and Postgres are stores. They adapt to this interchange. This interchange does not adapt to them.

This tag freezes the reference evaluator and the fixture pack. It does not claim two independent implementations or a production ingest path.

Freeze

Protocol EWP-0.1.0
Policy reference-v1
Fixtures canonical-14 + pathological-12
Fixture SHA-256 910b6e98bee3148460f15303810c8e4c447721252b02c7f4805f3c0ce75b98db
Evaluator SHA-256 cd56535a1d51fc0a6b5a4e1c0cb64636361fcc27f0002a8a352ea62a47bb87b8
Golden SHA-256 95f26b124ac813ef7b6f895bd43c20832f2026bfb8a25513ce6bfd7302088dd3

Gate: python3 tests/ci.py. If a store disagrees, the store is wrong.

What this version pins

  • check.result is input. opposes can open conflict. inconclusive cannot raise HUMAN or EXTERNAL.
  • Only trusted origins (tool, document, human, api, vendor, sensor) may raise HUMAN or EXTERNAL. Unknown origins, including episode, cannot.
  • Endogenous origin (extract, turn, derived, summary, model_introspection) cannot launder a method name into those classes.
  • Both polarities in the view imply OPEN even without a Conflict row.
  • DEGRADED blocks ACCEPTED. Incomplete retrieval cannot look like a finished search.
  • Freshness follows the check that conferred the chosen class, compared as instants (Z vs +00:00).
  • Scope caps a check only when it names a different entity in the same family (server01 vs server02).
  • Policy identity is reference-v1. strength is not an axis.
  • Historical ledger / MCP sketches live under historical/ and are not the protocol.

What this version is not

  • Not a memory system.
  • Not an authorization system. may_act is a sketch beside the freeze.
  • Not a claim that a third party has implemented the pack. docs/implementer/third_eval.py shows the prose is executable.
  • Not a specified ingest path. Building the bounded view is still the production risk.

Contents

Normative: docs/PROTOCOL_v0.1.md, docs/DESIGN_NOTE.md, docs/implementer/, protocol/warrant.py, tests/golden_warrantviews/.

Guide PDF: docs/EWP_v0.1.0.pdf.