Follow each domain approval with Microsoft access and its own Postmark invitation
Context and Problem Statement
OPDA already has recruitment and invitation decisions. They describe different activities, not one interchangeable email campaign:
| Activity | Governing record | Purpose and current boundary |
|---|---|---|
| Finance and Banking roster invitations | Proposed ADR-0065 and the August Postmark rollout plan | Individually authorised historical waves, using each recipient’s Microsoft invitation. These are not a reusable send population. |
| Public recruitment and trade-body outreach | Accepted ADR-0071 | Invite expressions of interest through /join; no automatic membership or marketing-list import. |
| Microsoft workspace provisioning and invitations | Accepted ADR-0070 | A private Team and separate organisation-isolated source-intake site per group; provision and verify before sending. |
| Bounded inbox assistance | Accepted ADR-0072 | Act on authorised email requests with verified postconditions and an explicit AI-inbox-agent disclosure. |
| Signup and website approval | Accepted ADR-0084 | HubSpot holds staff review decisions; AWS enforces eligibility and Cognito authenticates participants. |
The live Postmark account inspected on 8 September contains the Finance and Banking invitation and the earlier working-group interest verification template. The verification email belongs to the earlier pre-review flow; it is not an approval invitation. The Finance template contains Finance-specific Microsoft links, so sending it unchanged to every group would be incorrect.
On 8 September the operator requested invitations and Microsoft access after a contact-wide approval of its selected groups, plus SharePoint setup for every new approved company domain. That version 1 policy was implemented and verified; its dated evidence remains below. On 9 September the operator replaced blanket group approval with independent approval for each domain, requiring one domain-customised email based on the original invitation for each approved group. Selecting multiple groups is not approval for all of them.
This extends the approval follow-up. It does not reinterpret public form submission, the frozen historical HubSpot import, a newsletter subscription or a CRM seat as Microsoft access authority. It concerns participation administration, not SPDTF trust-framework or standards authority.
Decision Drivers
- Let staff approve or withdraw each person’s domains independently in HubSpot.
- Preserve reviewed scope and distinguish requested interests from effective access.
- Reuse the original invitation’s layout and detailed guidance, with domain-specific content.
- Provision new organisation areas safely instead of depending on a hand-built folder list.
- Keep website access independent of Microsoft provisioning delays or email delivery.
- Use a small, durable follow-up suitable for fewer than 1,000 participants, not a new CRM.
- Make withdrawal, retries and partial completion explicit without sending duplicate invitations.
Considered Options
- Keep a separate manual roster and send step for every applicant. Safe when carefully operated, but duplicates the decision staff have just made and leaves several lists to reconcile.
- Use HubSpot marketing automation for everything. The inspected Free Tools account does not provide the required unattended Microsoft provisioning; a marketing email is not authentication.
- Do every external action inside the approval webhook. Couples immediate website access to slow Microsoft operations, retries and ambiguous email outcomes.
- Use one durable follow-up for each trusted domain approval (chosen). Recompute website eligibility separately; prepare that domain’s Microsoft access and send its own invitation.
Decision Outcome
1. Independent human approval for each domain
Staff review the person, organisation relationship and requested interest, then set that domain’s review dropdown to Approved. This authorises only that domain and its invitation. For example, approval for Finance and Banking does not approve Conveyancing. Two independently approved groups produce two separate emails; pending or rejected groups receive neither grants nor an approval invitation. The action does not authorise historical campaign resends.
The schema and current content-version-3 templates use these exact names. Content revision does
not change independent-domain approval: contract.version=2 and its outbox semantics remain unchanged.
| Domain ID | Staff-owned HubSpot property | Version 3 Postmark alias | Template ID |
|---|---|---|---|
finance-and-banking | opda_review_finance_and_banking | finance-and-banking-approval-invitation-v3 | 46456605 |
conveyancing | opda_review_conveyancing | conveyancing-approval-invitation-v3 | 46456619 |
estate-agency | opda_review_estate_agency | estate-agency-approval-invitation-v3 | 46456606 |
surveying-and-valuation | opda_review_surveying_and_valuation | surveying-and-valuation-approval-invitation-v3 | 46456640 |
property-data-services | opda_review_property_data_services | property-data-services-approval-invitation-v3 | 46456620 |
property-technology | opda_review_property_technology | property-technology-approval-invitation-v3 | 46456621 |
Each dropdown has Requested (received), Under review, Approved, Rejected and Withdrawn. The website signup marks each requested domain Requested so staff can see what awaits a decision; the label was renamed from Pending on 2026-09-15 and the value is unchanged.
Clearing it also removes that domain’s approval. opda_requested_working_groups remains
interests only. The account-wide opda_review_status field was removed on 2026-09-15: the
domain dropdowns are the single control surface for approval and revocation, and no field
vetoes every group at once. The integration’s initial Requested marker neither approves a
domain nor places a review hold. The frozen 2026-09-10 Finance import receipts still hash the
retired field’s observation so they stay verifiable; nothing derives a decision from it.
Record actor/time, immutable participant binding, decision ID, domain version and reviewed scope.
Normal approvals require current, attributable CRM_UI history after DOMAIN_REVIEW_CUTOVER, with that domain requested at review. Forms and later interest edits cannot grant access.
The explicit 10 September Finance roster approval is a source-pinned, 372-person exception: a private AWS operator receipt binds the exact CRM observations, identity and Finance scope.
That historical import creates no onboarding jobs or emails, changes no Microsoft grants and preserves website enrolment. Microsoft acceptance is separate observed metadata, not proof of website enrolment.
Changed import observations lose their exception; later human reviews and withdrawals use the normal policy. Imports otherwise remain untrusted. No S3 backup or marketing consent is created.
Missing or contradictory evidence fails closed. Property Technology is never mapped to the separate cross-cutting Technology Working Group.
The 2026-09-09 read-only preflight reported eight remaining custom-property slots: overall limit 10/usage 2, contact-property limit 1,000/usage 11, with 403 active definitions. All six dropdowns were then created in OPDA participation and read back compatible, with no missing fields or blockers and two slots remaining. Definition counts are not quota usage. No field retirement, paid upgrade or runtime permission expansion was needed.
The frozen import is historical approval evidence, not a website-only entitlement or a wave of Microsoft invitations. CRM-managed website access requires at least one approved domain. Ordinary migration preserves only matching, explicitly approved pre-cutover frozen domain scopes after the bound version 1 operation is explicitly complete. Never infer domains from today’s interests or replay old mail. Unresolved invitation effects must not delay access removal:
- A global/account hold disables website access immediately and retains the version 1 path for account-wide, receipt-owned cleanup. Preserve the original unresolved operation reference.
- A partial withdrawal may seed denial-only version 2 state from a valid matching frozen prior approved scope. Withdraw only the named domain, preserve other prior approvals, and invalidate further execution of the old combined job. Create no new grants or invitations.
- If that prior scope is missing or invalid, fail closed into the legacy account hold and owned-grant cleanup; never reconstruct approved scope from requested interests.
Keep domainMigrationPending until the original participant-bound outcome is explicitly
settled as complete. Missing, pending, cancelled, attention or unknown-send outcomes are not
completion. Further denials continue during this hold; new grants remain blocked. Settlement
must reconcile evidence, never resend ambiguous mail merely to complete the ledger. Enforce
the approved-domain predicate at authentication without a bulk import reconciliation or mail wave.
2. Durable follow-up without delaying website access
Persist each domain’s reviewed snapshot and follow-up atomically with the effective approval. The reference-only work item contains an opaque operation ID, not contact details or invitation URLs. A separate bounded worker performs external effects; the approval webhook does not wait.
Reuse the AWS participant register, a dedicated queue and its dead-letter handling. Keep one onboarding worker with narrow access to the required Microsoft and Postmark credentials, rather than a general integration platform. Reconciliation repairs a committed operation whose queue notification was interrupted. Do not replay the public-submission queue or historical wave files.
Before every grant or send, recheck that domain’s current AWS decision, identity binding and account eligibility. Bind version 2 operations to participant, domain, immutable decision ID and domain version, not another domain’s changing state or a contact-wide invitation key. Refreshing an unchanged approval does not resend. A later approval for a different domain does not supersede this domain’s pending invitation. Hold one participant-wide lease while updating shared identity/ownership receipts; preserve independent per-domain operation snapshots. Interrupted work resumes from verified receipts. Pending or review-required is never called ready.
For recognised Microsoft propagation and safe pre-send availability waits, retain the existing SQS message for at most three short retries, after 15, 45 and 120 seconds. Change its visibility using the existing queue-scoped permission and return a partial batch failure; Lambda does not sleep. Exhausted retries leave the durable operation for scheduled recovery. Configuration waits, manual review and ambiguous sends do not enter this fast path. Do not scan the CRM to retry one operation. This follows AWS partial batch responses and message visibility.
One approved domain can enable website eligibility under ADR-0084, subject to enrolment and account holds. Microsoft and email follow asynchronously. Their outages must not undo valid website eligibility or grant withdrawn access. Other domain approvals remain independent.
3. Prepare Microsoft resources before declaring access ready
Follow ADR-0070’s private Team and separate SharePoint source-intake pattern for every group. Resource creation is explicit administration. Ordinary applicant approvals may provision members and organisation areas inside a verified group workspace; they cannot invent new Teams or sites.
Silently create or reuse the correctly bound Entra guest. Use sendInvitationMessage: false
and keep group welcome emails disabled. Reuse accepted identities without resetting redemption.
Microsoft documents both custom delivery of the returned invitation URL and the separate guest
redemption step. Microsoft Graph invitations
For every approved group:
- Verify the configured private Team, standalone intake site and ownership baseline.
- Add ordinary Team membership, never owner or administrator membership.
- For an approved company-domain identity, idempotently create or reuse its canonical company group and folder in Incoming Source Material / By Organisation.
- Break folder inheritance and assign only the expected company contributor group and authorised OPDA administrators/processors. Contributors cannot manage permissions or share material.
- Give the participant the necessary organisation-index and matching contributor membership.
- Read back the Team membership, folder identity and isolation before recording readiness.
New company domains are part of the same follow-up, not a later manual folder-creation task. Domain syntax alone is not proof of company authority: the human review must approve the organisation/domain relationship, and aliases must be explicitly recorded. Personal or generic email providers receive Teams-only access, with no provider-wide company group or folder. Do not change tenant-wide sharing policy, enable anonymous links or expose one company’s files to another to make provisioning succeed.
The unattended Microsoft identity must be independently provisioned and authorised. Prefer resource-scoped grants for the configured Teams and intake sites where supported. Selected SharePoint permissions require explicit assignment to the intended resources; consent alone does not grant site access. Never transfer an operator’s interactive refresh session into AWS or silently substitute tenant-wide directory write authority. Microsoft selected permissions
App-only guest membership needs a deliberate implementation choice: the direct Teams add-member API does not support adding guests with application permissions. Microsoft 365 group membership is an alternative, but group-to-Teams synchronisation can take 24 hours or more and depends on desktop-client activity. Keep the operation pending until actual Team membership is observed; never promise immediate Microsoft access from the group write alone. Teams guest restriction, membership synchronisation
SharePoint CSOM/REST app-only operations require certificate authentication. The operator’s delegated CLI session is useful for explicit administration, but it is not an unattended service credential. SharePoint app-only authentication
The dedicated OPDA Participation Onboarding service application uses Microsoft Graph
User.Read.All, User.Invite.All, GroupMember.ReadWrite.All, TeamMember.Read.All and
Team.ReadBasic.All. Its SharePoint-resource Sites.Selected permission has explicit
fullcontrol assignments on the six domain intake sites only. It has no tenant-wide
SharePoint, directory-write, user-write or Team-owner-write permission. The final two Graph
read permissions verify actual Team state rather than assuming group synchronisation.
The certificate and a separate receipt-encryption key are held in AWS Secrets Manager.
Rotate the certificate before its expiry; preserve the separate encryption key while existing
receipts require recovery. Encrypt the private receipt payload with authenticated encryption
bound to its participant, so redemption URLs are not plaintext in DynamoDB or retained recovery
copies. Follow ADR-0084’s native PITR boundary; onboarding does not require a separate S3 backup
service, which the operator removed from scope on 2026-09-09.
4. One original-style Postmark invitation per approved domain
Use six separate content-version-3 aliases from section 1, with subjects Your invitation to the [Domain] Working Group. Compile them from one shared original-invitation HTML/plain-text layout and a reviewed six-domain content registry. Retain the original 680-pixel table shell, CID logo, colours, typography, illustrated section headings and full detailed contribution, source-material, thread-first discussion and privacy guidance. Customise the domain explanation, relevant evidence examples and discussion topics; do not reduce them to generic group cards.
Preserve original Finance template 45998430, combined version 1 template 46437816 and
all six -v2 domain templates unchanged. Their historical content and delivery evidence remain;
new content aliases do not authorise replay, resend or alteration of earlier mail/outbox outcomes.
Each domain email contains:
- the participant’s name, the one approved domain and its relevant contribution guidance;
- one primary Open the [Domain] Working Group action using the stable first-party URL
https://opda.org.uk/_auth/workspace?group=<domain-id>, with no personal identifier or ticket; - verified discussion/resource links and the private source-folder link, or clear Teams-only guidance for a generic-provider account;
- an ordinary website reference, without email-code or separate Microsoft setup instructions;
- the existing guidance about contributions, thread-first discussion and authorised material; and
- the support address and Postmark unsubscribe control.
Send only after that domain’s required Microsoft postconditions are verified or have a deliberate Teams-only outcome; another domain can remain pending. Do not promise a pending company folder. Finance’s verified channel links remain ordinary references; other domains describe topics, not invented channels. Domain email models contain no redemption ticket or frozen Microsoft status. Keep tickets out of HubSpot, email content, logs, queue messages and public/template source.
Entry-page GETs and the established-identity access path are read-only. Authenticate the website
session, recheck current domain approval and immutable participant/Microsoft identity, then read
actual group and Team membership in the registered private, active Team. Existing owners may enter;
access checks never adopt manual grants or confer ownership. Missing access remains pending or denied.
Only a same-origin, authenticated POST may repair a missing/legacy invitation hand-off under the
participant-wide receipt lease. Recheck approval; silently reissue for the same pending guest with
sendInvitationMessage:false, resetRedemption:false, and verify the returned immutable ID and
fixed inviteRedirectUrl=https://opda.org.uk/_auth/workspace/continue. Never create a missing guest,
reinvite an accepted identity, infer an uncertain POST result, or grant permissions from entry.
Normal group entry reuses the resulting receipt; repair does not queue jobs or send any email.
Each tab retains only its allowlisted group ID and short expiry in sessionStorage; a shared
last-group cookie must not let concurrent emails overwrite destinations. OAuth sign-in transactions
are independently bound. After Microsoft consent, recheck session, approval, identity and actual
membership before opening that tab’s group. Callback arrival is not proof of acceptance. Missing
continuation state offers current approved groups; failures do not loop, poll the CRM or hold Lambda
open. Keep Microsoft account selection/consent native, including invited-alias redemption. Validate
all destinations against the fixed tenant/workspace registry, not a caller-supplied redirect.
Microsoft redemption rules.
Use the existing Postmark broadcast stream. Check its suppressions immediately before sending;
an unavailable check blocks the send. Do not remove a suppression or use a different stream to
bypass it. Set TrackLinks: None and TrackOpens: false on these messages. The shared server
must also have forced open tracking disabled: Postmark’s server-wide TrackOpens: true
overrides a message’s explicit false value. Read back the pinned live server and its tracking
settings before claiming a send. Keep historical wave messages’ explicit TrackOpens: true
unchanged; they retain their existing behaviour without requiring a forced server default.
Keep the same templates, stream and suppressions rather than migrating recipients to another
server. Postmark per-message tracking,
Postmark templates API
Deduplicate by participant, domain, immutable approval decision and domain version; pin the exact template ID, alias, subject and HTML/text fingerprint. Require exactly one matching domain in the payload and reconciliation metadata. A template edit does not resend. Record attempted, provider-accepted, failed or unknown delivery outcomes. If a send times out ambiguously, reconcile provider activity before retrying; do not claim exactly-once delivery from a local flag. Provider acceptance and an open event are not proof of inbox placement or Microsoft redemption.
ADR-0072’s AI-inbox-agent disclosure applies to that agent. This deterministic approval worker must not falsely claim an AI agent wrote or reviewed the invitation.
5. Withdrawal, reapproval and communication preferences
Withdrawing a domain removes only that person’s approval, owned Microsoft grants and unsent
mail for that domain. Other approved domains retain access and pending invitations. Website
eligibility and its session version remain unchanged while another approved domain remains.
Historical website-only import approval cannot bypass this rule by itself. The explicit
operator website allowlist (websiteAllowlist on the account, set with
scripts/website-allowlist.mjs and recorded with a reason and actor) keeps website sign-in
without any working-group workspace. It is an alternative website entitlement, never a group
approval or workspace grant, and participant lifecycle projections do not override it. On 2026-09-18 the four
legacy Auth0 allowlist accounts without a working group were granted it (operator decision).
Loss of the last approved domain removes website eligibility only when the allowlist is also
absent. Removing the final entitlement increments the access version and invalidates sessions.
The open-tab check updates the UI, not the security boundary; delivered data cannot be recalled.
Withdrawal also cancels unsent onboarding messages and queues removal of grants recorded as owned by this approval workflow. Remove membership references only, never the Entra user, organisation folder or source material. Preserve other approved participants and unrelated manual grants; if a pre-existing grant prevents complete Microsoft removal, report that fact for explicit review rather than claiming access has gone. Microsoft propagation is not instant.
The withdrawal path is:
- Staff change the relevant domain’s review from Approved to Withdrawn. Pending, Under review, Rejected or clearing the domain field also removes that domain’s approval.
- AWS records its decision/domain version first and recomputes website eligibility. Only loss of the final website entitlement increments the session access version. Identity-binding and session-integrity failures still deny access; lifecycle projections do not add eligibility gates.
- The committed domain decision creates an opaque withdrawal operation. Cancel only that domain’s unsent invitations before cleanup; dispatched email cannot be recalled.
- Read the participant-bound ownership receipts. Remove owned SharePoint contributor and index memberships first, then owned Microsoft 365 group membership references. Never delete an identity, company folder, source document or another participant’s access.
- Read back removal. Keep Microsoft propagation pending and retry through the existing
15-minute outbox relay; do not exhaust short queue retries while waiting for normal Teams
synchronisation. Ambiguous writes, manual grants and policy drift require explicit review.
Amended 2026-09-16. A write is ambiguous only when the provider gave no answer (timeout,
5xx). A 4xx response proves it was refused without effect: the grant is recorded
cancelled, 429 is retried through the relay and other refusals wait for review; a cancelled grant may be retried by a later current approval. The review itself isscripts/onboarding-review.mjs, which compares an uncertain grant with the live site and records the reviewer’s verdict (absent→ retry,owned→ ours,manual→ retained) before re-queuing the operation. The worker now tracesonboarding_source_effect_failed(effect key, provider HTTP status) andonboarding_operation_parked(stage, reason) so an alarm names its cause. Live evidence: a transient SharePoint failure ongrant-indexat 20:05:14Z parked op2daff653…with no invitation sent and no diagnosable reason. - Send one domain-specific withdrawal notice only after its managed Microsoft removals are verified. An initial rejection, historical unmarked cleanup or another denied status does not create a new notice. Pending propagation or retained manual grants must not produce a false claim that the working group’s access is gone.
- When the last approved domain is removed, create a separate website-disabled notice in the same decision transaction. Its notification-only outbox operation uses the existing queue, worker and private receipt ledger; it does not wait for Microsoft cleanup. Send only after the matching Cognito disablement and global sign-out have succeeded. Reapproval cancels stale notices.
- A fresh human approval for that domain after its latest withdrawal/hold may restore it and send its own invitation. Clearing a global hold alone restores no domains. Repeated holds must retain a fresh denial boundary, never let an older approval reactivate access. Stale jobs cannot override current decisions. Reuse verified identities/folders and retain manual grants.
Cleanup uses immutable identity and permission references, not a fresh lookup by mutable email. Retained ownership evidence allows cleanup after the public profile is erased. Authenticated receipt encryption uses a separate key that must survive certificate rotation. The current credential loader still validates certificate lifetime before returning that key, so expired credentials can block cleanup and notices until rotated; independent recovery is not yet verified.
Withdrawal notices retain the original invitation’s layout, with six domain templates and one
website template. They use Postmark’s transactional outbound stream, no tracking and no campaign
unsubscribe link. Invitations remain on their existing stream. Respect the selected stream’s
bounce/complaint suppressions; never remove a suppression to force delivery. Bind each notice to
its immutable decision, exact template pin and current recipient identity. Repeated events reuse
the original operation. Persist the send attempt before dispatch; reconcile ambiguous outcomes,
never blindly resend. A definitively undispatched preflight interruption may retry safely.
Email unsubscribe does not revoke membership. Participation approval is not consent to receive marketing campaigns. Recruitment outreach, newsletters, Cognito codes and Microsoft onboarding remain distinct purposes with their own recipients and controls.
Consequences
- Good, because each domain decision is attributable and drives only its own access and invitation.
- Good, because new company folders and permissions are verified before an invitation promises them.
- Good, because current Postmark assets and Microsoft boundaries are reused without a new CRM.
- Bad, because external provisioning can be partially complete and needs durable retries and review.
- Bad, because unattended Microsoft access requires explicit credential and resource-permission setup.
- Neutral, because website access can be ready before Microsoft onboarding or mail delivery.
Confirmation
Content version 3 preparation, 2026-09-10: all six new templates were created on server
20188829, passed 12 synthetic provider-render validations and byte-exact fingerprint readbacks.
Their IDs are in section 1 and settings.mjs; no mail was sent or historical template changed.
An isolated live Microsoft check reused the same pending guest, silently refreshed its fixed
callback in 3.25 seconds and passed both production URL validators. Test guests were removed;
no existing participant, membership or email delivery changed. This preparation does not itself
establish deployment or interactive consent. The browser redemption journey remains unverified
because this session’s Chrome backend is unavailable; API checks are not a substitute for it.
Version 2 readback, 2026-09-09: the active approval Lambda reports
DOMAIN_REVIEW_CUTOVER=2026-09-09T14:35:15Z. All six domain properties exist and the independent
domain policy is deployed. The following dated test also establishes deployment of the
withdrawal-notice amendment; the earlier version 1 evidence remains historical.
On 2026-09-09, all six version 2 templates passed Postmark parsing/rendering validation and
were created on server 20188829. Readback verified byte-exact HTML/text against the compiled
content pins. Historical -v2 IDs, in section 1’s domain order, are 46444294, 46444295,
46444297, 46444274, 46444261, 46444262; they are retained, not the new content pins.
No email was sent by this preparation; original Finance and combined version 1 content stayed unchanged.
Template provisioning alone does not activate domain approval or prove end-to-end delivery.
On the same date, seven original-layout withdrawal templates passed provider validation and
byte-exact readback on server 20188829; their IDs and fingerprints are pinned in settings.mjs.
Provisioning sent no mail. Live readback also confirmed six private Teams and six distinct,
non-group-connected source-intake sites, with the expected organisation isolation. Team-connected
collaboration files are a separate access path inherited from Microsoft 365 group membership.
Withdrawal and restoration test, 2026-09-09: commits 558d0280 and a089d7fe reached live
infrastructure and website deployments. Readback matched all 29 runtime files to committed bytes.
Both queues were empty at final verification. Real HubSpot interface decisions exercised two groups
for one authorised existing participant; no historical contact sweep or bulk notification was triggered.
- Removing the first group preserved website eligibility and the other group’s access. Its withdrawal email was delivered 71.630 seconds after the persisted review.
- Removing the last group disabled Cognito after 2.443 seconds; the independent website-disabled email was delivered after 5.171 seconds. A fresh real sign-in rejected a valid email challenge because the user was disabled. The account’s provider-version marker matched the denial version.
- Microsoft API readback confirmed removal from both private Teams and both separate source-intake contributor/index groups. Unrelated, manually granted membership and source material were preserved.
- The second withdrawal email took 19 minutes 33.171 seconds: its earlier pending operation awaited relay recovery and was eventually re-notified by a later review. This is not evidence of fast recovery. Section 2’s fix was then verified live: a 15-second queue retry completed propagation; worker executions took 13.582 and 5.684 seconds.
- Reapproval restored Cognito and both groups’ Microsoft access. Separate invitations were delivered 46.277 and 34.480 seconds after their respective reviews; both were also observed in the inbox. All five integration emails had provider delivery events, with no duplicate sends observed.
- A repeat real signup was quarantined for manual review after 9.578 seconds; it did not create a duplicate contact, erase the withdrawals or restore access. The participant finished approved for both test groups, active and unsuspended, with Cognito enabled and managed permissions restored.
Remaining verification boundary: Chrome reported ERR_BLOCKED_BY_CLIENT for the OPDA callback
and session-status routes, preventing establishment of a baseline website session for this test.
Logout of an already-open website session remains unverified live for this version. AWS recorded
global sign-out by the approval role at denial, but redacts the username; this is corroboration, not browser proof.
Synthetic tests cover session invalidation, replay, denied-status churn, reapproval races and uncertain sends. Validation
passed 792 tests with one deliberate skip, the 19-case IA audit and the 2,737-page static build.
Historical version 1 rollout and live evidence, 2026-09-09
The contact-wide Microsoft/email follow-up became live on 2026-09-09, alongside website approval and revocation under ADR-0084. The following dated evidence describes that earlier combined-invitation policy, not the newly accepted individual-domain policy or a backfill. During initial workspace provisioning on 2026-09-09, the five missing domain Teams and separate intake sites passed configuration and ACL readback under ADR-0070. That preparation added no applicants or company folders and sent no invitations.
The combined HTML/plain-text templates and pure payload builder are deployed, with 11 tests covering all six configured workspaces, conditional redemption, URL validation and tracking settings.
Postmark’s validation API accepted subject, HTML and text in six synthetic rendering cases: mixed, all-folder and Teams-only access, each with and without redemption.
On 2026-09-09 the new live Postmark template was created and read back as template 46437816 on server 20188829.
Its HTML/plain-text fingerprint is pinned by the service; neither earlier template was changed and no message was sent by template creation. The live recipient test is recorded separately below.
The dedicated Microsoft service application and certificate are provisioned. App-only reads succeeded on all six configured sites and private Teams; the unselected cross-cutting Technology intake returned HTTP 403. Finance’s member-sharing setting was aligned with the five new sites. No participant memberships, company folders or guest invitations were changed. The initial certificate expires on 2027-03-07. Its temporary local private-key copy was removed after the Secrets Manager copy was verified. No delegated refresh session was transferred.
Approval-time group snapshots, atomic reference-only outbox records, cancellation/withdrawal work, a certificate-authenticated API boundary, encrypted receipt storage and the Microsoft, SharePoint and Postmark adapters are deployed and tested. The consumer covers guarded provisioning, withdrawal, reapproval, erased-profile cleanup, stale jobs and ambiguous email outcomes. Its dedicated queue and narrowly scoped role are defined in CloudFormation; the deployment package copies only the runtime dependencies and CID logo. The packaged runtime also passed read-only assembly against the actual service secrets: participant-bound receipt encryption round-tripped, all six private Teams and typed membership reads succeeded, member sharing remained disabled on each intake site, and the live Postmark template matched its pin. No participant record, membership or invitation was changed by this check.
Automatic grants default to disabled. CI requires both OPDA_ONBOARDING_ENABLED=true and a prospective UTC OPDA_ONBOARDING_CUTOVER in YYYY-MM-DDTHH:mm:ssZ form to begin new onboarding.
For controlled verification before general activation, OPDA_ONBOARDING_CANARY_EMAIL_HASH may identify one explicitly authorised recipient by the lowercase SHA-256 of their normalised email.
It is empty by default and cannot bypass approval, snapshot or current-eligibility checks. Malformed configuration fails closed. Managed withdrawal remains enabled independently of both activation switches.
The dedicated worker and infrastructure were deployed on 2026-09-09 through successful CI runs 34296804034 and 34296804326.
The recipient-limited verification switch was subsequently deployed from commit 17d385f145ae1426fefd45910eb0d2c58e13e888 through infrastructure run 34297885445; AWS readback confirmed an active, successfully updated worker with general onboarding disabled.
Deployment is not proof of completed end-to-end onboarding.
The controlled recipient test then created two organisation areas inside the existing intake sites, preserving ADR-0070’s workspace and permission pattern.
A repeated readback exposed a verifier defect: SharePoint had added built-in Limited Access beside the parent’s existing administrator and processor roles.
The verifier now accepts that navigation-only role at the organisation index while still requiring the exact effective role, rejecting duplicates and additional effective grants, and leaving company-folder ACL checks unchanged.
No existing site or permission was replaced to make the check pass. This follows Microsoft’s documented automatic Limited Access behaviour.
The regression was reproduced before the fix; all 34 focused SharePoint tests then passed. The correction was deployed from fe54166b873259c1bec409e42efcf8ab183deb04 through successful infrastructure run 34345211765; the deployed verifier matched the committed bytes.
The controlled recipient subsequently completed real website login, withdrawal and reapproval. Withdrawal invalidated the open website session, disabled Cognito and removed both workflow-owned Microsoft memberships; reapproval restored them and reused the existing company folders.
Unrelated Finance membership and source material were preserved. One combined invitation was delivered, but Postmark reported open tracking enabled despite the per-message false value.
The documented server override exposed a missing server-settings preflight, now covered by a reproduced regression test. The server’s forced open-tracking default was then disabled; all other server settings, all three templates and the suppression list were unchanged. Historical wave payloads still explicitly enable open tracking.
The tracking safeguard was deployed from 304322810fff1f0329edd2fd2222634c7cadc763 through
successful infrastructure run 34346862468 and site run 34346862604. A fresh, trusted
reapproval restored the same two Teams and isolated organisation folders. Postmark reported
one invitation for that decision, with TrackOpens: false, TrackLinks: None, both selected
groups in HTML and plain text, and a delivered-to-recipient-server event. Provider activity
reconciliation accepted that exact message. No historical campaign was resent.
General activation completed through successful infrastructure run 34347405213. AWS readback
confirmed an active, successfully updated worker, ONBOARDING_ENABLED=true, an empty canary
restriction, and deployed Postmark/SharePoint source bytes matching the tested commit. The
approval cutoff remains 2026-09-09T01:07:12Z; the frozen historical import is excluded. The
onboarding queue and dead-letter queue were empty at verification. The test participant finishes
approved and active, with Cognito enabled and the requested Microsoft access restored.
Validation passed 672 of 673 Node tests, with one deliberate skip, the 19-case IA audit and a 2,737-page static build. Live verification covered all six service/workspace boundaries and the authorised two-group company-domain signup, approval, login, withdrawal and reapproval case. Teams propagation was observed before re-notifying the same durable operation during that historical test; the later bounded queue retry amends its relay-only recovery. Generic-provider Teams-only handling, new-guest redemption, suppression failures, ambiguous sends and race cases have synthetic/contract coverage; they are not represented as additional live recipient tests. Delivery evidence is not proof of inbox placement, readership or acceptance of a previously unredeemed Microsoft invitation.
Keep dated evidence and opaque receipts private. Future amendments need their own deployment and readback.
More Information
- ADR-0065 — Finance and Banking evidence-to-model workflow
- ADR-0069 — public recruitment and signup
- ADR-0070 — uniform Microsoft workspaces
- ADR-0071 — public recruitment campaign
- ADR-0072 — bounded inbox operations
- ADR-0084 — HubSpot signup and Cognito
- Historical Postmark invitation rollout
- Historical combined v1 invitation, HTML
- Historical combined v1 invitation, plain text
- Shared original-style v3 invitation, HTML
- Shared original-style v3 invitation, plain text
- Six-domain content/compiler:
src/approval-onboarding/domain-templates.mjs; payload boundary:invitation.mjs. - Withdrawal shells:
docs/templates/participation-access-change-email.{html,txt}; compiler:withdrawal-notice.mjs; delivery guard:notice-worker.mjs. - Property contract:
config/aws/hubspot-participation/properties.mjs(DOMAIN_REVIEW_PROPERTIES); policy/outbox:config/aws/hubspot-approval/domain-onboarding.mjs.
Comments
Loading comments…
Sign in to post a comment