DataTalksClub / DataTalksClub/website
Define the non-activating privacy kernel input contract
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Parent epic: #64
Authority-register prerequisite: #254
Blocked consumer: #255
Product outcome
Publish one immutable, machine-validated non-activating privacy-kernel input contract between the accepted #254 authority register and the #255 orchestration kernel. The contract supplies the exact policy identity, required-domain manifest identity and entries, exhaustive right/domain routing matrix, and bounded block/exception code catalogs that #255 must recognize. It never converts a source observation, planned right, or unresolved HUMAN/legal value into permission to process a real privacy request.
This is a source-only interface issue. Its first version is intentionally production-ineligible and fail-closed. It gives #255 a stable schema and identity to consume and reject safely while tests use explicitly synthetic activating fixtures. A later independently groomed, owner-authorized issue must publish a new immutable version before any production request can advance.
Why this is separate from #254
#254 owns the canonical legal/privacy authority register, source inventory, generated projection, and HUMAN/legal closure. Its frozen source-only candidate has an exact seven-path scope, engineer report, verification-plan identity, and independent security review. Adding a runtime-consumer contract now would materially change its schema, paths, acceptance criteria, and evidence envelope.
This issue therefore references #254 by immutable version/digest and adds no field to the frozen #254 candidate. It is not an acceptance, amendment, or rework authorization for that candidate. #254 continues through its own tester → PM → Refs #254 → merge/on-call lifecycle and remains open for HUMAN/legal closure.
Normative authority
_docs/PROCESS.md: raw intake, PM grooming, role-separated verification, source-only screenshot disposition, and immutable evidence envelopes._docs/specs/01-platform-architecture.md,_docs/architecture/app-boundaries.md, and_docs/architecture/shared-primitives.md: one deployment, domain ownership, shared application-service boundaries, idempotency/audit/durable-work primitives, and no cross-domain mutation._docs/specs/07-security-privacy-operations.md: named rights, full-erasure default, approved #23 facts, unresolved rights/hold/deadline/processor semantics, propagation, redaction, and restore fencing._docs/specs/10-verification-strategy.md: privacy contract, failure, redaction, and source-only evidence requirements._docs/specs/open-decisions.mddecision 12 and closed #23: the five accepted facts only; they do not approve domain-specific rights, deadlines, legal holds, or activation.- #64: privacy child ordering, adapter separation, fail-closed policy drift, and HUMAN gates.
- Accepted source-only slice of #254: sole authority/register and source-flow identity consumed by this issue.
- #255: downstream kernel consumer; its current prose is not authority for policy content and remains
needs groominguntil this issue is accepted and merged.
Dependency gate
Depends on the independently tested, PM-accepted, merged, and green-on-call source-only delivery of #254. Full HUMAN/legal closure of #254 is not required for this structural contract, but the exact accepted register_version, register_digest, source commit, schema, and flow IDs are required. Engineering must not start from the present frozen candidate or copy its provisional digest into this issue.
Any change to the accepted #254 register version/digest or referenced flow/gate IDs invalidates this candidate and requires regeneration, a new contract version, and fresh verification. Mutable branch names, issue prose, worktree paths, or an unmerged candidate digest are never valid authority identities.
Canonical files and ownership
This issue owns exactly four new source files:
_docs/legal/privacy-kernel-input-contract.json— sole hand-edited canonical kernel-input contract;_docs/legal/privacy-kernel-input-contract.schema.json— JSON Schema Draft 2020-12 structural contract;scripts/validate_privacy_kernel_input_contract.py— fail-closed semantic/cross-register validator;scripts/tests/test_privacy_kernel_input_contract.py— identity, coverage, matrix, code, drift, and redaction tests.
It may import the accepted #254 canonicalization helper but must not modify, duplicate, or shadow the #254 register/schema/renderer/validator. No generated Markdown copy, second manifest, Python policy constant, settings value, database row, fixture presented as production, or mutable “latest” alias is introduced.
Canonical identity and digest contract
The JSON has only these required top-level sections:
schema_version— integer1;contract_versionandcontract_digest;authority_register;activation;rights_catalog;policy;domain_manifest;right_domain_matrix;block_code_catalog;exception_code_catalog.
Versions are bounded immutable identifiers containing an ISO date plus positive revision. Digests are lowercase SHA-256 over UTF-8 canonical JSON using the accepted #254 deterministic key ordering, separators, Unicode, and self-digest omission rules. The full contract digest excludes only contract_digest; the policy digest excludes only its own digest; the manifest digest excludes only its own digest. Array order is canonical and semantically validated. Reordering, duplicate keys/rows, unknown fields, or mutable aliases fail.
authority_register pins the exact accepted #254 file path, schema_version, register_version, register_digest, inventory_as_of_commit, and required human-gate IDs. Validation loads that repository file and rejects any mismatch, missing gate/flow, unaccepted candidate identity, or source-register drift.
Non-activation contract
activation is exact and non-negotiable in version 1:
state:non_activating;production_processing_allowed:false;production_manifest_registered:false;production_policy_registered:false;synthetic_test_activation_allowed:trueonly for fixtures explicitly marked test-only and never loaded by production settings/registry discovery;blocking_human_gate_ids: every #254 HUMAN gate that affects rights, deadlines, holds/exceptions, notice, retention/propagation, or processor behavior;superseded_by:null.
The validator rejects true, active, an empty blocker set, a missing applicable #254 gate, or any wording/field that implies policy approval. No environment variable, runtime setting, startup registration, database seed, or default resolver may activate this artifact.
Rights catalog and naming boundary
The kernel catalog contains exactly these six #255 request-right identifiers:
accessportable_exportcorrectionrestrictionobjectionerasure
Each record pins its matching #254 register field (portable_export maps only to portability; the other five map by exact name), specification/issue authority IDs, and production_request_allowed: false. #254's withdrawal and publication_removal fields remain visible as coverage dependencies but are not silently aliased into a #255 right. Adding/removing/renaming a right requires a new issue and contract version.
Policy identity
policy contains a separate immutable policy_version and policy_digest, status exactly non_activating, the accepted #23 fact IDs copied by reference (never prose), every applicable unresolved #254 HUMAN-gate ID, and the exact pinned authority-register identity.
The policy section records only structural recognition:
- full erasure is the accepted default direction;
- the issued-real-name-certificate fact is a recognized exception code but remains block-only until its domain disposition/implementation is separately accepted;
- no deadline, appeal, escalation, legal-hold release, restriction/objection outcome, lawful basis, processor obligation, notice version, requester-proof rule, or production activation is supplied.
The validator rejects accepted/active/allowed states for those unresolved values, inferred notice/deadline values, free-form legal text, or a policy digest not bound to the exact #254 identity.
Required-domain manifest
domain_manifest contains its own immutable manifest_version, manifest_digest, status non_activating, and deterministic entries. It maps every accepted #254 flow ID exactly once either to a candidate adapter domain or to an explicit no-work/planned-absent classification; no flow may disappear through grouping.
The candidate adapter-domain keys are exactly:
accountscourseseventslegacy_datamailercontent_publicationoperations
Each entry records its accountable owning app/service, exact #254 flow IDs, current/legacy/public/aggregate classifications, future adapter issue or human_required, adapter_contract_version: null, and state blocked_unimplemented. These names are routing identities only; they do not authorize an adapter or cross-domain mutation.
The absent target Relay/email flow, inactive analytics-provider path/preferences, transient non-stored country suggestion, and any other #254 flow that cannot create durable domain work are still covered exactly once with one of planned_absent, inactive_no_provider, or no_persistent_work. They are not inserted into a live work set, and the validator requires their negative-source assertion and owning future issue/gate. A future source/model change requires a new manifest version; runtime inference may never add, omit, or mark a domain not applicable.
No production adapter version is invented here. #255 may recognize the schema and fail closed on all null/blocked entries; only later accepted domain-adapter issues may publish versions and an activating successor manifest.
Exhaustive right/domain matrix
right_domain_matrix contains exactly one row for every Cartesian pair of the six request rights and six candidate adapter domains: 36 unique rows, with no wildcard/default/fallback.
Each row contains:
rightanddomain_key;- exact contributing #254 flow IDs;
register_disposition, derived without elevation from the corresponding #254 right status;routing_state:required_if_activatedonly where #254 saysplanned, otherwisehuman_requiredornot_applicable;production_request_allowed: false;adapter_contract_version: null;- all blocking #254 gate IDs and future adapter issue IDs.
A planned #254 right means only that the owning issue intends to support it; it is not legal approval. human_required cannot become required_if_activated, and unlike flow dispositions cannot be merged to choose the more permissive value. A matrix row can become production-allowed only in a later owner-authorized immutable version after the applicable legal semantics and adapter are accepted. Unknown combinations are rejected, not treated as absent or allowed.
Bounded block and exception catalogs
The block catalog contains exactly these non-dispositive safe codes:
authority_human_requiredpolicy_not_activateddeadline_policy_unresolvedproof_unavailablemanifest_mismatchadapter_unavailableadapter_contract_mismatchadapter_capability_mismatchlegal_hold_activeexception_disposition_pendingdomain_retry_exhausteddomain_result_ambiguous
Each code pins its #255 block type, safe category, whether it is structurally resolvable, the required authority/gate, and an explicit statement that it cannot decide a right, release a hold, authorize retention/anonymization, or activate processing. These are bounded audit/result identifiers, not error prose or legal outcomes. Unknown/free-form codes fail validation.
The exception catalog contains exactly one version-1 code: issued_real_name_certificate. It references closed #23, applies only to courses, has state block_only, sets production_disposition_allowed: false, and links the educational-retention HUMAN gate/future courses adapter. Recognition causes exception_disposition_pending; it never itself authorizes retention, skips a domain, completes erasure, or generalizes to other educational records. No generic/other/custom exception code is allowed. A legal hold is a block, not an exception disposition; no hold-release code is supplied in version 1.
Validator and security behavior
Validation is read-only and performs no network, database, provider, or production access. It fails on:
- schema/version/digest/canonical-order errors or an unknown field;
- any mismatch with the accepted #254 register identity, flow IDs, right disposition, human gates, or accepted fact IDs;
- missing/duplicate flow coverage, domain entry, matrix pair, code, or cross-reference;
- an extra live domain, current classification for an absent/inactive flow, invented adapter version, or runtime inference/default;
- any production activation/allowance, accepted HUMAN value, disposition elevation, generic anonymize-and-retain, silent exception/hold release, or issued-certificate scope expansion;
- a wildcard/default/free-form right, domain, block, exception, error, or reason;
- a source path/symbol presented as legal authority, mutable branch/tag identity, empty/TBD/null placeholder outside explicitly permitted
nullversion fields, or nondeterministic digest; - names, emails other than the #254-approved privacy contact encountered only through its pinned source, usernames, IPs, tokens, credentials, cookies, sessions, provider payloads, domain record identifiers, production values, or reversible PII in source, fixtures, logs, or artifacts.
Tests use synthetic opaque UUIDs/digests and canaries only. The validator's output is bounded to safe paths, IDs, counts, and digests and never echoes rejected sensitive input.
Scope
- Add the exact four source-only files above.
- Bind an immutable non-activating policy and manifest identity to the accepted #254 register.
- Provide exact flow coverage, six-domain/six-right matrix, and bounded safe code catalogs.
- Test deterministic identity, drift, non-activation, fail-closed semantics, complete coverage, and sensitive-evidence rejection.
- Supply the stable artifact/API contract required to re-groom #255; do not implement #255.
Explicit non-goals
- No change to any #254 file, frozen candidate, report, schema, generated inventory, legal page, or HUMAN checkbox.
- No legal/privacy decision, legal advice, controller/processor approval, notice text/version, deadline, appeal/escalation rule, proof standard, hold/release policy, or production activation.
- No Django app/model/migration/service/registry/setting/URL/view/template/static/OpenAPI/Studio/admin/command/job/adapter/provider/runtime behavior.
- No production/test database, protected data, requester, AWS, GitHub-content mutation, Relay/Datamailer/provider call, export, correction, retention, erasure, tombstone, cache/search invalidation, or processor receipt.
- No production manifest, production verifier, fake adapter discoverable outside tests, guessed adapter version, or bypass around #251/domain-adapter issues.
- No commit, push, merge, deployment, or external operational change outside the normal issue lifecycle.
Acceptance criteria
- The four canonical files exist at the exact paths, with one hand-edited authority and no shadow policy/manifest/constants.
- Contract, policy, and manifest versions/digests are independently canonical, immutable, deterministic, and bound to the exact accepted/merged #254 register identity.
- Activation is exactly non-activating; production policy/manifest/request processing is false and cannot be enabled through settings, environment, registry discovery, fixtures, or defaults.
- The six-right catalog and exact #254 naming mappings are complete; withdrawal/publication-removal remain explicit uncovered kernel rights rather than aliases.
- Every #254 flow ID is classified exactly once; the six candidate adapter domains are exact, every adapter version is null/blocked, and absent/inactive/transient flows remain explicit negative coverage.
- The 36-row matrix is complete and duplicate-free, cannot elevate
planned/human_required, and setsproduction_request_allowed: falsein every row. - The exact 12 block codes and sole issued-certificate exception code validate with non-dispositive semantics; unknown/free-form codes and scope expansion fail.
- Cross-register drift, stale identity, missing/extra flow/domain/right/code, permissive state, wildcard/default, invented adapter version, hidden placeholder, digest drift, and sensitive-evidence mutations each have focused rejection tests.
- The validator passes against the accepted #254 artifact and produces bounded deterministic output; all fixtures/artifacts are synthetic and contain no protected/provider/production data.
- Focused tests, formatting/lint/type checks, migration-drift check, repository quality checks, and the graph-selected versioned verification plan pass using
uv/Make. - The final change graph proves no runtime/render path. Independent tester records Playwright and screenshots as
not_applicable; if any runtime/render path appears, the candidate returns to engineering because it violates scope. - Engineer, independent tester, and PM reports record exact base/head, accepted #254 version/digest, contract/policy/manifest digests, changed-path set, verification plan/artifact digests, and no pending/skipped required component.
Required verification scenarios
- Exact accepted #254 identity versus changed register version/digest/source commit/flow/gate/right/fact; all drift fails before any downstream use.
- Contract/policy/manifest self-digest tamper, key/array reorder, duplicate/unknown field, malformed version/digest, and stale immutable version.
- Every missing/duplicate/extra flow, domain, right, matrix pair, block code, and exception code; no fallback or wildcard succeeds.
- Attempted active/accepted/production-allowed state, non-null adapter version, removed HUMAN blocker, elevated planned/HUMAN right, inferred deadline/notice/hold outcome, generic exception, or certificate scope expansion.
- Absent Relay, inactive analytics, transient country suggestion, aggregate event evidence, legacy Datamailer, and public content coverage remain exact and cannot silently enter/leave a work set.
- Email/URL/token/cookie/session/AWS/GitHub/provider-payload/record-ID/free-text canaries at every string/object boundary are rejected without echoing the value.
Required verification commands
At minimum, plus the generated change-selective plan:
uv run --frozen python scripts/validate_privacy_authority_register.py
uv run --frozen python scripts/validate_privacy_kernel_input_contract.py
uv run --frozen python -m unittest scripts.tests.test_privacy_authority_register scripts.tests.test_privacy_kernel_input_contract
make migrations-check
make verification-quality
The independent tester reruns the focused validators/tests and every graph-selected component. Source-only screenshots are not_applicable only after the tester independently confirms zero render impact.
Delivery and downstream order
After #254 source-only delivery is green, this issue follows engineer → independent tester → PM acceptance → focused commit with Closes #281 → local no-ff merge/push → on-call green. #255 remains needs grooming throughout and may be rewritten only against the exact merged #281 file/schema/digests. No #255 engineering starts before that re-grooming. Domain adapters, runtime policy activation, and HUMAN/legal closure remain later, independently owned work.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Wait for the independently tested and merged #254 source-only delivery, then read the four owned files: the canonical contract and schema under _docs/legal, scripts/validate_privacy_kernel_input_contract.py, and its test module. Start by checking the accepted register identity and required gates, then run the validator and tests. Done means the immutable non-activating contract validates, covers the required flows and 36 matrix rows, and cannot activate production processing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100