Release govoplan-ops v0.1.22: unify interface contracts and documentation

This commit is contained in:
2026-09-08 01:32:48 +02:00
parent ac6b211827
commit cb8298748f
7 changed files with 22 additions and 11 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/ops-webui",
"version": "0.1.21",
"version": "0.1.22",
"private": true,
"type": "module",
"main": "webui/src/index.ts",
@@ -17,7 +17,7 @@
"README.md"
],
"peerDependencies": {
"@govoplan/core-webui": "^0.1.18",
"@govoplan/core-webui": "^0.1.45",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
+2 -2
View File
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
[project]
name = "govoplan-ops"
version = "0.1.21"
version = "0.1.22"
description = "GovOPlaN operations module for health, deployment profile, and sizing visibility."
readme = "README.md"
requires-python = ">=3.12"
authors = [{ name = "GovOPlaN" }]
dependencies = [
"govoplan-core>=0.1.42",
"govoplan-core>=0.1.45",
"govoplan-access>=0.1.18",
]
+1 -1
View File
@@ -2,4 +2,4 @@
__all__ = ["__version__"]
__version__ = "0.1.21"
__version__ = "0.1.22"
+3 -3
View File
@@ -100,7 +100,7 @@ def _route_factory(context: ModuleContext):
manifest = ModuleManifest(
id="ops",
name="Ops",
version="0.1.21",
version="0.1.22",
required_capabilities=(
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
@@ -209,7 +209,7 @@ manifest = ModuleManifest(
DocumentationTopic(
id="ops.runtime-coordination-and-recovery",
title="Drain runtime nodes and inspect recovery evidence",
summary="Ops projects shared runtime heartbeats, replica gaps, drain controls, and recovery states that require operator attention.",
summary="Ops projects shared runtime heartbeats, replica gaps, drain controls, and recovery states that require operator attention. Node controls remain pinned at the right edge of horizontally scrolled runtime tables.",
body="Use the runtime table to identify stale or composition-skewed API and worker replicas. Drain before replacement so API readiness closes and workers stop taking new queue work; cancellation is available while the node is still draining. The recovery table reports durable Core recovery operations. A rejected operation is a verified provider rejection and needs no recovery; outcome-unknown and recovery-required operations still require reconciliation through the owning module. Core module-lifecycle entries block every later install or live graph change: use the installer run id to verify package, backup, migration, and health evidence before rollback or forward repair. Mail SMTP and IMAP APPEND entries use stable attempt identifiers and digest-only evidence: reconcile the Mail command from provider evidence, never by replaying the original effect from Ops. Files blob writes, hard purge, reference-checked garbage collection, and conditional S3 connector writes record Core recovery evidence. For a Files connector outcome, inspect the provider request/content markers and revision before allowing another write to the fenced path; for blob GC, recheck FileVersion references and exact object absence. Development SQLite can show only handled-rollback reconstruction for caller-transaction blob uploads; after a hard SQLite process loss, run the owning Files integrity scan because an orphan may have no Ops ledger row. Dataflow database-only runs are atomic, while published-output runs use forward recovery: reconcile the recorded output digest and sink idempotency key before allowing another publication. Backup status separately projects only the sanitized deployment verification receipt: a verified status identifies a coordinated recovery point and isolated restore drill, while absent, expired, or invalid evidence blocks a release-changing migration.",
documentation_types=("admin", "user"),
audience=("operator", "system_admin"),
@@ -223,7 +223,7 @@ manifest = ModuleManifest(
translations={
"de": {
"title": "Laufzeitknoten leeren und Wiederherstellungsnachweise prüfen",
"summary": "Ops projiziert gemeinsame Laufzeit-Heartbeats, Replikatlücken, Leerungssteuerung und Wiederherstellungszustände, die betriebliche Aufmerksamkeit erfordern.",
"summary": "Ops projiziert gemeinsame Laufzeit-Heartbeats, Replikatlücken, Leerungssteuerung und Wiederherstellungszustände, die betriebliche Aufmerksamkeit erfordern. Die Knotensteuerung bleibt am rechten Rand horizontal gescrollter Laufzeittabellen angeheftet.",
"body": (
"Verwenden Sie die Laufzeittabelle, um veraltete API- und Worker-Replikate oder Replikate mit abweichender Modulzusammensetzung zu erkennen. "
"Leeren Sie einen Knoten vor dem Austausch, damit seine API-Bereitschaft geschlossen wird und Worker keine neue Warteschlangenarbeit annehmen; solange der Knoten noch geleert wird, kann der Vorgang abgebrochen werden. "
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/ops-webui",
"version": "0.1.21",
"version": "0.1.22",
"private": true,
"type": "module",
"main": "src/index.ts",
@@ -13,10 +13,11 @@
}
},
"scripts": {
"test:action-layout": "node scripts/test-action-layout.mjs",
"test:runtime-status": "rm -rf .runtime-status-test-build && mkdir -p .runtime-status-test-build && printf '{\"type\":\"commonjs\"}\\n' > .runtime-status-test-build/package.json && ../../govoplan-core/webui/node_modules/.bin/tsc -p tsconfig.runtime-status-tests.json && node .runtime-status-test-build/tests/runtime-status.test.js"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.18",
"@govoplan/core-webui": "^0.1.45",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
+7
View File
@@ -0,0 +1,7 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
const page = readFileSync(new URL("../src/features/ops/OpsPage.tsx", import.meta.url), "utf8");
assert.match(page, /id: "actions",\s*header: "",\s*width: 72,\s*sticky: "end",\s*resizable: false,\s*align: "right"/);
assert.match(page, /<TableActionGroup\s*minimumSlots=\{1\}/);
console.log("Runtime node controls use the shared pinned action layout.");
+4 -1
View File
@@ -399,7 +399,10 @@ function RuntimeNodeTable({
{
id: "actions",
header: "",
width: 56,
width: 72,
sticky: "end",
resizable: false,
align: "right",
value: (node) => node.state,
render: (node) => {
const busy = busyNodeId === node.node_id;