You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
v2.12.0 — a review can prove what it reviewed, and git/gh are dependencies
Two field reviews of aws/karpenter-provider-aws#9464 both cloned the
repository and neither could PROVE it. `tp new` took the target as free
text; the contract recorded task, read_only, write_allow, budget — no
origin, no base, no head, no record of how the code arrived. Both reports
stated the workspace and the diff base in prose, by hand, and a review
conducted entirely from a rendered web diff would have produced identical
artifacts and an identical gate.
tp target fetch <pr> acquires a pull request with the same two git
commands every time, and records them
tp target pin --base reads what the checkout IS — origin, head, base,
merge-base, dirty paths — and reduces it to one
comparable fingerprint
tp target tools is git present, is gh present and authenticated
tp new --target … does the pin (and optionally the fetch) at
activation and writes it into the contract
Findings cite the fingerprint in `meta.target`. `tp findings` prints
UNBOUND when they cite nothing or a different tree — reported, never
withheld, because a human is better served by the findings plus a warning
than by a refusal. The SIGN-OFF is what is gated: the PreToolUse screener
refuses dod / loop submit / loop approve / loop retro on a read-only
contract until the workspace is pinned. Same conversion as v2.9.0's
obligations, and just as narrow — doing the review is never blocked, only
declaring it finished, and a build contract (which already carries its
snapshot) is untouched.
GH AS A DEPENDENCY. A clone carries the code and none of the intent: a
PR's title, body, linked issues and review conversation are not in the git
objects at all. In the field gh was absent and that context arrived over
unauthenticated web reads nothing recorded. `tp onboard` and `tp target
tools` now report git and gh with versions and auth state; `--install`
installs gh through the host's own package manager; a remote-PR review
without gh fails loudly instead of degrading quietly.
taskplane deliberately does NOT download and execute a release tarball.
A hardcoded checksum nobody maintains is a worse guarantee than the
package source the user already trusts, and a test pins that target.py
never reaches for curl, urlopen, requests or tarfile.
Also: the release-tag gate's C4 exemption covered exactly one unreleased
version, which broke the moment two release commits stacked up locally
(v2.11.0 committed, v2.12.0 in the tree). It now exempts any version some
commit reachable from HEAD declares — prepared, not merely claimed.
2,013 tests, three legs. 9 mutations observed failing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQDTFvvooeVoKMfCfJD1Yh
Copy file name to clipboardExpand all lines: .claude-plugin/marketplace.json
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@
10
10
"name": "taskplane",
11
11
"source": ".",
12
12
"description": "AI software-delivery control plane for Claude and Codex. Design, build, review, or check status with one simple taskplane prompt while a strict harness enforces approved Design Contracts, dependency-aware Definition of Ready and Done, scoped execution, fingerprinted worker evidence, orchestrator validation, human approvals, 26 review lenses, durable project memory, and a live dashboard.",
Copy file name to clipboardExpand all lines: .claude-plugin/plugin.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
{
2
2
"name": "taskplane",
3
-
"version": "2.11.0",
3
+
"version": "2.12.0",
4
4
"description": "AI software-delivery control plane for Claude and Codex. Design, build, review, or check status with one simple taskplane prompt while a strict harness enforces approved Design Contracts, dependency-aware Definition of Ready and Done, scoped execution, fingerprinted worker evidence, orchestrator validation, human approvals, 26 review lenses, durable project memory, and a live dashboard.",
Copy file name to clipboardExpand all lines: .codex-plugin/plugin.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
{
2
2
"name": "taskplane",
3
-
"version": "2.11.0",
3
+
"version": "2.12.0",
4
4
"description": "AI software-delivery control plane for Claude and Codex: simple design, build, review, and status prompts backed by dependency-aware readiness, scoped execution, fingerprinted evidence, 26-lens review, and human approval.",
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,7 @@ lens rewrite and never bumped to.
23
23
24
24
| Version | Highlights |
25
25
| --- | --- |
26
+
| **v2.12.0** | **A review can now prove what it reviewed — and `git`/`gh` are dependencies, not conveniences.** Two field reviews of `aws/karpenter-provider-aws#9464` both cloned the repository and neither could prove it: `tp new` took the target as free text and the contract recorded no origin, no base, no head, no record of how the code arrived. Both reports stated the workspace and the diff base in PROSE, by hand, and a review conducted entirely from a rendered web diff would have produced identical artifacts and an identical gate. `tp target` closes it: `fetch` acquires a pull request with the same two git commands every time and records them, `pin` reads what the checkout actually is (origin, head, base, merge-base, dirty paths) and reduces it to a fingerprint, and `tp new --target <pr> --fetch --base <ref>` does both at activation and writes the pin into the contract. Findings cite that fingerprint in `meta.target`; `tp findings` says UNBOUND when they cite nothing or a different tree, and the PreToolUse screener refuses `dod`, `loop submit`, `loop approve` and `loop retro` on a read-only contract until the workspace is pinned — the same obligation-to-prohibition conversion as v2.9.0, never blocking the review itself. **And `gh` is now a declared dependency.** A clone carries the code and none of the intent: a PR's title, body, linked issues and review conversation are not in the git objects, so in the field that context arrived over unauthenticated web reads nothing recorded. `tp onboard` and `tp target tools` report git and gh with versions and auth state, `tp target tools --install` installs gh through the host's own package manager, and a remote-PR review without gh fails loudly instead of quietly degrading. taskplane deliberately does NOT download and execute a release tarball — a hardcoded checksum nobody maintains is a worse guarantee than the package source the user already trusts, and a test pins that target.py never reaches for curl, urlopen or tarfile. 2,013 tests, 9 mutations observed failing. |
26
27
| **v2.11.0** | **The applicability engine was never wired to the wave — and three v2.10.0 claims were not true.** Route v2 (content, graph and requirement signals producing a per-lens `deep | light | n/a` verdict, every skip carrying machine-checkable negative evidence) shipped in v2.4.0 and was unreachable from the CLI for six releases: `route()` enables it only when `stage` is passed, `cmd_lens` passed nothing, and the one caller that did pass `stage="review"` was the coverage REPORTER. The engine scored the diff for a report and the wave ignored it. Compounding it, `tp-engineering/SKILL.md` mandated `--all` on every review command, and `--all` disables the engine by construction — two independent causes, so fixing either alone changed nothing. On a Go type change plus a docs edit the glob router summoned 6 lenses deep and marked none n/a; the engine routes 2 deep, 4 light, 20 n/a. **And v2.10.0 claimed three fixes that had not landed.** `graph impact` still could not see intra-repo Go: the root-module prefix stripping went into the JavaScript resolver, the Go branch was never touched, and the helper could not have worked anyway — it looked the root path up by key in a SET, which is what the scanner holds. The three "minor" papercuts were reported done and all three reproduce. **Then the exit path, from a second field run.** `session-verify` demanded `tp ack <id>` while the budget refused `tp ack <id>` — twelve firings, no reachable state that satisfied it; `ack` is now unmetered (it discharges an obligation and cannot widen scope — unlike `clear`, which stays walled), the last actions of a budget are RESERVED for closing rather than added to it, and the hook names the real blocker instead of repeating an impossible instruction. `tp ack <id>` in the wrong directory returned `acknowledged` for an id nobody issued, and `graph html` there emitted 5,684 bytes of valid-looking dependency graph for a workspace that had never been scanned — both now refuse and say where the contract actually lives. `tp init` writes `.git/info/exclude`, never a reviewed repo's `.gitignore`. A read-only contract can create the directory it authorizes. `python3 -c` is screened as a grammar instead of refused as a blob — an allowlist of stdlib reads passes, every write shape and anything unparseable still fails closed. 1,974 tests, 14 mutations observed failing. |
27
28
| **v2.10.0** | **Nine defects a real upstream repo found that no self-review could.** v2.9.0 was run end-to-end against `aws/karpenter-provider-aws#9464` in a separate session. The harness held — not one write reached reviewed source — and nine defects surfaced that only appear at somebody else's scale. **The worst was silent:** `tp findings` printed `0 high · 3 med · 13 low` while the findings file carried `class: regression`, which the engine's own gate blocks. The reviewer read the headline, reported "0 confirmed regressions", and recommended approve. The engine had the answer and the headline did not say it — the skill has mandated that split since v2.3.1. The headline now reads it off `loop.classify_findings` (never a second implementation) and says `1 BLOCK (1R·0H·1P·0O)`. **Parallel lens dispatch did not work with more than one agent:** six lens contracts each allowing `.em-review/lens-<id>/**` intersected to the EMPTY set, so 4 of 6 lenses produced no evidence at all and the wave board read 2/6 for a finished review. Sibling waves — every member read-only, every write-allow under one common root — now merge their write-allows and sum their budgets instead of taking the minimum, which had given six agents one agent's 30 actions and killed them mid-task. Contracts that genuinely compete over separate trees still intersect to nothing. **The graph could not see intra-repo Go at all:** a root `go.mod` was skipped as "describes the repo, not a module", so every `pkg/**` import landed as `ext:` and `graph impact` reported 2 modules and no call structure on a 256-module repo — the review's only blocking finding had to be traced by hand. The root module path is now consumed as a PREFIX (never a module id, which would collapse the repo into one node). **`tp version` was broken on every Claude-side install**, including the shipped `.plugin`: it read only `.codex-plugin/plugin.json`, which the Claude package does not contain. CI never saw it because CI inspects the source tree, where both manifests exist. Also: `tp contracts` names stale slots a union is silently applying, `tp clear --all/--slot` releases them from outside, `tp findings --html` emits a self-contained document for hosts that cannot render fragments inline, and `> /dev/null` is no longer screened as a write. **Six lens agents each burned actions rediscovering that `go test` could not run** — one fact about the CHECKOUT, paid for six times, and 41.5% of that session's tokens went to sub-agents. `lens dispatch` now probes build/test runnability ONCE, before composing briefs, using a bounded cheap subcommand (`go list ./...`, `cargo metadata --offline`, `import pytest`) and never the suite itself; the verdict is stated in every brief with an explicit do-not-re-probe instruction, shown on the wave board, and returned as `runnability.summary` for the findings `meta.tests`. It is cached per tree state and PATH, so a whole wave shares one answer while installing the toolchain mid-review re-probes. It is information, never a gate: no screener, contract or gate may read it, and a test pins that. `TASKPLANE_RUNNABILITY=off` skips it. And an interrupted wave no longer costs the whole fan-out again: `lens dispatch --resume` re-briefs ONLY the lanes with no findings.json, reading the same on-disk source the wave board already reads (a corrupt or listless findings file counts as NOT landed, so it re-runs). In the session that produced this report, four of ten sub-agent transcripts existed because a wave was spawned in a turn that died before the agents reported — about 16% of its effective tokens, spent twice. Opt-in by design: a fresh review of a changed diff must re-run every lens. **One request was refused:** the report asked for `tp clear` to be exempt from metering so an exhausted agent could release itself. Clearing leaves the workspace ungoverned, where the screener abstains — that trades a deadlock for a bypass, and `TestTheWallHolds` pins it. Only pure reads are exempt; recovery happens from outside. 1,905 tests; 13 mutations observed failing, one of which found a position bug in this wave's own code (`echo tp clear` read as a release command). |
28
29
| **v2.9.0** | **An obligation is now a prohibition — the first mechanism in this product that makes a required artifact non-skippable.** A hook can DENY an action; it cannot COMPEL one. That asymmetry is why every prohibition here has always held at 100% — the screener refuses an out-of-scope write, `rm -rf .`, an interpreter escape — while every OBLIGATION the flow defines ("render the wave board", "show the graph") held at 0%, because the only thing standing behind it was an instruction in a skill. Five structural attempts to close that shipped between v1.5.3 and v2.8.2 and the same complaint arrived after each one. An instruction is not a mechanism. **The conversion is:** not "you must show the graph" but "you may not declare the work finished until the graph has been shown". A conclusion is a command, a command is a tool call, and a tool call can be refused. `tp new --owes review` records the artifacts a run owes BEFORE any of the work starts — so a skip is a recorded fact from the first second rather than an absence nobody can see — and the PreToolUse screener then refuses `dod`, `loop submit`, `loop approve`, `loop retro` and `loop gate` until each is discharged. It is deliberately narrow: it can never block an edit, a test, a search, or any other part of DOING the work, only the act of declaring it done, and `TASKPLANE_OBLIGATIONS=off` disables it while still recording, because a governance mechanism with no stated way out is one people route around by uninstalling. **A second premise fell with it.** `obligations.py` stated that the engine "CANNOT see whether a rendered artifact was actually put in front of a human" because the render "happens in the host, outside every process taskplane runs", and therefore that showing something could only ever be a CLAIM. That was wrong: a PreToolUse matcher is a regex over TOOL NAMES, and MCP tools are named `mcp__<server>__<tool>`, so a `mcp__visualize__.*` matcher reaches the render at the same seam that already screens writes and dispatches. `tp screen-render` now records every render as a FACT with its content fingerprint, which separates three failures that were previously indistinguishable: SKIPPED (demanded, never rendered), SUBSTITUTED (rendered — but not the artifact the engine built, which makes the byte-for-byte render contract checkable for the first time) and CLAIMED ONLY (acknowledged with no observation behind it). Rendering the engine's exact bytes discharges an obligation on its own, so the honest path is also the short one. The engine still cannot read the ledger — the block lives in the screener and the hooks, the deletability contract is unchanged, and `loop.gate` is untouched. A `Stop` hook (`tp session-verify`) reports anything still owed as the net underneath. 1,839 tests; 17 mutations of this behaviour observed failing. |
0 commit comments