feat(devkit): add resumable workspace automation and UI review tooling
Verified with the coordinated workspace changes by devkit full run 2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed). This shared UI pass does not mark the individual module reviews complete.
This commit is contained in:
Executable
+171
@@ -0,0 +1,171 @@
|
||||
# Devkit review bundles and issue evidence
|
||||
|
||||
Gitea remains the canonical backlog and review state log. These commands assemble
|
||||
guidance and append evidence; they do not create a second progress tracker, close
|
||||
issues, rewrite issue bodies, tick checkboxes, or certify a module review.
|
||||
|
||||
## Prepare a module review
|
||||
|
||||
```sh
|
||||
./devkit review campaign
|
||||
./devkit review campaigns --json --output /tmp/campaign-review.json
|
||||
./devkit review campaign --evidence RUN_ID
|
||||
```
|
||||
|
||||
Repository names, repository aliases and scope IDs from the
|
||||
[issue discovery inventory](../project/ui-review-issue-inventory.json) are accepted.
|
||||
`review bundle campaign` is an equivalent spelling. A bundle contains the current
|
||||
source inventory and fingerprint, canonical module/central issue links, the
|
||||
Core principle revision and content hash, applicable **planned** check stages,
|
||||
and a manual checklist. No checks or application servers are started. The
|
||||
optional output file is a local snapshot, not an authoritative state record.
|
||||
|
||||
The filename inventory is a starting point, not proof that all runtime surfaces
|
||||
were found. It does not import application manifests or optional modules. Review
|
||||
routes, panes, dialogs, settings, widgets, public forms, contributed/headless
|
||||
interfaces, missing-module behavior, permissions, English/German and narrow/wide
|
||||
layouts manually. Missing source, no UI files or no planned checks is never an
|
||||
automatic pass or N/A. Record exceptions and remaining work in the module issue.
|
||||
|
||||
Apply [UI-01 and UI-02, and the other Core principles](../../../govoplan-core/docs/UI_DESIGN_PRINCIPLES.md):
|
||||
books belong beside meaningful visible text; normal screens display compact
|
||||
data, with intentional scoped dialog editing. A bulk editing mode needs a
|
||||
documented reason. Record new principles and their back-propagation to previously
|
||||
reviewed modules through the [central review program](../project/UI_REVIEW_PROGRAM.md).
|
||||
|
||||
An explicit portable `--project project.json` does not inherit GovOPlaN issue
|
||||
links or principles. Its optional configuration is:
|
||||
|
||||
```json
|
||||
{
|
||||
"review": {
|
||||
"issue_inventory": "meta/docs/review-issues.json",
|
||||
"principles": "core/docs/UI_DESIGN_PRINCIPLES.md"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Paths are relative to `--workspace-root` and cannot escape it or traverse
|
||||
symlinks. The inventory uses schema version 1, `issues[]` with `scope_id`,
|
||||
`repository`, `number`, `url`, and optional `name`/`kind`; an optional `epic`
|
||||
contains `repository`, `number`, `url`. Snapshot issue-state fields are not
|
||||
reported as current state. Custom checks come from the project's selected
|
||||
profile (`--profile ui` by default).
|
||||
|
||||
## Preview and append evidence
|
||||
|
||||
```sh
|
||||
./devkit issues note --root govoplan-campaign --issue 103 \
|
||||
--evidence RUN_ID --summary 'Targeted checks passed.' \
|
||||
--next 'Manual module review and remaining fixes are still required.' --json
|
||||
|
||||
./devkit issues note --root govoplan-campaign --issue 103 \
|
||||
--evidence RUN_ID --summary 'Targeted checks passed.' \
|
||||
--next 'Manual module review and remaining fixes are still required.' \
|
||||
--env-file /private/gitea.env --apply
|
||||
```
|
||||
|
||||
`--root` is resolved relative to the selected **workspace root**, not the shell's
|
||||
current directory. In the normal siblings workspace, use `--root govoplan-campaign`
|
||||
or an absolute checkout path; do not use a path escaping the workspace.
|
||||
|
||||
The default is a completely offline dry run; it does not load credentials or
|
||||
contact Gitea. `--apply` explicitly authorizes comment creation. Tokens are read
|
||||
from `GITEA_TOKEN` or the explicit `--env-file` (environment wins); there is no
|
||||
implicit `.env` search. The credential file is parsed, never sourced, and is not
|
||||
printed or uploaded. Git's selected remote (default `origin`) determines the
|
||||
exact target: ambient `GITEA_OWNER`, `GITEA_REPO` and `GITEA_URL` cannot retarget
|
||||
the request. Credential-bearing HTTP Git remote URLs are rejected.
|
||||
|
||||
Use repeatable `--summary`/`--next`, `--body-file` for Markdown, or `--note-file`
|
||||
with structured JSON `{ "summary": ["..."], "next": ["..."], "body": "..." }`.
|
||||
Do not put secrets in notes, paths, check arguments or logs. Display redaction is
|
||||
best-effort protection, not permission to include confidential data.
|
||||
|
||||
For a bounded multi-issue operation, replace `--root`/`--issue` with
|
||||
`--target-plan targets.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"targets": [
|
||||
{
|
||||
"root": "govoplan-campaign",
|
||||
"issue": 103,
|
||||
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-campaign/issues/103"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Targets must be unique, inside the workspace and bound exactly to their Git
|
||||
remote/issue URLs, all on one exact Gitea base URL. Optional `issue_id` binds
|
||||
Gitea's immutable numeric ID as well. Every target, complete comment history,
|
||||
marker collision and local journal binding is checked before the first POST.
|
||||
Comments are then posted serially and read back against the exact issue. A
|
||||
closed issue stays closed; existing bodies, comments and checklists are untouched.
|
||||
|
||||
Each note has a stable hidden marker binding its issue, `--key` purpose
|
||||
(`verification` by default), and evidence run ID. Identical already-published
|
||||
notes are read back instead of reposted; changed content with the same marker
|
||||
is a collision, not an update. Use a distinct intentional `--key` for a separate
|
||||
follow-up. Without a receipt, the note's structured content determines identity.
|
||||
|
||||
A lost POST response is **not** retried automatically. The publisher scans all
|
||||
comment pages and reads back any matching comment. If it cannot confirm the
|
||||
result, it records `uncertain`, stops later posts, and exits nonzero. The next
|
||||
invocation reconciles again without replaying the POST. Only after inspecting
|
||||
the issue and local result, use `--apply --retry-uncertain` to permit one new
|
||||
attempt when the marker is still absent. Local journals and OS-released locks
|
||||
live in the workspace-scoped devkit state directory; do not delete them to bypass
|
||||
uncertainty. These are retry receipts, not issue state. Independent machines or
|
||||
different state directories cannot share a lock: coordinate publishers, because
|
||||
Gitea comment creation does not provide an atomic idempotency key.
|
||||
|
||||
## What a receipt does and does not prove
|
||||
|
||||
`--evidence RUN_ID` reads the workspace-scoped runner receipt and checks local
|
||||
integrity. `--evidence /path/to/receipt.json` accepts bounded validated external
|
||||
receipt metadata, explicitly labeled `external-unverified`. A self-consistent
|
||||
digest is not a signature or independent verification. Foreign-workspace,
|
||||
malformed and inconsistent successful receipts are rejected. Receipt-provided
|
||||
commands are never run; log files are not opened or uploaded, only referenced.
|
||||
Successful receipts must explicitly record a verified source snapshot; an
|
||||
external file's flag is still a reported claim, not an independent attestation.
|
||||
An aggregate containing a skipped stage cannot claim success. New versioned
|
||||
receipts additionally require independent verified checkpoints for passed phases.
|
||||
Failed/interrupted/stale aggregates remain labeled as such even when they contain
|
||||
reusable successful phases; reuse creates a new run and preserves the original.
|
||||
Stage coverage limitations are validated and retained in the note, including
|
||||
checks omitted by scoped profiles. Compact review output shows the first eight
|
||||
limitations and points to the complete list in its JSON bundle. A passing stage
|
||||
never implies that omitted compiler, browser, permutation or manual checks ran.
|
||||
|
||||
Documentation audit limitations are saved with their stage receipts, so later
|
||||
review bundles and issue notes retain the same scope as the original command.
|
||||
Managed inventory collectors use the explicit selected workspace throughout;
|
||||
an incomplete checkout never borrows sources or missing module imports from a
|
||||
fuller default workspace. Missing required Core/parser dependencies fail the
|
||||
audit. Legacy direct inventory commands without `--workspace-root` retain their
|
||||
discovery behavior; use the explicit option for reproducible evidence.
|
||||
|
||||
The note distinguishes `matches-current`, `historical-source-differs`,
|
||||
`different-project-not-compared` and unavailable comparisons. Matching source
|
||||
is a comparison at bundle/note preparation time, not a live test run or proof
|
||||
that a person completed review. If the source or environment has changed, run
|
||||
the appropriate checks again and keep historical evidence labeled honestly.
|
||||
|
||||
Versioned repository-input receipts compare the recorded repository scope, not a
|
||||
legacy whole-workspace hash. Partial scopes remain explicitly labeled in evidence
|
||||
notes. This comparison reads source only; receipt commands are never executed.
|
||||
Legacy receipts retain their original comparison format. A matching source scope
|
||||
does not prove that ignored build outputs, the environment or live services match.
|
||||
|
||||
Fixtures cover dry-run isolation, exact target bindings, capped/repeated
|
||||
pagination, collisions, append-only idempotency, uncertain POST reconciliation,
|
||||
secret-safe errors, receipt validation, portable projects and optional-module
|
||||
review boundaries:
|
||||
|
||||
```sh
|
||||
python3 -m pytest -q tests/test_devkit_issues.py tests/test_devkit_review.py
|
||||
```
|
||||
Reference in New Issue
Block a user