Metadata-Version: 2.4
Name: provenmap
Version: 0.1.0
Summary: An evidence-axes project map where DONE is computed, never filed: every status claim needs an evidence record, and 'connected' must be grep-proven.
Author: Usman
License-Expression: MIT
Project-URL: Homepage, https://github.com/Sicatho/provenmap
Project-URL: Issues, https://github.com/Sicatho/provenmap/issues
Keywords: roadmap,project-tracking,evidence,ai-agents,agentic,done,verification,cli
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Bug Tracking
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Dynamic: license-file

# 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

```bash
pip install provenmap
```

## Quickstart

```bash
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](examples/demo)) first:

```bash
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:

1. **A declaration is not a call.** `--callsite` pointing at a `def` / `class` line is refused. That the code exists is the `built` axis; `connected` demands that something *calls* it.
2. **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 `connected` clean for weeks.) Escapable only by naming a production entry point explicitly — which is then recorded, auditable, and your judgment on record instead of silent.
3. **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`/`parked` require a written trigger; `abandoned` requires a date and reason; `superseded` requires 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_approved` records (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 `designed` axis, and declaring each item's `census_targets`.
- **Mechanical (the agent's, or anyone's):** `built` records a commit; `connected` must be filed through `provenmap census --record`, which refuses everything it cannot prove — and the `file` command refuses to accept hand-filed callsite evidence on that axis at all; `verified` needs 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:

```json
"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-point` escape rather than pretending the declaration rules were checked.
- File-glob matching follows the platform: on Windows, `*.py` also matches `X.PY`, so census hit counts can differ across platforms for mixed-case trees.
- `--root` is 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
