Raise AUDIT-WP-0010 — admit tenant-engine as an attributive sender
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Closes the path for AUDIT-IN-0002. tenant-engine emits through a local
outbox and cannot land production events until audit-core admits the
sender, so this is another repo's production blocked on ours — a
workplan of its own rather than a task inside AUDIT-WP-0009.

The request arrives with its bound already declared: attributive class,
non-blocking drain, trade documented at tenant-engine/docs/evidence-
emission.md. Under §9.6 that is legitimate. Nothing needs renegotiating;
it needs admitting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
This commit is contained in:
tegwick 2026-08-29 14:54:18 +02:00
parent ebe3307e1c
commit 9dff75e59e

View file

@ -0,0 +1,122 @@
---
id: AUDIT-WP-0010
type: workplan
title: "Admit tenant-engine as an attributive sender"
domain: infotech
repo: audit-core
status: ready
owner: claude
topic_slug: railiance
created: "2026-08-29"
updated: "2026-08-29"
depends_on:
- AUDIT-WP-0005
---
# AUDIT-WP-0010 — Admit tenant-engine as an attributive sender
## Goal
Close `AUDIT-IN-0002`. `tenant-engine` emits mutation evidence through a local
outbox and **cannot land events in production until audit-core admits the
sender**. This is another repository's production blocked on ours, which is why
it is a workplan of its own rather than a task inside `AUDIT-WP-0009`.
The request is well-formed and arrives with its own bound already declared:
class **attributive**, drain non-blocking, documented at
`tenant-engine/docs/evidence-emission.md`. Under §9.6 that is a legitimate
trade — attributive evidence may deliberately trade away atomicity provided the
trade is declared and completeness is never claimed. `tenant-engine` declared
it. Nothing here needs renegotiating; it needs admitting.
Intake: `AUDIT-IN-0002` (`01a04d8f-b1c1-746a-8007-15221ebf0a48`), origin
`TEN-WP-0011-T04`. Onboarding follows INTENT principle 4 — a source is onboarded
when ownership, retention, access, export, and evidence policy are declared and
validated, not when events start arriving.
## Non-goals
- Reclassifying `tenant-engine` as load-bearing. It declared attributive and the
declaration is the emitter's to make; §9.6 obligations follow the class.
- Carrying any credential value in this repository, in a work record, in State
Hub, or in chat. The intake says so and it is right.
- Blocking on `AUDIT-WP-0009-T03`. The `evidence_kind` field lands there;
admission does not wait for it, and T04 below records the class in the
meantime.
## Tasks
```task
id: AUDIT-WP-0010-T01
status: todo
priority: high
```
Register the sender identity: name `tenant-engine`, `sources: [tenant-engine]`,
`may_write: true`, `may_read: false`, `secret_policy: redact`, tenants scoped as
the envelope requires. Follow the existing `user-engine` shape in
`deploy/externalsecret-senders.yaml` and `deploy/senders-scope.yaml`. No token
value in Git — projected only, per the established lane.
```task
id: AUDIT-WP-0010-T02
status: todo
priority: high
```
Provide the token lane. Coordinate the projected credential with the owning
credential operator through the `ops-warden` route, matching the custody pattern
already used for `user-engine`. Verify field presence without disclosure. Do not
transport a value through State Hub messages.
```task
id: AUDIT-WP-0010-T03
status: todo
priority: high
```
Extend the NetworkPolicy. `deploy/networkpolicies.yaml` currently admits
`user-engine`; add `tenant-engine`. `tests/test_networkpolicies.py` exists —
extend it so the second sender is asserted rather than assumed, and so a future
third sender fails the test rather than silently failing in production.
```task
id: AUDIT-WP-0010-T04
status: todo
priority: medium
```
Validate the envelope against what `tenant-engine` actually sends:
`schema_version: audit-core.event.v1alpha1`, `tenant` = affected `tenant_id`,
`action` = domain event type, `resource` = `tenant:<id>`, duplicate event ids
returning 200. Confirm the duplicate path reconciles rather than minting a
second link (`test_replay_reconciles_rather_than_duplicating`). If the envelope
needs a field this engine does not send, reply with the correction the intake
invited rather than accepting a lossy record.
Record the declared class (**attributive**, non-blocking drain, trade declared
at `tenant-engine/docs/evidence-emission.md`) alongside the sender registration,
so the §9.6 trade is documented here and not only in the emitter.
```task
id: AUDIT-WP-0010-T05
status: todo
priority: medium
```
Prove it end to end against the production receiver: a real event from
`tenant-engine` accepted, attributed to the right tenant, redacted per policy,
and linked into the chain. Record the evidence under `docs/evidence/`. Then
close `AUDIT-IN-0002` with outcome `promoted` citing this workplan, and reply to
`tenant-engine`.
## Acceptance
- `tenant-engine` events land in production, correctly attributed and redacted.
- The token never appears in Git, a work record, State Hub, or chat.
- The NetworkPolicy admits exactly the intended senders, asserted by test.
- The attributive trade is recorded on audit-core's side, and completeness is
nowhere claimed for this stream.
- `AUDIT-IN-0002` closed and the requester answered.
## Notes
`tenant-engine` did this the right way round: it built the outbox, declared the
class honestly, documented the trade, and asked before assuming it could emit.
The correct response is to move quickly, not to make it wait behind
`AUDIT-WP-0009`.