An evidence-axes project map where DONE is computed, never filed: every status claim needs an evidence record, and 'connected' must be grep-proven.
Project description
provenmap
A project map where DONE is computed, never filed.
Every tracker you have ever used lets anyone — you on an optimistic day, a teammate in a hurry, an AI coding agent that just announced "implemented and fully wired up!" — set a status field to done. The status is an assertion. Nothing checks it. Over time the board drifts from the code, and the drift is always in the same flattering direction.
Provenmap refuses assertions. Every item carries four independent evidence axes, each FALSE unless it holds an evidence record:
| Axis | Claim | Evidence demanded |
|---|---|---|
designed |
the design exists | a doc path — checked to exist on disk |
built |
the code exists | a commit hash or file path |
connected |
something on the production path calls it | a call-site file:line that is grep-real at filing time, plus the census digest |
verified |
a live run proved it | an artifact path — checked to exist; whether it matches the item's acceptance signal is your judgment, on record |
Enforcement is strictest on the two axes that lie most: hard connected evidence can only be filed through provenmap census --record (the generic file command refuses callsite-kind connected evidence outright), and verified hard-requires an on-disk artifact — while designed/built accept any recorded evidence kind.
DONE = all four axes evidenced. It is computed at read time. Storing done, progress, or status on an item, an arc, or the map itself is a validation error.
Built for my own workflow directing AI coding agents on the Ticos project, where "the model said it built it" and "production can actually reach it" turned out to be very different claims. Separated out in case it's useful elsewhere.
Install
pip install provenmap
Quickstart
provenmap init # scaffold a stamped map (provenmap.json) in the current directory
provenmap status # progress bars + the honesty counters
provenmap file A1.example designed --kind doc --ref docs/DESIGN.md --by you # any doc path that exists
provenmap census A1.example # grep the item's census_targets; add --record --callsite <root>/<file>:<line> --by you to file evidence
provenmap serve # read-only dashboard in the browser
(init scaffolds a starter item A1.example; rename and add items with provenmap edit.)
Or explore the fictional example in the repository (examples/demo) first:
provenmap status --map examples/demo/provenmap.json
ACTIVE-SCOPE completion : 75.0%
TOTAL-SCOPE completion : 62.5%
VERIFICATION DEBT : 2 built-but-not-verified item(s)
CENSUS-PENDING : 1 attestation-backed claim(s)
REACHABILITY-PENDING : 0 connected claim(s) with no proven path from a production entry point
pointer : CORE / CORE.search
[#####################-------] 75.0% CORE snippet core (active)
DBCV DONE CORE.store (M, active)
DB.. 50% CORE.search (M, active)
DBC. 75% CORE.export (S, active)
[----------------------------] 0.0% UX polish (queued)
.... 0% UX.themes (S, deferred)
What a grep proves — and what it does not
The connected axis is where trackers lie hardest, so it gets the most machinery.
provenmap census ITEM greps the item's declared census_targets across the production roots configured in the map, prints the hits (up to --limit) plus a digest over all of them, and — with --record — files connected evidence only when the claim survives three custody rules:
- A declaration is not a call.
--callsitepointing at adef/classline is refused. That the code exists is thebuiltaxis;connecteddemands that something calls it. - A module calling its own symbol is not a connection. If every production hit lies inside the module that declares the symbol, nothing else in production reaches it — refused. (The specimen that forced this rule: a module whose only callers were itself and the test harness filed
connectedclean for weeks.) Escapable only by naming a production entry point explicitly — which is then recorded, auditable, and your judgment on record instead of silent. - A connected filing with no entry-point evidence is DEBT, not proof. It records, but it counts as REACHABILITY-PENDING with a warning. Admissible — grep beats nothing — but never silently equal to a reachability-proven connection.
And the honest limit, stated so nobody over-reads the fence: a grep proves a symbol is mentioned; it cannot prove production reaches it. The census is a one-hop text search, not a call-graph walk. The digest is proof at filing time: validate re-checks that referenced files still exist, but it does not re-grep — re-run census after refactors to refresh a stale connection claim. connected is a cheap necessary condition — verified, a live run matching the item's acceptance signal, is the only axis that proves a thing is real. That is why VERIFICATION DEBT (built-but-not-verified) is the headline counter, not the completion percentage.
Tamper-evidence
All writes go through the CLI: schema-validated, atomic (tmp+rename), sha256-integrity-stamped, and appended to a changelog (provenmap.changelog.jsonl). Hand-editing the map breaks the integrity hash and turns provenmap validate RED — by construction, not by policy. Deliberate manual edits are allowed, but they cost an explicit provenmap restamp --by you --author-ack, which puts the acknowledgment on the record (the changelog records that an edit happened, not its diff).
The scope of that guarantee, honestly: the unkeyed hash defends against accidental and unrecorded edits — the silent drift class. It cannot stop a deliberate forger who recomputes the stamp, and doesn't try; nothing local can.
The other honesty mechanics
- Progress is weighted realistically: designed 0.15 / built 0.35 / connected 0.25 / verified 0.25 by default — an item that is designed and built still reads 50%, never 100%.
- Two completion numbers, always together: ACTIVE-SCOPE (deferred/parked/graveyard excluded) and TOTAL-SCOPE (deferred and parked included) — deferring work must never inflate progress.
- Dispositions are intent, never progress:
deferred/parkedrequire a written trigger;abandonedrequires a date and reason;supersededrequires a successor — and the graveyard renders visibly in the dashboard instead of vanishing. - Attestations are honest IOUs: a human/agent claim may temporarily stand in on the mechanical axes, but only marked
CENSUS-PENDING, and it is counted and displayed as such until converted into grep or artifact evidence. - Approvals sit above DONE: optional
operator_approved/bench_approvedrecords (an explicit human sign-off; a real benchmark artifact) render last and can never add progress or satisfy an axis.
Working with AI coding agents
This tool exists because agent-reported status inflates. The division of labor that works:
- Judgment (yours): item meaning, acceptance signals, sizes, dispositions, triggers, the
designedaxis, and declaring each item'scensus_targets. - Mechanical (the agent's, or anyone's):
builtrecords a commit;connectedmust be filed throughprovenmap census --record, which refuses everything it cannot prove — and thefilecommand refuses to accept hand-filed callsite evidence on that axis at all;verifiedneeds an artifact that exists on disk.
An agent that files its own roadmap state through provenmap at the end of every run either produces evidence or produces a visible refusal. Both are useful. (The edit command remains the full-document judgment escape hatch — validated, stamped, and changelogged, but judgment nonetheless; don't hand it to the agent.)
Configuration
The census configuration lives inside the map, so it is integrity-stamped with everything else:
"census": {
"production_roots": ["src"],
"aux_roots": ["tools"],
"include_globs": ["*.py"],
"skip_dir_prefixes": [".", "__pycache__", "tests", "test"],
"skip_file_prefixes": ["test_"],
"definition_pattern": "^(async\\s+def|def|class)\\s"
}
aux_roots are searched and reported but never count as production. definition_pattern is what makes custody rule 1 work; the default recognizes Python definitions — override it for other languages. All commands take --map (default ./provenmap.json); evidence paths resolve against the map's directory (--root to override).
Honest limits
- Single JSON file, single writer at a time — built for solo devs and small teams, not org-scale program management.
- The census is a line-regex search. Python-first defaults; other languages work via
include_globs+definition_pattern, with less sharp definition detection — and when the pattern matches no census line at all, recording demands the explicit--entry-pointescape rather than pretending the declaration rules were checked. - File-glob matching follows the platform: on Windows,
*.pyalso matchesX.PY, so census hit counts can differ across platforms for mixed-case trees. --rootis not persisted in the map: if you validate with a custom root, pass it consistently.- The dashboard is read-only by construction (POST is refused). All writes go through the CLI.
- The integrity stamp detects unrecorded edits; it does not authenticate authors.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file provenmap-0.1.0.tar.gz.
File metadata
- Download URL: provenmap-0.1.0.tar.gz
- Upload date:
- Size: 40.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09a08c1a00826a4bd9b949192bd21dbb58868c182e82d58abf9aff9981541bc2
|
|
| MD5 |
b38a469c85edba9776e1e9396dad7b0e
|
|
| BLAKE2b-256 |
14b3fa4010d89d694cc47dfe9ad52fa773d7d92dad2e00c6ec98bad78d28411d
|
Provenance
The following attestation bundles were made for provenmap-0.1.0.tar.gz:
Publisher:
release.yml on Sicatho/provenmap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
provenmap-0.1.0.tar.gz -
Subject digest:
09a08c1a00826a4bd9b949192bd21dbb58868c182e82d58abf9aff9981541bc2 - Sigstore transparency entry: 2336578499
- Sigstore integration time:
-
Permalink:
Sicatho/provenmap@32557befb59240e69db51b72d07b22a2ece2e141 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Sicatho
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@32557befb59240e69db51b72d07b22a2ece2e141 -
Trigger Event:
release
-
Statement type:
File details
Details for the file provenmap-0.1.0-py3-none-any.whl.
File metadata
- Download URL: provenmap-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a365f8ccf64db13ebffb1e938fa0813bddeec87a9c305c283337183f5ef7550
|
|
| MD5 |
762c8aa42149e9fe4260689259a4ed73
|
|
| BLAKE2b-256 |
dd2b5984acb68f0d19bd578a06d03aadbb6f35b3677e96e945a7558150e98efb
|
Provenance
The following attestation bundles were made for provenmap-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Sicatho/provenmap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
provenmap-0.1.0-py3-none-any.whl -
Subject digest:
1a365f8ccf64db13ebffb1e938fa0813bddeec87a9c305c283337183f5ef7550 - Sigstore transparency entry: 2336578503
- Sigstore integration time:
-
Permalink:
Sicatho/provenmap@32557befb59240e69db51b72d07b22a2ece2e141 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Sicatho
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@32557befb59240e69db51b72d07b22a2ece2e141 -
Trigger Event:
release
-
Statement type: