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
+3
View File
@@ -64,6 +64,7 @@ in `govoplan-records/docs/EAKTE_ARCHITECTURE.md`.
| Evidence collection and promotion | [Target Maturity Evidence Runbook](operations/TARGET_MATURITY_EVIDENCE_RUNBOOK.md) |
| Package publication and consumption | [Package Registry Releases](operations/PACKAGE_REGISTRY_RELEASES.md) |
| Release-console operation | [Release Console](operations/RELEASE_CONSOLE.md) |
| Repeated development, verification and evidence commands | [Developer Command Suite](operations/DEVKIT.md) |
| Module compatibility and install behavior | [Module Contracts and Installs](operations/MODULE_CONTRACTS_AND_INSTALLS.md) |
| Security-audit toolchain | [Security Audit](operations/SECURITY_AUDIT.md) |
@@ -75,6 +76,8 @@ in `govoplan-records/docs/EAKTE_ARCHITECTURE.md`.
meta, module, deployment, and website content.
- [Gitea Issues](project/GITEA_ISSUES.md) defines labels, templates, import, and
state-update conventions.
- [UI Review Program](project/UI_REVIEW_PROGRAM.md) defines the principle-led,
per-module review process and links the canonical Gitea review inventory.
## Evidence And Archive
+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.
+72
View File
@@ -0,0 +1,72 @@
# Check configuration and suite coverage
`devkit coverage` explains what a selected plan intends to run. It does not run
tests, start servers, or report successful verification:
```sh
./devkit coverage --profile quick --repo campaign
./devkit coverage --profile ui --repo portal --json
./devkit coverage --profile full --json
./devkit --project /path/to/project.json coverage --profile quick
```
The inventory accounts for declared `test` and `test:*` scripts in each
registered repository's root and `webui/package.json`, discovered UI structural
checks, and explicitly configured project checks. It is a suite inventory, not
an enumeration of every test function or recursive dependency. Unselected suites
remain visible; every row has a disposition and reason:
| Disposition | Meaning |
| --- | --- |
| `planned` | A selected stage directly invokes the suite. |
| `covered_elsewhere` | An exact equivalent invocation or an explicitly selected shared batch owns it; the covering stage is named. |
| `excluded` | The suite is outside the actual selected plan. |
| `unsupported` | Scoped discovery cannot safely interpret or locate the command; no command is guessed or executed. |
`full` means the existing canonical `check-focused.sh` gate. It does **not**
mean every package script or every component suite. Coverage reads the current
script's explicit npm/Node commands inside its seven registered marked phase
bodies, without executing shell code or inferring arbitrary functions, nested
scripts, npm hooks, branches or here-document contents. Each covered suite names
the `focused.<phase>` that owns it. The
current gate names four of the sixteen Core component suites: layout primitives,
page layout, DataGrid actions/sizing, and Mail components. The other twelve stay
explicitly excluded from that gate's component batch. `ui` runs the shared
sixteen-suite batch once; `quick` does not compile component tests.
Only Core's exact known component aliases receive that shared-batch treatment.
A different repository using the same filename, an unknown alias, or a compound
command containing the runner is not silently credited or launched. Ordinary
scoped source discovery accepts bounded direct `node`/`node --test` commands
targeting regular package-owned `.mjs` files in `scripts` or `tests`; shell
chains, extra flags, missing targets and symlinked targets are not rewritten.
An explicit invocation already present in the canonical full gate remains part
of that gate, even when the narrower discovery profile does not support it.
Coverage rows retain a command hash and, for supported commands, redacted argv.
Unsupported shell bodies are not copied into the inventory. This is display
hygiene, not permission to put secrets into project commands. Coverage is
attached to check plans/receipts; it never turns an excluded suite into a pass.
## Portable-project validation
The runtime validates custom project metadata against the published
[`project.schema.json`](../../tools/devkit/project.schema.json) using a small
dependency-free validator. All checks and profiles are validated before
selection, including checks the chosen profile does not execute. Unknown nested
fields such as `resource` or `timout_seconds`, malformed types, oversized values,
duplicate references, missing dependencies, unknown profiles and dependency
cycles fail with controlled errors. Repository aliases and resolved paths must
be unambiguous and confined to the workspace. Check `cwd` defaults to `.` when
omitted; configured paths cannot escape the workspace.
Package JSON is bounded to 1 MiB and 512 scripts; duplicate JSON keys, excessive
nesting and malformed script objects fail before planning. Command strings are
bounded to 8,192 characters. This validates configuration, not the safety of its
code: run only project manifests and test scripts you trust.
Checks may declare repository-scoped `inputs`, true data `deps`, order-only
`after`, and `reuse: "never"` for setup/output-producing work. Unknown repositories,
empty/duplicate scopes, overlapping edge types and cycles fail before execution.
Missing inputs deliberately fall back to all registered repositories. See
[checkpoint and input contracts](DEVKIT.md#canonical-phases-and-narrower-inputs).
+171
View File
@@ -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
```
+97
View File
@@ -0,0 +1,97 @@
# Selected-path Git maintenance
The optional `git` namespace of `tools/devkit/devkit.py` is a deliberately
narrow maintenance workflow. It is not a replacement for normal Git, the
release executor, required human review, or Gitea's canonical issue state.
From the Meta repository, preview and then save a plan for explicit files:
```sh
python3 tools/devkit/devkit.py git plan --repo core --path webui/src/example.ts --message "Fix the reviewed example"
python3 tools/devkit/devkit.py git plan --repo core --path webui/src/example.ts --message "Fix the reviewed example" --apply
```
Use the saved `git-…` plan ID for the remaining commands. Each mutation needs
its own `--apply`; an unqualified command only previews the operation:
```sh
python3 tools/devkit/devkit.py git commit git-PLAN_ID
python3 tools/devkit/devkit.py git commit git-PLAN_ID --apply
python3 tools/devkit/devkit.py git push git-PLAN_ID
python3 tools/devkit/devkit.py git push git-PLAN_ID --apply
python3 tools/devkit/devkit.py git status git-PLAN_ID
```
The immutable local plan binds the registered repository, HEAD, branch, origin
fetch/push URL hashes, Git configuration, complete index identity, explicit
selected file paths, working-tree hashes, expected Git blobs, and commit message.
Raw remote URLs and file contents are not stored. A changed input blocks the
operation; inspect it and create another plan instead of weakening the check.
Receipts are private local records with integrity checks, not signed approval
or a security attestation.
Commit captures each selected file once, verifies the captured bytes and Git
blob against the plan, and builds an isolated index/tree from the frozen HEAD
plus only those blobs. Git's normal identity rules create the commit object;
an atomic branch compare-and-swap publishes it only if the planned parent is
still current. Active hooks/signing remain refused rather than bypassed.
An editor racing with this operation cannot substitute newer working-tree
bytes: those edits remain uncommitted, and the helper never overwrites files.
The real index is protected by Git's standard index lock. Only selected entries
are updated from a prepared private copy; unrelated staging and index flags are
preserved. If the index changes independently, its new data is not overwritten
and the receipt requires reconciliation. The resulting parent, message,
changed paths, blobs/modes and unrelated index entries are verified.
Git refs and index files are separately atomic, not one filesystem transaction.
Independent writers that ignore the standard index lock can still change refs
during publication. The helper rechecks the exact recorded candidate before
index recovery and before recording success; it refuses an uncertain result
instead of adopting a newer HEAD or claiming that competing work was its own.
Directories, noncanonical paths, implicit globs, staging-all, amend,
force-push and extra-tag publication are not supported. A selected file with
different staged and working-tree changes is refused; decide explicitly which
version to commit using normal Git first.
Push requires the recorded commit to remain current, an unchanged origin and
one standard-transport push destination. It requests a normal, non-forced push
of that commit to the recorded branch and checks the remote branch afterward.
The push preview does not contact a remote. A normal push may run the remote's
usual CI or server-side hooks; this is an external effect of the separately
authorized push, not of planning or committing.
Local active hooks (including index-change hooks), filter/encoding attributes,
signing, external fsmonitor/SSH configuration, Git environment overrides,
in-progress merge/rebase/cherry-pick operations, submodules, symlinks and
assume-unchanged/skip-worktree entries, split indexes and replacement/graft
history are deliberately
unsupported. The helper
refuses these cases instead of disabling hooks, signatures or filters. An
unused globally installed filter definition alone does not block maintenance;
active attributes are checked across tracked files as well as selected files.
Custom remote receive-pack/upload-pack/helper commands, recursive submodule
pushes and partial-clone lazy fetch are also refused. Of inherited `GIT_*`
variables, only `GIT_OPTIONAL_LOCKS`, `GIT_TERMINAL_PROMPT` and `GIT_PAGER` are
allowed (every command explicitly passes `--no-pager`, so the pager is inert);
namespace, identity, alternate-index/object-directory and unknown overrides
are not silently removed. Git subprocesses have bounded input/output and
deadlines; cancellation terminates their owned process group, including
transport helpers. Network failures can still leave a remote effect uncertain,
which is why receipts require explicit reconciliation rather than blind retry.
An interruption or uncertain failure is recorded before any retry. Use
`git reconcile git-PLAN_ID` to preview, then add `--apply` to verify an
already-existing result. Reconciliation never makes a commit or push. It may
finish the selected real-index update after an interrupted commit publication,
but only when the original index fingerprint still matches; independent staged
work is preserved and requires normal Git resolution. For an
uncertain push it may read the frozen remote, but only with `--apply`. If no
planned commit is current, the helper reports that state and requires a fresh
plan after inspection. A forcibly killed process may leave its private scratch
index or an owned Git index lock; the helper never guesses that an existing
lock is safe to delete. Blob/commit preparation can leave unreferenced Git
objects for ordinary Git garbage collection. It never automatically resets,
restores, deletes, or rolls back user work.
The maintenance tests use disposable local repositories and local bare remotes.
They never commit or push the user's workspace repositories.
+121
View File
@@ -0,0 +1,121 @@
# Headless durable releases
The devkit `release` commands use the **same release application, request
validation, run store and bounded executors** as the
[release console](RELEASE_CONSOLE.md). They invoke its ASGI application inside
the current process, with an ephemeral internal token. No listening socket,
background server, browser session or externally supplied console URL is used.
The development environment's FastAPI/HTTPX dependencies load only when a
release command runs; ordinary devkit help does not import them.
This is a GovOPlaN-specific provider. Repository and origin authority still comes
from the release service's registered catalog. `--project` is explicitly rejected
for release commands; a portable project configuration must not silently override
that authority. A different workspace path does not authorize arbitrary release
repositories, remotes, commands, signing policies or source bindings.
The default compact output includes the overall status, selected repository
states and versions, source-preflight readiness, bounded gate findings and the
recommended next action. Run inspection also shows step-state counts and the
first outstanding steps. These are projections of the service response, not new
readiness checks. Use `--json` for the complete existing plan or receipt; compact
output deliberately omits executor commands, arguments and source bindings.
## Commands and boundaries
| Command | Purpose | Effect boundary |
| --- | --- | --- |
| `release status` | Current release dashboard | Offline by default; explicit remote/catalog flags enable their checks |
| `release plan` | Selective repository/version plan | Inspection only; does not create a run |
| `release list` | Bounded run history, with `--limit` and `--cursor` | Existing workspace-scoped store |
| `release show RUN_ID` | Exact verified run, steps, receipts and required confirmations | No release execution |
| `release create` | Freeze a selected repository/version plan | Preview by default; `--apply` persists a run |
| `release preview RUN_ID STEP_ID` | Frozen step and its current constraints | No step claim; catalog publication additionally uses the existing validated-candidate preview |
| `release execute RUN_ID STEP_ID` | One available durable step | Preview by default; `--apply`, explicit request ID and the step's exact confirmation are required |
| `release resume RUN_ID` | Mark persisted running attempts interrupted | Requires `--apply`; never assumes an effect succeeded |
| `release retry RUN_ID STEP_ID` | Prepare an eligible failed/read-only-interrupted step | Requires `--apply`; does not execute it |
| `release reconcile RUN_ID STEP_ID` | Record a proven uncertain-write outcome | Requires `--apply`, `--confirm RECONCILE` and an explicit outcome |
Create and transition commands require caller-chosen `--request-id` values.
Retain the same ID for an uncertain replay of the **same** command; changing
inputs under an existing ID fails closed. No command automatically retries a
mutation. These commands perform one explicit transition, not an implicit
"release everything" loop.
Read commands do not commit, tag, push, publish or apply database migrations.
The existing private run store can initialize its lock directory or upgrade a
legacy record while inspecting it; this does not advance release steps.
`--include-migrations` requests the existing audits, never migration application.
`--online`, `--remote-tags` and `--public-catalog` are explicit network-check
choices. A generic step preview describes frozen intent; it is not a claim that
live preflight, remote identity or release acceptance has passed.
## Example: review, freeze and execute one step
Run the devkit through the workspace `./devkit` entrypoint. These examples put
global options before `release`:
```sh
./devkit --workspace-root /path/to/workspace --format json release plan \
--repo-version govoplan-files=0.1.9
./devkit --workspace-root /path/to/workspace release create \
--repo-version govoplan-files=0.1.9 --request-id files-release-create-0001
./devkit --workspace-root /path/to/workspace release create \
--repo-version govoplan-files=0.1.9 --request-id files-release-create-0001 --apply
./devkit --workspace-root /path/to/workspace release show RUN_ID
./devkit --workspace-root /path/to/workspace release preview RUN_ID STEP_ID
./devkit --workspace-root /path/to/workspace release execute RUN_ID STEP_ID \
--request-id files-release-step-0001 --confirm REQUIRED_CONFIRMATION --apply
```
`RUN_ID`, `STEP_ID` and `REQUIRED_CONFIRMATION` stand for the actual values
returned by the frozen run. For read-only preflight/alignment/install-verification
steps, omit `--confirm` when the service reports an empty confirmation. Metadata,
commit, release-lock, source-tag, source-push, candidate-generation and catalog
publication steps keep the existing `UPDATE`, `COMMIT`, `LOCK`, `TAG`, `PUBLISH`,
`GENERATE` and `PUSH` confirmations respectively. Prerequisite ordering is enforced
by the same store; a later step cannot be forced through this adapter.
Version selection supports repeated `--repo-version REPO=VERSION`, or repeated
`--repo REPO` with `--target-version VERSION`. Every created run needs explicit
versions for all selected repositories. Conflicting version assignments are
rejected. Planning is selective; repositories are never silently selected merely
because their worktrees are dirty.
## Candidate publication and recovery
Use the frozen run's `catalog:selective-generator` and
`catalog:validate-sign-publish` steps, not the disabled legacy mutation endpoints.
Generation accepts repeated `--signing-key KEY_ID=PRIVATE_KEY_FILE`; these are
operator-owned key-file references, never inline key material. Signing arguments
are not emitted in devkit JSON or persisted by the adapter. Publication consumes
the candidate receipt created by that run, not an arbitrary candidate directory.
The existing source/runtime trust, immutable tag/remote identity, private
candidate checks and exact commit-delta checks remain authoritative.
After an interrupted write, inspect the run and the actual local/remote effect.
Use `resume --apply` if an attempt was left running. Then use `reconcile` with
`effect_absent`, `effect_succeeded` or `unresolved`, `--confirm RECONCILE`, a new
reconciliation request ID and `--apply`. Successful reconciliation still performs
the service's independent receipt checks. An unresolved effect must not be
retried or papered over by generating a new request ID. A failed/read-only
attempt may use `retry --apply` and a new explicit execute attempt only when
the existing lifecycle makes that safe.
## State and limitations
Every successful response exposes `state_location` and `candidate_location`.
Without `--state-dir`, the adapter uses the console's existing default private,
workspace-fingerprinted state directory. With `--state-dir PATH`, it uses
`PATH/release-console/workspace-<fingerprint>/release-runs`. Workspaces cannot
read or resume one another's runs. Existing ownership, symlink, permission,
retention and record-integrity checks are unchanged.
Release preparation can commit only the recognized, receipt-bound metadata
changes its executors produced. This command does **not** stage arbitrary source
changes, use `git add -A`, force-push, retarget tags or enable the disabled generic
prepare/sync/push endpoints. Normal selected-path maintenance requires its own
explicit reviewed-change workflow; it is not silently folded into release.
+11 -2
View File
@@ -354,8 +354,17 @@ such as `0.2.0` or `0.2.0-alpha1`, but requires the first three version numbers
to move forward.
Plain repository pushes are separate from catalog publication. `Preview Push`
shows the selected repository push commands. `Push Selected` requires `PUSH` in
the repository push confirmation field.
shows the selected repository push commands, but generic push, sync and prepare
mutation endpoints are disabled: they require a separate durable, receipt-bound
maintenance workflow and cannot be enabled by typing a confirmation. Source
release branch/tag publication uses the durable release-run steps described
above; do not route ordinary dirty worktrees through the legacy all-repository
stage/commit/tag helper.
The [headless devkit release commands](DEVKIT_RELEASE.md) invoke this same
application in-process without starting a server. They expose selective planning,
bounded status/history, create/show/preview/execute and explicit recovery while
retaining the same request IDs, confirmations, source bindings and receipts.
The source release panel retains `Preview Tag + Publish` as a non-mutating
inspection. Its legacy `Create Tags` and `Publish Tags` controls stay visible
+164
View File
@@ -0,0 +1,164 @@
# Product-wide UI review program
The [central Gitea epic](https://git.add-ideas.de/GovOPlaN/govoplan/issues/56)
coordinates the review; its linked module issues are the canonical backlog,
progress and evidence log. The [issue inventory](ui-review-issue-inventory.json)
is a discovery/link snapshot, **not a second progress tracker**. All reviews were
initialized pending. Implementing a shared component or moving a help icon does
not by itself complete a module review.
The visual and interaction rules live in Core's
[UI design principles](https://git.add-ideas.de/GovOPlaN/govoplan-core/src/branch/main/docs/UI_DESIGN_PRINCIPLES.md).
This document defines how to apply and verify those principles across repositories;
it does not fork their definitions. The usual [Gitea issue contract](GITEA_ISSUES.md)
still applies. At the user's request, this cross-product program is coordinated in
Meta; shared primitives and their implementation remain owned by Core.
## Scope and initial inventory
The September 2026 source/catalog baseline contains **77 review tracks**:
- **73 implemented scopes:** Core/shared shell and 72 manifest-backed modules.
- **4 registered placeholders:** Appointments, Ledger, XÖV and XTA/OSCI. They have
README-only repositories at initialization. Their separate readiness tracks
remain pending for future interfaces; they are not counted as implemented or
reviewed modules.
Meta and the public website are not business-module review scopes. Module IDs
come from actual manifests, not repository-name guesses: for example,
`govoplan-campaign` owns `campaigns` and `govoplan-dist-lists` owns `dist_lists`.
The inventory is derived from `repositories.json`, trusted module manifests and
the owning repository's source files. Changes to the catalog must be reconciled
with the central epic rather than silently dropping a module.
A module with no standalone WebUI is still in scope. Review its configuration
and administrator experience, contributed operator/public surfaces, widgets,
documentation, permissions, errors and interactions exposed through other
modules. A missing standalone page is not evidence of conformance. A reviewer
may mark a particular principle not applicable only with a concrete explanation
and source/runtime evidence. A placeholder likewise needs an explicit future-UI
gate, not a fabricated page inventory or an automatic green review.
## Work order and ownership
Prioritize user-visible defects, usability and consistent interactions before
broader features. Start with Core/shared-shell contracts and Campaign's complete
workflow, then Files, Mail, Templates, Notifications, Docs/Help, Dashboard, Quick
Access and Views. The remaining queue is ordered by observed defects, shared
dependencies and risk. This is a starting order, not a claim that those reviews
have started or finished; the central issue records the current focus.
For Campaign, use a compact, read-only campaign settings overview with explicit,
scoped edit dialogs. Large recipient or attachment grids may use the UI-02 bulk
editing exception: clearly entered edit mode, explicit Save and Cancel, dirty
navigation protection, and no silent loss or accidental save. This direction
must be implemented and verified in the Campaign review, not marked complete by
the program bootstrap.
Fix a repeated problem in the owning shared primitive or semantic contract first,
then migrate consumers and verify representative actual-module fixtures. Keep
module business behavior in its own repository and preserve optional module
boundaries. Do not replace concrete user evidence with a generic fixture alone.
Parallel reviewers may own different modules, but they must coordinate shared
Core files and browser fixtures instead of racing the same resources.
## Per-module review workflow
1. **Inventory.** Verify and extend the issue's source-derived seed: navigation,
pages, nested routes, dialogs, labels/forms, tables/trees, admin/system/tenant/
user settings, public/operator interfaces, widgets and optional-module
contributions. Follow actual module entrypoints and runtime contributions;
filename heuristics and manifest routes are a starting point, not an exhaustive
runtime audit. Note roles, permission boundaries and installed optional modules.
2. **Observe.** Exercise realistic narrow and wide viewports, German and English,
keyboard navigation and focus, empty/loading/error/success states, clean/dirty
edit modes, reload, navigation away and return, and restoration of personal
preferences. Include realistic row counts, long labels, horizontal overflow,
pagination and two-way column resizing with fixed columns between text fields.
3. **Record.** Keep a findings/TODO/done ledger in the module issue. Every finding
names the surface, reproduction, expected principle, impact, owner and linked
implementation/evidence. A source inventory, planned fix or green generic
test is not a completed finding. State product decisions and manual checks
explicitly with enough context to resolve them.
4. **Implement.** Prefer reusable shared primitives and action/page contracts.
Keep display mode readable and editing intentional. Preserve authorization,
server validation, save/cancel behavior and data integrity. Never send mail,
delete records, change live configuration or trigger other irreversible effects
merely to obtain UI evidence; use authorized fixtures or a safe test context.
5. **Verify.** Run proportionate unit, structure and actual-module browser tests.
Record commands, results, source revision and safe runtime evidence. Update the
owning module's manifest-driven EN/DE documentation for behavior changes; run
`tools/checks/check-manifest-shapes.py` and relevant cross-module checks.
6. **Conclude honestly.** Complete the principle matrix, evidence and manual
checks. Link unresolved follow-ups and blockers; do not close a supposedly
complete review while required work is still pending. Closing an issue requires
explicit reviewed scope and the applicable design-principle revision.
## Principle ledger and back-propagation
Use the stable IDs from Core in each issue. The initial revision covers UI-01
heading/label help placement; UI-02 display-first/scoped editing; UI-03 actions;
UI-04 table/card geometry; UI-05 loading/error/progress; UI-06 tree interaction;
UI-07 accessibility and German; UI-08 data integrity; and UI-09 propagation of
revised principles. Core remains the authoritative definition.
Each module maintains this matrix, initially entirely pending:
| Principle/revision | Applicable surfaces / justified N/A | Applied / remaining work | Evidence | Exception / owner / follow-up |
| --- | --- | --- | --- | --- |
| UI-01 … UI-09 | Pending inventory | Pending review | Not yet recorded | None approved |
Whenever a principle is added or changed:
1. Update Core's rule with its rationale, stable ID and revision/change reference.
2. List **all already-reviewed modules**, not just the current implementation's
consumers. Check whether the changed rule applies to each.
3. Record unchanged conformance with evidence, or reopen the review / create a
linked follow-up with owner, exact affected surfaces and required checks.
4. Update the central epic's propagation ledger. Previously reviewed modules with
outstanding applicable work are **follow-up required**, not silently green.
5. Resolve the propagation sweep only after every affected module has current
evidence or an explicit, owned and justified exception. Exceptions do not
silently change the shared rule.
Suggested central ledger:
| Principle change | Already-reviewed modules checked | Conformant evidence | Reopened / follow-up required | Exceptions / owner | Sweep state |
| --- | --- | --- | --- | --- | --- |
| Initial UI-01UI-09 baseline | None reviewed at initialization | None | All module reviews pending | None approved | Pending |
## Safe inventory/bootstrap automation
`tools/gitea/gitea-ui-review-program.py` derives the current scopes from the
catalog and source manifests, inventories routes and UI source entrypoints,
then deduplicates issues by a stable hidden marker and normalized exact title.
It includes closed issues in duplicate checks and never reopens, closes or
overwrites existing module issues. Ambiguous or unmanaged duplicates stop the
operation for review. Existing issue bodies, labels and review progress are
preserved. A failed POST is not automatically retried; a subsequent run checks
the marker again before deciding whether another create is needed.
Dry-run is the default. An authenticated dry-run performs only Gitea reads:
```sh
.venv/bin/python tools/gitea/gitea-ui-review-program.py \
--env-file /home/zemion/.config/gitea/gitea.env --epic 56
```
Creating missing review issues requires explicit `--apply`. Initial population
of the central epic's module-link block additionally requires
`--initialize-links`; it is accepted only for the untouched bootstrap placeholder.
Later runs must not rewrite checkboxes or human-maintained progress. Existing
complete links are verified read-only. The token is loaded through the shared
Gitea helpers and is never emitted in reports. A scoped `--ipv4` option works
around host-specific IPv6 connectivity while retaining HTTPS certificate and
hostname verification.
The tool emits a JSON result to stdout with source counts and issue links. The
checked-in inventory is a reviewed initialization snapshot of that result;
refreshing links does not authorize replacing live review status with the
snapshot. Test the automation offline with:
```sh
.venv/bin/python -m pytest tests/test_ui_review_program.py -q
```
+866
View File
@@ -0,0 +1,866 @@
{
"schema_version": 1,
"snapshot_purpose": "Issue discovery links; live Gitea issues own review state and evidence.",
"epic": {
"repository": "govoplan",
"number": 56,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan/issues/56"
},
"scope_count": 77,
"manifest_modules": 72,
"implemented_scopes": 73,
"catalogued_placeholders": 4,
"created": 77,
"missing": 0,
"issues": [
{
"scope_id": "core",
"name": "Core / shared shell",
"repository": "govoplan-core",
"kind": "core",
"ui_source_count": 111,
"number": 301,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-core/issues/301",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "access",
"name": "Access",
"repository": "govoplan-access",
"kind": "manifest",
"ui_source_count": 18,
"number": 23,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-access/issues/23",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "addresses",
"name": "Addresses",
"repository": "govoplan-addresses",
"kind": "manifest",
"ui_source_count": 1,
"number": 26,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-addresses/issues/26",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "admin",
"name": "Admin",
"repository": "govoplan-admin",
"kind": "manifest",
"ui_source_count": 9,
"number": 11,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-admin/issues/11",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "approvals",
"name": "Approvals",
"repository": "govoplan-approvals",
"kind": "manifest",
"ui_source_count": 4,
"number": 5,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-approvals/issues/5",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "assets",
"name": "Assets",
"repository": "govoplan-assets",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-assets/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "audit",
"name": "Audit",
"repository": "govoplan-audit",
"kind": "manifest",
"ui_source_count": 1,
"number": 10,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-audit/issues/10",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "booking",
"name": "Booking",
"repository": "govoplan-booking",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-booking/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "calendar",
"name": "Calendar",
"repository": "govoplan-calendar",
"kind": "manifest",
"ui_source_count": 10,
"number": 26,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-calendar/issues/26",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "campaigns",
"name": "Campaigns",
"repository": "govoplan-campaign",
"kind": "manifest",
"ui_source_count": 60,
"number": 103,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-campaign/issues/103",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "cases",
"name": "Cases",
"repository": "govoplan-cases",
"kind": "manifest",
"ui_source_count": 4,
"number": 8,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-cases/issues/8",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "certificates",
"name": "Certificates",
"repository": "govoplan-certificates",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-certificates/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "committee",
"name": "Committee",
"repository": "govoplan-committee",
"kind": "manifest",
"ui_source_count": 3,
"number": 5,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-committee/issues/5",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "connectors",
"name": "Connectors",
"repository": "govoplan-connectors",
"kind": "manifest",
"ui_source_count": 3,
"number": 20,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-connectors/issues/20",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "consultation",
"name": "Consultation",
"repository": "govoplan-consultation",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-consultation/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "contracts",
"name": "Contracts",
"repository": "govoplan-contracts",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-contracts/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "dashboard",
"name": "Dashboard",
"repository": "govoplan-dashboard",
"kind": "manifest",
"ui_source_count": 5,
"number": 6,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-dashboard/issues/6",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "dataflow",
"name": "Dataflow",
"repository": "govoplan-dataflow",
"kind": "manifest",
"ui_source_count": 5,
"number": 24,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-dataflow/issues/24",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "datasources",
"name": "Datasources",
"repository": "govoplan-datasources",
"kind": "manifest",
"ui_source_count": 1,
"number": 10,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-datasources/issues/10",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "decisions",
"name": "Decisions",
"repository": "govoplan-decisions",
"kind": "manifest",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-decisions/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "dist_lists",
"name": "Distribution Lists",
"repository": "govoplan-dist-lists",
"kind": "manifest",
"ui_source_count": 2,
"number": 10,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-dist-lists/issues/10",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "dms",
"name": "DMS",
"repository": "govoplan-dms",
"kind": "manifest",
"ui_source_count": 0,
"number": 3,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-dms/issues/3",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "docs",
"name": "Docs",
"repository": "govoplan-docs",
"kind": "manifest",
"ui_source_count": 2,
"number": 23,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-docs/issues/23",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "encryption",
"name": "Encryption",
"repository": "govoplan-encryption",
"kind": "manifest",
"ui_source_count": 1,
"number": 7,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-encryption/issues/7",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "erp",
"name": "ERP",
"repository": "govoplan-erp",
"kind": "manifest",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-erp/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "evaluation",
"name": "Evaluation",
"repository": "govoplan-evaluation",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-evaluation/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "facilities",
"name": "Facilities",
"repository": "govoplan-facilities",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-facilities/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "files",
"name": "Files",
"repository": "govoplan-files",
"kind": "manifest",
"ui_source_count": 8,
"number": 48,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-files/issues/48",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "fit_connect",
"name": "FIT-Connect",
"repository": "govoplan-fit-connect",
"kind": "manifest",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-fit-connect/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "forms",
"name": "Forms",
"repository": "govoplan-forms",
"kind": "manifest",
"ui_source_count": 2,
"number": 7,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-forms/issues/7",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "forms_runtime",
"name": "Forms Runtime",
"repository": "govoplan-forms-runtime",
"kind": "manifest",
"ui_source_count": 6,
"number": 7,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-forms-runtime/issues/7",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "grants",
"name": "Grants",
"repository": "govoplan-grants",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-grants/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "helpdesk",
"name": "Helpdesk",
"repository": "govoplan-helpdesk",
"kind": "manifest",
"ui_source_count": 1,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-helpdesk/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "identity",
"name": "Identity",
"repository": "govoplan-identity",
"kind": "manifest",
"ui_source_count": 1,
"number": 5,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-identity/issues/5",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "identity_trust",
"name": "Identity Trust",
"repository": "govoplan-identity-trust",
"kind": "manifest",
"ui_source_count": 1,
"number": 4,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-identity-trust/issues/4",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "idm",
"name": "IDM",
"repository": "govoplan-idm",
"kind": "manifest",
"ui_source_count": 3,
"number": 14,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-idm/issues/14",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "inspections",
"name": "Inspections",
"repository": "govoplan-inspections",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-inspections/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "learning",
"name": "Learning",
"repository": "govoplan-learning",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-learning/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "mail",
"name": "Mail",
"repository": "govoplan-mail",
"kind": "manifest",
"ui_source_count": 6,
"number": 25,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-mail/issues/25",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "mandates",
"name": "Mandates",
"repository": "govoplan-mandates",
"kind": "manifest",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-mandates/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "notifications",
"name": "Notifications",
"repository": "govoplan-notifications",
"kind": "manifest",
"ui_source_count": 3,
"number": 7,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-notifications/issues/7",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "ops",
"name": "Ops",
"repository": "govoplan-ops",
"kind": "manifest",
"ui_source_count": 2,
"number": 5,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-ops/issues/5",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "organizations",
"name": "Organizations",
"repository": "govoplan-organizations",
"kind": "manifest",
"ui_source_count": 4,
"number": 9,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-organizations/issues/9",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "parties",
"name": "Parties",
"repository": "govoplan-parties",
"kind": "manifest",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-parties/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "payments",
"name": "Payments",
"repository": "govoplan-payments",
"kind": "manifest",
"ui_source_count": 3,
"number": 3,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-payments/issues/3",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "permits",
"name": "Permits",
"repository": "govoplan-permits",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-permits/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "policy",
"name": "Policy",
"repository": "govoplan-policy",
"kind": "manifest",
"ui_source_count": 3,
"number": 14,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-policy/issues/14",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "poll",
"name": "Poll",
"repository": "govoplan-poll",
"kind": "manifest",
"ui_source_count": 0,
"number": 5,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-poll/issues/5",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "portal",
"name": "Portal",
"repository": "govoplan-portal",
"kind": "manifest",
"ui_source_count": 2,
"number": 4,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-portal/issues/4",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "postbox",
"name": "Postbox",
"repository": "govoplan-postbox",
"kind": "manifest",
"ui_source_count": 4,
"number": 29,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-postbox/issues/29",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "procurement",
"name": "Procurement",
"repository": "govoplan-procurement",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-procurement/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "projects",
"name": "Projects",
"repository": "govoplan-projects",
"kind": "manifest",
"ui_source_count": 1,
"number": 4,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-projects/issues/4",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "quick_access",
"name": "Quick Access",
"repository": "govoplan-quick-access",
"kind": "manifest",
"ui_source_count": 2,
"number": 3,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-quick-access/issues/3",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "records",
"name": "Records",
"repository": "govoplan-records",
"kind": "manifest",
"ui_source_count": 4,
"number": 10,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-records/issues/10",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "reporting",
"name": "Reporting",
"repository": "govoplan-reporting",
"kind": "manifest",
"ui_source_count": 3,
"number": 11,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-reporting/issues/11",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "resources",
"name": "Resources",
"repository": "govoplan-resources",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-resources/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "rest",
"name": "REST Connector",
"repository": "govoplan-rest",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-rest/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "risk_compliance",
"name": "Risk Compliance",
"repository": "govoplan-risk-compliance",
"kind": "manifest",
"ui_source_count": 1,
"number": 10,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-risk-compliance/issues/10",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "scheduling",
"name": "Scheduling",
"repository": "govoplan-scheduling",
"kind": "manifest",
"ui_source_count": 4,
"number": 10,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-scheduling/issues/10",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "search",
"name": "Search",
"repository": "govoplan-search",
"kind": "manifest",
"ui_source_count": 4,
"number": 6,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-search/issues/6",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "services",
"name": "Services",
"repository": "govoplan-services",
"kind": "manifest",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-services/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "soap",
"name": "SOAP Connector",
"repository": "govoplan-soap",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-soap/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "tasks",
"name": "Tasks",
"repository": "govoplan-tasks",
"kind": "manifest",
"ui_source_count": 3,
"number": 5,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-tasks/issues/5",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "templates",
"name": "Templates",
"repository": "govoplan-templates",
"kind": "manifest",
"ui_source_count": 1,
"number": 8,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-templates/issues/8",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "tenancy",
"name": "Tenancy",
"repository": "govoplan-tenancy",
"kind": "manifest",
"ui_source_count": 2,
"number": 7,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-tenancy/issues/7",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "tickets",
"name": "Tickets",
"repository": "govoplan-tickets",
"kind": "manifest",
"ui_source_count": 1,
"number": 3,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-tickets/issues/3",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "transparency",
"name": "Transparency",
"repository": "govoplan-transparency",
"kind": "manifest",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-transparency/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "views",
"name": "Views",
"repository": "govoplan-views",
"kind": "manifest",
"ui_source_count": 3,
"number": 6,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-views/issues/6",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "voting",
"name": "Voting",
"repository": "govoplan-voting",
"kind": "manifest",
"ui_source_count": 2,
"number": 8,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-voting/issues/8",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "wiki",
"name": "Wiki",
"repository": "govoplan-wiki",
"kind": "manifest",
"ui_source_count": 1,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-wiki/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "workflow",
"name": "Workflow",
"repository": "govoplan-workflow",
"kind": "manifest",
"ui_source_count": 6,
"number": 17,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-workflow/issues/17",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "workflow_engine",
"name": "Workflow Engine",
"repository": "govoplan-workflow-engine",
"kind": "manifest",
"ui_source_count": 0,
"number": 4,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-workflow-engine/issues/4",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "xrechnung",
"name": "XRechnung",
"repository": "govoplan-xrechnung",
"kind": "manifest",
"ui_source_count": 0,
"number": 3,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-xrechnung/issues/3",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "catalog:govoplan-appointments",
"name": "Appointments",
"repository": "govoplan-appointments",
"kind": "placeholder",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-appointments/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "catalog:govoplan-ledger",
"name": "Ledger",
"repository": "govoplan-ledger",
"kind": "placeholder",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-ledger/issues/1",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "catalog:govoplan-xoev",
"name": "Xoev",
"repository": "govoplan-xoev",
"kind": "placeholder",
"ui_source_count": 0,
"number": 2,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-xoev/issues/2",
"state_at_verification": "open",
"operation": "created"
},
{
"scope_id": "catalog:govoplan-xta-osci",
"name": "Xta Osci",
"repository": "govoplan-xta-osci",
"kind": "placeholder",
"ui_source_count": 0,
"number": 1,
"url": "https://git.add-ideas.de/GovOPlaN/govoplan-xta-osci/issues/1",
"state_at_verification": "open",
"operation": "created"
}
],
"snapshot_date": "2026-09-08",
"initial_review_status": "pending for every scope; this snapshot does not track subsequent issue progress"
}