Lgpd erasure coverage

LGPD Erasure — Conformance & Coverage Registry

Tracks which Koder components implement the cross-service erasure cascade contract per policies/identity-data-retention.kmd § R5 and specs/identity/erasure-flow.kmd.

When a user issues DELETE /v1/me on the Koder ID side, the request enters a 24-hour grace window then publishes identity.user.erased on the cross-service event bus. Every Koder component that stores data linked to a Koder ID subject *UST*subscribe to that event (or be explicitly opted out per the Skip table below) and apply the LGPD cascade — purge linked data, drop sessions, anonymize audit events for the 6-month forensics window.

This registry agglomerates the per-component conformance state. Pre-release release engineering MUST verify the row for the releasing component is at PASS (or PASS¹ — see the status enum) before tagging.

Status enum

Status Meaning Effect on AI / release engineering
*ASS* Listener wired into the longrunning entrypoint, cascade asserted endtoend against a real fixture (integration test green in CI), audit event emitted on koder:events:flowequivalent stream, regression suite locking the contract surface in place. Release engineering greenlights. AI can recommend the component as an LGPDcascade reference.
*ASS¹* Same as PASS *odulo a single deferred subticket*named in the notes — typically an endto-end integration test still landing while the listener + production store + audit emission + regression are already shipped. Release engineering greenlights with a followup gate (cited sub-ticket).
*ARTIAL* Some cascade elements live, others pending. Notes column enumerates what is and isn't. Release engineering blocks; sub-ticket required to close.
*ODO* Component stores KoderIDlinked data but no listener exists yet. Release engineering blocks; cascade ticket required before next major.
*/A* Component does not store KoderIDlinked data (read-only proxy, stateless renderer, etc.). Release engineering green-lights with no cascade requirement.
*KIP* Component is itself the identity provider (Koder ID) or otherwise outside the consumer surface — cascade contract does not apply. Release engineering green-lights.

Cascade surface

For each Koder component the registry tracks:

  • *istener*— the long-running goroutine that subscribes to

    the erasure stream

  • *tore*— production binding to the component's data layer

    (the adapter that actually deletes / anonymizes)

  • *udit*— completion-event emission (<service>.erasure.completed)

    on the canonical koder:events:<service> stream

  • *ntegration*— endtoend test against a real fixture
  • *egression*— structural test locking the contract surface
  • *iring*— listener actually booted from the entrypoint

A row is *ASS*when all six columns are green for the component's storage surface.

Components

# Date Component Status listener store audit integration regression wiring Notes
1 20260524 services/foundation/id/engine/services/auth *ASS* N/A Inprocess listener services/auth/internal/listener/erasure_listener.go consuming the same event bus directly inside idengine. No audit emission needed — idengine is the sourceof-truth for the cascade state.
2 20260524 services/foundation/id/engine/services/sso *ASS* N/A Sibling of #1; same architecture.
3 20260524 products/dev/flow/engine/services/erasure (Koder Flow) *ASS* *romoted PASS¹ → PASS on 20260524*when FLOW-135 shipped — endtoend cascade integration test landed in tests/integration/erasure_cascade_test.go (2 tests, both green in 5.5s against the standard XORM SQLite fixture). Full FLOW119 epic done (FLOW117 Phase 1 + FLOW130..139). Concrete coverage: *istener*services/erasure/listener.go (FLOW117 — 11 unit tests against fakeStore covering nolink/alreadypurgedhappy-pathlookuperror/purgeerrormalformed-envelope). *tore*[`serviceserasureproduction_store.go`](........productsdevflowengineserviceserasureproductionstore.go) (FLOW-131 — 1:1 adapter to `usermodel.GetUserIDByExternalUserID + usermodel.GetUserByID + userservice.DeleteUser(ctx, u, true), compile-time var _ FlowUserStore assertion). **audit** [serviceserasureaudit_publisher.go`](........productsdevflowengineserviceserasureauditpublisher.go) (FLOW-132 — emits flow.erasure.completed on koder:events:flow with `sourceeventid / flowuserid / flowusername / elapsedms data fields, best-effort semantics, 7 unit tests including 2 negative-firing assertions for no-link and already-purged paths). **integration** [testsintegrationerasurecascadetest.go`](........productsdevflowenginetestsintegrationerasurecascadetest.go) (FLOW135 — TestErasureCascade_RealForgejoData drives full cascade against fixture user 2 + linked Koder ID subject, asserts user row purged + externalloginuser gone + audit envelope shape; TestErasureCascade_NoLinkedUser_AckedNoOp asserts noop path doesn't emit audit). *egression*[`testsregressionerasure001noeventbusmirror.test.sh`](........productsdevflowenginetestsregressionerasure/001noeventbusmirror.test.sh) (FLOW136 — antimirrorreintroduction guard locking the FLOW130 Option A decision: go.mod require+replace pair, upstream import present, four types declared as aliases, Flownamespaced constants stay local; negativetested with struct injection). *iring*routers/init.go erasure.Boot(ctx) sibling of backup_scheduler.Boot(ctx) (FLOW133, RFC004 Phase 2 pattern), envvar + app.ini [flow_erasure] config plumbing (FLOW134 — setting.FlowErasure with KODER_FLOW_ERASURE_ENABLED + KODER_REDIS_URL + KODER_FLOW_ERASURE_CONSUMER_ID overrides). *I*.koder-flow/workflows/erasure-cascade.yml (FLOW137 — pathfiltered; structural + unit + integration jobs all active as of 20260524). *rivacy template*contrib/legal/privacy.html.sample §"Data Retention and Deletion of Data" rewritten 20260524 (FLOW138) to reflect the 24hgrace + cascade + 6monthanonymized contract (deployment to live instances gated on owner signoff per memory [KDS owner-curated content]). Authcoverage crossref: koder-id-auth-coverage.md Flow row 20260512. Production posture: cascade is dormant on flow.koder.dev until operator sets KODER_REDIS_URL (defaultoffonemptyURL per FLOW-133 boot logic).

Skipped components (explicit outofscope decisions)

Components reviewed and declared outside the LGPD cascade surface with rationale. A Skip is reversible — when concrete demand surfaces, open a new cascade ticket on the component and remove the row.

# Component Decision Rationale
S1 services/foundation/id (itself) *KIP*(20260524) Koder ID is the cascade source, not a consumer. The DELETE /v1/me endpoint + the cascade orchestrator + the 24hgrace timer + the bus publisher all live inside id/engine; there is no separate listener to write. The inprocess listeners in services/auth and services/sso (#1, #2 above) are separate Sectors counted independently.

Adding a new component

  1. The component stores data linked to a Koder ID subject (via

    external_login_user or equivalent). If not, the row is N/A with one-line rationale.

  2. Open a phase-1 ticket on the component for the listener +

    production store + unit tests (model: FLOW-117).

  3. Open phase2 subtickets following the FLOW-119 split

    (FLOW-130..139): eventbus dep decision, production_store, audit_publisher, startup wiring, config knobs, integration test, contract-drift regression, CI workflow, privacy template (if applicable), and this registry row.

  4. Reference the Flow row (#3) as a worked

    example.

Cross-references

Source: ../home/koder/dev/koder/meta/docs/stack/registries/lgpd-erasure-coverage.md