EVENTS-001B: approved event-source admission contract (pure, source-only)#440
Merged
Conversation
✅ Deploy Preview for luminous-fox-7c393f ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #439. Second conservative, safe-by-default source-only slice of parent #121 (EVENTS-001A) — the INGEST half of the public-event pipeline whose PUBLISH half is the §8.6
projectPublicEventprojection (#399). Parent #121 stays open.functions/eventSourceAdmission.js— a non-throwing frozen-verdict reducerclassifyEventSourceAdmission(approvedSourceEvidence, deliveryEvidence)that decides whether one raw, untrusted structured-source delivery may be admitted as a private draft, returning exactly one frozen verdict:admit/refused/denied. Imports onlynode:util; imported by nothing; reads no clock, env, network, Firestore, or provider; zero runtime behavior, awaits no deploy.§8.6 (throwing projector) decides what a public VIEW may contain from a trusted reviewed record. This (non-throwing reducer) decides the arrow before it — an approved source's untrusted delivery → a private draft — and defers all public-CONTENT validation (control chars, markup, URL scheme, timestamp ranges, timezone, ordering, event-type vocabulary, tighter public bounds) back to §8.6. Defense in depth; no sibling duplicated.
Four marquee safety properties, encoded structurally:
sourceIdmatches the delivery's. Null descriptor →source_not_approvedwithout ever parsing the untrusted payload; inactive →source_inactive; non-public kind →source_kind_not_public; mismatch →source_mismatch.unexpected_field, never admitted. No protected-field NAME appears in the source; a protected offer is linked only via the opaqueprotectedOfferRef.lifecycle: 'draft',published: false; decision vocabulary has no publish/approve verb.draftId= collision-free join of (sourceId, sourceEventId, sourceRevision) over a reserved|the opaque grammar excludes; same revision → SAME id, new revision → DISTINCT id.Tests (
functions/eventSourceAdmission.test.js, 92 cases): full admit/refused/denied matrix; source-authorization battery (null/inactive/non-public-kind/mismatch, each proven to not parse the payload); the public/protected boundary (every protected field name as an extra key →unexpected_field, incl. non-enumerable; opaqueprotectedOfferRefnull-and-handle); never-auto-publish asserted on enums + across the matrix; injective draftId sweep; malformed batteries for both arg positions (proxy/revoked-proxy/foreign-proto/symbol/accessor-never-invoked/extra-and-missing); fail-closed check ordering; a never-throws hostile sweep in both positions; determinism/immutability/frozen singletons; and a source-boundary test locking the require set to exactly{node:util}, header§8.6a/EVENTS-001B, no protected/secret vocabulary in code, and imported-by-nothing.SYSTEM_DESIGN.md §8.6a documents the compose/defer-to-§8.6 rationale, a flowchart, the four properties, and explicit distinctness vs §8.6/§8.5a/§8.5b/§8.7/§8.22.
Local: ESLint 8.56.0 exit 0;
jest eventSourceAdmission92/92 green (secrets unset).