Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions LIMITATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,17 @@ do. Read this before trusting any single output.
- Four built-in claims (route-test-coverage, admin-authorization,
billing-webhook-signature, jwt-authentication). User-defined claims are not
supported yet, deliberately.
- Route test coverage is attributed statically (test imports and route names),
not by executing tests. A route exercised only indirectly can be reported as
uncovered.
- Admin authorization reports WEAK when it finds no authorization evidence.
That means DevTime found nothing, never that a route is confirmed
unprotected: global middleware and framework decorators are not detected.
- Route test association is established from test imports only, and a static
import association is not execution coverage. Tests that exercise a route
through a running server (supertest, TestClient) or through an unresolved
helper are reported as unassociated, so this claim currently abstains on many
real repositories.
- Admin authorization is established only from a guard at the route's own call
site. Guards applied by a router mount, a server-wide middleware, or a
framework decorator are reported as unresolved. WEAK means DevTime found no
connected evidence, never that a route is confirmed unprotected.
- Billing webhook signature verification is connected per handler by file.
Verification reached through an imported helper is not resolved yet.
- Verification is rule-driven over scanner signals; it inherits every scanner
coverage limitation listed here.
- Statuses mean "per DevTime's evidence rules", not formal proof or a security
Expand Down
4 changes: 2 additions & 2 deletions QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ python -m venv .venv
source .venv/bin/activate # Windows (PowerShell): .venv\Scripts\Activate.ps1
# Windows (Git Bash): source .venv/Scripts/activate
pip install -e ".[dev]"
pytest # optional: all tests pass (142 at v0.5.0)
pytest # optional: all tests pass (157 at v0.5.1)
```

## 3. Create the demo repo
Expand Down Expand Up @@ -132,7 +132,7 @@ A fresh-clone check was run on the current candidate:
- **OS:** Windows 11 (Git Bash)
- **Python:** 3.11.9
- **Install:** `pip install -e ".[dev]"`
- **Tests:** all passing (142 at v0.5.0)
- **Tests:** all passing (157 at v0.5.1)
- **Demo:** `dtc init` / `dtc scan` / `dtc concepts` / `dtc explain "Billing Webhooks"`
all produced the expected output from a clean `git clone`.

Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ dtc scan
dtc verify
```

On the demo repo that ends with signature verification SUPPORTED, JWT
authentication SUPPORTED, and `2 of 3 routes have a referencing test`. Point it at
your own repository and the answers change:
On the demo repo that ends with billing webhook signature verification
SUPPORTED, JWT authentication SUPPORTED, and route test association WEAK, naming
the routes with no test importing them. Point it at your own repository and the
answers change:

