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.
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
Copy the full commit from baseline.commit in the plan into PLAN_BASE_SHA:
PLAN_BASE_SHA="<commit from the plan's baseline.commit>"
uv run tenchi verify \
--base-ref "$PLAN_BASE_SHA" \
--change-plan .tenchi/changes/create-project.json \
--jsonUse that recorded commit even if origin/main has advanced since generation.
Repeating the ref name works only while it still resolves to the plan's commit.
The 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;
- 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. When the code producer is untrusted, keep
acceptance tests and the process that evaluates them outside the worktree the
producer can edit.
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.
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 outcomes. Runtime observer outcomes and evaluation reports
omit invocation inputs, generated outputs, and exception messages. Manifests
publish application-supplied schemas, descriptions, and other declaration
metadata; keep that metadata safe to share. Failed
checksteps retain bounded command output, which is also included inverifyreports. Tenchi does not redact what your tests or validation commands print. - Compatible. A change preserves existing callers or the guarantees a policy protects. Current inputs must accept historical valid inputs; current outputs must remain understandable to existing consumers. Job comparisons protect stored messages, while evaluation comparisons protect the strength of the quality gate. These comparisons do not require the documents to be identical.