Keep review obligations visible and reconcile owner evidence (RISK-WP-0006, RISK-WP-0007)

check_all runs every check stage even when one fails; malformed dates are
reported rather than aborting; accepted findings and closure evidence are
shown; defer requires a valid future date. Adds SCOPE.md, the scope
assessment, the open-findings source review and a unittest suite. Stops
tracking __pycache__.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 6903@bnt-lap001
Assistant-Session: 8319e8a8-ffa6-4eb3-b8bf-b29945628f89
This commit is contained in:
tegwick 2026-09-22 07:56:58 +02:00
parent 29f50d5143
commit bbbede5f47
25 changed files with 1007 additions and 43 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__/
*.pyc

View file

@ -1,7 +1,7 @@
PY := python3
TOOLS := tools
.PHONY: help register check checked due fixes coverage
.PHONY: help register check checked due fixes coverage test
help:
@echo "make register - rebuild REGISTER.md from findings/"
@ -15,18 +15,14 @@ register:
@$(PY) $(TOOLS)/register_index.py
check:
@$(PY) $(TOOLS)/register_index.py --check
@echo
@$(PY) $(TOOLS)/register_check.py
@echo
@$(PY) $(TOOLS)/inbox_check.py
@$(PY) $(TOOLS)/check_all.py
checked:
@$(PY) $(TOOLS)/record_check.py $(ARGS)
@$(PY) $(TOOLS)/register_index.py
due:
@$(PY) $(TOOLS)/register_check.py | sed -n '/Checks due/,/^$$/p'
@$(PY) $(TOOLS)/register_check.py
@$(PY) $(TOOLS)/inbox_check.py
fixes:
@ -34,3 +30,6 @@ fixes:
coverage:
@$(PY) $(TOOLS)/coverage.py
test:
@PYTHONDONTWRITEBYTECODE=1 $(PY) -m unittest discover -s tests -v

View file

@ -40,4 +40,19 @@ make check # verify the index, then report what is going quiet
embargoes due for re-decision, escalations awaiting the operator, and what is
owed at the production transition. It changes nothing.
All check stages run even when the index is stale; the command still exits
nonzero for a failed stage. `make due` shows the full obligation report and
inbox freshness, including full regulatory policies, embargo review deadlines
and publication handovers that remain pending after a finding closes.
`make checked` accepts finding, regulatory determination and full policy IDs;
it records an actual review, not a repair for an overdue warning.
`make fixes` distinguishes owner workplans from recorded acceptance obligations.
`make check` and `make due` also show explicit `closure_condition` evidence still
owed by live findings, even when a source workplan has finished. Acceptance
terms and a finished workplan are not proof of runtime closure.
Run `make test` for isolated regression checks. Python 3 and PyYAML are required.
- Intent: `INTENT.md`
- Current capability: [SCOPE.md](SCOPE.md)

View file

@ -1,6 +1,6 @@
# Register
Generated by `tools/register_index.py` from `findings/`. Do not edit by hand. Last built 2026-09-02.
Generated by `tools/register_index.py` from `findings/`. Do not edit by hand. Last built 2026-09-05.
3 live of 11 findings; 3 notes below the floor.
@ -9,9 +9,9 @@ Generated by `tools/register_index.py` from `findings/`. Do not edit by hand. La
| ID | Finding | System | Severity | Disclosure | Escalation | Fix owner | Status | Cadence | Next check |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| [RISK-F-0011](findings/RISK-F-0011-qonto-audit-deny-stream-completeness.md) | qonto-assistant audit.deny stream completeness is not established | qonto-assistant | medium | public | none | qonto-assistant | open | instant (0) | **due** |
| [RISK-F-0010](findings/RISK-F-0010-embedded-backup-webdav-credential.md) | Forgejo backup source embeds a WebDAV credential default | railiance-platform | low | embargoed | none | railiance-platform | open | 1h (1) | 2026-09-02 09:11Z |
| [RISK-F-0010](findings/RISK-F-0010-embedded-backup-webdav-credential.md) | Forgejo backup source embeds a WebDAV credential default | railiance-platform | low | embargoed | none | railiance-platform | open | instant (0) | **due** |
| [RISK-F-0009](findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md) | agent-high-risk-boundary denies 6 of 17 high-risk lanes; the direct bao path is unprotected for the rest | railiance-platform | **high** | public | none | railiance-platform | fixed | instant (0) | **due** |
| [RISK-F-0008](findings/RISK-F-0008-audit-retention-legal-basis-assumed.md) | The legal basis for retaining audit facts against an erasure request has been assumed, never established | audit-core | medium | public | **answered** (t2, answered) | risk-nexus | accepted | 1h (1) | 2026-09-02 09:11Z |
| [RISK-F-0008](findings/RISK-F-0008-audit-retention-legal-basis-assumed.md) | The legal basis for retaining audit facts against an erasure request has been assumed, never established | audit-core | medium | public | **answered** (t2, answered) | risk-nexus | accepted | 1h (1) | **due** |
| [RISK-F-0007](findings/RISK-F-0007-unverified-tenant-boundary.md) | No consumer's tenant boundary is verified anywhere | estate | **high** | public | **answered** (t4, assigned) | per-consumer, on request | fixed | instant (0) | **due** |
| [RISK-F-0006](findings/RISK-F-0006-apps-pg-no-backup-configured.md) | apps-pg has no backup configured at all: R0 means no recovery | railiance-platform | **high** | public | **answered** (t3, answered) | railiance-platform | fixed | instant (0) | **due** |
| [RISK-F-0005](findings/RISK-F-0005-audit-core-unfiltered-read-path.md) | audit-core read path applies no tenant filter; the bound is deployment, not code | audit-core | medium | public | none | audit-core | fixed | instant (0) | **due** |
@ -35,8 +35,8 @@ Silence never buys a softer grade — see `docs/method/dependencies.md`.
| Finding | Who | What would change | Default if silent | On |
| --- | --- | --- | --- | --- |
| RISK-F-0011 | qonto-assistant | a published cadence plus a reconciliation view would let a later observation support completeness; a rejection keeps the grade and records that estate observation must not treat the stream as complete | the medium grade stands; missing cadence is recorded as a stalled remediation, and observation remains staffed with completeness pending | 2026-09-16 |
| RISK-F-0010 | railiance-platform | the finding becomes fixed and the embargo lifts | the low grade and embargo stand; missing fix tracking is recorded as a stalled remediation | 2026-09-15 |
| RISK-F-0011 | qonto-assistant | accepted deployed-instance evidence supports bounded stream completeness and permits closure; source-only evidence keeps the finding open | the medium grade stands; missing deployed acceptance is recorded as a stalled remediation, and observation remains staffed with completeness pending | 2026-09-16 |
| RISK-F-0010 | railiance-platform | the finding becomes fixed and the embargo lifts | the low grade and embargo stand; absent provider invalidation and recovery evidence is recorded as a stalled remediation | 2026-09-15 |
| RISK-F-0008 | audit-core | a working keyed commitment narrows RISK-REG-0001 to retained-by-obligation categories only | encrypt-then-hash recorded as the only known route, and the retention period recorded as unstateable | 2026-11-17 |
## Embargoes

71
SCOPE.md Normal file
View file