```bash
cd your-repo
Expand Down Expand Up @@ -106,7 +107,7 @@ Contradictions:
- **UNKNOWN** - the surface exists but coverage cannot responsibly decide
- **NOT_APPLICABLE** - the repository has no surface this claim is about

Four built-in claims ship: route test coverage, admin authorization, billing
Four built-in claims ship: route test association, admin authorization, billing
webhook signatures, and JWT authentication. `dtc verify` leads with what it can
actually verify in your repository, and when nothing applies it says what would
make a claim verifiable instead of dead-ending.
Expand Down
93 changes: 93 additions & 0 deletions RELEASE_NOTES_v0.5.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# DevTime v0.5.1 - three false SUPPORTED results, fixed

An external review of v0.5.0 reproduced three cases where `dtc verify` reported
SUPPORTED with no justifying evidence. All three reproduced against the released
code. This release fixes them.

A reproducible false reassurance is still a product failure, and these were the
exact failure DevTime exists to catch: a file's *name* being treated as evidence
about the file's *behavior*.

## What was wrong

**Administrative routes reported as protected when nothing checked them.**
`src/admin/permissions.ts` containing `router.get("/admin/permissions", handler)`
reported "1 of 1 administrative route(s) show an authorization check". The
evaluator matched a combined text that included the file path, so the word
"permissions" in the filename satisfied its "permission" token. No guard existed
anywhere in the repository. This was security-adjacent and is the reason this
release exists.

**Any test sharing a word with a route counted as testing it.**
A route `GET /users` and an unrelated test named "formats users display names"
produced SUPPORTED. Imports were matched by substring, so `superusers` counted as
`users`, and different HTTP methods on one path were merged.

**A signature helper anywhere in the repository protected every webhook.**
A billing webhook handler with no verification, plus an unrelated helper that
nothing called, reported SUPPORTED.

## What changed

**Authorization must be at the route's own call site.** The route extractor now
captures each route's own arguments, so a guard is attributed to the route it
actually wraps. Guards that are imported but never applied, named in a comment,
named in a string, or applied to a different route in the same file are no
longer evidence. Authentication is distinguished from authorization:
`requireAuth` establishes identity, not permission, and is reported as such.
Guards applied by a router mount or a server-wide middleware are reported as
unresolved, never as protected. A missing signal stays WEAK, never CONTRADICTED.

**Test association requires an import.** Only a test importing a route's
implementation module can support the claim, matched on exact module stems.
Route identity keeps the HTTP method. Name similarity is now reported as an
explicit unverified suggestion that can never raise the status. The claim is
renamed in output to **Route Test Association** and its statement no longer says
"exercised by tests", because a static association is not execution coverage.

**Webhook verification is connected per handler.** A signature call must appear
in the handler's own file. Verification in an unrelated module, or inside a test
file, no longer protects production code. Mixed repositories report per-handler
counts ("1 of 2 handlers verify a provider signature").

**Routes in test, example, and fixture directories are not application
surface.** They are excluded from the route inventory rather than counted as
untested. On the Express repository this changed the inventory from 142 routes,
nearly all of them from its own `test/` and `examples/` directories, to 9.

## An honest trade-off

Removing the false positives means `route-test-association` now abstains far more
often. On three real repositories it reports zero associated routes, because
their tests exercise routes through a running server (supertest, TestClient)
rather than by importing route modules. That is the correct trade - "I cannot
establish this" is better than a false "your routes are tested" - but the claim
is less useful than its v0.5.0 numbers suggested. Those numbers were mostly
name collisions. Resolving request-based association is the next step.

## Compatibility

- The claim id `route-test-coverage` is unchanged. Only its display name and
statement changed.
- JSON output stays `schema_version: 2`.
- No command, concept, or MCP tool was renamed or removed.
- Route signals gain `handlers` metadata and a line number; existing databases
are re-scanned normally with no migration.

## Notes

- 157 passing tests (16 new). Every reproduction above is now a permanent
regression test, including the adversarial cases: commented guards, unused
imports, guards inside strings, authentication-only guards, two routes in one
file with only one guarded, import stem collisions, and signature calls in
test files.
- The legitimate patterns still resolve: a guard at the call site is SUPPORTED,
a test importing its route is SUPPORTED, and a handler verifying signatures in
its own file is SUPPORTED.
- Known gaps, unchanged by this release: router-level and application-level
guards, verification through an imported helper, and request-based test
association are all reported as unresolved rather than assumed.

## Names

- PyPI distribution: `devtime-ei`. Python import: `devtime`. CLI: `dtc`.
30 changes: 20 additions & 10 deletions VERIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,28 @@ so plainly is more useful than an ominous UNKNOWN.

## Built-in claims

- **route-test-coverage** (v0.5) - "HTTP routes are exercised by tests." Reports
how many routes have a referencing test and names the ones that do not.
Attribution is by test imports and route names; end-to-end specs are excluded
because they match by accident. Absence of tests is missing evidence, never a
contradiction.
- **route-test-coverage** (id kept for compatibility; now presented as *Route
Test Association*) - "HTTP routes have tests that import their
implementation." Association is established from test imports only, matched on
exact module stems so `users` does not match `superusers`. Route identity keeps
the HTTP method. A test that merely shares a word with a route path is reported
as an unverified suggestion and can never raise the status. Routes defined in
test, example, or fixture files are not application surface and are excluded
from the inventory. A static association is not execution coverage.
- **admin-authorization** (v0.5) - "Administrative routes require an
authorization check." A missing authorization signal is WEAK, never
CONTRADICTED: authorization can be applied globally or by a wrapper the
scanner cannot see, and reporting an endpoint as unprotected when it is not
would destroy the trust this tool is built on.
authorization check." Authorization is established only from a guard applied at
the route's own call site. Authentication is not authorization: `requireAuth`
establishes identity, not permission. Guards that are imported but unused,
named in a comment, named in a string, or applied to a different route in the
same file are not evidence. Guards applied by a router mount or a server-wide
middleware are reported as unresolved, never as protected. A missing signal is
WEAK, never CONTRADICTED.
- **billing-webhook-signature** - "Incoming billing webhooks verify the payment
provider's signature."
provider's signature." Verification is connected per handler: a signature call
must appear in the handler's own file. A helper elsewhere in the repository -
even one nothing calls - does not protect a handler, and a call inside a test
file does not protect production code. Mixed repositories report per-handler
counts.
- **jwt-authentication** (v0.3) - "Authentication uses JWT access tokens."
Includes the documentation-vs-implementation detector: documentation claiming
JWT while the only JWT usage found is invitation/verification tokens is a
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "devtime-ei"
version = "0.5.0"
version = "0.5.1"
description = "Local-first Engineering Intelligence for software repositories"
readme = "README.md"
requires-python = ">=3.11"
Expand Down Expand Up @@ -50,7 +50,7 @@ dev = [
Homepage = "https://github.com/Shakargy/devtime"
Repository = "https://github.com/Shakargy/devtime"
Issues = "https://github.com/Shakargy/devtime/issues"
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.5.0"
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.5.1"
Demo = "https://youtu.be/1Hiu3Y9J_SI"

[project.scripts]
Expand Down
4 changes: 2 additions & 2 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
"source": "github"
},
"websiteUrl": "https://github.com/Shakargy/devtime",
"version": "0.5.0",
"version": "0.5.1",
"packages": [
{
"registryType": "pypi",
"identifier": "devtime-ei",
"version": "0.5.0",
"version": "0.5.1",
"transport": {
"type": "stdio"
}
Expand Down
2 changes: 1 addition & 1 deletion src/devtime/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""DevTime - local-first Engineering Intelligence for repository memory."""

__version__ = "0.5.0"
__version__ = "0.5.1"

# Version metadata (Builder Edition, Chapter 20).
EVIDENCE_MODEL = "2026.06.1"
Expand Down
Loading
Loading