From 8bda6e28b4aaf596c3a6f3efbef5cdd829a45732 Mon Sep 17 00:00:00 2001 From: codex Date: Sat, 22 Aug 2026 22:35:37 +0200 Subject: [PATCH] canon: resolve work-record governance packets --- WORK-RECORDS.md | 8 + canon/standards/work-record-types.yaml | 12 ++ canon/standards/work-record-types_v0.1.md | 20 ++- intakes.md | 32 ++++ tests/test_validate_work_records.py | 40 ++++- tools/validate_work_records.py | 15 +- .../CUST-WP-0063-inbox-governance-packets.md | 139 ++++++++++++++++++ 7 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 intakes.md create mode 100644 workplans/CUST-WP-0063-inbox-governance-packets.md diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index 4ea5136..218d3bc 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -61,6 +61,7 @@ | workplan | CUST-WP-0060 | finished | — | workplans/CUST-WP-0060-work-record-canonization.md | | workplan | CUST-WP-0061 | finished | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md | | workplan | CUST-WP-0062 | proposed | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md | +| workplan | CUST-WP-0063 | finished | — | workplans/CUST-WP-0063-inbox-governance-packets.md | | task | ADHOC-2026-05-02-T01 | done | — | workplans/ADHOC-2026-05-02.md | | task | ADHOC-2026-07-02-T01 | done | — | workplans/ADHOC-2026-07-02.md | | task | CUST-WP-0001-T01 | done | — | workplans/CUST-WP-0001-custodian-agent-runtime.md | @@ -399,6 +400,11 @@ | task | CUST-WP-0062-T04 | wait | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md | | task | CUST-WP-0062-T05 | wait | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md | | task | CUST-WP-0062-T06 | wait | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md | +| task | CUST-WP-0063-T01 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md | +| task | CUST-WP-0063-T02 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md | +| task | CUST-WP-0063-T03 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md | +| task | CUST-WP-0063-T04 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md | +| task | CUST-WP-0063-T05 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md | | intake | CUST-IN-0001 | closed | green | intake-legacy-suggestions-migration.md | | intake | CUST-IN-0002 | closed | green | intake-legacy-suggestions-migration.md | | intake | CUST-IN-0003 | closed | green | intake-legacy-suggestions-migration.md | @@ -409,3 +415,5 @@ | intake | CUST-IN-0008 | open | blue | intake-legacy-suggestions-migration.md | | intake | CUST-IN-0009 | open | blue | intake-legacy-suggestions-migration.md | | intake | CUST-IN-0010 | open | green | intake-legacy-suggestions-migration.md | +| intake | CUST-IN-0011 | open | red | intakes.md | +| intake | CUST-IN-0012 | open | green | intakes.md | diff --git a/canon/standards/work-record-types.yaml b/canon/standards/work-record-types.yaml index 0fd19ee..29c4f97 100644 --- a/canon/standards/work-record-types.yaml +++ b/canon/standards/work-record-types.yaml @@ -8,6 +8,10 @@ kinds: id_patterns: - "^[A-Z]+-WP-[0-9]{4}$" lifecycle: [proposed, ready, active, blocked, backlog, finished, archived] + legacy_patterns: + - pattern: "^MASON-0001$" + source: ops-mason bootstrap workplan created before WP infix convention + grandfathered: true - kind: task id_patterns: - "^[A-Z]+-WP-[0-9]{4}-T[0-9]{2,3}$" @@ -20,6 +24,9 @@ kinds: - pattern: "^[A-Z]+-WP-[0-9]{4}-LEGACY-T[0-9]{2}$" source: archived-workplan legacy task renumbering grandfathered: true + - pattern: "^MASON-0001-T[0-9]{2,3}$" + source: ops-mason bootstrap tasks created before WP infix convention + grandfathered: true - kind: intake id_patterns: - "^[A-Z]+-IN-[0-9]{4}$" @@ -49,6 +56,8 @@ kinds: - kind: register-entry id_patterns: - "^RISK-[0-9]{3}$" + - "^RISK-F-[0-9]{4}$" + - "^RISK-REG-[0-9]{4}$" - "^TD-[0-9]+$" - "^CAP-[0-9]+$" - "^CCR-[0-9]{4}-[0-9]{4}$" @@ -69,3 +78,6 @@ origin_values_recommended: residual: residual handoff: handoff legacy_suggestion_prefix: "legacy-suggestion:" +identity_reconciliation: + repeated_same_id_same_uuid: duplicate_source_occurrence + repeated_same_id_different_uuid: identity_collision diff --git a/canon/standards/work-record-types_v0.1.md b/canon/standards/work-record-types_v0.1.md index 28c28c0..83fe1ea 100644 --- a/canon/standards/work-record-types_v0.1.md +++ b/canon/standards/work-record-types_v0.1.md @@ -6,7 +6,7 @@ domain: custodian status: active version: "0.1" created: "2026-07-20" -updated: "2026-07-22" +updated: "2026-08-22" scope: fleet related_workplans: - CUST-WP-0060 @@ -58,12 +58,12 @@ attention_cost, …) extend the spine; they never replace it. | Kind | Id scheme | Meaning | Absorbs / legacy | | --- | --- | --- | --- | -| `workplan` | `{PREFIX}-WP-NNNN` | structured, dependency-bearing body of work | — | -| `task` | `{WP-ID}-TNN` (workplan) · `ADHOC-YYYY-MM-DD-TNN` | smallest executable unit | issue-core issues become external projections only | +| `workplan` | `{PREFIX}-WP-NNNN` | structured, dependency-bearing body of work | `MASON-0001` (single bootstrap record, grandfathered) | +| `task` | `{WP-ID}-TNN` (workplan) · `ADHOC-YYYY-MM-DD-TNN` | smallest executable unit | `MASON-0001-TNN` (grandfathered); issue-core issues become external projections only | | `intake` | `{PREFIX}-IN-NNNN` | spark: idea, finding, directive, request | hub suggestions (legacy, read-only close-out); `AWQ-NNN` (grandfathered) | | `decision` | `{PREFIX}-DEC-YYYY-NNN` | approval package + resolution | `DEC-YYYY-NNN` (binky, grandfathered as-is) | | `engagement` | `{PREFIX}-ENG-YYYY-NNN` | scheduled external interaction (counterparty, prepared material, time window) | `OH-YYYY-NNN` (grandfathered) | -| `register-entry` | existing schemes: `RISK-NNN`, `TD-…`, `CAP-…`, `CCR-YYYY-NNNN`, `ADR-NNN` | risks, technical debt, capability requests, credential change requests, architecture decisions | unchanged semantics, brought under the spine | +| `register-entry` | existing schemes: `RISK-NNN`, `RISK-F-NNNN`, `RISK-REG-NNNN`, `TD-…`, `CAP-…`, `CCR-YYYY-NNNN`, `ADR-NNN` | risks/findings, regulatory records, technical debt, capability requests, credential change requests, architecture decisions | unchanged semantics, brought under the spine | Rules: @@ -77,6 +77,13 @@ Rules: follows the legacy-meter discipline of `workplan-terminology-fleet_v0.1.md`. +Risk Nexus findings (`RISK-F-*`) and regulatory records (`RISK-REG-*`) are +registered as variants of `register-entry`, not as parallel work kinds. Their +lifecycles remain owned by the register convention. `RISK-N-*` notes are +deliberately not registered: a note has no lifecycle, so it does not meet the +core definition of a work record. A note becomes part of the backbone only +when an event promotes its substance into a lifecycle-bearing kind. + ## Identity layering - **UUIDv7 is primary** for bookkeeping, relations, dependencies, and @@ -87,6 +94,11 @@ Rules: required reading. - The hub writes the UUID back into the source file at first index (pattern: today's `state_hub_*_id` fields). +- A repeated source block with the same canonical id **and the same UUID** is + one record with duplicate source occurrences. Index it once, retain every + source location as diagnostic provenance, and report the duplication for + governed cleanup. The repetition must not mint a second record. The same + canonical id with different UUIDs is an identity collision and fails closed. ## Abstract lifecycles (canon-fixed, minimal) diff --git a/intakes.md b/intakes.md new file mode 100644 index 0000000..2ea4855 --- /dev/null +++ b/intakes.md @@ -0,0 +1,32 @@ +# Custodian intake records + +## CUST-IN-0011 — Provision a monitored external security-report Contact URI + +```yaml +id: CUST-IN-0011 +kind: intake +title: "Provision a monitored external security-report Contact URI" +status: open +lane: red +priority: high +owner: the-custodian +tags: [needs-human, compliance-relevant] +origin: residual +origin_ref: CUST-WP-0063 +notes: "The minimal RFC 9116 security.txt route is approved for policy.coulomb.social/.well-known/security.txt, with reports routed privately to risk-nexus and no bounty, response-time, or safe-harbour promise. Completion requires the operator to select and provision a real monitored Contact URI; no address may be invented or published before its receiving path is verified." +``` + +## CUST-IN-0012 — Repair the malformed legacy inbox message identity + +```yaml +id: CUST-IN-0012 +kind: intake +title: "Repair the malformed legacy inbox message identity" +status: open +lane: green +priority: low +owner: hub-core +origin: residual +origin_ref: CUST-WP-0063 +notes: "State Hub returns unread risk-nexus message id 0b8dd0bf-41d-47da-96ac-40e443c32e47, whose second UUID group has only three characters. PATCH /messages/{id}/read rejects it during UUID path parsing, so the already-handled superseded request cannot be marked read through the supported API. Repair must preserve the message body and chronology, assign or map a valid stable identity, and then apply the read transition without direct ad hoc database mutation from this repo." +``` diff --git a/tests/test_validate_work_records.py b/tests/test_validate_work_records.py index 51b8b8e..9f7ec04 100644 --- a/tests/test_validate_work_records.py +++ b/tests/test_validate_work_records.py @@ -4,7 +4,7 @@ Covers: - load_registry / classify — id pattern matching against the live canon registry, incl. grandfathered legacy schemes (AWQ-, DEC-, OH-, task - single-digit / -LEGACY- variants) + single-digit / -LEGACY- variants, and the exact MASON-0001 bootstrap) - load_validators — jsonschema-backed per-kind checks (intake, decision, engagement): required-field gates on non-terminal records, historical grace on terminal ones @@ -64,6 +64,8 @@ class TestClassify: ("DEC-2026-004", "decision"), ("OH-2026-003", "engagement"), ("CUST-WP-0060-T1", "task"), + ("MASON-0001", "workplan"), + ("MASON-0001-T01", "task"), ], ) def test_grandfathered_legacy_ids(self, kinds, legacy_id, expected_kind): @@ -72,6 +74,11 @@ class TestClassify: def test_unregistered_id_returns_none(self, kinds): assert classify("FOO-QX-001", kinds) is None + def test_risk_register_species(self, kinds): + assert classify("RISK-F-0008", kinds) == "register-entry" + assert classify("RISK-REG-0001", kinds) == "register-entry" + assert classify("RISK-N-0003", kinds) is None + class TestValidators: def test_intake_open_without_lane_errors(self, validators): @@ -305,6 +312,37 @@ class TestMainEndToEnd: assert result.returncode == 0, result.stdout assert "2 checked" in result.stdout + def test_mason_bootstrap_ids_pass_unmodified(self, tmp_path): + (tmp_path / "legacy-mason.md").write_text( + textwrap.dedent( + """ + ```yaml + id: MASON-0001 + title: "legacy Mason bootstrap" + status: finished + ``` + ```task + id: MASON-0001-T01 + status: done + priority: high + ``` + """ + ), + encoding="utf-8", + ) + result = self._run(tmp_path, "--strict") + assert result.returncode == 0, result.stdout + assert "2 checked" in result.stdout + + def test_task_fence_rejects_non_task_registered_id(self, tmp_path): + (tmp_path / "wrong-fence.md").write_text( + "```task\nid: CUST-WP-0063\nstatus: active\n```\n", + encoding="utf-8", + ) + result = self._run(tmp_path) + assert result.returncode == 1 + assert "registered as workplan, not task" in result.stdout + def test_terminal_record_grace_does_not_mask_structural_errors(self, tmp_path): """Historical grace waives missing-field ('required') errors on terminal records, but a genuine value violation (bad lane enum) diff --git a/tools/validate_work_records.py b/tools/validate_work_records.py index 25240ba..e947616 100644 --- a/tools/validate_work_records.py +++ b/tools/validate_work_records.py @@ -35,9 +35,8 @@ ID_LIKE_RE = re.compile(r"^[A-Z][A-Z0-9]*(-[A-Z0-9]+)+-?[0-9]*$") SKIP_DIRS = {".git", "node_modules", ".venv", "history", "agents_backup"} TERMINAL = {"closed", "resolved", "done", "cancel", "finished", "archived"} -# task blocks are validated inline (state-hub owns their full parsing) -TASK_ID_RE = re.compile(r"^([A-Z]+-WP-[0-9]{4}-(LEGACY-)?T[0-9]{1,3}" - r"|ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}-T[0-9]{2})$") +# task blocks are validated inline (state-hub owns their full parsing). The +# registry is the sole id-pattern authority, including grandfathered schemes. TASK_STATUS = {"wait", "todo", "progress", "done", "cancel", "in_progress", "blocked"} # aliases per migration window @@ -163,9 +162,13 @@ def main() -> int: f"species are sidetracks (work-record-types_v0.1)") continue checked += 1 - if fence == "task" or kind == "task": - if not TASK_ID_RE.match(rid): - errors.append(f"{rel}: task id '{rid}' malformed") + if fence == "task" and kind != "task": + errors.append( + f"{rel}: task fence id '{rid}' is registered as {kind}, " + "not task" + ) + continue + if kind == "task": st = block.get("status") if st is not None and st not in TASK_STATUS: errors.append(f"{rel}: {rid}: bad task status '{st}'") diff --git a/workplans/CUST-WP-0063-inbox-governance-packets.md b/workplans/CUST-WP-0063-inbox-governance-packets.md new file mode 100644 index 0000000..c7c97c1 --- /dev/null +++ b/workplans/CUST-WP-0063-inbox-governance-packets.md @@ -0,0 +1,139 @@ +--- +id: CUST-WP-0063 +type: workplan +title: "Resolve legacy identifier and Risk Nexus governance packets" +domain: infotech +repo: the-custodian +status: finished +owner: codex +topic_slug: custodian +created: "2026-08-22" +updated: "2026-08-22" +origin: handoff +origin_ref: "statehub-inbox:08067461-bb95-42e2-b8de-b492fb99f56e" +--- + +# Resolve legacy identifier and Risk Nexus governance packets + +Resolve the current Custodian inbox requests without renaming historical work +records or inventing an external security contact. The packet covers the +Ops Mason legacy `MASON-0001` scheme, Risk Nexus register species, the proposed +production-transition definition, and the minimal external-report route. + +The operator already ruled that Risk Nexus's lifecycle-bearing register +records must join the work-record backbone. The remaining canon judgment is +their placement under the existing `register-entry` kind and the exclusion of +notes, which deliberately have no lifecycle and therefore do not meet the +canon definition of a work record. + +## Triage the coordination packet against current canon + +```task +id: CUST-WP-0063-T01 +status: done +priority: high +``` + +Read the source residuals and proposals, current canon, validator behavior, +relevant Repo Manager ownership decisions, and the source records themselves. +Distinguish decisions that can be made from missing real-world inputs. + +## Extend the work-record registry and validator coverage + +```task +id: CUST-WP-0063-T02 +status: done +priority: high +``` + +Grandfather the exact `MASON-0001` workplan/task scheme. Register Risk Nexus +findings and regulatory records as `register-entry` schemes. Keep `RISK-N-*` +notes unregistered because they have no lifecycle. Make the validator consume +the registry as its sole task-id authority and add regression coverage. + +**Done (2026-08-22):** the machine registry and prose canon carry the exact +Mason schemes and the two Risk register species. The validator no longer has a +second hard-coded task-id grammar. Thirty-five focused tests pass; this repo is +strict-clean at 412 records; the live Ops Mason files classify the legacy ids +without a sidetrack warning. + +## Resolve repeated historical source identity + +```task +id: CUST-WP-0063-T03 +status: done +priority: high +``` + +Record that repeated source blocks carrying the same canonical id and same +hub UUID are one record with duplicate source occurrences, not two records. +Ask Repo Manager to index the UUID once, preserve both source locations as +diagnostic provenance, and reject creation of a second identity. + +**Done (2026-08-22):** canon and machine copy now distinguish a duplicate +source occurrence (same id, same UUID) from an identity collision (same id, +different UUID). Decision `3c487545-ee40-4049-89fa-34b41747a7eb` records the +ruling. Handoffs went to Ops Mason (`8e65a254`) and Repo Manager (`48eff8d3`). +The Ops Mason source intake also lacks its required `lane`; that exact local +correction was returned to its owner rather than silently changed here. + +## Resolve and route the Risk Nexus policy requests + +```task +id: CUST-WP-0063-T04 +status: done +priority: high +``` + +Adopt the proposed production-transition definition and Custodian declaration +authority. Approve the minimal RFC 9116 route at Policy Nexus, routed to Risk +Nexus, without adding a bounty, response-time promise, or safe-harbour policy. +Keep selection and provisioning of a real monitored Contact URI as a live +human-needed intake rather than publishing an invented address. + +**Done (2026-08-22):** decisions `051de446-7ae9-4eca-a766-14345655ab35` and +`937bf962-9297-40d5-a3e4-356532f179c7` adopt the production-transition +definition and approve the bounded RFC 9116 route. Risk Nexus received the +consolidated outcome in `477ec6f9`; Policy Nexus received its publication gate +in `2d86983b`. The missing real Contact URI remains live as `CUST-IN-0011`. + +## Close coordination and reconcile State Hub + +```task +id: CUST-WP-0063-T05 +status: done +priority: medium +``` + +Record decisions, send outcome messages, mark handled inbox messages read, +hand off every residual as a live work record, run repository verification, +and run `statehub fix-consistency`. + +Five of six unread source messages were marked read. The sixth has malformed +legacy id `0b8dd0bf-41d-47da-96ac-40e443c32e47`; the typed API rejects it +before the read transition. That repair is live residual `CUST-IN-0012` rather +than an invisible note. + +**Done (2026-08-22):** all handled messages are read where the API permits; +the malformed-id repair was routed to Hub Core in `ffc8d656`. The complete +repository suite passes (72 tests), strict work-record validation passes with +413 records, and `git diff --check` is clean. Final consistency reconciliation +regenerates the work-record index; identifier write-back is correctly deferred +to the single Repo Manager registrar after commit and push. + +## Closure Review + +The packet is resolved. Canon, machine registry, validator behavior, tests, +State Hub decisions, and owner handoffs now agree. No historical identifier or +UUID was rewritten. + +Two actionable leftovers are live records before closure: + +- `CUST-IN-0011` — select, provision, and receipt-test the monitored public + security Contact URI before Policy Nexus publishes `security.txt`; +- `CUST-IN-0012` — repair the malformed legacy message identity so its handled + request can transition to read through the supported API. + +Decision ids: `3c487545-ee40-4049-89fa-34b41747a7eb`, +`051de446-7ae9-4eca-a766-14345655ab35`, and +`937bf962-9297-40d5-a3e4-356532f179c7`.