feat(devkit): add resumable workspace automation and UI review tooling
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s

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:
2026-09-09 02:03:17 +02:00
parent 14b19fbead
commit 2ffdb23f69
67 changed files with 17306 additions and 94 deletions
+300
View File
@@ -0,0 +1,300 @@
# Developer command suite
`./devkit` is the maintained entry point for repeated development work. It uses
ordinary local programs, not an AI service. People, CI and coding agents use the
same commands and results. It composes existing GovOPlaN checks and release
services rather than defining parallel product rules.
## Start here
From the Meta checkout:
```sh
./devkit commands
./devkit doctor --repo core
./devkit context --changed
./devkit check --profile quick --repo campaign --dry-run
./devkit coverage --profile ui --repo campaign
./devkit check --profile quick --repo campaign
./devkit latest
./devkit review campaign
```
Use `--help` on each command. `--json` (or `--format json`) returns structured
results; the default summary intentionally omits full logs and source contents.
Global options work before or after the command. `--workspace-root` is the parent
directory of the registered repositories, not the Core checkout. Unknown
repository filters fail rather than silently widening/narrowing scope.
The launcher prefers Meta's `.venv/bin/python`, or the explicit `PYTHON`
executable, with `python3` as the no-venv fallback. Checks resolve `NODE` and
`NPM` from explicit environment settings or `PATH`; no username-specific Node
installation path is required. Doctor reports repairs but never installs
packages, changes configuration, kills an occupied port or starts a server.
## Command contracts
| Command | Purpose | Effects |
| --- | --- | --- |
| `context [--changed] [--repo NAME]` | Offline Git state, instruction/documentation paths and review links | Reads only; upstream counts are not freshly fetched |
| `doctor [--repo NAME] [--profile PROFILE]` | Interpreter, dependency, browser and test-resource preflight | Reads only; repair suggestions are not executed |
| `check --profile PROFILE` | Registered checks with explanations, bounded logs and a receipt | Runs trusted tests/builds; `--dry-run` only plans |
| `coverage --profile PROFILE [--repo NAME]` | Declared suite dispositions and explicit coverage limits | Reads only; not execution evidence |
| `runs [--limit 10] [--before RUN]`, `latest` | Discover recent runs without looking up state-directory paths | Reads only; malformed latest evidence is not replaced with an older pass |
| `status RUN`, `summary RUN` | Stage counts and failure log locations | Reads only |
| `logs RUN --stage STAGE --tail 40 [--final-only]` | Provisional live output or a hash-verified final stage log | Reads only; provisional output never proves a pass |
| `resume RUN` | Replan the previous check selection and reuse eligible successful stages | Runs remaining checks, creating a new receipt |
| `recover RUN [--apply]` | Recover an abandoned check-run record after acquiring its OS lock | No test replay; apply changes only the local record |
| `review MODULE` | Source inventory, principle revision, issue links, check plan and walkthrough checklist | Does not perform or complete a module review |
| `docs audit [--repo NAME] [--changed]` | Owning manifest/help/translation checks and visible-label gaps | Local checks only; never translates or edits content |
| `issues note …` | Preview and explicitly append deduplicated evidence | Remote comment creation only with `--apply` |
| `release …` | Existing durable release planning/execution/recovery | Explicit `--apply`, request IDs and existing step confirmations |
| `git …` | Frozen, explicit-path maintenance commit and exact branch push | Preview first; mutations require `--apply`; no stage-all, force or tags |
Git maintenance is a separate, selected-path workflow; see
[Git maintenance](DEVKIT_MAINTENANCE.md). Issue notes and module bundles are
documented in [Evidence and review commands](DEVKIT_EVIDENCE.md). The complete
release command syntax, limitations and examples are in
[Headless release operations](DEVKIT_RELEASE.md).
## Check profiles and their limits
- `quick`: existing manifest/interface invariants, import/help guards and selected
module source/structure tests. It does not compile component suites or run the
full browser matrix.
- `ui`: quick/source contracts plus the shared Core component batch, compiled
once in an isolated directory. This is not a full visual/usability review.
- `backend`: existing manifest/interface checks and selected repository backend
test suites. Shared backend-test state is serialized.
- `full`: the canonical `tools/checks/check-focused.sh`, including optional-module
build permutations and integrated browser conformance. Repository filters do
not reduce this required cross-module completion gate.
`--changed` includes uncommitted work, commits ahead of the locally cached
upstream and repositories with commits but no configured upstream.
Missing/unreadable repositories remain visible as errors. For the
GovOPlaN profiles, Core or Meta changes conservatively select every registered
consumer; other changes expand through declared interface consumers. This is
not complete semantic dependency analysis. Use the full gate for cross-module
completion as required by `AGENTS.md`.
The module catalog reuses declared direct-Node tests and established structural
script names. Arbitrary shell chains are not guessed or rewritten. Unsupported
declared scripts remain visible with a reason; only exact known Core component
aliases are covered by the shared component runner. Invalid package metadata is
an error, not an empty test inventory.
`coverage` inventories declared suites as `planned`, `covered_elsewhere`,
`excluded` or `unsupported`, naming their covering stage where applicable. The
same inventory accompanies check dry runs and saved receipts. **Full means the
canonical focused gate, not every test in every package.** Its inventory follows
explicit canonical commands conservatively; it does not infer arbitrary nested
shell commands or npm hooks. Add new deterministic checks to the owning
package/canonical gate and the catalog's tests as appropriate. Coverage planning
does not execute the scripts it inventories or assert that they passed. See
[Coverage and validation details](DEVKIT_COVERAGE.md) for examples and boundaries.
Independent checks can run with `--jobs 1..8` (default 2). Shared resources use
OS locks for the current user, including across runs with different evidence
directories. Browser/port locks are shared across that user's workspaces. Full runs
reserve the shared WebUI/backend/browser resources. Standalone Core component
commands use isolated temporary build directories; `npm run test:components --
page-layout documentation-help` compiles once for that batch. Managed temporary
output is cleaned; no user worktree is reset or restored.
## Evidence, interruption and safe reuse
A check announces its run ID and saves a `preparing` receipt before source and
environment fingerprinting. Progress on stderr shows elapsed time, stage counts
and active stages; it also distinguishes `checking` from final snapshot
verification (`finalizing`). `--json` keeps stdout as one final JSON result and
emits structured progress events on stderr; `--quiet` suppresses these events.
Use `latest`, `status RUN` and `logs RUN --stage STAGE` from another terminal
while a check runs. Counts are stages, not a guessed percentage of test effort.
Live snapshots are private, bounded, explicitly provisional and not accepted for
reuse or issue evidence. A completed stage log can be hash-verified before the
whole run finishes, but only the final run snapshot verifies the overall result.
`--final-only` rejects unfinished logs. Run history supports cursor pagination
(up to 100 rows per page), bounds directory scanning, and never deletes evidence.
An explicitly selected `--project` also filters run discovery by project file.
Default records are private below
`$XDG_STATE_HOME/govoplan/devkit/workspace-<identity>/runs/<run>/` (fallback
`~/.local/state`). `--state-dir` selects another base; workspace scoping still
applies. Status changes are atomically persisted with restrictive file modes;
symlinked evidence paths are rejected. A record contains source/environment/plan
fingerprints, stage reasons, status, exit code, timing and log identities.
Stages distinguish pending, running, passed, failed, timed out, blocked, skipped,
stale and interrupted. A skipped or unexecuted stage is never a pass. A source or
environment change during verification marks the overall result **stale**, even
when individual subprocesses returned zero. Such a result is not passing evidence.
`resume RUN` replans the current selection and compares each phase independently.
Matching **verified checkpoints** are reused; changed/new phases and phases
without a checkpoint run again. A checkpoint binds the exact command and working
directory, declared repository inputs, transitive data-dependency identities,
devkit implementation/schema, tool/dependency metadata and environment. Logs must
retain their recorded hashes; a missing or changed cached log fails closed.
The summary reports how many checkpoints were reused; JSON records `input_scope`,
`cache_key`, `checkpoint_verified`, `reused_from` and the reuse/rerun reason.
Each checkpoint is saved while its resource locks remain held, only after exit
zero, a verified final log, and matching before/after inputs and environment.
A phase that changes its own inputs is stale, even if another phase later restores
those bytes. Final verification rechecks all passed/reused phases against current
inputs before the new aggregate can pass. An interrupted, failed or stale run may
donate an independently verified matching checkpoint, but never becomes passing
evidence itself. Old receipts remain readable: legacy monolithic logs and receipts
without these checkpoints cannot be retroactively split or reused as verified phases.
After a hard crash, `recover RUN` shows the abandoned owner and guidance. Inspect the
recorded commands and manually stop any surviving test/build processes before
using `recover RUN --apply --confirm-processes-stopped`. The command verifies the
run lock is free before marking the record interrupted. A free parent lock alone
does **not** prove children stopped after a hard kill. Recovery does not replay
processes or infer that a partially completed operation succeeded.
### Canonical phases and narrower inputs
The full gate has seven explicit phases: `preflight`, `tooling`, `backend`,
`core-ui`, `module-builds`, `browser`, and `module-ui`. Devkit stage IDs are
`focused.<phase>`. The authoritative Bash bodies remain in
`tools/checks/check-focused.sh`; the bounded metadata in
`tools/checks/focused-phases.json` names their order and resources. The direct
shell command still runs every phase in the original fail-fast order. For inspection:
```sh
tools/checks/check-focused.sh --list-phases
./devkit check --profile full --jobs 1
./devkit resume RUN_ID --jobs 1
```
For example, a browser failure no longer forces successful backend/build phases
to run again if their inputs still match. Standalone `--phase browser` is available
for diagnostics, but is not a substitute for the complete gate or its receipt.
Scopes are whole repositories, not inferred file globs. A trusted check may declare
`"inputs": {"repos": ["canonical-repository-name"]}`; no declaration means the whole
registered workspace. Dry runs show that boundary. Native source-discovery checks
retain broad scopes where cross-module dependencies cannot safely be narrowed.
Changes outside an explicit scope do not invalidate it, but tool/environment
changes remain conservatively global. Scope declarations are a correctness
contract: include every source repository that the check reads, not only its cwd.
Native discovery ownership/presence is rechecked at phase boundaries, so a newly
appearing module or WebUI directory invalidates the in-flight environment identity.
Unregistered native sibling sources disable reuse with an explicit coverage note;
register them before relying on cached results. Ordinary generated files inside
existing source directories do not change this directory-shape identity.
Every snapshot rereads repository presence, HEAD, index/flags and tracked plus
non-ignored untracked membership, including assume-unchanged files. File hashes
use a bounded **in-process-only** memo with file identity/ctime/mtime/size checks
before and after an open file descriptor; no persistent mtime cache is trusted.
In-repository regular-file symlink targets are included; escaping or directory
symlinks fail closed. Ignored files, undeclared external data and service state
are not source evidence and need explicit verification.
Environment probes stream bounded regular-file contents and reject concurrent
replacement, growth and symlink retargeting. Stable venv executable and dependency
directory symlinks remain supported without changing the executable path; absent
optional metadata remains optional. Environment identities are not persistently
cached and remain deliberately global.
These checkpoints cache **verification results, not output artifacts**. The full
gate's phases were audited so later phases do not require an earlier phase's
retained build output. A custom setup/build that produces files consumed later
must declare `"reuse": "never"`; its consumers must use `deps`. Until output
manifests/restoration exist, do not assume a cached successful build recreates
deleted ignored artifacts.
Check output is drained without unbounded memory growth. Stored output retains
the beginning and actual final tail within an 8 MiB bound per stage, with a small
truncation marker and an omitted-byte count; output truncation does not change
the subprocess exit result. `logs` exposes at most 200 lines and 16 KiB. Live
snapshots retain at most 64 KiB after redaction. Incomplete live lines and cut
retention-boundary lines are withheld to avoid exposing fragments of secrets;
very long single-line output may therefore be absent from live views.
Known environment credentials and common authorization patterns are
redacted as display hygiene. **Never pass credentials as check arguments or print
them from tests.** Redaction is not a general secret-classification guarantee.
JSON command output is a redacted presentation; the receipt file at the reported
path is the canonical local record. Cancellation and deadlines terminate the
owned process group; a parent leaving running descendants does not pass.
During source/environment fingerprinting, cancellation is observed between
probes; the current bounded probe may finish first. Cancellation during final
verification is recorded as interrupted, never as a passing run.
Deliberately detached processes are outside that group: this is not a sandbox.
These local hash-bound records detect accidental changes; they are not signed
attestations, a security certification, proof of complete test coverage, or
permission to publish. External service state and undeclared dependencies still
need explicit verification. No automated result closes a Gitea issue or marks a
module reviewed. Detailed logs remain local unless deliberately shared. Old run
directories are not automatically deleted; review retention before removing any
evidence referenced by an issue.
## Reuse in another project
The runner, repository context, doctor and evidence primitives are usable with an
explicit local JSON project manifest. The example at
`tools/devkit/examples/project.json` registers ordinary Python tests and a Git
whitespace check; the format is described by
`tools/devkit/project.schema.json`.
```sh
/path/to/govoplan/devkit --workspace-root /path/to/project \
--project /path/to/project/devkit-project.json check --profile quick --dry-run
```
Repository paths and check working directories must remain inside the selected
workspace. Check arguments are arrays, not shell-evaluated strings. The supported
tool placeholders are `{python}`, `{node}`, `{npm}` and `{workspace}`. Check
dependencies form an acyclic graph; resources serialize incompatible tasks.
`deps` declares actual data dependencies: consumers rerun whenever a dependency
runs again. `after` declares only fail-fast execution ordering: a failed predecessor
skips the follower, but a successfully rerun independent predecessor does not
invalidate the follower's inputs. Both edge types are validated together for
cycles, missing IDs and overlap. `reuse` is `verified` by default or `never` for
setup/output-producing checks. Repository `inputs` names are canonical, unique,
nonempty and validated even for unselected checks.
The complete custom manifest is validated, including unselected checks/profiles:
unknown fields, misspellings, invalid bounds/types and unresolved dependencies
fail early. This prevents silently ignored resource or timeout declarations.
Portable `doctor` always requires its Python runtime, plus tools needed by the
selected checks and their dependencies and tools explicitly configured in the
manifest. Without `--profile`, all declared profiles are considered. Unused
Node/npm are marked `not_required` and do not block Python-only projects. Declare
indirect tool dependencies explicitly: arbitrary script contents are not
analyzed. Native GovOPlaN retains its Python/Node/npm requirements.
Only use project manifests and scripts you trust: running a registered test is
ordinary code execution, not a sandbox. Platform-specific release and Docs
commands reject generic project manifests; put another project's checks in its
own profiles rather than pretending its release policy is GovOPlaN's.
The initial runtime targets POSIX environments with Python 3.11+ and OS advisory
locks; it does not claim Windows support. No globally installed service or Codex
plugin is needed. Keep this implementation versioned and reuse it; avoid copying
diverging helper implementations into each project.
Devkit is not a complete build system: it does not infer semantic dependencies,
restore output artifacts, sandbox checks, or share signed remote caches. Repository
scopes intentionally stop short of file/glob narrowing; environment identities
remain global. These are explicit boundaries, not claims of exhaustive coverage.
## Development and conformance
```sh
./.venv/bin/python -m pytest -q tests/test_devkit_*.py
./.venv/bin/python -m pytest -q tests/test_focused_phases.py
node --test tests/test-devkit-display-labels.mjs
./.venv/bin/python -m unittest tests.test_documentation_structure
```
The focused gate includes the Python command-suite regression tests. Fixture
tests use temporary repositories/processes and mocked issue/release transports;
they do not commit user work, send mail, publish artifacts or change live issues.
Documentation is part of each command change: update `--help`, this guide and the
corresponding targeted contract tests together.