evolving
ev is git for decisions. It records human-authored decisions and the grounds they
rest on as an immutable, content-addressed tick chain, binds either a test-check or a
human re-check to each ground, and resurfaces a decision when a bound check goes red. It
deals in facts, not verdicts — there are no scores, no ranks, no auto-judgements;
just an honest record of what was decided, why, who is on the hook, and whether the check
guarding each reason is still alive.
Status
0.0.1 — an early, honest cut on the way to the 0.1.0 honest-resurface slice. A
single self-contained Rust binary, no network, no daemon; the store lives in a local
.evolving/ directory.
Shipped today: recording decisions and their grounds (ev decide), binding a test or
human re-check after the fact (ev guard), reading a decision (ev show), and auditing the
chain and its refusals (ev verify). Still landing toward 0.1.0: evaluating a bound
check's liveness and resurfacing a decision when it goes red (ev check), plus the
reopen / list / log surface. So today ev freezes the contract — it records what
must stay true and how it would be checked — but does not yet run the checks for you.
Install
This installs an ev binary on your PATH (the package is named evolving; the command
is ev).
Build from source:
# binary at target/release/ev
Quickstart
Create the store:
Record a decision with a chosen ground (re-checked by a human at a named time) and a road-not-taken:
Record a decision whose chosen ground is guarded by a test rather than a human. A test binding must carry a counter-test (the test that should flip red if the claim breaks), at least one platform / trigger / surface for liveness, and the commit it was last verified at:
Attach a test to an unbound ground of the current HEAD decision after the fact with
ev guard. Because the check is part of the hashed payload, this writes a new child
rather than mutating the existing tick:
<HEAD-id> is the id printed by the most recent ev decide/ev guard. The third
positional argument names which ground to bind (by claim text or by index); it is required
only when more than one ground is still unbound.
Audit the chain and the refusals, then read a decision in full:
ev verify confirms every id equals the hash of its payload, that lineage is
forward-only, and that every tick validates against the closed schema and check shape.
The model
- Tick — one decision in the chain. Its hashed payload is
{decision, observe, grounds, parent_id};id,status,held_since, andblameare bookkeeping kept outside the hash. - Ground — a reason a decision rests on. A ground is either chosen (a reason for
the decision taken) or a road-not-taken (
rejected:<option>, a reason an alternative was declined). - Check — what keeps a chosen ground honest over time. Either a Test (a test
selector plus its counter-test, the platforms/triggers/surfaces that keep it live, and
the
verified_at_shait last passed at) or a human Person re-check (a reference to when/where a person re-affirms the ground). - Identity —
id = first 12 hex of SHA-256over the canonical-JSON of{decision, observe, grounds, parent_id}. - Append-only — the chain is never edited in place. A change is a new child whose
parent_idpoints at its predecessor.
The refusals it enforces (the red lines)
- Closed schema. A tick with any field outside the fixed schema is rejected.
- A human re-check stays human. A ground re-checked by a person can never be force-bound to a test.
- A rejected road carries no check. A road-not-taken cannot take a check in
0.1.0(reserved for a future rejection-rationale liveness feature). - The system is never the subject of self-evolve language. Self-evolve / self-improve verbs must take a human subject, not the system (best-effort lexical lint).
- Every mutating op names a human. A decision or a guard must carry a
--blame(or a resolvablegit config user.name). - No auto-close. Nothing closes, prunes, or stops a decision on its own; a human authors every change.
Honesty / trust boundary
ev completes one specific picture: does a human-vetted decision stay live, and is the
check guarding it itself alive? It does that by content-addressing the decision record and
by demanding that every test binding name a counter-test and the surfaces that keep it
live, so a check that has quietly died is visible.
It does not claim tamper-resistance of offline test outcomes — ev records that a
test was bound and the commit it was verified at, but it cannot prove an offline test
result was honest. That is a documented boundary, not a guarantee.
License
Apache-2.0.