@sonordev/contracts 2.17.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.20.0
4
+
5
+ - Publish the `resonance`, `resonance-constants` and `signal-experiments` entries with matching CommonJS, ESM and TypeScript surfaces. Add the documentation manifest used by sonor.dev. These validation contracts grant no campaign approval or spending authority.
6
+
7
+ - Bind current Meta configuration review to the existing semantic definition digest plus a nondecreasing audit revision. Add required native `currentDefinitionDigest` metadata so metadata-only saves can preserve multiple unchanged channel configurations. Original snapshots stay immutable; exact prepared-plan, approval and native root fences remain unchanged.
8
+
9
+ - Add pure native measurement bootstrap save/current/snapshot/response contracts and one deterministic page projection using existing semantic digest bytes. Native page resources retain UTC millisecond revisions; rule revisions use full existing evidence digests. Project/site CAS, actual protected writer and one read-only native freshness resolver remain separate adoption requirements.
10
+ - Add pure Meta configuration save/snapshot/view/response contracts, exact existing-audience or admitted-setup mappings, immutable friendly review material, shared digest/projection helpers, minimal optional mandate feed selection and post-acceptance original feed review. Preserve the raw existing mandate-draft response and no-feed request bytes. Saved profile references require actual persisted operation IDs and integer configuration revisions; parsing grants no native capability or approval.
11
+ - Add closed explicit `provider_managed` Meta age intent alongside unchanged absent, omitted and bounded behavior. Actual first same-root PAUSED creator observation and unchanged activation comparison remain native owner work; existing consumers must explicitly support the new branch before adoption.
12
+
13
+ - Add an optional original Meta website-visit feed grant and a closed internal `deliver_website_visit` command through the existing Resonance parser and digests. Preserve omitted legacy fields and require explicit native feed authority; parsing doesn't authenticate a producer or permit manual origination.
14
+ - Add same-occurrence reported path and Meta cookie observation shapes, one fixed SDK observation policy and canonical semantic configuration/profile digest helpers. Add original-time checks with an inclusive five-minute local freshness bound and zero future allowance. These are Sonor rules, not Meta acceptance guarantees; native capture, consent, admission and delivery remain separate.
15
+ - Represent explicit omitted or bounded original Meta age selection. Absent fields retain legacy bytes and don't choose defaults. Actual policy, compiler and normalized readback support remain adapter responsibilities.
16
+
17
+ - Add a closed Google qualified-conversion delivery command and explicit original mandate operation. Reference one original Google channel and a persisted conversion ID. Optional plan, mandate and time context checks public grant consistency and the original prepared definition revision; private facts, native receipts, current consent and final admission remain server-owned. Existing launch grants never expand automatically.
18
+
19
+ - Add closed finite Meta candidate policy, lifecycle evidence and one-action decision variants through the existing Resonance entry. Reference original candidate channel IDs, preserve mature allocation, and bind later graph evidence without a digest cycle. Fixed exploration explicitly has no performance-decision policy. Optional actual evidence/plan arguments check cross-object scope and action consistency; native funding and admission remain server-owned.
20
+
21
+ - Add optional, closed `clickIdentifiers` to page-view measurement occurrences. Accept exactly one bounded `gclid`, `gbraid` or `wbraid`; other occurrence kinds reject it. Export its parser, type and JSON Schema. Identifiers describe observed lineage and grant no conversion or provider authority.
22
+
23
+ - Add strict Google configuration draft, snapshot, view and review contracts, one canonical projection and a digest-input helper. Prepared Google Search previews require either actual existing-goal evidence or bounded one-action setup intent for creation after the same mandate; other channels use explicit `null`. Require the explicit historical `qualified_at_observation_v1` provider signal profile, distinct from current Sonor outcome counts. Draft declarations stay bound to their campaign and creative scope; parsing grants no provider or approval authority.
24
+
25
+ - Add strict command-preparation request and response parsers. Preparation reports existing mandate or current owner approval requirements and never grants authority. Add `@sonordev/contracts/resonance-constants` for browser wire literals without campaign schemas.
26
+
27
+ - Add canonical Signal experiment create/update parsers and bounded Resonance audience/experiment management commands. Add reviewed public source-marker fields and the explicit first-party last-touch attribution model. These parsers validate wire data and grant no approval or provider authority.
28
+
29
+ - Add `@sonordev/contracts/resonance`: strict campaign, account capability, prepared-plan, mandate lookup, command, receipt, measurement and consent boundaries for connected campaign operations. Money uses exact decimal-string micros with checked provider-unit conversion. Parsing validates data and scope; it never grants advertising or spending authority.
30
+ - Retain the 2.19 review-photo presentation exports and all existing contracts.
31
+
32
+ ## 2.19.0
33
+
34
+ - Add an optional per-review photo presentation to `@sonordev/contracts/broadcast-layouts`: `REVIEW_PHOTO_PRESENTATIONS`, `ReviewPhotoPresentation` and `isReviewPhotoPresentation` support the explicit `background` choice. Input consumers handle an omitted choice by preserving the saved value and `null` by clearing it to automatic. Existing automatic layouts, composition seeds and variation draws are unchanged.
35
+ - Keep the decision-role entry and all other published contracts behavior unchanged.
36
+
37
+ ## 2.18.0
38
+
39
+ A minor release: one new entry, `@sonordev/contracts/decision-roles`. Every other entry is unchanged.
40
+
41
+ - **What a job title says about a buying decision.** `DECISION_ROLES` is the four parts a person can play (`owner`, `decision_maker`, `influencer`, `gatekeeper`), strongest first, and `decisionRoleForTitle(title)` returns the one a title names, or `null` when it names none. The role comes from the title alone, by eight rules read in order with the first match deciding, so "Vice President of Sales" is a decision maker, "Executive Assistant to the CEO" is a gatekeeper and "Marketing Coordinator" is an influencer. "Principal" is an owner unless it names a job, so "Principal Engineer" has no role. A title is read whole (it isn't split on "&" or "/") and only its first 200 characters count. `DecisionRole` is the type. Anything that finds the people on a company's website can import it, so two scans of the same page can't give one person two roles.
42
+
3
43
  ## 2.17.0
4
44
 
5
45
  A minor release: one new entry, `@sonordev/contracts/crm-disposition`. Every other entry is unchanged.
package/README.md CHANGED
@@ -19,7 +19,7 @@ pnpm add @sonordev/contracts
19
19
  | `@sonordev/contracts/seo-pages` | Which `seo_pages` row a path resolves to on a multi-site project | the Sonor API, Signal, site-kit's sitemap sync |
20
20
  | `@sonordev/contracts/seo-meta` | Whether a title or description is fit to ship | site-kit, Signal's SEO gate |
21
21
  | `@sonordev/contracts/llms` | llms.txt sanitizers, the word-safe cut they use (`clipAtWordBoundary`), what each page line says (`pickLlmsPageDescription`: summary, curated meta, served meta, schema description, then a cleaned scrape; `llmsPageTitle`, `isLlmsListablePage`, `groupLlmsPages`, `selectLlmsPages`) and the contract version | site-kit, the Sonor API, Signal's schema validation |
22
- | `@sonordev/contracts/forms` | The honeypot policy | site-kit forms, the Sonor API's form intake |
22
+ | `@sonordev/contracts/forms` | Shared form validation helpers | site-kit forms, the Sonor API's form intake |
23
23
  | `@sonordev/contracts/fleet` | The fleet heartbeat's wire shape | site-kit, the Sonor API |
24
24
  | `@sonordev/contracts/slots` | Slot payload signing, contract v2 (HMAC; Node only). Signs and verifies v1 for older site-kit releases | the Sonor API, site-kit on the server |
25
25
  | `@sonordev/contracts/slot-content` | What a slot of each kind may hold (`normalizeSlotValue`), safe links, the rich-text parser. No `crypto`, so browsers can import it | the Sonor API, site-kit, the dashboard editor |
@@ -41,6 +41,10 @@ pnpm add @sonordev/contracts
41
41
  | `@sonordev/contracts/funnels` | Incomplete drafts, launch definitions, command/readiness/receipt schemas, bounded public pages and presentation-only brand overrides | Sites, APIs, UI and agent adapters share the same rules |
42
42
  | `@sonordev/contracts/inbox` | Which inbox cards are decisions a bulk action leaves alone (`isDecisionCard`, `DECISION_INSIGHT_TYPES`) | Signal's inbox decides what "Mark all read" and "Dismiss all" may touch, the dashboard previews the same result before the write |
43
43
  | `@sonordev/contracts/crm-disposition` | What a rep's call outcome (positive, negative or left voicemail) changes on a prospect: the call's outcome and sentiment, the contact's stage, the company's status, today's reminder and outreach (`dispositionTransitions`), and the reasons a negative outcome carries | the Sonor API applies an outcome, the dashboard's calling screen offers the same three buttons and reasons, the sales extension stops flipping a company on dial |
44
+ | `@sonordev/contracts/decision-roles` | The part a job title says a person plays in a buying decision (`DECISION_ROLES`: owner, decision maker, influencer, gatekeeper), read from the title alone by `decisionRoleForTitle` | the Sonor API's site-people scan and Signal's site-people scout read the same map |
45
+ | `@sonordev/contracts/resonance` | Campaign, consent, measurement, plan, mandate and command parsers, types and JSON schemas | Sites, APIs and the dashboard share the same wire rules |
46
+ | `@sonordev/contracts/resonance-constants` | Small browser-safe measurement wire constants | Browser readers that don't need campaign schemas |
47
+ | `@sonordev/contracts/signal-experiments` | Shared Signal experiment create and update validation | APIs and the dashboard use one experiment boundary |
44
48
 
45
49
  ## Focus closing artwork
46
50
 
@@ -149,6 +153,65 @@ dispositionTransitions('negative', { reason: 'do_not_call' })
149
153
  change incompatibly. The wire values (the three outcomes and five reasons) are
150
154
  stored and sent, so they don't change.
151
155
 
156
+ ## Decision roles
157
+
158
+ When a company's website lists its people, what each job title says about a
159
+ buying decision has to be read the same way wherever the list is built.
160
+ `decisionRoleForTitle` is that rule, written once, so a person can't be an
161
+ influencer in one scan and an owner in another. The role comes from the title
162
+ the page gives and never from a model's opinion: a model can find the people,
163
+ and code decides the role.
164
+
165
+ ```ts
166
+ import { DECISION_ROLES, decisionRoleForTitle } from '@sonordev/contracts/decision-roles'
167
+
168
+ DECISION_ROLES // ['owner', 'decision_maker', 'influencer', 'gatekeeper']
169
+ decisionRoleForTitle('Vice President of Sales') // 'decision_maker'
170
+ decisionRoleForTitle('Executive Assistant to the CEO') // 'gatekeeper'
171
+ decisionRoleForTitle('Marketing Coordinator') // 'influencer'
172
+ decisionRoleForTitle('Principal Engineer') // null
173
+ ```
174
+
175
+ The first rule that matches the title decides, in this order:
176
+
177
+ | Order | The title says | Role |
178
+ |---|---|---|
179
+ | 1 | an executive, administrative, office or personal assistant, "assistant to", secretary, receptionist, front desk | `gatekeeper` |
180
+ | 2 | vice president (VP, SVP, EVP, AVP) | `decision_maker` |
181
+ | 3 | owner, co-owner, founder, co-founder, proprietor, president, CEO, chief executive, managing, senior, name or equity partner, a lone "Partner", or "Principal" that isn't a job | `owner` |
182
+ | 4 | a chief of something else (COO, CFO, CTO, CMO, "Chief ... Officer") | `decision_maker` |
183
+ | 5 | general manager (or GM), director, operations manager, estimator, estimating manager, project manager, superintendent | `decision_maker` |
184
+ | 6 | office manager, administrator, administrative, admin | `gatekeeper` |
185
+ | 7 | marketing, HR, human resources, recruiting, talent acquisition, sales, business development | `influencer` |
186
+ | 8 | coordinator | `gatekeeper` |
187
+
188
+ - **Order is the meaning.** "Vice President of Sales" is a decision maker, not
189
+ an owner because it says president and not an influencer because it says
190
+ sales. "Marketing Director" is a decision maker, because director comes
191
+ before marketing. "Marketing Coordinator" is an influencer, because
192
+ marketing comes before coordinator. "Executive Assistant to the CEO" is a
193
+ gatekeeper, because the assistant rule comes before the CEO rule.
194
+ - **"Principal" is an owner unless it names a job.** "Principal" alone is an
195
+ owner. "Principal Engineer", "Principal Architect", "Principal Consultant",
196
+ "Principal Designer", "Principal Developer" and "Principal Analyst" say
197
+ nothing about ownership, so they have no role.
198
+ - **A title is read whole.** A title that names two jobs isn't split, and the
199
+ strongest role doesn't win; the first rule above that matches does. "Owner &
200
+ Office Manager" is an owner. "Receptionist & Owner" is a gatekeeper.
201
+ - **"Assistant" alone isn't a gatekeeper.** "Assistant Project Manager" and
202
+ "Assistant General Manager" are decision makers, as the manager rules read
203
+ them. "Assistant to the Project Manager" is a gatekeeper.
204
+ - **No title or no match is `null`.** "Technician", a bare "Manager",
205
+ "Accounting Manager", an empty string, whitespace, `null`, `undefined` and
206
+ anything that isn't a string all say no role. The map doesn't guess.
207
+ - **Case, `&` and periods don't matter.** "C.E.O.", "FOUNDER & CEO" and
208
+ "Vice-President" read the same as their plain spellings.
209
+ - **Only the start of a title is read.** Titles come off scraped pages, so
210
+ the first 200 characters decide and the rest is ignored.
211
+
212
+ The four role values are stored and sent, so they don't change. `DECISION_ROLES`
213
+ lists them strongest first, which is the order a screen should rank them in.
214
+
152
215
  ## Schema placeholders
153
216
 
154
217
  `schema-placeholders` finds the parts of a JSON-LD value that a template left
@@ -793,6 +856,7 @@ import { createHash } from 'node:crypto'
793
856
  import {
794
857
  ARTICLE_COVER_LAYOUTS, CARD_LAYOUTS, isCardLayoutId, normalizeArticleCoverLayout,
795
858
  normalizeReviewCardVariation, reviewCardVariationFromDigest, reviewCompositionSeed,
859
+ REVIEW_PHOTO_PRESENTATIONS, isReviewPhotoPresentation,
796
860
  } from '@sonordev/contracts/broadcast-layouts'
797
861
 
798
862
  CARD_LAYOUTS // ['stacked', 'headline', 'split', 'anchor']
@@ -801,6 +865,9 @@ isCardLayoutId('stacked') // true: an old post still reads
801
865
  normalizeArticleCoverLayout('stacked') // 'anchor'
802
866
  normalizeArticleCoverLayout('split') // 'headline'
803
867
  normalizeReviewCardVariation('spotlight') // 'signature'
868
+ REVIEW_PHOTO_PRESENTATIONS // ['background']
869
+ isReviewPhotoPresentation('background') // true
870
+ isReviewPhotoPresentation(null) // false: a clear operation is handled by the caller
804
871
 
805
872
  // On the server: a review's composition, stable for its identity.
806
873
  const digest = createHash('sha256').update(reviewCompositionSeed(projectId, reviewId)).digest()
@@ -829,6 +896,13 @@ reviewCardVariationFromDigest(digest) // 'signature' or 'frame'
829
896
  as Signature and anything unknown as the default, Signature.
830
897
  **`isReviewCardVariation`** is the strict check for a request that must
831
898
  name a drawn one.
899
+ - **`REVIEW_PHOTO_PRESENTATIONS`** lists explicit per-review photo choices:
900
+ `background` places the primary photo behind the review text. The
901
+ `ReviewPhotoPresentation` type and `isReviewPhotoPresentation` guard share
902
+ that supported set. The guard accepts explicit values only; input consumers
903
+ handle omission (preserve a saved choice) and `null` (clear it to automatic)
904
+ separately. Existing records without a choice keep their deterministic
905
+ composition; presentation doesn't change the seed or variation draw.
832
906
  - **A review's composition never moves.** It's drawn from the SHA-256 of
833
907
  `reviewCompositionSeed(projectId, reviewId)`, never from anything a person
834
908
  can edit. `reviewCardVariationFromDigest` reads the first four bytes
@@ -1086,3 +1160,442 @@ Use `parseFunnelCreateArgs`, `parseFunnelUpdateArgs`, `parseFunnelRevisionArgs`,
1086
1160
  `parsePublishedFunnelPage` refuses private definition fields and unsafe asset URLs. It supports bounded text paragraphs and bullet lists, with a managed form slug and canonical campaign identity. `managedFunnelPath` reserves `/f/:slug`; a consuming site must opt in and verify its actual routes.
1087
1161
 
1088
1162
  `parseFunnelReadiness`, `parseFunnelOperationReceipt` and the detail/catalog/preview parsers validate bounded response envelopes. Operation receipts bind the exact command target and approved action, and always report zero messages sent by the configuration command. Preview and published-version detail parsers preserve the exact launch or rollback evidence.
1163
+
1164
+
1165
+ ## Adopting 2.20.0
1166
+
1167
+ Use the same contracts version in every application that exchanges Resonance
1168
+ payloads. This release includes the 2.19 review-photo presentation exports and
1169
+ adds the Resonance and Signal experiment entries. Existing package subpaths stay
1170
+ available. Import a specific entry rather than the package root.
1171
+
1172
+ ```ts
1173
+ import { parseMoney } from '@sonordev/contracts/resonance'
1174
+
1175
+ const budget = parseMoney({ currency: 'USD', amountMicros: '1250000' })
1176
+ ```
1177
+
1178
+ The parsers validate wire data. They don't approve a campaign, authorize spending
1179
+ or confirm provider delivery. Keep those checks in the application that owns the
1180
+ action. Deploy accepting server parsers before enabling new browser fields.
1181
+
1182
+ ## The resonance contract
1183
+
1184
+ Import pure parsers, types and JSON schemas from `@sonordev/contracts/resonance`.
1185
+ `parseResonanceCampaignDraft` accepts bounded incomplete setup; `parseResonanceCampaignDefinition`
1186
+ requires resolved goals, resources, destinations, channels and budget. Existing funnel,
1187
+ Broadcast, Outreach, Files, brand and experiment records retain ownership. Nested
1188
+ references must match the campaign's project and owned-site scope. Server lookups
1189
+ must still validate ownership, current revisions, policy and actual permission.
1190
+
1191
+ `Money` is `{ currency: 'USD', amountMicros: '1250000' }`, exactly 1.25 USD.
1192
+ `parseMoney`, `addMoney`, `moneyToProviderUnits` and `moneyFromProviderUnits` use
1193
+ integer arithmetic. Never pass amounts through `Number` or assume every currency
1194
+ uses cents. Conversion requires the verified provider/account exponent (0, 2, 3 or
1195
+ 6) and native limit; fractional units, overflow and currency mismatch fail.
1196
+ Supported currency codes are exported as `RESONANCE_CURRENCIES`; actual advertiser
1197
+ eligibility, minimum budgets and delivery semantics remain provider checks.
1198
+
1199
+ The initial paid profiles are `google_search` and `meta_retargeting`, distinct
1200
+ from provider IDs `google_ads` and `meta_ads`. They are closed plans, not arbitrary
1201
+ provider JSON or a claim to support every campaign type. Prepared plans bind exact
1202
+ ordered creative copy/media/crop references, destinations, budgets, goal/policy
1203
+ revisions and server-owned compiled manifest references. `resonancePlanIssues`
1204
+ reports blocked, missing or stale capabilities without turning them into success.
1205
+
1206
+ `parseResonanceMandateApprovalPayload(value, target)` validates the exact business
1207
+ payload and project/campaign target. It doesn't approve anything. Resolve original
1208
+ principal and approval provenance through the existing Action Ledger; compute and
1209
+ verify the server digest over `resonanceMandateDigestInput` before admitting effects.
1210
+ The command digest input similarly canonicalizes only parsed command fields.
1211
+ Launch/update/resume and optimization require exact plan/mandate lookups. Safety
1212
+ pause/finish/reconcile commands require root revision and idempotency identity but
1213
+ no fresh creative approval, so stale creative evidence cannot prevent a stop.
1214
+
1215
+ An immutable `PreparedPlan` is stored as an existing campaign version; it is review
1216
+ evidence, not approval authority. Receipt state and unresolved exposure remain
1217
+ separate from approval. An uncertain provider admission requires reconciliation
1218
+ before retry; it must not release liability or repeat creation automatically.
1219
+
1220
+ Metric observations distinguish observed zero from unknown, insufficient, delayed
1221
+ and unavailable values, retain window/timezone and native-unit evidence, and use
1222
+ exact counts/money/ratios. Consent and conversion parsers validate scoped evidence;
1223
+ a browser cannot mint a trusted lead by passing validation. Accepted source rows,
1224
+ current consent/withdrawal and experiment exposure must be verified server-side.
1225
+ No scripts, credentials, cookies or customer personal data belong in these DTOs.
1226
+
1227
+
1228
+ The save/binding/accept command parsers use the same strict wire rules. Updates
1229
+ require an expected root revision; root creation can omit it. Account bindings
1230
+ select existing provider resources, never credentials. Optimizer evidence and
1231
+ immutable decisions have separate parsers: they retain unknown tracking/power
1232
+ checks, exact before/after allocations and remote snapshot identities. Resolve
1233
+ minimum evidence, lag, cooldown and mandate coverage from the referenced frozen
1234
+ policy on the server. Parsed metrics or an actionable decision alone never grant
1235
+ spending authority. A blocked or no-op decision cannot carry allocation effects.
1236
+
1237
+
1238
+ Public measurement configuration is a separate closed DTO. It carries only typed
1239
+ Google Ads tag/Meta pixel identifiers, permitted resource rules and basic consent
1240
+ policy. A measurement occurrence is a view, explicit interest or experiment
1241
+ exposure; it cannot declare an accepted conversion. Consent updates preserve
1242
+ unknown, denied and withdrawn states. These parsers don't load any tags, collect
1243
+ browser data or turn a reported grant into server-verified permission. The browser
1244
+ runtime and server evidence/withdrawal checks must implement those controls.
1245
+
1246
+ Page-view occurrences can include optional `clickIdentifiers`, with exactly one
1247
+ closed shape: `{ gclid: string }`, `{ gbraid: string }` or `{ wbraid: string }`.
1248
+ `parseResonanceClickIdentifiers`, `ResonanceClickIdentifiers` and
1249
+ `RESONANCE_CLICK_IDENTIFIERS_JSON_SCHEMA` share that boundary. Values contain
1250
+ 1 to 1024 characters, with no whitespace or control characters. This is the
1251
+ application's transport bound. Other occurrence kinds reject the field.
1252
+ The browser reads the current URL only after the required advertising grants
1253
+ and scoped proof are available. An observed identifier doesn't authenticate a
1254
+ paid click. The server must verify the same subject, site, current consent and
1255
+ actual form occurrence before using it for conversion matching. Identifiers
1256
+ don't belong in public configuration, receipts, results or logs. Deploy the
1257
+ accepting server parser before enabling browser emission.
1258
+
1259
+ Initial acceptance uses only `{ expectedRevision, ledgerActionId }`. The server
1260
+ loads the approved native payload and current kill state and returns the canonical
1261
+ mandate reference. Clients must never guess a kill revision to construct authority.
1262
+
1263
+
1264
+ Managed definitions contain the closed `optimization.policy`; prepared plans freeze
1265
+ an identical `resolvedEvidencePolicy`. Initial inline policies have `sourceRef: null`.
1266
+ A genuine existing source can supply optional provenance, but a new campaign doesn't
1267
+ need a synthetic experiment, self-referencing plan or new policy table. The first
1268
+ algorithm is explicitly observational qualified-lead CPQL allocation with approved
1269
+ maturity, coverage, uncertainty, attribution, lag and cooldown values. Executable
1270
+ allocation and current source/mandate admission remain server-owned.
1271
+
1272
+ ### Finite preapproved Meta candidates
1273
+
1274
+ The optimization policy also supports the closed `finite_meta_candidates_v1`
1275
+ branch with `decisionKind: 'preapproved_candidate_operation'`. One policy
1276
+ variant belongs to each original plan. The existing mature allocation branch
1277
+ keeps its meaning and shape.
1278
+
1279
+ The finite policy uses `candidateChannelIds` to reference original Meta channels
1280
+ in the same definition. Their existing creatives, account, site, independent
1281
+ adset lifetime cap and original budget flight remain authoritative. The policy
1282
+ doesn't copy those inputs or contain compiled graph hashes. It records an exact
1283
+ reviewed order and schedule, one activation per candidate, concurrency, allowed
1284
+ actions, a typed exploration ceiling, tracking requirements and hard stops.
1285
+ `performanceDecisionPolicy` is explicitly `null`: this profile supports fixed
1286
+ exploration and approved safety stops, with no measured winner, adaptive pruning,
1287
+ budget increase, promotion or causal A/B claim.
1288
+
1289
+ Preparation resolves the original graphs and binds them with the policy in the
1290
+ existing review digest. The existing mandate seals that review. Later evidence
1291
+ and decisions reference the resulting graph identities; their hashes never feed
1292
+ back into the definition policy. No new policy registry or mandate field is used.
1293
+
1294
+ `ResonanceFiniteMetaCandidatePolicy`, `ResonanceFiniteMetaCandidateEvidence` and
1295
+ `ResonancePreapprovedCandidateOperationDecision` narrow the existing generic
1296
+ types. Their parsers, JSON Schemas and digest helpers share the existing
1297
+ `resonance` entry. Cold lifecycle evidence records unobserved measurement as
1298
+ `null`, with no borrowed donor outcomes or invented mature zero. An actionable
1299
+ decision carries exactly one `materialize_and_activate`, `activate_held` or
1300
+ `pause_candidate` action. Blocked and no-op decisions carry none. These decisions
1301
+ don't carry mature adjustments or a fabricated zero-to-cap transfer.
1302
+
1303
+ Pass the actual prepared plan as the optional second argument to
1304
+ `parseResonanceOptimizationEvidence` to check original public scope, manifest,
1305
+ cap and flight. Pass actual evidence and, when available, that plan as the second
1306
+ and third arguments to `parseResonanceOptimizationDecision` to check policy,
1307
+ action, fixed order, freshness and commitment-reference consistency. Parsing a
1308
+ standalone object checks its closed shape; it can't authenticate referenced rows
1309
+ or establish approval. Servers must load and verify the actual accepted plan,
1310
+ native claim, current permission and protected evidence before admission.
1311
+
1312
+ The API and database reserve the full independent cap before the first create.
1313
+ Activating an already paused candidate adds no new exposure only when its exact
1314
+ original physical commitment is already fully held. Resource presence or a
1315
+ reference alone doesn't prove that condition. Pause and donor decreases don't
1316
+ release old holds; uncertain effects retain their original key and reconcile.
1317
+ The public optimize command and existing Ledger workflow are unchanged.
1318
+
1319
+ Provider spend, clicks and impressions retain their own `provider_aggregate`
1320
+ counting unit and `provider_reported` attribution. First-party qualified-cohort
1321
+ observations keep the original objective's counting unit and attribution model.
1322
+ They aren't interchangeable evidence, and neither enables a performance
1323
+ decision in this fixed profile.
1324
+
1325
+ Ordinary optimize actions, including an explicitly allowed candidate pause,
1326
+ remain inside the current policy and mandate expiry. At or after expiry,
1327
+ creation and activation stop; any needed pause uses the existing current-owner
1328
+ safety pause or escalation path. This contract doesn't create post-expiry
1329
+ permission or a second stop-validity clock.
1330
+
1331
+ Public measurement transport uses the dedicated `X-Sonor-Resonance-Subject`
1332
+ header. Config reads do not issue identity. Only an explicit preference action
1333
+ can receive `subjectProof`, `expiresAt`, `currentConsentRevision` and the four
1334
+ purpose receipts. This is an opaque scoped proof, kept in browser memory. Proof expiry isn't
1335
+ consent expiry and must not force recurring consent prompts. Valid current CMP
1336
+ state may support scoped proof renewal/resumption through the authoritative API;
1337
+ until a valid proof is available, exports stay off. Config itself never bootstraps identity.
1338
+ `expectedConsentRevision` atomically fences the complete subject preference batch.
1339
+ The browser must discard stale grant replies, stop immediately on withdrawal,
1340
+ and never replay pre-consent events or bootstrap identity on config/page load.
1341
+ These contracts describe evidence, not an implemented transport or real-person identity.
1342
+
1343
+
1344
+ Tracking-only legacy campaign views retain revision zero; managed campaigns require
1345
+ at least revision one. Creation can adopt a tracking root at zero, but updates need
1346
+ a managed revision. Unknown admission in any child forces reconciliation and cannot
1347
+ be hidden by a failed root label or retry advice. Known reconciled/rejected work
1348
+ may still retry the same original operation when the server authorizes it.
1349
+
1350
+ `parseResonanceSubjectRenewCommand` accepts only current consent/config/policy
1351
+ revisions. Renewal rotates a proof without granting or changing consent. It requires
1352
+ the scoped subject transport and current server/CMP checks; it isn't permission to
1353
+ bootstrap identity from a config read or recover someone else's receipt.
1354
+
1355
+
1356
+ Public renewal includes schema version and the asserted project/site envelope as
1357
+ well as current revisions; the server resolves and verifies that scope from proof
1358
+ and credential. Finite allocation horizons carry verified UTC start/end, timezone
1359
+ and source revision, so eligible total/lifetime budgets can be compared on the
1360
+ same actual period without relabeling daily averages as hard lifetime caps.
1361
+
1362
+ `cpqlMissingOutcomeBound` computes the named observational sensitivity method from
1363
+ trusted unique-contact totals: eligible `n`, fully resolved attribution/dedupe/final
1364
+ qualification intersection `c`, and qualified subset `k`. It returns the ceiling of
1365
+ `10000*(n-c)/(2*k+n-c)`, or unknown when no positive source universe exists. This
1366
+ isn't statistical confidence, causal lift or permission to inject counts from a
1367
+ browser. API source producers must verify the complete universe and spend period;
1368
+ without that witness, the evidence bound remains unknown. Coverage stays separate.
1369
+
1370
+ ### Successor management and attribution fields
1371
+
1372
+ The local 2.20 candidate adds `@sonordev/contracts/signal-experiments` as the
1373
+ single parser for the existing Signal create/update payload. It exports
1374
+ `parseSignalExperimentCreate`, `parseSignalExperimentUpdate`, their types and
1375
+ JSON Schemas. Both operations check unique variant keys and the existing
1376
+ weight-sum tolerance of 0.01. Percentages must be finite and within 0 to 100.
1377
+ Optional allocation and targeting defaults remain the existing service's job.
1378
+ Parsing doesn't grant access or select a variant.
1379
+
1380
+ `/resonance` adds audience draft save and experiment create/update, lifecycle,
1381
+ complete and link command parsers. Each managed experiment command requires
1382
+ `expectedRevision` and `idempotencyKey`. Audience drafts reference the current
1383
+ measurement config's resource rule IDs. The server resolves their scope and
1384
+ provider retention limit. Saving a draft uploads no people or audiences.
1385
+
1386
+ Public source markers use the `sonor_source` parameter and bounded
1387
+ `rsm1.<claims>.<signature>` format. A prepared channel preview can carry an
1388
+ `attributionMarker`; its destination URL must contain exactly that reviewed
1389
+ marker. An occurrence can carry the bounded `sourceMarker` value. The pure
1390
+ parser checks format and URL coherence. The server verifies the signature,
1391
+ purpose, accepted immutable plan and actual resource scope.
1392
+
1393
+ `first_party_last_touch_marker_v1` describes server-recorded first-party source
1394
+ mapping under the reviewed attribution window. It doesn't establish a paid
1395
+ click, a human visit or a causal effect. Unresolved source linkage stays
1396
+ unallocated. The existing resource, audience-rule and experiment-reference
1397
+ readers are also exported so owner projections can use the same validators.
1398
+
1399
+ Qualified-lead prepared plans require a non-null `resolvedQualificationRule`.
1400
+ Other objectives carry an explicit null. The objective keeps the selected
1401
+ `qualificationRule`; the prepared projection shows its actual CRM project ref,
1402
+ `crmVariant`, native `ladderSnapshot`, eligible form and cohort boundaries.
1403
+ `semantic_key` and native preset stage IDs can be null. The parser preserves
1404
+ those native values and never manufactures a stage UUID or infers qualification
1405
+ from a stage's position or won/lost flag.
1406
+
1407
+ The three selected stage partitions must be disjoint and exhaust the resolved
1408
+ native ladder. The public projection must match the selected partitions, native
1409
+ ref, source form, counting unit and maturity delay. API persistence resolves one
1410
+ canonical witness and uses that same object for internal resource evidence and
1411
+ public review. The server must verify its actual source and digest. These shape
1412
+ checks don't establish that a caller supplied genuine database rows.
1413
+
1414
+ `PreparedPlan.expiresAt` is an initial acceptance freshness deadline. Continuing
1415
+ an already accepted campaign uses its current native mandate and budget limits,
1416
+ with current resource and capability checks. The pure initial-readiness helper
1417
+ doesn't replace those authority checks.
1418
+
1419
+ ### Preparing a campaign command
1420
+
1421
+ `parseResonanceCommandPrepareRequest` reads only `expectedRevision` and `idempotencyKey`. The API resolves the accepted plan, current resources and authority for launch, update or resume. `parseResonanceCommandPrepareResponse` reads `{ command, covered, approvalRequirement, reasonCodes }`, where `command` may be `null` and `approvalRequirement` is `existing_mandate`, `current_owner` or `null`. A covered command still needs its required native approval and claim. Resume after a pause requires the current owner's approval through the existing action ledger.
1422
+
1423
+ `@sonordev/contracts/resonance-constants` exports `RESONANCE_SUBJECT_HEADER`, `RESONANCE_SOURCE_MARKER_PARAMETER` and `RESONANCE_ATTRIBUTION_MODEL` without loading campaign schemas. The main Resonance entry re-exports these same literals. Browser adapters can use the constants entry when they don't need a parser.
1424
+
1425
+ ### Delivering a qualified Google conversion
1426
+
1427
+ The existing `ResonanceCommand` union adds `operation: 'deliver_conversion'`. It requires the usual schema version, campaign, prepared plan, review digest, expected revision, idempotency key and mandate reference, plus `channelIds` with exactly one original Google channel and `conversionId` for the persisted canonical qualified fact. The command carries no click identifiers, personal data, provider payload, values, timestamps, native destination or approval flags.
1428
+
1429
+ The original mandate must explicitly include `deliver_conversion` in `allowedOperations`. A launch-only grant doesn't gain delivery permission. The existing original review binds the goal, source, qualification witness and Google configuration; there's no second delivery policy object. The initial profile is `qualified_at_observation_v1` for one managed-form qualified source and one destination. Existing goals with multiple actions are rejected for delivery. Cross-account action ownership remains unsupported.
1430
+
1431
+ `parseResonanceCommand(value, { preparedPlan, mandate, now })` optionally checks those actual parsed objects for original scope and prepared definition revision, goal, budget, account, site, single-action Google profile and the original dispatch window. The one-argument call remains shape validation. An accepted plan's initial freshness deadline doesn't create a reporting tail: new dispatch must remain within its original mandate and budget window. Ordinary delivery stops after expiry; read-only receipt reconciliation doesn't resend it.
1432
+
1433
+ These checks don't authenticate a persisted fact, current principal, kill or finish state, qualification, consent continuity, native claim or export deduplication. The server must verify the protected same-root goal-installation receipt and current native ownership. Setup intent only binds the reviewed local action and strategy; actual destination resolution requires its original successful native setup receipts. Missing or stale provenance blocks delivery. Parsing neither proves that setup ran nor authorizes a provider request. Accepted provider ingestion doesn't establish attribution or bidding success.
1434
+
1435
+ ### Google campaign configuration
1436
+
1437
+ `parseResonanceGoogleConfigurationSaveCommand` reads a strict draft request
1438
+ with `schemaVersion: 1`, `expectedCampaignRevision`, `expectedRevision`,
1439
+ `idempotencyKey`, the required `signalSemantics`,
1440
+ `declaration: { statement, category }` and one top-level mode:
1441
+
1442
+ - `existing`: `nativeGoal: { externalId, actionIds }`, using full native Google
1443
+ resource names. The unique action set is sorted by the parser.
1444
+ - `admitted_setup`: `setupIntent: { requestedGoalName, requestedActionName }`.
1445
+ These are intended display names, bounded to 160 characters, not purported
1446
+ native resources. The server
1447
+ derives the complete setup specification.
1448
+
1449
+ Revision `0` expects no saved configuration. The server checks the campaign
1450
+ and configuration revisions and recovers the original operation by its key.
1451
+ Parsing doesn't save, approve or spend anything. Save the campaign and channel
1452
+ first, retain their IDs, then save their configuration. The configuration
1453
+ response supplies the resulting `campaignRevision`, configuration `revision`,
1454
+ `operationId` and `replayed`. Retry an uncertain save with its original key and
1455
+ body before starting another operation. Re-read the actual campaign after an
1456
+ uncertain initial draft save; its stable ID may now have a later revision.
1457
+
1458
+ The required `signalSemantics` is `qualified_at_observation_v1` for both
1459
+ modes and the setup specification. It describes an explicitly reviewed
1460
+ **historical provider bid signal**, distinct from Sonor's unchanged
1461
+ `current_at_observation` qualified counts. It doesn't promise equal counts or
1462
+ provider count retraction. Existing and new setup profiles currently support
1463
+ only `qualified_lead` with `unique_qualified_contact` and a 1–90 day window.
1464
+ Actual producer eligibility, permanent contact/destination deduplication and
1465
+ delivery remain server checks. Other goal profiles are unsupported.
1466
+
1467
+ The declaration's explicit statement is
1468
+ `DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING`; its category is `general`,
1469
+ `housing`, `employment` or `financial_products_services`. The server binds it
1470
+ to actual source, account, creative, copy, destination and region scope, with
1471
+ the actual declarant UUID, timestamp and original
1472
+ `declaredForCampaignRevision`. No permanent statement is inferred from a brand
1473
+ or site. These fields aren't approval identities. The exact statement and
1474
+ resource effects are reviewed within the same campaign mandate.
1475
+
1476
+ `parseResonanceGoogleConfigurationSnapshot` reads the canonical public snapshot
1477
+ with `configurationRevision` and `configurationDigest`. Its top-level mode
1478
+ remains explicit. Existing-mode native goal name and revision may be `null`
1479
+ when draft evidence is unavailable; a real empty provider label stays empty.
1480
+ `parseResonanceGoogleConfigurationReview` requires actual name and SHA-256
1481
+ revision for existing mode.
1482
+
1483
+ Setup mode contains `setupSpec` and `setupDigest`, with no `nativeGoal` or
1484
+ purported native ID/revision. `ResonanceGoogleUploadClicksCustomGoalSpec` has
1485
+ one singular `action`, one matching `goalActionKey`, fixed local dependency
1486
+ keys, requested names and `exclusive_custom_goal_v1`. There are no
1487
+ `actions[]` or `goalActionKeys[]` aliases. The bounded first setup profile is
1488
+ `qualified_lead` with `unique_qualified_contact`, an `UPLOAD_CLICKS` action,
1489
+ `QUALIFIED_LEAD`, `ONE_PER_CLICK`, `primaryForGoal: false`, and the exact
1490
+ objective attribution window from 1 through 90 days. Other new setup pairs
1491
+ are unsupported; longer windows aren't clamped. Actual contact deduplication
1492
+ and delivery identity remain upstream responsibilities. Native per-click
1493
+ counting doesn't implement global contact deduplication. Canonical outcomes
1494
+ and provider reports remain separate.
1495
+
1496
+ `projectResonanceGoogleConfiguration(snapshot, { ready, activationReadiness,
1497
+ reasonCodes })` is the one public view/review projection. The view renames
1498
+ `configurationRevision` to `revision` and adds fresh resolver metadata.
1499
+ `ready` means reviewable, not activated: planned setup uses `pending_setup`,
1500
+ unready configuration uses `blocked`, and existing setup requires final
1501
+ verification or verified native evidence. An unready view returns
1502
+ `review: null`. The corresponding view/save-response parsers validate these
1503
+ shapes without granting authority.
1504
+
1505
+ `resonanceGoogleSetupDigestInput` and
1506
+ `resonanceGoogleConfigurationDigestInput` return canonical JSON for the server
1507
+ hash function. The configuration input omits only its self
1508
+ `configurationDigest`; initial content needs no placeholder. Private
1509
+ eligibility or authorization evidence doesn't belong in this public snapshot.
1510
+ `RESONANCE_GOOGLE_SOURCE_CATEGORIES` and `googleConversionActionSemantics`
1511
+ share native vocabulary with explicit counting and window inputs; vocabulary
1512
+ membership grants no broader setup eligibility.
1513
+ `googleUploadClicksSetupSemantics({ source, countingUnit, attributionWindowDays })`
1514
+ is the shared narrow policy check. It doesn't establish an actual source
1515
+ producer or delivery identity.
1516
+
1517
+ Every prepared preview requires `googleConfiguration`: a strict existing or
1518
+ setup review for Google Search, explicit `null` for other channel kinds.
1519
+ Project, campaign, channel, site, account binding, source, measurement,
1520
+ counting, window and regions must match the enclosing plan. Preparing setup
1521
+ performs no provider mutation. After the same native mandate and admission,
1522
+ actual receipts resolve local keys to native IDs without rewriting the
1523
+ accepted public plan. Activation still needs current native eligibility,
1524
+ source, consent and authority checks. No parser proves those checks occurred.
1525
+
1526
+
1527
+ ### Original Meta website-visit feed
1528
+
1529
+ `ResonanceMandateScope` accepts an optional `websiteVisitFeed` with the profile `sonor_sdk_page_view_fresh_v1` and a `channels` list. Each entry selects an original Meta channel, a `measurementConfigRef`, `resourceRuleRefs` and a `matchingProfileRef`. Account, dataset and site come from that same channel in the reviewed plan. The matching-profile reference identifies the protected configuration-save receipt, its positive integer CAS revision and its digest. No feed is granted when the field is absent. A launch permission, measurement setting or visitor consent alone doesn't grant this feed.
1530
+
1531
+ `RESONANCE_WEBSITE_VISIT_PROFILE` is the fixed, immutable local policy. `resonanceWebsiteVisitProfileDigestInput()` returns its canonical bytes for the server to hash. `resonanceMeasurementConfigDigestInput(config)` parses the measurement config and returns canonical semantic bytes, excluding only `expiresAt`. Current expiry still needs a separate check at capture and every dispatch. Renewal changes no original grant window; a semantic change at the same revision changes the digest. Both helpers retain approved list order and use the same canonical serializer as the existing mandate and command digests.
1532
+
1533
+ The existing command union adds `deliver_website_visit` for the protected native operation path. It carries one original Meta channel and an internal `occurrenceId`, alongside the existing plan, review, revision, idempotency and mandate references. It carries no matching values, timestamps, dataset or provider body. `parseResonanceCommand(value, { preparedPlan, mandate, now })` checks original public grant consistency; it can't establish a protected producer, native claim or permission to send. Manual, public API and MCP entry points must reject attempts to originate this command. Native consumers must use the existing action ledger, standing approval and durable admission path.
1534
+
1535
+ Measurement occurrences gain optional `pagePath` and `metaCookieObservation` fields on `page_view` only. The cookie observation has source `sdk_reported_first_party_cookie` and one or both actual reported `fbp`/`fbc` values. Each value is limited to 1–1024 characters with no whitespace or controls. Matching requires the path and existing resource reference on that same occurrence and navigation. The API must verify the owned site and exact approved rule/path/resource. A separate-origin API can't infer the site's first-party cookies from its own Cookie header. Raw matching belongs only in protected capture persistence, never ledger payloads, operation requests, results, receipts, public configuration or read responses.
1536
+
1537
+ This is an SDK-reported observation. It doesn't prove that a person rendered a page or create a qualified lead or business conversion. The server-only event ID is the internal occurrence UUID; browser/server pairing is unsupported when the browser uses its different public event ID.
1538
+
1539
+ `resonanceWebsiteVisitEventTime({ occurredAt, receivedAt }, { mandate, approvedAt, now })` checks the local time arithmetic and returns epoch seconds from the original reported `occurredAt`. The first receipt and final attempt must each be within 300,000 milliseconds of that original time, inclusive, with zero future allowance. Both original times must follow the original accepted feed approval and stay within its original window. It never substitutes receipt, retry or regrant time. This is Sonor's conservative policy, not a Meta age limit or acceptance guarantee. An authenticated exact-body replay must return its original stored identity and first receipt before new-capture age checks, without insertion, enrichment, queueing or resend. Current consent epochs, grant, kill, claim and global dedupe checks remain native owner responsibilities.
1540
+
1541
+ These pure contracts don't install capture, a protected configuration writer, a matching-profile producer or native delivery. Those owners must implement and verify the actual preparation, original-delivery and terminal non-effect response boundaries before adoption. Parsing a valid payload doesn't make a provider ready or prove delivery.
1542
+
1543
+ ### Original Meta age selection
1544
+
1545
+ An original Meta channel accepts optional `ageConstraint: { mode: 'bounded', min, max } | { mode: 'omitted' } | { mode: 'provider_managed' }`. The provider-managed intent has separate native observation requirements described below. Bounded values are integers from 1 to 120 with `min <= max`; these are local transport bounds, not country, category or provider policy. An absent field preserves legacy bytes and leaves new preparation unresolved. It doesn't select a default. Explicit omission or bounds require an actual current policy witness, and native readback must account for any source-backed normalization. Adapters must block unknown policy rather than ignore the selection or invent ages. This representation doesn't establish that a compiler, account or provider supports it.
1546
+
1547
+ ### Native measurement bootstrap and Meta configuration
1548
+
1549
+ The pure setup contracts describe native owner inputs and saved projections. They don't create provider resources, grant visitor consent, approve spend, or enable the website-visit feed. Native API, SQL, preparation, approval and provider owners must adopt and verify them separately.
1550
+
1551
+ `ResonanceMeasurementConfigurationSaveCommand` selects actual native pages using `{pageId, observedRevision, observedDigest}`. Its closed input also includes `schemaVersion: 1`, `site`, `expectedCampaignRevision`, `expectedConfigurationRevision`, `idempotencyKey`, `enabled` and the basic consent-purpose requirements. It accepts no caller path, rule ID, resource reference, expiry or readiness flag. The three advertising purpose requirements are mandatory; a requirement doesn't grant that purpose to a visitor.
1552
+
1553
+ The native sequence starts with a managed draft and its owned sites; channels can be absent or empty. Measurement bootstrap uses that real draft as an operation audit home. It creates no complete advertising channel. After saving real page rules, the existing audience owner can create logical rules, and the campaign owner can save a complete Meta channel with those returned references. Meta configuration then maps those same logical rules to existing native audiences or admitted creation intent. A present channel still requires its complete original fields.
1554
+
1555
+ Measurement configuration CAS is scoped to project/site. Zero expects actual absence; a legacy or malformed row without protected provenance must block. An audit campaign's revision check doesn't partition the site configuration or advance that campaign's review revision. `projectResonanceMeasurementConfiguration(command, context)` accepts an authorized project, protected current projection, reloaded safe page facts and a native transport expiry. It derives one rule per actual page UUID, sorted by page ID. The page resource revision is canonical UTC milliseconds; the rule revision is the existing full native evidence digest. This preserves distinctions between source updates within one millisecond. Native SQL must independently validate the facts and recompute CAS decisions under its locks.
1556
+
1557
+ Native semantic `configRevision` and `policyRevision` are positive decimal strings. Identical semantics and a new cache expiry preserve them. Page evidence, selected rules or enabled-state changes advance the configuration revision; only consent-policy changes advance the policy revision. Initial provider destinations are `[]`; updates preserve explicitly configured destinations. The helper returns the configuration, friendly page projections and `configurationDigestInput` from the existing `resonanceMeasurementConfigDigestInput`. Hash that exact string once. The save-request digest helper retains original request array order, while derived semantic pages and purposes are sorted.
1558
+
1559
+ Measurement `Current` distinguishes actual `unconfigured` revision zero from a saved `configured` projection with current reasons. `Snapshot` contains the original audit campaign, operation, configuration and friendly page evidence. `SaveResponse` adds `replayed`. The native owner must return an exact original same-key result before fresh CAS/source checks, while enforcing current read permission; a changed request conflicts. No parser proves native provenance.
1560
+
1561
+ The agreed native freshness model is one read-only current-configuration resolver. It checks actual current ownership, protected saved provenance, native page evidence, configuration and policy, then issues a 300-second cache envelope from the database clock. All native purpose, consent, intake, audience, attribution and feed gates must use that same resolver. Reads must not mutate settings, create renewal operations or change original saved bytes. The cache envelope never extends consent, capability, mandate, feed, flight or kill authority. Source drift requires an explicit protected save. This is an adoption requirement, not a claim that those native ports are implemented by this package.
1562
+
1563
+ `ResonanceMetaConfigurationSaveCommand` contains the expected campaign/configuration revisions, schema version, idempotency key and exact original logical audience mappings:
1564
+
1565
+ ```ts
1566
+ { audienceRuleId, mode: 'existing', nativeAudienceRef: { externalId, revision } }
1567
+ // or
1568
+ { audienceRuleId, mode: 'admitted_setup' }
1569
+ ```
1570
+
1571
+ The original channel remains the editable account, dataset, Page, Instagram, country, category, age, budget, creative and destination definition. Save accepts no duplicate channel, provider request, created audience ID for setup intent, matching data or approval flag. The existing native audience reference uses its actual numeric external ID and source evidence revision.
1572
+
1573
+ `ResonanceMetaConfigurationSnapshot` freezes the original channel, root/configuration revisions, reviewed definition digest, saved operation UUID, advertiser and nullable native names, measurement/profile references, friendly rules and resolved audiences. Each audience row is `{audienceRuleRef, name, resourceRuleRef, excludedResourceRuleRefs, selection}`. Its logical name is separate from `selection.nativeAudienceName`; its positive rule is separate from exclusions. Existing selection carries the native reference/name. Admitted selection carries `setup: {kind: 'meta_website_audience_v1', localOutputKey, specDigest}`. The local key is the original SDK `audience:<id>:<revision>` key; `specDigest` identifies the existing SDK audience input. Native HTTP request and compiled graph identities remain distinct private preparation evidence.
1574
+
1575
+ The matching-profile ID is the actual persisted save operation UUID. Its revision is the positive **integer** configuration CAS; measurement configuration/policy strings are different fields. Native save must atomically persist the real operation, settings and snapshot before exposing that reference. A new explicit Meta save advances its configuration CAS and campaign review revision; the snapshot carries the resulting root revision. A replay advances neither. Draft metadata receipts don't require fabricated prepared versions or operational channel rows.
1576
+
1577
+ `resonanceMetaConfigurationDigestInput` omits only its self digest and preserves all original material, including friendly labels. `projectResonanceMetaConfiguration(snapshot, currentMetadata)` returns `{view, review}`. Metadata contains `currentCampaignRevision`, native-owner-derived `currentDefinitionDigest`, `observedAt`, nullable `expiresAt`, `reasonCodes` and `pendingRequirements`. `readyForReview` is derived output: no blockers, a current root revision at least as new as the saved audit revision, an exact match between the current semantic definition digest and the saved reviewed definition digest, and a nonexpired observation horizon. Metadata-only root revision bumps can therefore preserve multiple unchanged channel configurations; original snapshots keep their real save revisions. Native owners must still verify the exact original channel, configuration CAS, saved operation, configuration digest and current source/resource/account/policy facts. A matching campaign digest never substitutes for those checks. The review is the unchanged original snapshot when those prerequisites hold, otherwise `null`. Pending native creation, validation or age observation never grants execution. Pure timestamp ordering doesn't prove freshness when a cached view is consumed; the actual owner and UI must withdraw stale reviewability.
1578
+
1579
+ ### Explicit feed selection and original review
1580
+
1581
+ `parseResonanceMandateDraftRequest` preserves the existing `{expectedRevision, allowedOperations, expiresAt}` request and accepts an optional minimal selection:
1582
+
1583
+ ```ts
1584
+ websiteVisitFeedSelection: {
1585
+ channels: [{ channelId, expectedConfigurationRevision, resourceRuleRefs: [{ id, revision }] }]
1586
+ }
1587
+ ```
1588
+
1589
+ Absent selection preserves no-feed behavior. Empty lists, duplicate selectors, full editable grants and copied destination/profile/readiness fields are rejected. The native owner resolves the exact saved configuration, profile receipt and positive rule versions through the existing mandate authority. An excluded-only page can't become a selected feed permission.
1590
+
1591
+ The existing mandate-draft response remains the raw `ResonanceMandateApprovalPayload`. Before acceptance, reviewers use that original payload with exact immutable configuration review snapshots; mismatched refs, digests, revisions or plan material block review. Latest labels must not replace original reviewed labels. Actual native approval can use the existing legitimate member or invited delegated-agent authority.
1592
+
1593
+ `ResonanceWebsiteVisitFeedReview` is a separate **post-acceptance** projection: `{schemaVersion: 1, approval, mandateRef, configurations, current}`. It requires a genuine nonnull accepted mandate reference. Before acceptance, the native read returns its typed unavailable/not-found result. Original historical snapshots remain readable under current authorized scope when current state is invalidated or unavailable. `eligible` describes current review observation and grants no execution authority. No-feed requires `not_enabled` and an empty configuration list. The saved configuration audit revision can precede the exact original approval/plan revision, but can never follow it. The optional original prepared-plan context checks exact approval/plan revision, matching channel material and definition digest. Native original reads must supply the actual stored plan and verify the selected original configuration identities. Preparation, approval, claim and acceptance still require the exact current native root revision; this configuration review rule does not relax those fences. Actual approval provenance, hashes, source facts, consent and admission remain native checks.
1594
+
1595
+ Native owners plan separate original configuration and accepted feed-review reads under the existing protected configuration/mandate owners. This package adds no endpoint, approval surface or provider client. Public, manual and MCP entry points must continue to reject internal `deliver_website_visit` before filing; a parser or service label never proves protected origin.
1596
+
1597
+ ### Provider-managed age intent
1598
+
1599
+ The additional closed original Meta intent is `{mode: 'provider_managed'}`. It accepts no bounds, default flag or observed native values and never replaces absent, `omitted` or `bounded` intent. Its review promise is: “Use Meta age settings; record the initial observed configuration before activation.”
1600
+
1601
+ Native create and validation requests must omit both age keys. Before activation, the first genuine same-root PAUSED AdSet creator receipt and complete scoped read must seal initial age values **and key presence** once in the existing protected operation. Activation must compare that unchanged observation and every independent non-age, consent, authority and budget gate. Later changes block. This intent makes no claim about exclusive default authorship, unlimited ages, legality or serving. Existing three-mode consumers need explicit preservation, editing and review support before adopting this branch.