Bind Vergabe pilot fixtures and prepare native recovery preflight
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1abf1-7e95-7141-87c9-ee78332bf790
This commit is contained in:
parent
cb7582de55
commit
177a85d05f
8 changed files with 327 additions and 2 deletions
35
docs/evidence/2026-11-05-vergabe-identified-page-gates.json
Normal file
35
docs/evidence/2026-11-05-vergabe-identified-page-gates.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"schema": "railiance.vergabe-pilot-anonymous-page-probes.v1",
|
||||
"observed_at": "2026-11-05T21:27:44.219543+00:00",
|
||||
"runtime_mutations": false,
|
||||
"reads": [
|
||||
{
|
||||
"path": "/demo-company/ausschreibungen/1/",
|
||||
"method": "GET",
|
||||
"cookies_supplied": false,
|
||||
"final_status": 200,
|
||||
"final_host": "vergabe-teilnahme.coulomb.social",
|
||||
"final_path": "/demo-company/accounts/login/",
|
||||
"netkingdom_welcome_present": true
|
||||
},
|
||||
{
|
||||
"path": "/demo-company/ausschreibungen/1/aufgaben/1/",
|
||||
"method": "GET",
|
||||
"cookies_supplied": false,
|
||||
"final_status": 200,
|
||||
"final_host": "vergabe-teilnahme.coulomb.social",
|
||||
"final_path": "/demo-company/accounts/login/",
|
||||
"netkingdom_welcome_present": true
|
||||
},
|
||||
{
|
||||
"path": "/demo-company/ausschreibungen/1/dokumente/1/",
|
||||
"method": "GET",
|
||||
"cookies_supplied": false,
|
||||
"final_status": 200,
|
||||
"final_host": "vergabe-teilnahme.coulomb.social",
|
||||
"final_path": "/demo-company/accounts/login/",
|
||||
"netkingdom_welcome_present": true
|
||||
}
|
||||
],
|
||||
"binary_document_download_tested": false
|
||||
}
|
||||
23
docs/evidence/2026-11-05-vergabe-local-issue-return.json
Normal file
23
docs/evidence/2026-11-05-vergabe-local-issue-return.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"schema": "railiance.vergabe-pilot-user-return.v1",
|
||||
"reported_on": "2026-11-05",
|
||||
"workplan": "RAPPS-WP-0014",
|
||||
"task": "RAPPS-WP-0014-T03",
|
||||
"evidence_source": "User confirmation and application URLs in the active conversation",
|
||||
"evidence_kind": "user_reported",
|
||||
"company": "demo-company",
|
||||
"local_issue_badge_visible_in_both_accounts": true,
|
||||
"exact_issue_key_independently_verified": false,
|
||||
"fixture": {
|
||||
"ausschreibung_id": 1,
|
||||
"aufgabe_id": 1,
|
||||
"dokument_id": 1,
|
||||
"task_url": "https://vergabe-teilnahme.coulomb.social/demo-company/ausschreibungen/1/aufgaben/1/",
|
||||
"document_detail_url": "https://vergabe-teilnahme.coulomb.social/demo-company/ausschreibungen/1/dokumente/1/"
|
||||
},
|
||||
"document_ui_review": "pending",
|
||||
"populated_restart_or_recovery_verified": false,
|
||||
"personal_account_identifiers_recorded": false,
|
||||
"credentials_or_tokens_recorded": false,
|
||||
"runtime_mutations_by_agent": false
|
||||
}
|
||||
20
docs/evidence/2026-11-05-vergabe-native-inventory.json
Normal file
20
docs/evidence/2026-11-05-vergabe-native-inventory.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"schema": "railiance.vergabe-pilot-native-inventory.v1",
|
||||
"observed_at": "2026-11-05T21:25:35.760984+00:00",
|
||||
"runtime_mutations": false,
|
||||
"native_inventory_complete": false,
|
||||
"cluster_read": "ok",
|
||||
"cluster_matches_expected": true,
|
||||
"nodes_read": "forbidden",
|
||||
"deployment_read": "forbidden",
|
||||
"claims": {
|
||||
"media": {
|
||||
"read": "forbidden"
|
||||
},
|
||||
"app-state": {
|
||||
"read": "forbidden"
|
||||
}
|
||||
},
|
||||
"database_cluster_read": "forbidden",
|
||||
"helm_read": "request_failed"
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# Vergabe native recovery inventory
|
||||
|
||||
Prepared under RAPPS-WP-0014-T03. The user has identified Ausschreibung 1,
|
||||
task 1 and document 1, and confirmed the local issue is visible to both accounts.
|
||||
This packet prepares the native metadata read needed before a populated restart
|
||||
and coherent three-store recovery action can be pinned.
|
||||
|
||||
The [action](action.json) embeds the complete source of
|
||||
[`tools/vergabe_pilot_inventory.py`](../../../tools/vergabe_pilot_inventory.py)
|
||||
as one `python3 -c` argument, bound to `kube:railiance01`, profile `kube-admin`,
|
||||
agent `custodian-agt`, cwd `/` and an empty proposed environment.
|
||||
|
||||
Action digest:
|
||||
`sha256:2014e62a84b0875fec155dbfd1be26963d9a39ab931092d26c5dfb9e627ffbd7`.
|
||||
Source SHA256:
|
||||
`b610059b5d7398138062de51edab3555b973cfbb61f02fa684184852805d7507`.
|
||||
|
||||
The command reads the cluster UID, node conditions, the exact pilot Deployment,
|
||||
the two named PVCs, `databases/apps-pg` status and Helm release summaries. It
|
||||
checks the recorded immutable image, Recreate/single-writer readiness and exact
|
||||
mounts. Child output/errors are captured; the receipt contains booleans,
|
||||
read-status codes and Helm revision. It stops immediately on a different cluster.
|
||||
There are no resource mutations, pod exec, application queries or file captures.
|
||||
|
||||
The current caller's [inventory receipt](../../evidence/2026-11-05-vergabe-native-inventory.json)
|
||||
is incomplete: the cluster UID matches, while node, Deployment, PVC and CNPG
|
||||
reads are forbidden and Helm listing fails. This caller did not execute a
|
||||
privileged proposal. The workstation has no installed `gexec` command; proposal
|
||||
preparation used the existing gated-executor source CLI/action format only.
|
||||
|
||||
For attended execution, review this exact JSON with `gexec show` in the admitted
|
||||
founder runtime, sign it with that runtime's existing approver key and submit
|
||||
through its configured spool. The environment orientation §6 requires the
|
||||
gated executor for privileged actions. No signing key, elevated kubeconfig or
|
||||
new standing agent grant is requested by the packet. The result must report
|
||||
`native_inventory_complete: true` before using its expected release as the
|
||||
baseline of a separately reviewed capture/restart operation.
|
||||
|
||||
Validation: source compilation and synthetic command responses cover success,
|
||||
immediate wrong-cluster refusal, image drift and exclusion of a private canary
|
||||
from the receipt. Ruff is unavailable in the current shell. No native pass,
|
||||
snapshot, restart, off-host publication or restore has occurred.
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -8,7 +8,10 @@ the other account after reload; see the [workflow return](evidence/2026-11-05-ve
|
|||
The user confirmed the uploaded file is available from the other account; see
|
||||
the [document return](evidence/2026-11-05-vergabe-document-return.json). The
|
||||
document UI still needs user review. File hash equality and signed-out download
|
||||
refusal are unverified. Task edits, local-issue workflow and recovery remain pending.
|
||||
refusal are unverified. The user also confirms the **LOKAL** issue badge is
|
||||
visible in both accounts; the [issue return](evidence/2026-11-05-vergabe-local-issue-return.json)
|
||||
binds Ausschreibung 1, task 1 and document 1 from their supplied URLs. Task
|
||||
edits, domain approval/submission and recovery remain pending.
|
||||
|
||||
The other session does not update automatically, and a fresh login was needed
|
||||
after a short interval. The user wants a full working day without renewed login
|
||||
|
|
@ -74,6 +77,9 @@ confirms the recorded cluster UID, public health and the NetKingdom welcome
|
|||
gate. Node, Deployment and PVC reads are forbidden to the current agent identity;
|
||||
fresh image/release/claim status remains unverified. The binding's expected image
|
||||
and claims are historical reference values until a permitted native readback.
|
||||
The [native inventory packet](proposals/2026-11-05-vergabe-recovery-preflight/README.md)
|
||||
now provides the exact metadata-only action; its current-caller receipt remains
|
||||
incomplete. It prepares the baseline read, rather than a snapshot or restart.
|
||||
|
||||
After the populated workflow, prepare the exact attended recovery action from
|
||||
the existing [pilot recovery contract](vergabe-teilnahme-pilot.md#persistence-and-recovery)
|
||||
|
|
|
|||
162
tools/vergabe_pilot_inventory.py
Normal file
162
tools/vergabe_pilot_inventory.py
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Read-only, value-free recovery inventory for the demo-company pilot.
|
||||
|
||||
Uses the caller's existing kubectl/Helm context for resource status and Helm
|
||||
release summaries. No Secret output, values, logs, pod exec or resource changes.
|
||||
Child output/errors stay private.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
CLUSTER_UID = "a553c742-0115-43d4-99a4-a5ca56fe0786"
|
||||
NAMESPACE = "vergabe-demo-company"
|
||||
RELEASE = "vergabe-teilnahme"
|
||||
IMAGE = (
|
||||
"forgejo.coulomb.social/coulomb/vergabe-teilnahme@sha256:"
|
||||
"a26444f59c259698159c69ccb96f73dc648a261ece4c86bb2037a9d977870d91"
|
||||
)
|
||||
CLAIMS = {"media": "vergabe-teilnahme-media", "app-state": "vergabe-teilnahme-app-state"}
|
||||
|
||||
|
||||
def read_json(argv):
|
||||
try:
|
||||
result = subprocess.run(argv, capture_output=True, timeout=20, check=False)
|
||||
if result.returncode:
|
||||
return None, "forbidden" if b"Forbidden" in result.stderr else "request_failed"
|
||||
return json.loads(result.stdout), "ok"
|
||||
except (OSError, subprocess.TimeoutExpired, ValueError, UnicodeError):
|
||||
return None, "unavailable_or_invalid_response"
|
||||
|
||||
|
||||
def kube(*args):
|
||||
return read_json(["kubectl", "--request-timeout=12s", *args, "-o", "json"])
|
||||
|
||||
|
||||
def collect():
|
||||
receipt = {
|
||||
"schema": "railiance.vergabe-pilot-native-inventory.v1",
|
||||
"observed_at": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
"runtime_mutations": False,
|
||||
"native_inventory_complete": False,
|
||||
}
|
||||
cluster, status = kube("get", "namespace", "kube-system")
|
||||
receipt["cluster_read"] = status
|
||||
if cluster is None:
|
||||
return receipt
|
||||
receipt["cluster_matches_expected"] = cluster.get("metadata", {}).get("uid") == CLUSTER_UID
|
||||
if not receipt["cluster_matches_expected"]:
|
||||
return receipt
|
||||
|
||||
nodes, status = kube("get", "nodes")
|
||||
receipt["nodes_read"] = status
|
||||
if nodes is not None:
|
||||
matching = [
|
||||
n for n in nodes.get("items", [])
|
||||
if any(a.get("address") == "92.205.62.239"
|
||||
for a in n.get("status", {}).get("addresses", []))
|
||||
]
|
||||
receipt["node_address_matches_expected"] = len(matching) == 1
|
||||
if len(matching) == 1:
|
||||
conditions = {c.get("type"): c.get("status")
|
||||
for c in matching[0].get("status", {}).get("conditions", [])}
|
||||
receipt["node_ready"] = conditions.get("Ready") == "True"
|
||||
receipt["node_pressure_clear"] = all(
|
||||
conditions.get(c) == "False"
|
||||
for c in ("MemoryPressure", "DiskPressure", "PIDPressure")
|
||||
)
|
||||
|
||||
deployment, status = kube("get", "deployment", RELEASE, "-n", NAMESPACE)
|
||||
receipt["deployment_read"] = status
|
||||
if deployment is not None:
|
||||
spec = deployment.get("spec", {})
|
||||
pod = spec.get("template", {}).get("spec", {})
|
||||
app = next((c for c in pod.get("containers", []) if c.get("name") == "app"), {})
|
||||
ready = deployment.get("status", {})
|
||||
receipt["deployment"] = {
|
||||
"image_matches_expected": app.get("image") == IMAGE,
|
||||
"replicas": spec.get("replicas"),
|
||||
"ready_replicas": ready.get("readyReplicas", 0),
|
||||
"updated_replicas": ready.get("updatedReplicas", 0),
|
||||
"generation_observed": ready.get("observedGeneration", 0)
|
||||
>= deployment.get("metadata", {}).get("generation", 1),
|
||||
"recreate": spec.get("strategy", {}).get("type") == "Recreate",
|
||||
"mounts_match_expected": all(
|
||||
any(v.get("name") == name
|
||||
and v.get("persistentVolumeClaim", {}).get("claimName") == claim
|
||||
for v in pod.get("volumes", []))
|
||||
for name, claim in CLAIMS.items()
|
||||
) and all(
|
||||
any(m.get("name") == name and m.get("mountPath") == path
|
||||
for m in app.get("volumeMounts", []))
|
||||
for name, path in (("media", "/app/media"), ("app-state", "/app/.issue-facade"))
|
||||
),
|
||||
}
|
||||
|
||||
receipt["claims"] = {}
|
||||
for name, claim in CLAIMS.items():
|
||||
data, status = kube("get", "pvc", claim, "-n", NAMESPACE)
|
||||
row = {"read": status}
|
||||
if data is not None:
|
||||
row["bound"] = data.get("status", {}).get("phase") == "Bound"
|
||||
row["identity_present"] = bool(data.get("metadata", {}).get("uid"))
|
||||
receipt["claims"][name] = row
|
||||
|
||||
database, status = kube("get", "cluster", "apps-pg", "-n", "databases")
|
||||
receipt["database_cluster_read"] = status
|
||||
if database is not None:
|
||||
db_status = database.get("status", {})
|
||||
receipt["database_ready"] = (
|
||||
db_status.get("instances", 0) > 0
|
||||
and db_status.get("readyInstances", 0) == db_status.get("instances")
|
||||
and bool(db_status.get("currentPrimary"))
|
||||
)
|
||||
|
||||
releases, status = read_json([
|
||||
"helm", "list", "--all", "--namespace", NAMESPACE,
|
||||
"--filter", "^vergabe-teilnahme$", "--output", "json",
|
||||
])
|
||||
receipt["helm_read"] = status
|
||||
if isinstance(releases, list):
|
||||
rows = [r for r in releases if r.get("name") == RELEASE]
|
||||
if len(rows) == 1:
|
||||
receipt["helm"] = {
|
||||
"deployed": rows[0].get("status") == "deployed",
|
||||
"revision": int(rows[0]["revision"]),
|
||||
"chart_matches_expected": rows[0].get("chart") == "vergabe-teilnahme-0.2.1",
|
||||
}
|
||||
|
||||
dep = receipt.get("deployment", {})
|
||||
release = receipt.get("helm", {})
|
||||
receipt["native_inventory_complete"] = (
|
||||
receipt.get("node_address_matches_expected") is True
|
||||
and receipt.get("node_ready") is True
|
||||
and receipt.get("node_pressure_clear") is True
|
||||
and dep.get("image_matches_expected") is True
|
||||
and dep.get("replicas") == dep.get("ready_replicas") == dep.get("updated_replicas") == 1
|
||||
and dep.get("generation_observed") is True
|
||||
and dep.get("recreate") is True and dep.get("mounts_match_expected") is True
|
||||
and all(c.get("bound") is True and c.get("identity_present") is True
|
||||
for c in receipt["claims"].values())
|
||||
and receipt.get("database_ready") is True
|
||||
and release.get("deployed") is True and release.get("chart_matches_expected") is True
|
||||
)
|
||||
return receipt
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
receipt = collect()
|
||||
except Exception:
|
||||
receipt = {"schema": "railiance.vergabe-pilot-native-inventory.v1",
|
||||
"native_inventory_complete": False, "failure": "invalid_inventory_response",
|
||||
"runtime_mutations": False}
|
||||
print(json.dumps(receipt, indent=2))
|
||||
return 0 if receipt["native_inventory_complete"] else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
|
@ -196,7 +196,7 @@ id: RAPPS-WP-0014-T03
|
|||
status: wait
|
||||
needs_human: true
|
||||
decision_id: d06307e5-2737-461a-a2f4-a12c3b492a9a
|
||||
intervention_note: "Both accounts sign in; created records and uploaded document are visible from the other account (user-confirmed 2026-11-05). Next: remaining task/local-issue and negative-access checks, then populated restart, coherent off-host recovery, isolated restore, rollback and ownership. Document UI review stays pending; session/OTP refinement is deferred. railiance-platform owns storage/custody delivery."
|
||||
intervention_note: "Both accounts sign in and see created records, the uploaded document and LOKAL issue (2026-11-05). Fixture: Ausschreibung/task/document 1. Remaining shared task edit, approval/submission and access checks precede populated restart/recovery. Exact metadata-only inventory packet is prepared; current caller lacks native reads. Off-host recovery, isolated restore, rollback and ownership remain open. Document UI review stays pending; session/OTP refinement is deferred."
|
||||
priority: high
|
||||
assignee: the-custodian
|
||||
blocking_reason: "Await populated two-user/document workflow, coherent PostgreSQL/media/issue-state off-host recovery point, isolated restored workflow, rollback evidence and support ownership. September 25 proves database restore and restart only."
|
||||
|
|
@ -300,6 +300,27 @@ acceptance, byte/hash equality, anonymous refusal and populated recovery are
|
|||
not inferred. Requested the task's local issue badge/key check from both
|
||||
sessions next. T03 retains its remaining workflow, recovery and ownership scope.
|
||||
|
||||
2026-11-05 local-issue return: the user confirms the LOKAL badge is visible
|
||||
from both accounts and supplies task/document URLs, binding Ausschreibung 1,
|
||||
task 1 and document 1. Receipt:
|
||||
`docs/evidence/2026-11-05-vergabe-local-issue-return.json`. Signed-out HTTP reads
|
||||
of these identified tender/task/document pages reach the NetKingdom login page;
|
||||
the document-detail URL is not the binary file URL, so direct file refusal
|
||||
remains unverified. Requested the remaining shared task-edit and domain
|
||||
approval/demo-submission results together.
|
||||
|
||||
Prepared `tools/vergabe_pilot_inventory.py` and exact metadata-only action
|
||||
`docs/proposals/2026-11-05-vergabe-recovery-preflight/action.json` for the
|
||||
existing attended executor. Cluster UID matches, but the current caller's
|
||||
native inventory remains incomplete (node/Deployment/PVC/CNPG reads forbidden,
|
||||
Helm listing failed). No privileged proposal was executed; `gexec` is absent
|
||||
from this workstation. Source compilation/synthetic success, wrong-cluster,
|
||||
image-drift and output-canary checks pass. This is a preflight packet, not the
|
||||
capture/restart operation. Existing database-only helpers omit both file stores;
|
||||
the platform primary-archive helper currently has no Vergabe application profile.
|
||||
Off-host publication/readback still needs its owner-bound storage/custody path.
|
||||
T03 remains wait for the remaining workflow and operational recovery evidence.
|
||||
|
||||
|
||||
## Validate synthetic sizing against the exact release and shared contention
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue