--- id: KG-WP-0003 type: workplan title: "Evidence completeness and live observation" domain: infotech repo: kings-guard status: finished owner: kings-guard topic_slug: netkingdom created: "2026-08-29" updated: "2026-09-01" source_review: history/2026-08-29-layer-model-v0.7-scope-intent-review.md standard: net-kingdom/canon/standards/security-layer-model_v0.7.md state_hub_workstream_id: "a6c1c760-1386-58fa-9392-d9c3c4dadc41" --- # Evidence completeness and live observation Close the gap between what `INTENT.md` and `SCOPE.md` now claim under Security Layer Model v0.7 and what `src/kings_guard/` actually does. Carries G1–G8 of `history/2026-08-29-layer-model-v0.7-scope-intent-review.md`. Two things are being fixed. The repository consumes evidence and treats a quiet stream as a healthy one, which the statute now forbids (§9.6). And statute §12's fourth step — *kings-guard observes it in operation* — is unstaffed, because every input is a fixture. ## Boundaries this workplan does not cross - **No actuation.** kings-guard proposes containment and never performs it (§9.2). T06 makes proposals reconstructable; it does not make them act. - **No Tooling contact.** `dependencies = []` stays empty; `make check-layer` must stay green on every task. `qonto-assistant` publishes its own stream and is not a Tooling row, so T07 needs no engine in the path. - **No engine gap worked around.** Identity and secret observation stay at zero. ## Dependency order ```text T01 evidence classification -> T02 emission-cadence declaration (draft, handed to Taxonomy) -> T03 stream-completeness evaluation -> T04 completeness in the posture output T05 immune memory is not a state plane (independent) T06 proposals carry their origin (independent) T07 live observation (independent; makes the rest real) T08 agent-principal conformance checks (after T05) ``` ## Task: Classify consumed evidence load-bearing or attributive ```task id: KG-WP-0003-T01 status: done priority: high state_hub_task_id: "dd660dbf-9148-5f35-aa4a-74deb10e6f8a" ``` Statute §9.6 attaches different obligations to each class, and the repository currently records neither. `ImmuneObservation` carries `source_system` and no class; `SecurityGenome` declares no sources at all. Done when: - the evidence class is expressible on a declared source and on an observation; - `specs/ImmuneContracts.md` states the obligation difference — a load-bearing source MUST declare a cadence, an attributive source SHOULD — and states that the class is the source's declaration, not kings-guard's inference; - the `qonto-assistant` fixture declares a class for its audit stream, with the reasoning recorded; - tests cover both classes. **Done 2026-09-01:** `DeclaredEvidenceSource` on the genome and `evidence_class` on `ImmuneObservation`. The adapter copies the source declaration and refuses to infer class from event contents. qonto `audit.deny` / `audit.heartbeat` are load-bearing; `audit.allow` is attributive, with reasoning in the fixture. `tests/test_evidence_class.py` covers both classes. ## Task: Draft the emission-cadence declaration and hand it to Taxonomy ```task id: KG-WP-0003-T02 status: done priority: high state_hub_task_id: "5b66aec0-a753-5039-bcbe-bc69cf1ad13e" ``` Statute §17 requires the artifact and records kings-guard as its drafter, being its only consumer. Ownership stays with Taxonomy. Inventing a local shape is the drift §17 exists to prevent, so this is a draft for handover, not an internal schema. Must cover both forms, because one does not substitute for the other: - an **expected rate** for volume classes; - **reconciliation or a heartbeat** for low-volume load-bearing classes — revocations, denials, containment actions — where rate monitoring cannot work because a suppressed month is indistinguishable from a quiet one. The required property is a positive claim that can itself go missing. Done when: - the draft lives in `specs/` and is written against `qonto-assistant` as the one real source; - it explains where the declaration belongs — alongside the security genome, on the argument that expected cadence is a claim of intent like the rest of the genome — and why; - `GH-WP-0002-T04` is referenced as the reference instance for the heartbeat form; - it is sent to gate-house and to the Taxonomy repositories for ownership, and the handover is recorded. **Done 2026-09-01:** Draft at `specs/EmissionCadenceDeclaration.md`, worked example against `qonto-assistant`, both forms specified, genome-adjacent rationale stated, `GH-WP-0002-T04` / `approval-engine/cadence.yaml` cited as the heartbeat reference. Runtime consumer is `src/kings_guard/fixtures/qonto_assistant_cadence.json` (draft-shaped, not a fork). Handover messages sent to `gate-house`, `net-kingdom`, and `info-tech-canon`. ## Task: Evaluate the stream, not only the observation ```task id: KG-WP-0003-T03 status: done priority: high state_hub_task_id: "2cd878c0-8b70-5f2b-9f82-c4d74df5833c" ``` `PostureEvaluator.evaluate()` is stateless and per-observation. An event that is never emitted is never evaluated, so the last posture stands and suppression biases posture optimistic. Silence must become a finding in its own right. Done when: - a stream-level evaluation path exists alongside the per-observation one; - an unmet declared cadence produces a finding; - a missing heartbeat, or a reconciliation divergence between the source's own state transitions and the evidence count per class, produces a finding; - the findings are distinguishable from content findings — the stream observed, not its contents; - no Tooling contact is introduced; the source publishes its own stream. **Done 2026-09-01:** `PostureEvaluator.evaluate_stream` / `evaluate_with_stream` compare a declared cadence to arrived events. Unmet rate, missing heartbeat, and reconciliation divergence emit `stream:*` findings, distinct from content findings, and a `stream_completeness` signal. No Tooling client. Tests in `tests/test_stream.py`. ## Task: Carry stream completeness in the posture output ```task id: KG-WP-0003-T04 status: done priority: high state_hub_task_id: "73367acf-d888-5acc-ae85-7231a9cbe9fe" ``` `confidence_score` starts at 70 and rises with field richness of the record received. It measures the record, never the stream: a well-formed observation from a 90%-suppressed stream scores 85. The judgment must be able to say *this rests on a stream I cannot vouch for.* Done when: - completeness is separated from richness in `PostureAssessment`; - an unmet cadence or missing heartbeat degrades the completeness dimension; - the rationale text says so in words, not only in a number; - a posture derived from an incomplete stream can never read as more trustworthy than one derived from a complete one. **Done 2026-09-01:** `PostureAssessment` carries `stream_completeness` and `completeness_reason` separately from `confidence_score`. Rationale states completeness in words. `assessment_trust_key` orders completeness above richness, so a 95-from-degraded stream cannot outrank a 70-from-complete one. `tests/test_completeness.py`. ## Task: State and test that immune memory is not a state plane ```task id: KG-WP-0003-T05 status: done priority: medium state_hub_task_id: "d7ed9faf-58ee-59a1-ad1e-b2fcf817317f" ``` Statute §3.4 rule 3: agent memory, tool-call traces and prompt caches MUST NOT become state another layer depends on at runtime unless catalogued as Tooling. `ImmuneMemoryEntry` has no such rule, and `INTENT.md` stage 5 (federated memory) is exactly the shape that could drift into one. Done when: - `specs/ImmuneContracts.md` states it: immune memory informs kings-guard's own judgment and may be published as evidence; no engine, PEP or workload may read it as a runtime input, and making it one is a §4 Tooling catalog change; - a test asserts the constraint rather than leaving it to prose; - the constraint is reflected in the `Direction of Evolution` stage-5 entry. **Done 2026-09-01:** `ImmuneMemoryEntry.runtime_input_for_other_layers` is `forbidden`. `specs/ImmuneContracts.md` states the rule. `tests/test_immune_memory.py` asserts the evaluator does not take memory as input and that INTENT stage 5 keeps the constraint. ## Task: Make containment proposals reconstructable to their origin ```task id: KG-WP-0003-T06 status: done priority: medium state_hub_task_id: "98326ed2-ee5f-58ce-9f99-429e621117a6" ``` §9.2 rules that a containment action is a decision record, not a side channel. `EffectorRequest` names a target and an action and carries no reference to what produced it, so once a proposal leaves this repository it cannot be tied back to the observation that caused it. Done when: - an effector request carries the originating observation and signal identity; - the eventual decision record can name what the proposal was rendered for; - `docs/AdjacentSystemBoundary.md` states the expectation on the receiving side; - the authority boundary remains explicit and no value widens authority. **Done 2026-09-01:** `EffectorRequest` carries originating observation and signal ids, stream completeness, and a restrictive direction. Authority boundaries in use remain `advisory_only` and `metadata_only`. Applied `gate-house/docs/contracts/posture-findings-return.md` through this task. `docs/AdjacentSystemBoundary.md` rule 7 states the receiving-side expectation. `tests/test_effector_origin.py`. ## Task: Observe qonto-assistant in operation ```task id: KG-WP-0003-T07 status: done priority: high state_hub_task_id: "ae516be8-5199-5f81-b47f-7843b5993f97" ``` Statute §12's fourth step is aspiration until this is done, and §19's verdict names kings-guard as the watching half of *can propose and decide but cannot watch or act*. Every input today is a hand-built fixture; ten tests pass and none has met a real event. Nothing blocks it. `qonto-assistant` publishes its own genome record and audit stream, needs no engine in the path, and its genome has not drifted since it was written. Done when: - real emitted audit events from `qonto-assistant` reach the evaluator; - the observation mapping is confirmed against real events or corrected, and the correction is reported back to `qonto-assistant`; - output stays advisory — posture hints and metadata-only evidence, nothing that actuates; - the fixture is retained as a regression case rather than deleted; - gate-house is told that step four is staffed, with what was found. **Done 2026-09-01:** Real events from `qonto-assistant.audit.AuditLogger` via `CapabilityService` (allow + deny) reach the evaluator. Mapping confirmed: `request_id`, `capability`→`resource_scope`, `decision`, `protocol` hold. Corrections reported to `qonto-assistant`: `AuditEvent` still omits `identity_binding` and `egress_destination`; no heartbeat is published yet, so deny-class completeness is unknown. Fixture retained. Output stays advisory. gate-house notified that §12 step four is staffed for this lane. `tests/test_live_qonto_observation.py`; `python3 -m kings_guard.main --pilot qonto-assistant --live`. ## Task: Check the agent-principal rules that can be checked ```task id: KG-WP-0003-T08 status: done priority: medium state_hub_task_id: "e7003fb3-2e7c-5440-b489-b619b3f0c65d" ``` All four §3.4 rules are now claimed in `INTENT.md` and none is verified. The no-Tooling-client claim showed the pattern: a claim in prose becomes a claim in a test, and the test carries the reason. Done when: - `scripts/check_layer_conformance.py` covers what is mechanically checkable — at minimum rule 1, no standing credential held in the repository or its configuration; - rule 3 is covered by T05; - rules that remain assertion rather than test are recorded as such in `layer.yaml`, honestly, rather than implied to be checked; - `make check-layer` stays green. **Done 2026-09-01:** `scripts/check_layer_conformance.py` scans for standing credential files and secret literals (rule 1). Rule 3 is `tests/test_immune_memory.py`. `layer.yaml` `agent_principal_rule_checks` records rule 2 as assertion and rule 4 as mixed. `make check-layer` green; `pyproject.toml` `dependencies = []`. ## Success criteria 1. Every task above is `done`. 2. `make test` and `make check-layer` both pass. 3. `pyproject.toml` still declares `dependencies = []`. 4. `INTENT.md` and `SCOPE.md` claim nothing the implementation does not do. 5. The emission-cadence draft has been handed to Taxonomy and the handover recorded. 6. gate-house has been told that §12's fourth step is staffed. ## Residuals No leftover kings-guard work is parked only in prose. Source-side follow-ups were sent as coordination messages, not new workplans here: - `qonto-assistant` — emit `identity_binding` and `egress_destination` on `AuditEvent` if they become known; publish the cadence declaration and a deny-class heartbeat. Until then deny-class completeness stays unknown. - Taxonomy (`net-kingdom`, `info-tech-canon`) — take ownership of `specs/EmissionCadenceDeclaration.md`. kings-guard will consume what they publish and will not fork it. - `secrets-engine` secret-use evidence contract — assented as a proposed Lifecycle surface; observation stays at zero until it ships. Not a WP-0003 residual. Pre-existing open intake `KG-IN-0002` (architecture vocabulary sweep) is unrelated and remains open.