@ -0,0 +1,71 @@
# SCOPE — risk-nexus
Updated 2026-09-05 (Europe/Berlin), including RISK-WP-0006 and RISK-WP-0007. This describes the checked-in capabilities;
[INTENT.md](INTENT.md) remains the intended remit. Evidence and remaining gaps
are in the [dated assessment](history/2026-09-05-014333-scope-intent-assessment.md).
`risk-nexus` is a file-based risk register and regulatory reference collection,
owned by `the-custodian`, with Python command-line tools for indexing, review
bookkeeping and reports. Humans or agent sessions make the judgements and act
on the reports. This repository contains no web service, intake API, deployment
or independent scheduler, and does not itself serve `risk.coulomb.social`.
## What it can do
| Capability | Implemented scope and evidence |
| --- | --- |
| Record findings and notes | YAML front-matter and Markdown in `findings/` and `notes/`; [filing contract](findings/README.md) separates reporter facts from register grading. Research, review and observation have produced records. Incident intake is a written procedure; external-report contact provisioning remains routed elsewhere. |
| Grade and explain decisions | [Method instruments](docs/method/) define severity, disclosure, escalation, review, dependencies and verification. Dated rulings and finding histories record applied decisions. Scoring and acceptance are judgements, not computed decisions. |
| Generate a readable register | `make register` builds `REGISTER.md` from findings and notes, including constraints, finding waits, embargoes and cadence. It is an index, not the source of truth. |
| Report review work | `tools/register_check.py` reports due checks, missing grades, selected malformed fields, unknown statuses, waits/defaults, tracked fix state, embargo conditions and review dates, pending handovers and escalations, production re-score flags and regulatory reviews including full policies. `fixed` and `withdrawn` leave the ordinary watch list, but disclosure obligations remain visible; accepted, mitigated and unknown statuses remain watched. |
| Record review outcomes | `make checked ARGS="<id> clean\|moved\|defer ..."` updates an eligible record's timestamps, checker, cadence and review history, then regenerates the index. Clean climbs one rung from `instant` toward `1q`; moved resets; defer records a supplied date and reason. Completion of the review procedure and operator authorization for deferral are not enforced by the tool. |
| Read remediation records | `make fixes` resolves supported workplan/task IDs in live findings against sibling checkout files under `/home/worsch`, including an archive convention. It reports status, missing tracking and severity-based inactivity windows using the workplan file's last commit date. This is a proxy for recorded activity, not proof of task progress or a deployed fix. |
| Keep closure obligations visible | Live findings can state `closure_condition`, reported independently of source workplan completion. An accepted finding without fix tracking reports its recorded accepter, ending condition, resolvable regulatory determination and review date; missing fields still produce an incomplete-acceptance/missing-tracking warning. This does not verify that acceptance remains valid. |
| Check inbox freshness | `tools/inbox_check.py` reads up to 100 State Hub messages and matches names/IDs against live findings checked earlier. It reports potentially newer evidence; it neither interprets nor acknowledges messages. |
| Count reporting coverage | `make coverage` counts names appearing as system, fix owner or reporter and compares them with State Hub repo slugs when available. It measures mention coverage, not assessment coverage or assurance. |
| Retain regulatory research | One determination in `docs/regulatory/`, a thirteen-entry policy catalogue, and four full policy records. Sources, dates and activation conditions are stored for retrieval. Review discovery includes nested full policies; catalogues are excluded. All discovered records accept recorded outcomes. |
| Record disclosure and handover | Public, embargoed and restricted states express disclosure decisions. Finding metadata records publication status and addresses supplied by `policy-nexus`. Publication and access control are external; a `public` decision does not prove a completed handover. |
| Describe scheduled work | Two `activity-definitions/` files describe an hourly inbox watch and a daily 07:15 Europe/Berlin sweep. They ask an external activity system to instruct a session. They do not execute reviews or guarantee that a session acts. |
## Operating dependencies and limits
- Python 3, PyYAML, Make and Git are required for the relevant local commands;
no dependency manifest is checked in. `make test` runs isolated regression tests.
- State Hub reads use hard-coded `http://127.0.0.1:8000` endpoints. Fix tracking
assumes local sibling repositories and specific workplan naming/formatting.
- `make check` verifies the index and runs register and inbox reports even if a
prior stage fails, returning nonzero for any failed stage. Rendering includes the
current date and time-dependent due labels, so staleness need not mean source
records changed. `make due` runs the full obligation report and inbox check directly,
including nested policies, due embargo reviews and pending publication handovers
across closed as well as live findings.
- Reports do not send escalations, apply defaults, expire acceptances, lift
embargoes, close findings or block delivery. Operational warnings generally
return exit code zero. Selected validation exists, not comprehensive schema
enforcement; invalid date strings are tolerated by parsing and selected fields
are reported for repair. Deferrals require valid future dates.
- Incident deadlines and production-transition events
are procedural obligations without dedicated automated deadline/event handling.
The production-transition definition remains `proposed`.
- Historical verification records distinguish owner evidence, checkout evidence
and live reads. They do not establish current infrastructure access or health.
## Current recorded footprint
The checkout contains eleven findings: eight fixed, two open and one accepted;
three notes; one regulatory determination; four full policies out of thirteen
catalogue entries; and three verification records. Both open findings now carry
owner workplan tracking and explicit pending runtime/provider evidence. The
accepted finding carries a resolvable determination and an overdue substantive
review, displayed as a recorded acceptance obligation. Two findings are marked
published, eight pending handover, and one embargoed. These are repository
records, not a fresh verification of the affected systems or published sites.
## Ownership boundary
The repo owns risk intake records, grading, disclosure decisions, regulatory
research retention and escalation/review procedures. Fixes and incident response
belong to system owners; publication belongs to `policy-nexus`; canon and
estate-level decisions belong to the custodian/operator. It provides neither
legal advice nor compliance certification, estate-wide detection, or a delivery
gate. Completing the intended remit does not require taking over those roles.

View file

@ -1,6 +1,6 @@
# STATE — risk-nexus
**Updated:** 2026-09-02
**Updated:** 2026-09-05
**Domain:** infotech · **Repo:** risk-nexus · **Owner:** the-custodian
## One-line posture
@ -20,13 +20,41 @@ backup credential, and an accepted medium on audit retention.
| `RISK-WP-0003` | **finished** | Regulatory intake; the legal policy set |
| `RISK-WP-0004` | **finished** | Running the register: cadence, verification, inbox-before-grading |
| `RISK-WP-0005` | **finished** | The seven gaps from `history/2026-08-21-intent-gap-analysis.md` |
| `RISK-WP-0006` | **finished** | Reporting survives a stale index; full policies, embargo deadlines and closed-finding handovers stay visible; regression coverage and State Hub registration. |
| `RISK-WP-0007` | **finished** | Owner evidence reconciled, runtime/provider closure conditions recorded, and accepted obligations distinguished from missing engineering fixes. |
## Scope correction and reporting repair — 2026-09-05
`SCOPE.md` now describes the checked-in capability. The timestamped assessment
in `history/2026-09-05-014333-scope-intent-assessment.md` records the remaining
gaps behind the earlier claim that WP-0005 closed them all.
WP-0006 repairs the reporting path: `make check` runs every stage even after
failure; `make due` exposes regulatory policies and disclosure obligations;
malformed date strings no longer abort reporting; invalid deferrals cannot
write; archived completed workplans no longer trigger false inactivity alarms.
Eight regression tests pass. The live report now exposes four overdue policies,
eight pending publication handovers, and the existing overdue findings.
These are visibility repairs, not substantive reviews or evidence of closure.
The daily activity source includes those obligations. Its live synchronization
and end-to-end delivery remain unverified. External intake, incident clocks,
production-transition decisions and estate assessment coverage remain open.
WP-0007 then reconciled the owner evidence in RISK-V-0003. Qonto's source
cadence/reconciliation exists; KG-WP-0005-T03 waits for deployed acceptance.
RPF-WP-0029 removed the backup fallback; T02 waits for provider invalidation
and recovery receipts. Both findings were recorded as moved and remain open
at `instant`; F-0010 remains embargoed. F-0008's substantive review remains
overdue and its existing acceptance terms are displayed explicitly. Ten tests
pass. WP-0007 and four tasks are registered in State Hub.
## The register
| ID | Sev | Status | Disclosure | Cadence | System |
| --- | --- | --- | --- | --- | --- |
| `RISK-F-0011` | medium | open | public | instant | qonto-assistant |
| `RISK-F-0010` | low | open | embargoed | 1h | railiance-platform |
| `RISK-F-0010` | low | open | embargoed | instant | railiance-platform |
| `RISK-F-0009` | high | fixed | public | instant | railiance-platform |
| `RISK-F-0008` | medium | accepted | public | 1h | audit-core |
| `RISK-F-0007` | high | fixed | public | instant | estate |
@ -76,8 +104,8 @@ outcome.
| Who | On | Defaults |
| --- | --- | --- |
| qonto-assistant | heartbeat / emission-cadence and a reconciliation view for `audit.deny` (`F-0011`) | 2026-09-16 |
| railiance-platform | revoke or invalidate the provider credential, remove the source default, name fix tracking (`F-0010`) | 2026-09-15 |
| qonto-assistant | deployed-instance capture and King's Guard acceptance under `KG-WP-0005-T03`; source cadence/reconciliation now exist (`F-0011`) | 2026-09-16 |
| railiance-platform | provider invalidation and recovery receipts under `RPF-WP-0029-T02`; source fallback removed (`F-0010`) | 2026-09-15 |
| the-custodian | canon kinds packet | 2026-09-17 |
| audit-core | keyed commitment; `platform-pg` co-residency horizon | 2026-11-17 |
@ -107,10 +135,10 @@ statehub fix-consistency --repo risk-nexus
## Known conditions
- **Workplans are not indexed in the hub.** C-06 on all four: this instance is
- **Earlier workplans were not indexed in the hub.** C-06 on the earlier set: this instance was
not the identifier registrar. Needs a run with `STATEHUB_REGISTRAR=1` on the
production instance. The estate's read model cannot see any `risk-nexus`
workplan.
production instance. WP-0006 now has a registered Hub workplan and five task
UUIDs; this implementation did not repair historical workplan registration.
- **C-31** fires on `RISK-F-` ids until canon registers the kinds. Packet sent.
Defaults 2026-09-17.
- **OpenBao is unverifiable from here** (403). Every grade touching an OpenBao

View file

