Verify a generated change
A change plan connects a contract-driven generator request to the final
tenchi verify receipt. Use one when a human or coding agent should prove that
the generated use case was implemented, tested, and wired to the intended HTTP
contract.
Change-plan version 2 supports use cases generated with --from-contract.
Plans are JSON files with a content-derived plan_id, the Git baseline, the
contract and use-case identities, generated paths, one exact pytest target, and
a fixed set of completion conditions.
Verification terms
These words keep one meaning across tenchi verify, change plans, and the
coding-agent guides.
- Baseline. The Git commit that
--base-refresolves to. A ref such asorigin/maincan move later, so the receipt records the commit and every comparison uses that same historical state. - Receipt. The result of
tenchi verify: one JSON object covering the source digest, verification policy, checks, architecture, compatibility reports, and any change plan.tenchi checkproduces a result; onlyverifyproduces a receipt. - Evidence. What a
[verify]stage intenchi.tomlrequires, such as a passing check or a compatible OpenAPI report. Each stage ends aspassed,failed,skipped,not_configured, ornot_verifiable. - Source digest. A SHA-256 hash of the application tree, including nonignored untracked files, captured before verification and rechecked after every project-owned stage.
- Plan ID. The
sha256:…identity of a change plan, derived from its content. Any change to the plan produces a new ID. - Payload-safe. A result that never contains request bodies, case inputs, prompts, model output, secrets, or exception text. Tenchi's manifests, reports, and observer outcomes all hold to this.
- Compatible. A historical comparison passes when the new version still accepts everything the old version accepted. The comparison is one-way: it does not ask whether the two versions are equal.
Preview the generation
Start from a committed baseline, then preview the files and boundary Tenchi would generate:
uv run tenchi make use-case projects create_project \
--from-contract app.features.projects.contracts:create_project_contract \
--dry-run --jsonThe preview does not write application files. Review its derived signature and planned paths before accepting the generation.
Create the files and plan together
Run the generator without --dry-run and provide a project-relative plan path:
uv run tenchi make use-case projects create_project \
--from-contract app.features.projects.contracts:create_project_contract \
--plan .tenchi/changes/create-project.json \
--base-ref origin/main \
--jsonTenchi resolves origin/main to a baseline commit before writing anything.
The generated use-case file, failing test, and plan are created as one
filesystem operation; if any write fails, Tenchi removes the files created by
that operation.
The JSON result contains the complete plan, its destination, and a plan_id
such as sha256:…. Keep that ID in the task description, review record, or
orchestrator state. Any plan-content change produces a different ID, and the
final verification receipt reports the ID it actually checked.
Combining --plan PATH with --dry-run includes the prospective plan and
path in the result but writes neither the generated files nor the plan.
Implement the behavior
Replace the generated NotImplementedError and failing test. Remove both
# tenchi: incomplete markers only after the behavior and its direct test are
implemented. Keep the generated test function name—test_create_project in
this example—because the plan binds completion evidence to that exact pytest
target. Bind the contract and use case explicitly in the feature's routes.py;
the generator does not rewrite composition modules.
Run the normal validation loop while working:
uv run tenchi check --jsonVerify the requested structure
Use the same baseline named in the plan:
uv run tenchi verify \
--base-ref origin/main \
--change-plan .tenchi/changes/create-project.json \
--jsonThe change-plan section passes only when:
- the plan and verification resolve to the same baseline commit;
- both generated files exist and contain no incomplete marker;
- the exact contract and use case are registered, and the current contract still produces the accepted use-case signature;
- one registered route binds that contract and use case through exact application-map evidence; and
- exactly one top-level test function matches the target, directly references the imported use case, and neither the module nor function rebinds that imported name;
- the callable collected by pytest comes from that exact source definition, so a decorator that replaces or wraps the function fails as ambiguous; and
- pytest collects at least one invocation of that function, and every setup, call, and teardown reports success. Skipped, expected-failure, unexpected pass, deselected, failed, errored, uncollected, and ambiguous invocations all fail the plan.
Tenchi normally records this evidence during the pytest step of tenchi check.
If the repository's current and historical verification policies both disable
the general check stage, Tenchi runs only the planned pytest target so the plan
cannot waive its own execution requirement.
Tenchi reads the plan before running project-owned validation commands and again before returning the receipt. If a test or import mutates the plan during verification, the receipt fails.
What the receipt proves
A passing plan proves that the generated structure was completed and that its
planned test ran successfully in the project's own pytest process. It does not
prove business correctness, and nothing outside the repository attests the
run. The JSON receipt identifies this boundary as
provenance: "project_pytest_process".
Project-owned conftest.py files, pytest plugins, fixtures, and imported test
code run in that same interpreter. Code with permission to modify and execute
the repository can therefore interfere with the evidence collector. Tenchi
clears inherited PYTEST_ADDOPTS, PYTEST_PLUGINS, and PYTHONPATH so shell
configuration cannot silently redirect the run, but it does not describe this
in-process evidence as tamper-proof. Use an external evaluator with withheld
tests—such as the repository's agent-change benchmark—or an isolated CI policy
owned outside the edited worktree when the code producer is adversarial.
The receipt also does not prove that the test called the use case, that its
assertions are strong enough, or that the implementation satisfies the product
requirement. Review the use case, policy, ports, and test behavior as usual;
tenchi check and the historical compatibility stages remain part of the same
final receipt.
Pytest marks such as @pytest.mark.parametrize remain suitable because they
preserve the test function's source identity. A custom decorator that returns a
different callable cannot provide plan-bound execution evidence.
Plans created before schema version 2 are not accepted. Generate a new plan with the current Tenchi version before editing its files; do not hand-edit an older plan into the new shape.
The plan file is repository-owned data, not a signed instruction. Tenchi
validates its content-derived identity and refuses weakened completion
conditions, but someone who can edit the repository can replace the whole
plan and receive a new ID. Preserve the initially accepted plan_id outside
the edited worktree when the exact requested intent needs independent review.