Skip to content

Latest commit

 

History

History
146 lines (129 loc) · 10.5 KB

ROADMAP.md

File metadata and controls

146 lines (129 loc) · 10.5 KB

Roadmap

Themes, not promises: dates are targets and slip when reality intervenes.

0.1 — the bounded run (shipped 2026-10-13)

  • boundary proxy with cap enforcement (max_usd, max_tokens, max_model_calls, max_wall_seconds)
  • append-only hash-chained ledger, canonical JSON, RFC 6962 Merkle root
  • receipts with embedded price table, usage inclusion proofs, limits disclosure
  • offline docket verify (Python) and an independent Node verifier, both bound to the committed conformance vectors
  • findings engine: runaway loops, uncached repeats, oversized context, denied calls, deny-write violations, premium-model leakage
  • filesystem snapshots and diffs, egress decisions, SDK + raw-HTTP recording
  • offline demo with a scripted provider, and a tamper demonstration
  • zero runtime dependencies; format specification docket/receipt/v1
  • mutation testing of the cryptographic modules and the ledger (tools/mutate.py), with every survivor classified as a gap or an equivalent mutant — scores in docs/testing.md

Shipped since 0.1 — what the "production engineering" list turned out to be

A concept-by-concept answer to the usual checklist (rate limiting, breakers, Kubernetes, Helm, backpressure, exactly-once, p99, on-call, …) lives in docs/production-coverage.md: what is implemented and tested, what is recorded but not enforced, what is a validated artefact that has never been executed here, and what is deliberately refused with a reason. The short version, as of this commit:

  • per-call latency recorded, summarised under a stated rule, and recomputed by both verifiers
  • --port (a fixed loopback port an orchestrator can probe), --upstream NAME=URL (a mock, gateway or self-hosted model, recorded as evidence without its query string), and the boundary's /docket/healthz, /docket/readyz, /docket/metrics documented
  • DOCKET_AGENT_MODE=backoff: full jitter, capped, honouring Retry-After — the client half of the rate-limit contract
  • a container recipe, a compose smoke test, a pod topology and a Helm chart, each checked statically by tools/deploy_check.py (16 checks) whose own tests break every invariant on purpose — and none of them executed, because no container runtime exists here
  • an invariant suite: one writer per ledger, 200 events from 8 threads, a replayed call recorded twice, a killed agent, a clock that lies
  • load and endurance measured, not estimated: make load (2,000 calls over 8 threads → 175.93 calls/s, client p50 44 ms) and make soak (12,002 calls paced over ten minutes, 0 drops, receipt still verifying), with the boundary's memory measured at ≈1.1 KiB per recorded event — and a control run at half the duration showing the same per-event cost, so the growth is the event list rather than a leak. Reports in docs/measurements/2026-10-15-2core/; the harness refuses to call a run evidence when the client's count and the ledger disagree
  • policy.denial_code: one reader for "the boundary refused this", shared by the reference agent and the load driver, which fixed a real defect (a provider's own error.code was being read as a Docket refusal) and closed a 502 in RateLimiter (a Decimal rate used to fail inside the request; nan silently disabled the limiter)

0.2 — make it easy to adopt — target: 6 weeks

  • docket init --from <framework> presets for Claude Code, Codex CLI, Gemini CLI, aider, OpenCode, and a generic HTTP profile. Each writes a policy that names the models that framework calls and prints the command that attaches it. tests/test_presets.py loads every policy back through the real parser and runs five of them end to end against the scripted provider.
  • GitHub Action: run an agent step under a policy, upload the receipt as an artifact, fail the job on a policy violation or an unverifiable receipt. The composite action lives at action.yml, with receipt, exit-code, spend, calls, verified and cap-exceeded as outputs. tests/test_action.py executes its own run: blocks against a real supervised run — including the tampered-receipt and cap-fired paths — and tests/test_action_smoke.py covers the scripted provider and smoke agent it depends on. .github/workflows/action-smoke.yml runs it in Actions on every push.
  • docket watch — tail a live run with a spend meter, safe to leave on a second terminal. It follows a ledger file as a supervisor appends to it, prints each event with a running total costed against the same price table the boundary used, and stops on session.end or after a quiet window, saying which. Nothing here talks to the boundary or a provider. tests/test_watch.py drives it against a real supervised run in another thread.
  • receipt --redact profiles for circulating evidence externally (paths, argv, secrets). docket report --redact paths,argv,hosts,secrets writes a redacted receipt and ledger, re-chains the pair so it still verifies, records what it replaced under a redaction block, and never touches the originals. tests/test_redact.py asserts every profile on its own leaves a verifying pair, and that the strings a client should not see are absent from both files.
  • honest coverage: record provider responses the boundary saw without parsing them, so an unknown provider is recorded rather than reduced to a guess about itself. Every model.response event now carries response_sha256 over the exact bytes returned to the agent, and [evidence] record_responses additionally keeps a bounded copy of each body, named by that digest, in a responses sub-directory of the run directory. docket verify re-hashes every retained body, so one that was edited or deleted after the run fails. The point is the case Docket cannot read: a fourth usage-block shape has its tokens estimated from the response text, and that text used to be discarded, so the estimate could never be checked. tests/test_evidence_retention.py covers the digest, truncation, the reserved-headroom boundary, a write that fails, the verifier's re-hash, and what --redact does with a path it cannot carry.
  • packaging: tests/test_packaging.py executes every install path the README names, against the version the tree declares rather than a literal, and skips with a stated reason when that version is not on PyPI yet rather than failing or pretending. Measured on 0.2.0: uv tool install docket-ai (uv 0.13.3), pipx install docket-ai (pipx 1.18.4) into a throwaway PIPX_HOME, and a clean python -m venv running the whole documented journey (init → run → verify). The pipx test resolves the binary from the directory pipx wrote to, not from PATH: the previous version called shutil.which("docket") and found whichever docket happened to be installed already, which is how it passed on a clean machine and failed on the release candidate. Still open: a Homebrew formula needs a tap repository and a released bottle, which is separate work and is not claimed here.

How this page is kept honest. Every [x] above is a claim that something exists, and a claim about code that nothing checks is the same failure mode as a stale test count: it was true when written and nobody noticed when it stopped being true. tests/test_roadmap.py walks every checked box on this page and requires it to name a file, a command, or a measurement that exists in the tree. An unchecked box is a plan; a checked box is a statement of fact, and it is held to one.

0.3 — verification anyone can run — target: Q1 2027

  • Go verifier (single static binary, no dependencies). Shipped in 0.1.5: verify-go/ builds with go build, passes go vet, gofmt and go test, and is one of the three implementations held to the 132-vector corpus. It was listed here as unshipped while all of that was true, which is the kind of stale row this page now has a guard against.
  • Rust verifier (crate + CLI) 💰
  • TypeScript/browser verifier (verify a receipt by dropping it into a static page, fully client-side) 💰
  • docket verify --explain — for each failing check, the smallest thing you can do next
  • verifier conformance kit: vectors + a runner any implementation can point at, published with a compatibility table
  • a public "verify this receipt" static demo page (no upload; the file never leaves the browser)

0.4 — evidence that survives scrutiny — target: Q2 2027

  • signed receipts by default in CI contexts (Ed25519, key from env or OS keychain)
  • transparency-log anchoring: optional append of a receipt digest to a public log (RFC 6962-style, generic — the goal is a trusted timestamp, never a blockchain) 💰
  • witness co-signing: a second party countersigns a receipt without seeing contents
  • multi-run attestations: "these 200 receipts all verify against this key" for procurement
  • docket diff semantics for policy changes: what a stricter cap would have done to last week's traffic (retrospective enforcement) 💰

1.0 — long-term support — target: H2 2027

  • format frozen with a compatibility promise and a published deprecation policy 💰
  • security-fix window for the previous major, stated in months, not vibes 💰
  • documented disaster story: what to do when a receipt fails to verify in production
  • case studies from regulated-industry adopters (published with their consent)

Explicitly not on the roadmap

  • A hosted service. There will be no Docket Cloud; the promise is that evidence need not pass through anyone's account.
  • A dashboard. Rendering is someone else's product; Docket emits receipts, JSON and Markdown. Dashboards subscribe to the ledger format.
  • A sandbox. Containers, gVisor, seccomp and hypervisors are better at enforcement than a user-space tool; Docket records and bounds, and says so.
  • Prompt/content recording by default. Evidence that requires storing what people typed will not be the default, whatever it would cost to make it a feature.
  • Blockchain anything. A transparency log needs witnesses and hashing, not tokens.