@ -13,6 +13,8 @@
| workplan | RISK-WP-0003 | finished | — | workplans/RISK-WP-0003-regulatory-intake.md |
| workplan | RISK-WP-0004 | finished | — | workplans/RISK-WP-0004-run-the-register.md |
| workplan | RISK-WP-0005 | finished | — | workplans/RISK-WP-0005-close-the-intent-gaps.md |
| workplan | RISK-WP-0006 | finished | — | workplans/RISK-WP-0006-keep-review-obligations-visible.md |
| workplan | RISK-WP-0007 | finished | — | workplans/RISK-WP-0007-reconcile-owner-evidence.md |
| task | RISK-WP-0001-T01 | done | — | workplans/RISK-WP-0001-make-the-register-decidable.md |
| task | RISK-WP-0001-T02 | done | — | workplans/RISK-WP-0001-make-the-register-decidable.md |
| task | RISK-WP-0001-T03 | done | — | workplans/RISK-WP-0001-make-the-register-decidable.md |
@ -41,3 +43,12 @@
| task | RISK-WP-0005-T05 | done | — | workplans/RISK-WP-0005-close-the-intent-gaps.md |
| task | RISK-WP-0005-T06 | done | — | workplans/RISK-WP-0005-close-the-intent-gaps.md |
| task | RISK-WP-0005-T07 | done | — | workplans/RISK-WP-0005-close-the-intent-gaps.md |
| task | RISK-WP-0006-T01 | done | — | workplans/RISK-WP-0006-keep-review-obligations-visible.md |
| task | RISK-WP-0006-T02 | done | — | workplans/RISK-WP-0006-keep-review-obligations-visible.md |
| task | RISK-WP-0006-T03 | done | — | workplans/RISK-WP-0006-keep-review-obligations-visible.md |
| task | RISK-WP-0006-T04 | done | — | workplans/RISK-WP-0006-keep-review-obligations-visible.md |
| task | RISK-WP-0006-T05 | done | — | workplans/RISK-WP-0006-keep-review-obligations-visible.md |
| task | RISK-WP-0007-T01 | done | — | workplans/RISK-WP-0007-reconcile-owner-evidence.md |
| task | RISK-WP-0007-T02 | done | — | workplans/RISK-WP-0007-reconcile-owner-evidence.md |
| task | RISK-WP-0007-T03 | done | — | workplans/RISK-WP-0007-reconcile-owner-evidence.md |
| task | RISK-WP-0007-T04 | done | — | workplans/RISK-WP-0007-reconcile-owner-evidence.md |

View file

@ -77,9 +77,12 @@ condition: 'true'
action:
task_template: 'risk-nexus: work the register due list'
description: >-
Run `make due` in risk-nexus, then work each listed finding through the five
Run `make due` in risk-nexus, then work each due finding through the five
questions in docs/method/check-procedure.md and record the outcome with
`make checked`. Findings at the `instant` rung are due immediately; the
`make checked`. Also review due regulatory records and full policies,
re-decide due embargoes, and reconcile pending publication handovers,
including closed findings, per docs/method/check-procedure.md.
Findings at the `instant` rung are due immediately; the
ladder climbs only on a clean check. Escalate only what
docs/method/escalation.md says to escalate, batched into one operator
conversation. If nothing is due, that is a complete run and worth nothing

View file

