evolving 0.0.1

git for decisions — an immutable, content-addressed ledger of human-authored decisions that resurfaces when a bound check goes red
Documentation

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

cargo install evolving

This installs an ev binary on your PATH (the package is named evolving; the command is ev).

Build from source:

git clone https://github.com/wan9yu/evolving
cd evolving
cargo build --release
# binary at target/release/ev

Quickstart

Create the store:

ev init

Record a decision with a chosen ground (re-checked by a human at a named time) and a road-not-taken:

ev decide "build our own retrieval; reject pgvector" \
  --observe "evaluating retrieval backend for v2" \
  --assume "team has bandwidth to maintain it long-term" \
  --revisit "Q3" \
  --reject "pgvector: would lock our schema" \
  --blame "You"

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:

ev decide "restore-safety counter DB-backed; reject Redis" \
  --observe "multi-pod restore-safety counter" \
  --assume "no Redis; multi-pod coordination via the existing DB" \
  --assume-test "pytest tests/test_redis_absent.py" \
  --counter-test "pytest tests/test_redis_absent.py::test_redis_injection_flips_red" \
  --on-platform linux-ci \
  --triggered-by pyproject.toml \
  --surface pyproject-deps \
  --verified-at-sha d308afac1b2c3d4e5f60718293a4b5c6d7e8f901 \
  --reject "Redis: a new infra dependency" \
  --blame "You"

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:

ev guard "pytest tests/test_schema_frozen.py" <HEAD-id> "schema stays frozen" \
  --counter-test "pytest tests/test_schema_frozen.py::test_schema_change_flips_red" \
  --on-platform linux-ci \
  --triggered-by schema.sql \
  --surface schema-ddl

<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
ev show <id>

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, and blame are 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_sha it last passed at) or a human Person re-check (a reference to when/where a person re-affirms the ground).
  • Identityid = first 12 hex of SHA-256 over 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_id points 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 resolvable git 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.