Repository navigation
Releases: koliha/ewp
Release list
EWP 0.2.0
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(wasprotocol, a generic top-level name that could collide in a tester's environment):from ewp.warrant import warrant_now,python -m ewp.mcp_server. Theewp-mcpandewp-ingestcommands are unchanged. - Policy is
reference-v2. Subject binding, supersession scope, availability, and input validation changed, soreference-v1no longer names this evaluator's judgments.warrant_nowrefusesreference-v1and any other identity it does not implement. WarrantViewcarriesprotocol_version(EWP-0.2.0). Reproducibility is stated over protocol version + view + policy +evaluated_at.WarrantView.normative()isprotocol_version,proposition_id,view_id,policy_id,policy_version,evaluated_at, and the five axes.rationale_codesandstrengthare 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.scopeis never scraped. There is no family inference: a check aboutinvoice-999orprinter-7no longer verifies acustomer-42orserver01proposition. A check that omits subjects cannot verify a view that declares them. - A
superseded_byedge supersedes the proposition only if itsfrom_idis theproposition_idor a variantproposition_id:<suffix>. Unrelated edges in the bounded view no longer mark itSUPERSEDED. - 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_checkno longer crashes on an unparsable timestamp; it considers only checks available at T. - Closed enums fail closed:
polarity,result, conflictstatus, and lineagekindoutside their enums make the view invalid (InvalidEvidenceView). Previouslyresult: "pending"verified likesupports,status: "Open"read as no conflict, andpolarity: "oppose"was silently dropped. - Origin trust: only
tool|document|human|api|vendor|sensormay raiseEXTERNAL/HUMAN; endogenous and unknown origins cap atINDIRECT.result=opposesopens conflict and blocksACCEPTED;result=inconclusivecannot 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-winview whose records were all about another proposition evaluated toACCEPTED. - Field types are enforced:
subjectsmust be lists of strings (a bare string was iterated as characters, socustomer-99could verifycustomer-42on shared letters);freshness_policy_secondsmust be a non-negative int, not bool;degradeda bool;retrieval_scopea 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_idmust carry oneSourceRef. Previously one source with twolineage_ids counted as two independent lineages in memory while SQLite refused the same view. omitted_sourcesand conflictproposition_idsmust 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 bareKeyError/TypeError, and turned a null id into the string"None"); the third evaluator checks the same required fields. - An unparsable
evaluated_atis refused with a clear message by both reference evaluators and the third evaluator (the third evaluator used to returnUNACCEPTED).
Action gate
may_actreturnsDENYfor aSUPERSEDEDproposition at high risk and at leastREQUIRE_CONFIRMATIONotherwise (low risk used to returnMAY_ACT).may_actrefuses an unknown risk level instead of treating it as medium.high_requires_no_open_conflictandreversibleare live.
Store and adapters
- SQLite partitions every record by
proposition_id. Previously two propositions sharing aview_id(e.g.mcp), or sharing record ids likea1/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'ssubjects[]. A Mem0 round trip used to turn acustomer-42/customer-99mismatch intoEXTERNAL/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'screated_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 carrypolarity=opposes. Parked sidecars need a matchingproposition_idand are found by kind/content/name, not by Graphiti's assigned UUID. - Mem0 memories without
metadata.ewp.proposition_iddo not enter a proposition view. - The JSON codec keeps falsy values:
freshness_policy_seconds: 0used to become 30 days and an emptyretrieval_scopeused to read ascomplete. A missingview_idis 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_viewappends atomically. Previously a second view for a proposition replaced the first's metadata and merged its evidence under the oldview_id. Unknown propositions raiseMissingViewError. Older development databases are refused.SQLiteAdaptercloses 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.jsonis replaced atomically. Two concurrent writers used to both pass the identity check, and oneview_idvanished from the history; readers could also hit a half-writtenlatest.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 itsview_idis in the history: only committed snapshots are immutable. A file whoseview_idis 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 withJSONDecodeError, 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/bcollided witha_b), writes and reads are validated (astatus: "Open"conflict used to be stored as resolved), and views are immutable snapshots like SQLite. - Mem0 keeps every
SourceReffield (source_id,observed_at,extractor_id),assertion_confidence: 0, and theview_id. - Graphiti edges carry
roles, so an evidence-only record no longer comes back as an assertion (which could liftUNACCEPTEDtoTENTATIVE) and an assertion-only record no longer gains supporting evidence. Ingest storessnapshot_id/extractor_id; parkedsubjectsandview_idare decoded safely. - Live Graphiti (experimental):
search_viewapplies the parked sidecar (it used to drop checks, conflicts, lineage, subjects, and freshness); ingest writes evidence-only sources and setsreference_timefrom the source'sobserved_at. - New
ewp-ingestcommand 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 usec1). 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 IMMEDIATEtransactions, soextend_viewis 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...
v0.1.0
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.resultis input.opposescan open conflict.inconclusivecannot raiseHUMANorEXTERNAL.- Only trusted origins (
tool,document,human,api,vendor,sensor) may raiseHUMANorEXTERNAL. Unknown origins, includingepisode, cannot. - Endogenous origin (
extract,turn,derived,summary,model_introspection) cannot launder a method name into those classes. - Both polarities in the view imply
OPENeven without aConflictrow. DEGRADEDblocksACCEPTED. Incomplete retrieval cannot look like a finished search.- Freshness follows the check that conferred the chosen class, compared as instants (
Zvs+00:00). - Scope caps a check only when it names a different entity in the same family (
server01vsserver02). - Policy identity is
reference-v1.strengthis 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_actis a sketch beside the freeze. - Not a claim that a third party has implemented the pack.
docs/implementer/third_eval.pyshows 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.