@ -40,6 +40,18 @@ Then, per due finding:
be met while the embargo still holds, if a sibling finding would be exposed
by publishing (`RISK-F-0003`).
Also work the non-finding obligations printed by `make due`: review the sources
and activation context for each due regulatory determination or full policy;
re-decide due embargoes; and reconcile pending publication handovers with the
publication owner's evidence, including for closed findings. Regulatory reviews
use `make checked ARGS="<RISK-REG-or-RISK-POL-id> clean|moved ..."` after the
review. A handover report is not authorization to publish embargoed content.
Index validation failure does not suppress later `make check` stages. Read the
reports before regenerating the index. A successful regeneration is not a
review outcome. Invalid date fields remain work to repair rather than evidence
that a check is current.
Then record it, in the same sitting:
```

View file

@ -0,0 +1,104 @@
---
id: RISK-V-0003
type: verification
title: "Owner-source progress and outstanding runtime evidence"
date: "2026-09-05"
owner: risk-nexus
workplan: RISK-WP-0007
findings: [RISK-F-0011, RISK-F-0010, RISK-F-0008]
---
# Owner-source review — 2026-09-05
This is a checkout and inbox review, not a runtime probe. No credentials were
used or reproduced, no system was changed and no legal determination was renewed.
Files can include uncommitted owner work; repository HEAD is context, not proof
that every inspected change is in that commit.
## Qonto deny-stream completeness
Read State Hub notice `c6442eef-34fc-46a7-9639-10f2cd6120fc` (2026-09-04),
QONTO-WP-0005, `specs/audit-emission-cadence.yaml`, `src/qonto_assistant/audit.py`,
the application lifespan/reconciliation endpoint, and KG-WP-0005.
The source now declares process instance/sequence semantics, a 24-hour default
active-process heartbeat, startup and best-effort shutdown, and reconciliation
counts. AuditLogger serializes emission and exposes source counters; the app
wires the heartbeat lifecycle and identity-checked snapshot route. Qonto records
88 passing tests on its latest review; that suite was not rerun by risk-nexus.
King's Guard records local source-path validation and explicitly leaves
KG-WP-0005-T03 waiting for authorized deployed evidence.
**Conclusion:** the old statement that no source cadence/reconciliation exists
is obsolete. Runtime completeness remains unestablished. F-0011 stays open,
medium and public, with QONTO-WP-0005 and KG-WP-0005-T03 as tracking.
**Closure evidence owed:** qonto's runtime owner supplies a bounded capture from
one deployed instance, naming the deployed revision, configured heartbeat
interval and observation window. It covers startup, a request transition,
periodic heartbeat timing, sequence/instance continuity and a same-instance
reconciliation snapshot. King's Guard compares received counts and source counts,
records any gaps and the acceptance decision. Evidence may support only the
observed instance/window, never an unbounded all-time completeness claim.
The original 2026-09-16 default remains; a completed source plan does not close
the runtime finding. This narrows the existing evidence request; no new request
or message was sent in this sitting.
## Backup credential
Read RPF-WP-0029 and inspected `tools/cmd/forgejo-backup` in memory for the
named shell fallback without outputting credential-bearing lines. No nonempty
literal fallback for `RAILIANCE_BACKUP_NC_TOKEN` remains in that script.
The owner records fail-closed input tests as complete under T01. T02 is `wait`:
provider-side invalidation and encrypted upload/restore receipts are absent.
**Conclusion:** source removal is established in the checkout; predecessor
invalidation is not. F-0010 stays open, low and embargoed. RPF-WP-0029-T02 names
the remaining provider/recovery work. The 2026-09-15 embargo review/default
stands. No inference is made about whether the predecessor is still valid.
Only non-secret invalidation, governed ciphertext upload and restore receipts
can complete the remaining evidence; source removal alone cannot lift the hold.
## Accepted retention obligation
Read the existing acceptance and determination references in F-0008 and
`audit-core/docs/erasure-and-audit.md`. Audit Core still documents the
cleartext-hash confirmation problem and says keyed commitments are not built.
No new answer to the co-residency horizon or keyed-commitment wait was present
in the fetched risk-nexus inbox. This is not proof that no answer exists elsewhere.
F-0008 already has a named accepter, an ending condition, a real determination
and a next check. The reporting problem is classifying that accepted obligation
as an untracked fix. The report should expose its existing acceptance terms
without inventing engineering work or treating acceptance as closure. Its
substantive review remains due: this sitting does not establish that the
real-person/counterparty trigger has not fired and does not renew the legal basis.
## External intake and scheduled reviews
Searched policy-nexus publication configuration, workplans and deployment files
for a security contact/security.txt or delivered external-report route. None
was found in those inspected sources. The existing intake proposal remains the
available evidence; current public endpoints and estate-wide contact availability
were not verified. Publishing a new contact requires its actual receiving owner.
Searched activity-core's local definitions and evidence for the two risk register
activities. No matching execution receipt was found in those paths. The two
definitions in risk-nexus remain source instructions. Their live registration,
execution and completed-session chain are unverified; this search is not proof
that the activities do not run. No deployment or synchronization was attempted.
## Source provenance
| Inspected source | SHA-256 of the non-secret document |
| --- | --- |
| qonto-assistant QONTO-WP-0005 | `f3b21ed7d046e7a4e5e8eee1397dcdcf1a17211f75786da3a0a2258b44802c3a` |
| qonto-assistant cadence declaration | `69db6068b2e262f6b9108903cf7c5a7764efba5c981344c50df496018bc98ed9` |
| qonto-assistant audit.py | `573e669914ae2ae77dfbf0a0929ef080cfbcb7dd4e0ba79e9408dd401fd74437` |
| railiance-platform RPF-WP-0029 | `396d2e167b8bd1141671fadd864660a1e8bc6efb1ea3a09be3465e841ce33144` |
| audit-core erasure-and-audit.md | `40d0f86ad401c3fb413fb21346a77210b6840d52f05093b31143a11b8a3a878b` |
Observed HEADs: qonto `e5611147fd72a23e58618b87b0c3b96c807d0043`,
railiance-platform `f637989a6911a7a13812cba223ffc007d78d6302`,
audit-core `95dcb78e17d46889c17b55e3ba1aadbcceec6a99`,
policy-nexus `c1b60f322e3bcddff3cece618ece2bd3686169e1`.

View file

@ -365,3 +365,17 @@ achievable. An accepted risk still gets checked.
- **2026-08-20** — not clean: Trigger list ruled: no external determination in build mode; accepted with the legal policy set as the compensating control. Cadence instant → instant; checked again immediately.
- **2026-09-01** — not clean: the regulatory record now states target periods per category; the remaining gap is whether platform-pg co-residency can achieve them, while the keyed-commitment question is unchanged. Grade and acceptance hold. Cadence instant → instant; checked again immediately.
- **2026-09-02** — clean check: acceptance, RISK-REG-0001, and the audit-core keyed-commitment wait unchanged. Cadence instant → 1h (1 clean in a row); next check 2026-09-02 09:11Z.
## Evidence inspection — 2026-09-05 (review remains due)
[RISK-V-0003](../docs/verifications/2026-09-05-open-findings-source-review.md)
records a source/inbox inspection. The technical owner still documents the
cleartext-hash limitation; no new answer to the existing wait appeared in the
fetched risk-nexus inbox. The report now displays this record's existing
accepter, ending condition, determination and review date as a recorded
acceptance obligation, rather than inventing a fix plan to fill `fix_tracking`.
This is not a clean check or a renewed acceptance. Whether the real-person or
counterparty condition has fired, and the substantive regulatory review, remain
unestablished here. The overdue review, existing grade and acceptance terms are
preserved; absence of a new inbox answer cannot certify the condition false.

View file

@ -12,7 +12,9 @@ date_filed: "2026-08-23"
system: railiance-platform
environment: production
fix_owner: railiance-platform
fix_tracking: unset
fix_tracking: RPF-WP-0029-T02
closure_condition: "provider invalidation plus governed ciphertext upload and restore receipts; source fallback removal alone does not lift the embargo"
verification: RISK-V-0003
# Graded by risk-nexus 2026-09-01 — docs/rulings/2026-09-01-inbox-sweep.md
severity: low
severity_at_production: low
@ -25,20 +27,20 @@ embargo_condition: "the provider credential is revoked or invalidated and the li
embargo_since: "2026-09-01"
embargo_review: "2026-09-15"
escalation: none
last_checked: "2026-09-02T08:11:17Z"
next_check: "2026-09-02T09:11:17Z"
cadence: 1h
clean_streak: 1
last_checked: "2026-09-05T00:05:51Z"
next_check: "2026-09-05T00:05:51Z"
cadence: instant
clean_streak: 0
waiting_on:
- who: railiance-platform
what: "revoke or invalidate the provider credential, remove the source default, name fix tracking, and demonstrate governed ciphertext upload plus restore"
what: "complete RPF-WP-0029-T02: revoke or invalidate the provider credential and demonstrate governed ciphertext upload plus restore; source fallback removal is established"
since: "2026-09-01"
would_change: "the finding becomes fixed and the embargo lifts"
default: "the low grade and embargo stand; missing fix tracking is recorded as a stalled remediation"
default: "the low grade and embargo stand; absent provider invalidation and recovery evidence is recorded as a stalled remediation"
default_at: "2026-09-15"
graded_by: risk-nexus
ruling: RISK-RULING-2026-09-01-A
checked_by: "grok/risk-nexus"
checked_by: "codex/risk-nexus"
---
# RISK-F-0010 — Forgejo backup source embeds a WebDAV credential default
@ -118,7 +120,21 @@ does not soften the assessment.
Reasoning: `docs/rulings/2026-09-01-inbox-sweep.md`.
## Source remediation reconciled — 2026-09-05
RPF-WP-0029-T01 records source fallback removal and fail-closed input checks.
This register confirmed the named fallback is absent in the current script
without displaying or testing any credential. RPF-WP-0029-T02 remains `wait`
for provider invalidation and governed encrypted upload/restore receipts.
[RISK-V-0003](../docs/verifications/2026-09-05-open-findings-source-review.md)
records the boundary: source removal does not establish invalidation of the
predecessor. Open, low, embargoed and no escalation remain appropriate on the
available evidence. The 2026-09-15 review/default is unchanged. The historical
source-default statements above describe the earlier assessments.
## Reviews
- **2026-09-01** — graded from the filed report and a redacted current-source check. The literal default remains; no fix record was found. Cadence starts at instant.
- **2026-09-02** — clean check: literal source default remains; no fix tracking; embargo and 2026-09-15 wait unchanged. Cadence instant → 1h (1 clean in a row); next check 2026-09-02 09:11Z.
- **2026-09-05** — not clean: Confirmed source fallback removal and RPF-WP-0029 tracking; provider invalidation and encrypted upload/restore receipts remain pending. Low grade and embargo retained; see RISK-V-0003. Cadence 1h → instant; checked again immediately.

View file

@ -12,7 +12,9 @@ date_filed: "2026-09-02"
system: qonto-assistant
environment: production
fix_owner: qonto-assistant
fix_tracking: unset
fix_tracking: QONTO-WP-0005 / KG-WP-0005-T03
closure_condition: "authorized deployed-instance capture accepted by kings-guard: heartbeat timing, sequence continuity and same-instance reconciliation"
verification: RISK-V-0003
# Graded by risk-nexus 2026-09-02 — docs/rulings/2026-09-02-qonto-deny-stream.md
severity: medium
severity_at_production: medium
@ -29,20 +31,20 @@ revision: "graded-1"
last_reviewed: "2026-09-02"
review_interval: 6m
escalation: none
last_checked: "2026-09-02T07:20:00Z"
next_check: "2026-09-02T07:20:00Z"
last_checked: "2026-09-05T00:05:51Z"
next_check: "2026-09-05T00:05:51Z"
cadence: instant
clean_streak: 0
waiting_on:
- who: qonto-assistant
what: "publish a heartbeat or emission-cadence declaration and a reconciliation view for the audit.deny stream, or reject that obligation"
what: "supply runtime-owner deployed-instance capture for kings-guard acceptance under KG-WP-0005-T03; source cadence and reconciliation now exist"
since: "2026-09-02"
would_change: "a published cadence plus a reconciliation view would let a later observation support completeness; a rejection keeps the grade and records that estate observation must not treat the stream as complete"
default: "the medium grade stands; missing cadence is recorded as a stalled remediation, and observation remains staffed with completeness pending"
would_change: "accepted deployed-instance evidence supports bounded stream completeness and permits closure; source-only evidence keeps the finding open"
default: "the medium grade stands; missing deployed acceptance is recorded as a stalled remediation, and observation remains staffed with completeness pending"
default_at: "2026-09-16"
graded_by: risk-nexus
ruling: RISK-RULING-2026-09-02-A
checked_by: "grok/risk-nexus"
checked_by: "codex/risk-nexus"
---
# RISK-F-0011 — qonto-assistant audit.deny stream completeness is not established
@ -141,6 +143,22 @@ wait makes that last statement expire.
Reasoning: `docs/rulings/2026-09-02-qonto-deny-stream.md`.
## Source remediation reconciled — 2026-09-05
The missing-source statements above describe intake, not the current checkout.
QONTO-WP-0005 is finished: cadence, heartbeat lifecycle, instance/sequence fields
and an identity-checked reconciliation view now exist. King's Guard's local
source-path checks are recorded complete, but KG-WP-0005-T03 waits for an
authorized deployed capture. Notice `c6442eef-34fc-46a7-9639-10f2cd6120fc`
explicitly requests independent deployed-stream acceptance before closure.
[RISK-V-0003](../docs/verifications/2026-09-05-open-findings-source-review.md)
records the inspected evidence and bounded acceptance requirements. Status
remains open, medium, public, no escalation: deployed completeness is still
unknown, with no evidence of suppression or an authorization bypass. The
2026-09-16 default is retained, now describing the actual remaining obligation.
## Reviews
- **2026-09-02** — graded from the Gate House intake, the named conformance review, and a current-source check of qonto-assistant. Local lockout is in-process; the emitted deny stream still has no cadence or reconciliation view. Cadence starts at instant.
- **2026-09-05** — not clean: Reviewed owner notice, cadence/logger/endpoint and KG-WP-0005; source remediation exists, deployed-instance acceptance remains pending under KG-WP-0005-T03. See RISK-V-0003. Cadence instant → instant; checked again immediately.

View file

@ -0,0 +1,192 @@
---
type: history
title: "Repository scope against INTENT: capabilities and remaining gaps"
date: "2026-09-05"
assessed_at: "2026-09-05T01:43:33+02:00"
author: codex
repo: risk-nexus
source_revision: "29f50d5143afc8c9d9884810dc34e39adf6edd43"
---
# Scope against intent
The repository implements a usable, manually operated risk register with
reporting aids. It does not yet deliver the full intended assurance that known
risks cannot go quiet, regulation stays current, or reports can arrive from any
source. [SCOPE.md](../SCOPE.md) was absent and has been created to describe the
actual capability and its dependencies.
This assessment reads the local implementation, records and workplans, and runs
read-only reports. It does not re-grade findings, verify external fixes, check
publication endpoints, or reassess the legal correctness of regulatory texts.
External operational claims below are identified as recorded or unverified.
The timestamp prefix uses Europe/Berlin; the inspection timestamp is
2026-09-04 23:43:33 UTC. The existing modified Python bytecode file was left alone.
## INTENT ownership claims
| INTENT claim | Assessment | Evidence and boundary |
| --- | --- | --- |
| Finding intake from research, review, incident and external report | Partial | [Filing contract](../findings/README.md), eleven finding files and observation-sourced F-0011 demonstrate internal intake. [Incident/external method](../docs/method/intake.md) supplies a procedure but records the external contact as only routed. No intake service or incident clock is implemented here. |
| Severity and triage | Implemented as a judgement workflow | [Severity method](../docs/method/severity.md), dated rulings and all three live records carry grades. Tools surface absent grades but do not compute or independently verify them. |
| Remediation tracking: owner, state and stalls | Partial | [Fix tracker](../tools/fix_tracker.py) reads supported owner workplans and flags inactivity. All three live findings currently report no fix tracking; local workplan commits are only a progress proxy. |
| Disclosure timing and deliberate holds | Implemented records; partial follow-through | [Disclosure method](../docs/method/disclosure.md) and F-0010 record a conditional embargo. Public/pending/published metadata distinguishes decisions from delivery, but embargo review deadlines and pending publication are not actively checked. |
| Regulatory intake and retained research | Partial | [Regulatory collection](../docs/regulatory/README.md) retains one determination; the [policy catalogue](../docs/regulatory/policies/README.md) names thirteen positions, four written in full. Policy review dates are outside tool discovery. |
| Written escalation rule and operator attention | Rule implemented; delivery procedural | [Escalation method](../docs/method/escalation.md) defines triggers and delivery states. The checker prints pending and seven-day-unacknowledged items; it does not send, retry, acknowledge or apply defaults. |
The intended boundaries are substantially preserved: no remediation service,
publication host, legal-advice service or canon authority has been added.
Verification is bounded by the [verification method](../docs/method/verification.md).
There is a wording conflict to resolve: the adopted review method says re-scoring
occurs before a production declaration completes, while INTENT excludes delivery
blocking and the proposed transition method says it does not gate the event.
No delivery gate is implemented.
## Gaps and concrete completion criteria
### 1. The review entry point can suppress the overdue reports
**Priority: high. Owner: risk-nexus.** `make check` fails on stale `REGISTER.md`
before running the register or inbox checker. The index embeds today's date and
time-dependent due labels ([generator](../tools/register_index.py)), so the
passage of time alone can stop the operational report. The direct checker
currently reports all three live findings overdue and a two-day heartbeat gap.
Separate index validation from report execution so a stale index still exposes
due work, heartbeat and inbox evidence. Completion means the stale-index case
reports both the failure and the operational work list. Actual overdue reviews
must be performed with evidence; regenerating the index cannot satisfy them.
### 2. Regulatory policies can silently expire outside the review loop
**Priority: high. Owner: risk-nexus.** `register_lib.regulatory()` uses a
non-recursive `docs/regulatory/*.md` scan. All four full policies are nested in
`policies/`, have `next_check: 2026-08-20T21:30:00Z`, and are omitted from both
the due report and `record_check.py`'s eligible records. Method review intervals
likewise have no general due-date reporting. This contradicts INTENT's retained,
non-silently-expiring regulatory knowledge requirement.
Discover and review the full policy records, make them eligible for recorded
outcomes, and define how method review dates are maintained. Distinguish the
nine catalogue-only entries from sourced determinations, with owners and dates
for elaboration when activation approaches. Completion means an overdue nested
policy appears in the work list and can receive a recorded review.
### 3. External and incident intake remain incomplete in operation
**Priority: high. Owners: risk-nexus; policy-nexus and the-custodian for contact delivery.**
The intake method still says no external contact exists and describes a routed
proposal. Local evidence establishes neither a delivered contact nor a tested
external-to-register path; it does not establish the current state of the whole
estate. Incident fields and urgent timing are prose only: the tools do not
process `incident` or `first_observed`, enforce incident cadence, or report the
notification deadline described by the method. No incident-marked finding was
found in this checkout.
Obtain evidence of a discoverable contact and a report reaching triage. Add
deadline handling for incident records and demonstrate an urgent intake exercise
with an owner and escalation record. The legal basis for any deadline remains
subject to the regulatory record's own review; this assessment does not validate it.
### 4. Remediation visibility is incomplete for the live register
**Priority: high. Owners: risk-nexus and the named system owners.** F-0010,
F-0011 and accepted F-0008 all have unset tracking. The inbox check finds a newer
F-0011 remediation notice naming QONTO-WP-0005, so the register is demonstrably
behind incoming evidence. The notice is not proof the defect is fixed.
Read and reconcile that evidence, obtain the applicable tracking records, and
record an explicit reviewable acceptance obligation where a fix plan is not
appropriate. The tracker resolves only a workplan ID syntax and expected file
layout, uses whole-file commit time rather than task transitions, and does not
verify deployed state. Completion means every live finding has an actionable
tracking or acceptance record and inactivity remains visible independently of
register check frequency. Task shorthand and archived completed-status handling
also need care: the parser requires full IDs, and the appended `[archived]`
suffix prevents the current exact completed-state comparison from matching.
### 5. Expiry, escalation and execution still depend on an attending session
**Priority: high. Owners: risk-nexus; activity-core for execution evidence.**
The tools report lateness and suggested actions but do not apply them. A heartbeat
printed by the same command nobody runs cannot provide independent delivery
assurance. The two activity definitions request work; their presence does not
prove scheduler registration, execution, session completion or operator receipt.
The observed overdue records show the intended cadence is not currently reflected
in recorded outcomes. No escalation is presently reported as awaiting an answer.
Demonstrate scheduled instruction delivery through to a completed review, and an
independently visible missed-run condition. Demonstrate acknowledgement and the
single permitted re-raise/default path for an escalation. Human judgement should
remain required; reliable delivery need not automate grading or send repeated nags.
### 6. Disclosure and production obligations are recorded but not fully followed
**Priority: medium. Owners: risk-nexus, policy-nexus and the-custodian.**
The checker lists embargo conditions but never compares `embargo_review` with
the clock. It does not list pending publication handovers; eight findings have
that state, including fixed records outside the normal live watch list. Two
findings are marked published; those metadata were not verified against a site.
The [production definition](../docs/method/production-transition.md) remains
`proposed`, contains historical counts and refers to F-0007's former acceptance
although that finding is now fixed. The checker reports only live flagged
findings (currently F-0008), not an event-driven acceptance expiry or policy
activation process.
Completion means due embargo decisions and pending handovers remain actionable
independently of closure; the custodian settles the transition definition and
conflicting declaration wording; an event record identifies the applicable
re-scores, acceptance decisions and policy activations without silently adding a gate.
### 7. Coverage measures mentions, not whether systems have been assessed
**Priority: medium. Owners: risk-nexus with estate inventory owners.**
[coverage.py](../tools/coverage.py) combines system, owner and reporter strings,
including values such as `estate` and `per-consumer, on request`. It has no
last-assessed date, assessment scope or evidence for a clean assessment. Thus a
mentioned repo is not necessarily assessed, and an unmentioned repo is unknown.
The current inventory request did not yield a denominator; the historical
7-of-117 count must not be presented as current coverage.
Record assessment provenance and dates against canonical repo identities, with
explicit unknowns. Completion means a clean assessment, a reported defect and
an unassessed system can be distinguished without turning this repo into the
estate's scanner or remediation team.
## What good looks like: current result
- **Known gaps have severity and owner:** met for the recorded live findings;
completeness across the estate is unproven.
- **Applicable regulation is found before needed:** not established. The
[previous assessment](2026-08-21-intent-gap-analysis.md) records retrospective
discovery of already-live obligations. A catalogue improves retrieval but
does not erase that history or provide ongoing horizon scanning.
- **Stalled fixes are visible while stalled:** partially supported by a local
file reader, presently limited by missing tracking and overdue reviews.
- **Necessary operator judgement is reached without noise:** procedures and
historical rulings exist; current end-to-end delivery assurance is unverified.
- **Findings expire or escalate; the register stays readable:** the small
register and note floor are implemented. Timely follow-through remains a
process requirement rather than a guaranteed outcome.
[WP-0005](../workplans/RISK-WP-0005-close-the-intent-gaps.md) and STATE.md call the
previous seven gaps closed. The delivered tools and procedures are real progress,
but routing a contact request, drafting a transition definition, printing a
heartbeat and counting mentions do not establish those end-to-end outcomes.
Historical completion records were preserved; this assessment records the
remaining capability gaps rather than rewriting their history.
## Verification results
| Read-only check | Observed result |
| --- | --- |
| `PYTHONDONTWRITEBYTECODE=1 make check` | Failed at stale index, Make exit 2; subsequent report stages did not execute. |
| `PYTHONDONTWRITEBYTECODE=1 python3 tools/register_check.py` | Exit 0; three live findings, all overdue by about 6264 hours; two-day heartbeat warning; three missing fix trackers; one overdue top-level regulatory record; no pending operator escalations. |
| `PYTHONDONTWRITEBYTECODE=1 make fixes` | Exit 0; all three live findings report `NO FIX TRACKING`. |
| `PYTHONDONTWRITEBYTECODE=1 python3 tools/inbox_check.py` | Exit 0; nine messages returned, including a newer F-0011 remediation notice dated 2026-09-04. No messages were acknowledged or sent. |
| `PYTHONDONTWRITEBYTECODE=1 make coverage` | Exit 0; eleven distinct mention strings; inventory endpoint unavailable within the tool's attempts, so current denominator unknown. The separate inbox request succeeded. |
Warnings returning zero are advisory output, not a clean bill of health. The
review tools were run directly after the stale-index failure to inspect their
results without regenerating unrelated files or claiming reviews had happened.

View file

@ -0,0 +1,157 @@
import contextlib
import datetime as dt
import io
import pathlib
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "tools"))
import check_all
import fix_tracker
import record_check
import register_check
import register_lib as lib
NOW = dt.datetime(2026, 9, 5, tzinfo=dt.timezone.utc)
class ReviewWorkflowTests(unittest.TestCase):
def report(self, findings=(), regulatory=()):
output = io.StringIO()
with patch.object(lib, "findings", return_value=list(findings)), \
patch.object(lib, "regulatory", return_value=list(regulatory)), \
patch.object(lib, "records_with_waits", return_value=[]), \
patch.object(fix_tracker, "report", return_value=[]), \
patch.object(register_check, "NOW", NOW), contextlib.redirect_stdout(output):
self.assertEqual(register_check.main(), 0)
return output.getvalue()
def test_all_stages_run_after_failure(self):
for failed_stage in range(3):
results = [subprocess.CompletedProcess([], int(i == failed_stage)) for i in range(3)]
with patch.object(check_all.subprocess, "run", side_effect=results) as run, \
contextlib.redirect_stdout(io.StringIO()):
self.assertEqual(check_all.main(), 1)
self.assertEqual(run.call_count, 3)
self.assertTrue(run.call_args_list[-1].args[0][1].endswith("inbox_check.py"))
def test_all_success_and_spawn_failure(self):
with patch.object(check_all.subprocess, "run", return_value=subprocess.CompletedProcess([], 0)), \
contextlib.redirect_stdout(io.StringIO()):
self.assertEqual(check_all.main(), 0)
with patch.object(check_all.subprocess, "run", side_effect=[OSError("unavailable"),
subprocess.CompletedProcess([], 0), subprocess.CompletedProcess([], 0)]) as run, \
contextlib.redirect_stdout(io.StringIO()):
self.assertEqual(check_all.main(), 1)
self.assertEqual(run.call_count, 3)
def test_nested_policy_discovered_reported_and_reviewable(self):
with tempfile.TemporaryDirectory() as directory:
root = pathlib.Path(directory)
policies = root / "docs/regulatory/policies"
policies.mkdir(parents=True)
(policies / "README.md").write_text("Catalogue without front-matter")
policy = policies / "example.md"
policy.write_text('---\nid: RISK-POL-9999\nnext_check: "2026-08-20"\n'
'cadence: instant\n---\n\n# Policy\n')
with patch.object(lib, "REPO", root):
records = lib.regulatory()
self.assertEqual([r["id"] for r in records], ["RISK-POL-9999"])
self.assertIn("RISK-POL-9999 — due", self.report(regulatory=records))
with patch.object(lib, "findings", return_value=[]), patch.object(lib, "now", return_value=NOW), \
contextlib.redirect_stdout(io.StringIO()):
self.assertEqual(record_check.main(["RISK-POL-9999", "clean", "review evidence"]), 0)
reviewed = lib.load(policy)
self.assertEqual(reviewed["cadence"], "1h")
self.assertIn("review evidence", policy.read_text())
def test_invalid_dates_do_not_abort_reports(self):
finding = dict(id="RISK-F-9999", _path=pathlib.Path("test.md"), status="open",
next_check="not-a-date", severity="high", cadence="instant")
report = self.report([finding], [dict(id="RISK-POL-9999", next_check="bad")])
self.assertIn("next_check is not a date", report)
self.assertIn("RISK-POL-9999 — invalid date", report)
self.assertIn("Publication handovers pending", report)
self.assertIsNone(lib.moment("2026-99-99"))
self.assertEqual(lib.moment("2026-09-05T00:00:00"), NOW)
def test_regulatory_deferral_expires_and_bad_date_stays_visible(self):
policy = dict(id="RISK-POL-9999", next_check="2026-08-20", deferred_to="2026-09-06")
self.assertIn("Regulatory records due:\n none", self.report(regulatory=[policy]))
policy["deferred_to"] = "2026-09-04"
self.assertIn("RISK-POL-9999 — due", self.report(regulatory=[policy]))
policy["deferred_to"] = "bad"
self.assertIn("invalid date: deferred_to", self.report(regulatory=[policy]))
def test_disclosure_obligations_survive_closure(self):
findings = [dict(id="RISK-F-9998", _path=pathlib.Path("a.md"), status="fixed",
disclosure="embargoed", embargo_condition="owner verifies", embargo_review="2026-09-01"),
dict(id="RISK-F-9999", _path=pathlib.Path("b.md"), status="fixed",
disclosure="public", publication="pending-handover")]
report = self.report(findings)
self.assertIn("RISK-F-9998 — embargo review due", report)
self.assertIn("RISK-F-9999 (fixed) — pending policy-nexus", report)
findings[0].pop("embargo_review")
self.assertIn("missing or invalid embargo_review", self.report(findings))
findings[0]["embargo_review"] = "2027-01-01"
self.assertIn("Embargo reviews due:\n none", self.report(findings))
def test_bad_deferral_does_not_write_and_review_clears_old_deferral(self):
with tempfile.TemporaryDirectory() as directory:
path = pathlib.Path(directory) / "record.md"
original = '---\nid: RISK-F-9999\ncadence: instant\ndeferred_to: "2027-01-01"\n---\n'
path.write_text(original)
with patch.object(lib, "findings", side_effect=lambda: [lib.load(path)]), \
patch.object(lib, "regulatory", return_value=[]), patch.object(lib, "now", return_value=NOW), \
contextlib.redirect_stdout(io.StringIO()):
for value in ("bad", "2020-01-01"):
with self.assertRaises(SystemExit):
record_check.main(["RISK-F-9999", "defer", value, "operator reason"])
self.assertEqual(path.read_text(), original)
record_check.main(["RISK-F-9999", "moved", "new evidence"])
self.assertNotIn("deferred_to", lib.load(path))
def test_archived_completed_fix_is_not_stalled(self):
with tempfile.TemporaryDirectory() as directory:
root = pathlib.Path(directory)
archive = root / "owner/workplans/archived"
archive.mkdir(parents=True)
(archive / "260901-TEST-WP-0001-fix.md").write_text(
'---\nid: TEST-WP-0001\nstatus: finished\nrepo: owner\n---\n')
finding = dict(id="RISK-F-9999", status="open", severity="high", fix_tracking="TEST-WP-0001")
with patch.object(fix_tracker, "ESTATE", root), patch.object(lib, "findings", return_value=[finding]), \
patch.object(lib, "now", return_value=NOW), \
patch.object(fix_tracker, "last_commit", return_value=NOW - dt.timedelta(days=100)):
report = "\n".join(fix_tracker.report())
self.assertIn("finished [archived]", report)
self.assertNotIn("UNCHANGED", report)
def test_accepted_obligation_requires_a_resolvable_basis_and_review(self):
finding = dict(id="RISK-F-9999", status="accepted", fix_tracking="unset",
accepted_by="operator", accepted_until="real data arrives",
determination="RISK-REG-9999", next_check="2026-08-01")
with patch.object(lib, "findings", return_value=[finding]), \
patch.object(lib, "regulatory", return_value=[dict(id="RISK-REG-9999")]):
report = "\n".join(fix_tracker.report())
self.assertIn("RECORDED ACCEPTANCE", report)
self.assertIn("not a fix or renewed acceptance", report)
self.assertNotIn("NO FIX TRACKING", report)
finding["next_check"] = "bad"
self.assertIn("ACCEPTANCE INCOMPLETE: next_check", "\n".join(fix_tracker.report()))
self.assertIn("NO FIX TRACKING", "\n".join(fix_tracker.report()))
finding["next_check"] = "2026-08-01"
with patch.object(lib, "findings", return_value=[finding]), patch.object(lib, "regulatory", return_value=[]):
self.assertIn("resolvable determination", "\n".join(fix_tracker.report()))
def test_completed_source_does_not_hide_closure_evidence(self):
finding = dict(id="RISK-F-9999", _path=pathlib.Path("test.md"), status="open",
fix_tracking="TEST-WP-0001 (finished)", closure_condition="runtime acceptance receipt")
report = self.report([finding])
self.assertIn("Closure evidence pending:\n RISK-F-9999 — runtime acceptance receipt", report)
if __name__ == "__main__":
unittest.main()

25
tools/check_all.py Normal file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env python3
"""Run all read-only checks, retaining failures without hiding later reports."""
import pathlib
import subprocess
import sys
TOOLS = pathlib.Path(__file__).resolve().parent
STAGES = (("register_index.py", "--check"), ("register_check.py",), ("inbox_check.py",))
def main() -> int:
failed = False
for stage in STAGES:
try:
result = subprocess.run([sys.executable, str(TOOLS / stage[0]), *stage[1:]])
failed = result.returncode != 0 or failed
except OSError as exc:
print(f"{stage[0]}: could not run: {exc}", flush=True)
failed = True
print(flush=True)
return int(failed)
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -68,6 +68,7 @@ def resolve(fix_tracking: str) -> list[dict]:
"id": full,
"repo": fm.get("repo", path.parent.parent.name),
"state": (state or "unreadable") + (" [archived]" if archived else ""),
"completed": str(state).lower() in ("done", "finished", "cancel"),
"workplan_status": fm.get("status"),
"moved": last_commit(path),
})
@ -81,6 +82,22 @@ def report() -> list[str]:
continue
tracking = f.get("fix_tracking")
if not tracking or str(tracking).startswith("unset"):
if f.get("status") == "accepted":
missing = [key for key in ("accepted_by", "accepted_until", "determination")
if not f.get(key) or str(f[key]) == "unset"]
if lib.moment(f.get("next_check")) is None:
missing.append("next_check")
determinations = {r.get("id") for r in lib.regulatory()}
if f.get("determination") and f["determination"] not in determinations:
missing.append("resolvable determination")
if not missing:
lines.append(
f"{f['id']} — RECORDED ACCEPTANCE by {f['accepted_by']}; "
f"ends when: {f['accepted_until']}; basis {f['determination']}; "
f"review {f['next_check']} (not a fix or renewed acceptance)"
)
continue
lines.append(f"{f['id']} — ACCEPTANCE INCOMPLETE: {', '.join(missing)}")
lines.append(f"{f['id']} ({f.get('severity')}) — NO FIX TRACKING; owner {f.get('fix_owner')}")
continue
resolved = resolve(tracking)
@ -93,7 +110,7 @@ def report() -> list[str]:
if r["moved"]:
age = (now - r["moved"]).days
window = STALL_DAYS.get(f.get("severity"), 30)
done = str(r["state"]).lower() in ("done", "finished", "cancel")
done = r.get("completed", False)
flag = "" if done or age <= window else f" ← UNCHANGED {age}d (window {window}d)"
lines.append(f"{f['id']}{r['id']}: {r['state']}, last changed {r['moved']:%Y-%m-%d}{flag}")
else:

View file

@ -57,6 +57,8 @@ def main(argv: list[str]) -> int:
fail("`defer` needs a date and the operator's reason")
until, why = rest[0], rest[1]
new_rung, streak, nxt = rung, int(f.get("clean_streak", 0)), lib.moment(until)
if nxt is None or nxt <= now:
fail("`defer` needs a valid future date")
line = f"- **{now:%Y-%m-%d}** — deferred to {until} by explicit operator decision: {why}"
defer = until
else:
@ -71,6 +73,8 @@ def main(argv: list[str]) -> int:
}
if defer:
subs["deferred_to"] = defer
else:
text = re.sub(r"(?m)^deferred_to:.*\n", "", text)
for key, value in subs.items():
quoted = f'"{value}"' if key not in ("cadence", "clean_streak") else value
if re.search(rf"(?m)^{key}:", text):

View file

@ -16,7 +16,8 @@ NOW = lib.now()
def main() -> int:
fs = [f for f in lib.findings() if lib.watched(f.get("status"))]
all_findings = lib.findings()
fs = [f for f in all_findings if lib.watched(f.get("status"))]
lines: list[str] = []
def section(title: str, rows: list[str], quiet: str) -> None:
@ -50,9 +51,9 @@ def main() -> int:
# reported by name, and never silently ignored.
ids = {f["id"] for f in lib.findings()}
malformed: list[str] = []
for f in fs:
for f in all_findings:
fid = f["id"]
for field in ("last_checked", "next_check", "embargo_since", "deferred_to"):
for field in ("last_checked", "next_check", "embargo_since", "embargo_review", "deferred_to", "escalation_sent"):
if f.get(field) and lib.moment(f[field]) is None:
malformed.append(f"{fid}{field} is not a date: {f[field]!r}")
if (c := f.get("cadence")) and c not in lib.CADENCE_NAMES:
@ -147,6 +148,10 @@ def main() -> int:
# RISK-WP-0005-T01: the fix's own state, read from the owner's workplan
# file rather than from our memory of what they told us.
section("Fix state", fix_tracker.report(), "no finding claims a tracked fix")
section("Closure evidence pending", [
f"{f['id']}{f['closure_condition']}"
for f in fs if f.get("closure_condition")
], "none recorded")
if due_defaults:
section("Defaults now due — apply them", due_defaults, "none")
if deep:
@ -154,11 +159,26 @@ def main() -> int:
embargo = [
f"{f['id']} — lifts when: {f.get('embargo_condition')}"
for f in fs
for f in all_findings
if f.get("disclosure") == "embargoed"
]
section("Embargoed", embargo, "none")
embargo_due = []
for f in all_findings:
if f.get("disclosure") != "embargoed":
continue
when = lib.moment(f.get("embargo_review"))
if when is None:
embargo_due.append(f"{f['id']} — missing or invalid embargo_review; re-decide the hold")
elif NOW >= when:
embargo_due.append(f"{f['id']} — embargo review due {f['embargo_review']}; re-decide the hold")
section("Embargo reviews due", embargo_due, "none")
section("Publication handovers pending", [
f"{f['id']} ({f.get('status')}) — pending policy-nexus handover: {f.get('publication_id', 'no publication id')}"
for f in all_findings if f.get("publication") == "pending-handover"
], "none")
# T05 — an escalation nobody acknowledged is indistinguishable from one
# never sent, which is the failure this register fixed for its own inbox
# and not, until now, for the path that matters more.
@ -184,6 +204,14 @@ def main() -> int:
reg = []
for r in lib.regulatory():
invalid = [field for field in ("last_checked", "next_check", "review_by", "deferred_to")
if r.get(field) and lib.moment(r[field]) is None]
if invalid:
reg.append(f"{r.get('id')} — invalid date: {', '.join(invalid)}; review required")
continue
until = lib.moment(r.get("deferred_to"))
if until and NOW < until:
continue
when = lib.moment(r.get("next_check")) or lib.moment(r.get("review_by"))
if when is None:
reg.append(f"{r.get('id')} — no next_check set")

View file

@ -82,7 +82,7 @@ def regulatory() -> list[dict]:
d = REPO / "docs" / "regulatory"
if not d.exists():
return []
return sorted((load(p) for p in d.glob("*.md") if p.name != "README.md"),
return sorted((load(p) for p in d.rglob("*.md") if p.name != "README.md"),
key=lambda r: r.get("id", ""))
@ -112,7 +112,12 @@ def moment(value) -> dt.datetime | None:
if isinstance(value, dt.date):
return dt.datetime.combine(value, dt.time(0, 0), tzinfo=dt.timezone.utc)
if isinstance(value, str) and value not in ("", "unset"):
return dt.datetime.fromisoformat(value.replace("Z", "+00:00")).astimezone(dt.timezone.utc)
try:
parsed = dt.datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError:
return None
return (parsed.replace(tzinfo=dt.timezone.utc) if parsed.tzinfo is None
else parsed.astimezone(dt.timezone.utc))
return None

View file

@ -0,0 +1,130 @@
---
id: RISK-WP-0006
type: workplan
title: "Keep review obligations visible when the index or records are stale"
domain: infotech
repo: risk-nexus
status: finished
owner: the-custodian
topic_slug: risk-nexus
created: "2026-09-05"
updated: "2026-09-05"
depends_on_workplans:
- RISK-WP-0005
state_hub_workstream_id: "900ba790-c5b8-523c-947f-5cd743fa1d58"
---
# RISK-WP-0006 — keep review obligations visible
## Problem and priority
The [scope assessment](../history/2026-09-05-014333-scope-intent-assessment.md)
found that `make check` stops before showing overdue work, all four full legal
policies are outside review discovery, and disclosure obligations disappear
from the work list. These are the first priorities: they hide known obligations
and can be corrected within this repository without a new service or mandate.
Malformed dates must not defeat the repaired reporting path.
## Tasks and acceptance
### T01 — Run every check stage even if another fails
```task
id: RISK-WP-0006-T01
status: done
priority: high
state_hub_task_id: "44f58905-fc81-571f-b112-e37001b02ed9"
```
Run index, register and inbox checks independently, preserving a nonzero result
if any stage fails. A stale index and a broken register stage must still allow
the inbox stage to run. No regeneration or grading as a side effect.
### T02 — Include full policies in the review workflow
```task
id: RISK-WP-0006-T02
status: done
priority: high
state_hub_task_id: "4a9cd603-7722-5e3b-833e-b65109f33d8a"
```
Discover nested regulatory records, excluding README catalogues. Full policies
must appear when due and accept recorded outcomes. `make due` must expose these
obligations to existing scheduled sessions, not filter them out. Invalid dates
must be reported without aborting the report; invalid deferrals must not write.
### T03 — Keep disclosure obligations visible after closure
```task
id: RISK-WP-0006-T03
status: done
priority: high
state_hub_task_id: "3d250ebe-1d06-55f2-a4cc-8a716b12414f"
```
Report due or missing embargo review dates and pending publication handovers
across all findings, including fixed findings. Surface them through `make due`.
Do not publish, lift embargoes or change finding statuses automatically.
### T04 — Correct the archived fix completion signal
```task
id: RISK-WP-0006-T04
status: done
priority: medium
state_hub_task_id: "79b0c627-9fff-59e2-a400-8d3e9585504b"
```
An archived completed workplan must not be reported as an unchanged unfinished
fix just because its display status carries an archive suffix. Preserve the
archive label and the documented whole-file timestamp limitation.
### T05 — Verify, document and reconcile registration
```task
id: RISK-WP-0006-T05
status: done
priority: high
state_hub_task_id: "96d06e61-84e7-5c3a-9d79-b700408afaf7"
```
Add focused regression tests for the failures above using isolated files and
mocked external reads. Run them and the live read-only reporting path. Update
SCOPE, usage and the operational instructions, and reconcile the workplan and
task records with State Hub. Record actual registration results and residuals.
## Scope boundary and next priorities
This plan repairs visibility, not the overdue substantive reviews themselves.
External intake delivery, urgent incident handling, scheduler-to-session delivery
proof and the production declaration require separate operational decisions or
cross-repository work. They remain open in the assessment. Missing fix records
and the F-0011 notice require evidence reconciliation, not automatic closure.
No legal conclusions, grades, acknowledgements or messages are generated here.
## Verification and completion evidence
Implementation complete for T01T04. Eight isolated regression tests pass via
`make test`, covering stage failures, nested policy discovery and recorded
reviews, invalid dates and deferrals, disclosure after closure, and archived
completed fixes. `git diff --check` passes.
Live validation first ran with a stale index: every report still executed and
Make returned nonzero. After `make register`, `make check` and `make due` both
returned zero while exposing all four overdue policies, eight pending handovers,
three overdue findings and the newer F-0011 inbox notice. No finding or policy
was stamped reviewed, re-graded or closed.
Registration: the normal CLI and an outside-sandbox retry timed out on State Hub
reads. A longer-timeout full reconciliation was stopped after prolonged API
reads without a completion result. Targeted registration succeeded
through the same workplan/task API and deterministic IDs used by the reconciler.
The workplan UUID is `900ba790-c5b8-523c-947f-5cd743fa1d58`; all five task
UUIDs are recorded beside their source blocks. Completion and the file binding
are synchronized through the API; the local index uses the reconciler renderer.
Residuals: external contact delivery, incident clocks, independent execution
assurance, substantive overdue reviews, method review scheduling and production
transition decisions remain open. The updated activity definition is local
source; deployment/synchronization to activity-core was not performed.

View file

@ -0,0 +1,113 @@
---
id: RISK-WP-0007
type: workplan
title: "Reconcile owner evidence and keep runtime closure obligations visible"
domain: infotech
repo: risk-nexus
status: finished
owner: the-custodian
topic_slug: custodian
created: "2026-09-05"
updated: "2026-09-05"
depends_on_workplans:
- RISK-WP-0006
state_hub_workstream_id: "ac12733f-3f4b-5c7b-aee7-7115b9c4db72"
---
# RISK-WP-0007 — reconcile owner evidence
The repaired reports expose work the register had not read. Reconcile it before
building another mechanism. Source remediation is progress; deployed acceptance
and credential invalidation require their own evidence.
## T01 — Reconcile the qonto return
```task
id: RISK-WP-0007-T01
status: done
priority: high
state_hub_task_id: "d3f0a9b7-4374-5350-b0b4-d7ac4f782acb"
```
Read the newer inbox notice, source cadence/logger/endpoint and observer workplan.
Link QONTO-WP-0005 and KG-WP-0005-T03 to F-0011; replace the stale missing-source
claim with the concrete runtime acceptance obligation. Keep the medium grade
and open status until that obligation is demonstrated. Record a moved check.
## T02 — Reconcile backup source remediation
```task
id: RISK-WP-0007-T02
status: done
priority: high
state_hub_task_id: "215b8b0b-aef0-5575-bf12-b08dc2941cbe"
```
Read RPF-WP-0029 and verify source fallback removal without displaying, testing
or copying credential material. Link provider invalidation/recovery tracking;
keep the low grade, open status and embargo until the original conditions hold.
Record a moved check, retaining the existing deadline.
## T03 — Distinguish accepted obligations from missing fixes
```task
id: RISK-WP-0007-T03
status: done
priority: high
state_hub_task_id: "a17feb05-2c2c-5372-adbb-9d2c095f55fd"
```
Report an accepted record's accepter, expiry condition, determination and review
date when those fields resolve to a real record. Do not invent a fix workplan
for F-0008 or suppress incomplete acceptance records. Surface closure conditions
even when the source workplan is completed. Cover both paths with regression
tests. Inspect F-0008's technical evidence without renewing legal conclusions
or certifying that its real-data trigger remains false.
## T04 — Record verification boundaries and register the result
```task
id: RISK-WP-0007-T04
status: done
priority: medium
state_hub_task_id: "ebf1edad-6e0e-5fdc-9781-5e79cff8b117"
```
Retain dated source evidence, explicit next evidence and owners. Inspect local
external-intake/publication and activity evidence; state exactly what remains
unverified. Update scope/state/index, run tests and reports, register this
workplan and its tasks, and verify completion in State Hub.
## Boundaries
No messages, acknowledgements, deployments, credential actions, publication,
new spending or automatic finding closure. Existing source-owner workplans
remain authoritative. This plan closes the register's reconciliation work,
not the owners' unresolved runtime obligations or the substantive legal reviews.
## Completion evidence
Completed 2026-09-05. RISK-V-0003 retains the inspected source evidence,
provenance and runtime/provider acceptance requirements. F-0011 now tracks
QONTO-WP-0005 and KG-WP-0005-T03; F-0010 tracks RPF-WP-0029-T02. Both received
`moved` outcomes and remain at `instant`; no same-sitting clean check was made.
Grades, open statuses, the credential embargo and original default dates remain.
F-0008's technical inspection is explicitly not a completed substantive review.
Its existing acceptance is now reported with its determination and due date;
invalid/incomplete acceptances still produce missing-tracking warnings. The
closure-evidence section survives completed source workplans.
Ten isolated tests pass via `make test`; document links and `git diff --check`
pass. The generated register and live checker expose the two waiting owner tasks,
recorded acceptance, four overdue full policies and eight publication handovers.
State Hub registration succeeded for workplan
`ac12733f-3f4b-5c7b-aee7-7115b9c4db72` and all four tasks (UUIDs in source).
Completion status and backing-file binding are reconciled through the same API;
the local WORK-RECORDS index is regenerated with the State Hub renderer.
Still external or unverified: runtime capture/observer acceptance, provider
invalidation/recovery receipts, acceptance-trigger facts and legal reviews,
external contact delivery and scheduled-session completion. Source searches
establish no stronger conclusion. No messages or acknowledgements were sent.