## 2.6.0 — 2026-11-14

**Summary.** 2.6.0 follows 2.5.0. It adds AccessPoint Learning, scripted people in Lab mode, rolling releases and Hosted
AccessPoint, and a subscription that lapses now leaves AccessPoint read-only instead of stopping it. The main areas:

- **AccessPoint Learning**, AccessPoint's in-product training: *How we decide*, a coach beside twelve decisions people make
  on a case, with your organization's own coach notes; learning modules your organization writes in the **Studio**; learning
  paths that give them to the right people, by hand or by audience rules; **My learning** with its module player; checks and
  decisions with model answers; completion records with reminders and a CSV export; certificates and their verification;
  recertification; the *Training coverage* and *Obligation coverage* reports; a glossary, training obligations and training
  done elsewhere; content-quality figures with a link check; and Realizer's first learning paths — five for every
  jurisdiction, two for Canada federal, and the PIA course. Learning is part of the core product; writing modules, checks,
  decisions and certificates needs the new **AccessPoint Learning** module, included in every marketplace plan.
- **Lab mode** — *train mode*, renamed. In its training cases the people around the trainee now answer as the scenario scripts
  them: outside the organization the requestor, a consulted third party, a complainant and the regulator's contact; inside it
  **simulated people** — colleagues who exist only in the training copy — who search, review, advise, sign off and give opinions.
- **Rolling releases.** A request is answered in numbered **releases** — Release 1, 2, … and the final release — each recording
  exactly which records went out, at which redaction state, with which page numbers, letter and delivery; a release can carry
  its own instalment of the fee and be held until it is paid; a release schedule gives the estimated dates the requestor was
  told; a corrected release re-issues records with corrected redactions, and a supplemental release follows the final one — on a
  closed request too; the requestor's portal page groups the records by release, each with its index. Every response package is
  now built through a release.
- **Read-only, never stopped.** A Microsoft 365 deployment whose subscription has expired beyond its grace period, or that
  Realizer revoked, becomes read-only instead of stopping; a hosted trial ends on a **Free plan** instead of a lock-out.
- **The guided welcome** for newcomers, in both editions.
- **Hosted AccessPoint:** session limits each organization chooses; Settings, Subscription and reports that follow what the
  service runs; the organization's own e-mail, with sending limits; add-ons added and removed through Stripe; sign-up from the
  demo; plans in CAD, USD, GBP and EUR, the currency set by the billing country; lifecycle e-mails, the purge of an unused Free organization after warnings, and a download of all its data; Canada on
  its own host, `ca.app.realizer.io`, behind the global entry `app.realizer.io` — where sign-up and sign-in start: it shows where
  an organization's data is kept and finds each person's region — ready for more regions.
- **Redaction:** every redaction action follows the redaction's own case, so advisors and reviewers flag and discuss redactions
  on their own requests; video and audio marks are managed in the side panel's card.
- **Jurisdiction packs:** Nova Scotia's new Act switches itself on 1 April 2027 through settings that change on a date; an
  Alberta PIA type; the Canada federal pack in the Standard on Privacy Impact Assessment's words.
- **Reports:** the Reports menu lists only the reports a person can open, in every edition.
- **AI Assist:** Realizer's recommended models move to gpt-6-luna and gpt-6.1-sol; you choose — the recommended models or your
  own — when you deploy, or name deployments of your own in Settings → Features → AI Assist.
- **Platform:** .NET 10.0.14 security servicing, SharePoint Framework 1.24.1 and React 18.3.1, PDF.js 6.5.438.
- **Realizer's own services:** the AccessPoint Training Lab (learn.realizer.io), the marketing demo (demo.realizer.io),
  hosted reporting in Realizer's admin console and its *Active now* page.

Each of *Security*, *Action required*, *What's new* and *Fixes* below is grouped by the same areas.

### Security

#### The release's security review (2026-11-12)

The review of every change since 2.5.0 (`docs/code-reviews/2026-11-12-security.md`) found two problems that let one person deny a
service to others, and a set of smaller ones. All are fixed in this release.

- **Public portal: one visitor could stop every requester's verification codes for an hour** (F-1). The organization's hourly limit
  on codes, added earlier in 2.6.0, counted codes for made-up case references that are never mailed, so one address could use it
  up and every requester's codes — intake confirmation, case status, deliveries, payments — were refused. The limit now counts and
  refuses intake codes only (the one kind mailed to an address nobody has proven yet), and one client address (an IPv6 address by its /48) may take at most
  `Portal:IntakeCodesPerHourPerSource` (10) of the organization's hourly 60; past the 60 a visitor who has asked for fewer than two
  codes this hour is still admitted, up to a ceiling of 180 (`Portal:IntakeCodesPerHourCeiling`); a code the cap refused was
  never sent and never counts. Status, My requests, delivery and payment codes go
  only to an address already on file and are never refused by it.
- **Hosted: one signed-in person could get the API blocked for every organization on a stamp** (F-2). The web host's calls reached
  the API through a Front Door rule that limits each caller address, and every user's calls came from the web host's own address.
  The API's edge now exempts the stamp's own outbound addresses, and the web host limits each signed-in session itself
  (`RateLimit:ApiPerSessionPerMinute`, 1,200 a minute).
- **Portal links** (F-3): the portal's own database login can no longer change the portal address directory, and the API names a
  portal link only on a host under the deployment's hosted domain.
- **Hosted sign-in** (F-4, S4-19): a member's stored e-mail address and a new organization's owner come only from an address the
  sign-in proves; "Who can join" refuses a listed organization's guest accounts. **Kudu (SCM)** on the hosted sites now refuses
  every address except the deployment's own temporary rule (F-5). Invitation links carry their token where no server log keeps it
  (S4-18); the hosted app no longer publishes source maps or accepts its style nonce for scripts (S4-15, S4-40).
- **Storage limits** (F-6): the plan's storage cap now counts the file being uploaded and the uploads already in progress.
- **AccessPoint Learning** (F-7, F-8, S4-8 – S4-10): a check's attempt limit and a recorded pass hold across servers; certificate
  verification says whether the printed name differs from the directory name, and leads see the printed name; approving a module
  approves the revision the approver previewed; a check with an attempt limit shows its answers once passed or on the last attempt;
  and nothing is written by a read while the licence is read-only.
- **Rolling releases** (S4-10 – S4-14): a schedule's court-order reference and note are shown only to people who can change the
  request or see requestor details; released-record outcomes follow the documents list's rule; reads change nothing while the
  licence is read-only; a schedule date far outside the request's time is refused with a reason instead of an error.
- **Smaller hardening** (S4-1 – S4-7, S4-34, S4-35, S4-38): a request's record-only state is never named to someone who cannot see
  the request; the AI consent's Administrator name is shown only to administrators; the outbound-link guard also refuses IPv6 forms
  that reach a private IPv4 address; closing a record-only request changes only its closing fields; the first-setup retry waits for
  a writable licence; portal host lookups are limited per client; the release engine reads a damaged record's tagging only when it
  is small enough to parse whole.
- **Realizer's own services** (S4-27 – S4-32): pack answers are never stored by a shared cache; Stripe's error text never reaches
  Realizer's logs or console; a refused private pack is audited by reason code only; a closed hosted region cannot learn which
  organization ids exist; and a Free-plan group used from two regions raises an alert.
- **The Training Lab** (F-9 – F-14, S4-22 – S4-26): learner joins are limited per network and a class can stop taking new learners;
  mail to one address is capped across purposes and classes; repeated wrong sign-in codes lock new-browser sign-in for a day;
  AI drafting counts against the provider's monthly budget; the 1 MB request limit holds on the Lab's server; sign-in answers take
  the same time whether or not an address belongs to a member; platform sessions are re-checked on every request; and the Lab's
  pipeline runs the product's secret scan and dependency checks before it deploys.
- **Hosted: a member removed and let back in no longer gets their old roles back** (bug review 2026-11-12 F-6). Removing a member
  now ends every role they held (the grants stay in the history, inactive), and a member let back in — by an invitation or an
  approved request to join — holds exactly the roles that invitation gives. Before, a removed Administrator invited back with no
  role was an Administrator again. Removing a member also ends their access to particular cases (advisor, reader and collaborator
  grants), the coverage delegations they give or receive, and their Lab mode roles — the same rules as offboarding a person in the
  Microsoft 365 edition — and clears their open case assignments: unassigned where a case may have nobody, cancelled through the
  item's own path where it must have someone — cancelling a custodian's assignment also cancels every open task under it,
  including tasks assigned to other contributors — and requests they were the access officer for pass to the person who removes them
  (finished work keeps their name as history). Each step is audited. Granting a person a role they held before now re-activates that grant (in every
  edition).

#### Read-only licences and the hosted Free plan (hosted onboarding)

- **One read-only rule for every write, enforced on the server (hosted onboarding O1).** Every POST, PUT, PATCH and DELETE
  endpoint is now classified — read-safe (a query sent as a POST, your own view state), export, Lab mode or write — and a guard
  test fails an unclassified one. A lapsed licence refuses every write with `403 licence-read-only` through ONE filter; a module a
  plan makes read-only (the hosted Free plan) is refused `403 module-read-only` by the same gates that refuse an unlicensed one;
  and a request recorded past the Free plan's cap refuses its case work (`403 request-record-only`) at every request write gate —
  including the extension-request, consultation and request-link routes, whose own record is resolved to its request and refused
  when it cannot be found (security review 2026-11-06 PS-1).
- **The first moments after a start no longer let writes through without a licence.** Until the API has read its licence, a write
  is refused with a retryable `503 licence-state-pending` (reads still go through) — before, the 60-second startup window let every
  request through.
- **A lapsed licence pauses every outbound feature**: e-mail and Teams notices (the training copy's too), the public portal's intake
  and payments, repository connectors and AI Assist — what abuse might have led to a revocation stops with it.
- **Personal settings stay open while read-only, and only the caller's own** (owner, 2026-11-06): a private saved view, a private
  saved report and your own notification preferences are a new class of endpoint, *personal*; the part of those endpoints that
  reaches beyond you — a shared or default view, a report shared with the organization, another person's preferences — is still
  refused `403 licence-read-only`, and a saved report still runs with the viewer's rights.
- **No real record can enter Lab mode on a read-only licence** (PS-9): uploads into the training copy are forced off while the
  licence is the hosted Free plan's or lapsed, whatever Settings → Training says, so read-only and the Free cap cannot be sidestepped
  in a training case. The Lab library's fictional records are unaffected.
- **The procurement extension cannot be replayed**: Realizer's control plane records it on the subscription with a single
  conditional write, so a second request — from any stamp, or forged — is refused `409 trial-extension-used`.
- **Hosted: "Download all of your organization's data" never reaches the operator's tenant lifecycle** (hosted onboarding O4,
  security review 2026-11-06 PS-8). It goes through an export-only façade that knows only the request's own organization — never a
  tenant id from the request — and offers start, status and download and nothing else (no purge, suspend, switch or import);
  only an Administrator of that organization, in production, may start it; each ZIP downloads ONCE (a single conditional claim),
  expires after 14 days, is streamed through the API — to the browser's own downloads through a five-minute, single-use link bound
  to the job, the Administrator and the organization, never a storage link — and every start and download is audited. A guard test
  pins the tenant lifecycle to the operator command and names the façade as the one other caller of its export writer.
- **Hosted: the activity summary carries counts and dates only** (O3). The licence refresh reports, per organization, the dates of
  the first real request, the first assessment, the first Lab case finished and the second member, the member count, the members
  signed in over the last 30 days and the last sign-in day — never a name, an address or any case content; schema tests on both
  sides (the stamp's summary type, the publisher's `HostedTenantActivity` table and its wire type) fail on a text field.
- **Hosted: lifecycle e-mails are Realizer's fixed texts** (O3/O4): no organization-chosen value in a subject, the organization's
  name HTML-encoded in the body, display name *AccessPoint* and Reply-To Realizer support (never the organization's own), each
  notice claimed once by a unique row before it is sent, and every message counted on the organization's e-mail budget.
- **Hosted: Realizer deletes its own records of a deleted organization** (the hosted launch work item, 2026-11-07). When a stamp
  deletes an organization it tells the control plane — with its own identity, for an organization pinned to that stamp, a date and
  a kind only — and 90 days later the publisher deletes or anonymizes what it held: no table keeps the organization's name, its
  first owner's name or address, or its sign-up attribution; one evidence row keeps a SHA-256 of the organization's id, dates and
  counts. The deletion waits only while Stripe still bills the organization (cancel it in Stripe); a subscription row revived after
  the purge never holds it, and is ended. The admin console's audit stays append-only.
- **Hosted onboarding: the security review's fixes (2026-11-07)** before release:
  - **A purge warning that reached nobody is no notice.** An inactive Free organization is purgeable only after warnings that
    reached at least one active Administrator; one delivered to nobody is sent again, the purge refuses it, and the operator's
    listing shows it (`inactive-free-unwarned`) with how many the last warning was sent to and delivered to.
  - **The organization export never fills the instance's disk.** Its ZIP streams straight to storage (no second copy on disk);
    a start that would leave the export folder under its reserve (4 GB by default) is refused (`503 organization-export-no-space`),
    the runner claims a job only with room, and a running job stops if the reserve is reached.
  - **The export's download link is spent by its first request**, before anything streams — a replay, even after a failed first
    attempt, is refused, while the export stays downloadable from a new link — and the API redacts `?token=` from its request
    telemetry (every download link and viewer).
  - **A read-only organization takes no new member**: accepting an invitation after the licence lapsed is refused
    (`403 licence-read-only`), and a token-redeemed write sent with no organization header still asks the token's licence.
  - **No background job writes case data while read-only**: redaction-suggestion jobs, the post-conversion redaction pipeline and
    the media drain's frame-scan proposals check at write time and skip, logged.
  - **A hosted Free licence missing its read-only list fails closed** to the Free plan's rule, never all-writable.

#### Hosted pricing: the paid tiers (hosted pricing design P1)

- **The record-only rule holds on every hosted plan, and a waiting request is unlocked only by a unit.** A request recorded past the
  allowance refuses its case work (`403 request-record-only`) until a request from the allowance covers it — whatever period it arrived
  in. Before, a request recorded on the 31st was freed when the month turned, without using the new month's allowance. ONE rule
  (`RecordOnlyRequests`) and ONE writer of the unlock (`RequestCovering`, earliest due date first).
- **A staff upload past the plan's storage is refused** (`409 storage-quota-exceeded`, at the one upload rule): what arrives with a
  received request is never refused and nothing is deleted. The figures go only to administrators.
- **The privacy program's inventory is written only where the plan includes the program.** Creating, changing or deleting a system, a
  vendor or its agreements, or a control of the library answers `403 module-read-only` on a plan where the program is read-only
  (Essentials); reads, a subject's system links and a case's commitments are unchanged.
- **The Free plan is recognized by its plan, never by its read-only modules.** The trial's stricter e-mail limits and the Lab mode upload
  lock (PS-2, PS-9) apply to the Free plan and a lapsed licence; a paid tier's read-only registers no longer trigger them.
- **Overage billing is gone:** no metered line in Checkout, no meter events and no usage reports for billing.

#### Hosted pricing: the drip and bank (hosted pricing design P2)

- **Allowance follows payment, and only Stripe's own record grants it.** A paid month or year, an upgrade's prorated difference, the
  trial's and the Free plan's allowance and Realizer's grants are written by ONE writer at the publisher (`HostedAllowanceGrantService`);
  a paid period is granted only after the publisher reads the INVOICE back from Stripe and finds it paid, for the organization's own
  customer and current subscription — never from a webhook's body or a browser's return. A replayed event grants nothing more; an unpaid
  invoice grants nothing.
- **The grants ride in the signed licence** (`grants`, with `allowance: "bank"`), and the stamp writes each into its append-only usage
  ledger once, under a lock; the ledger's two new columns change neither its append-only guard nor the runtime's `DENY UPDATE, DELETE`.
- **Two creations never take the same last unit.** A case's draw is settled again at its save, inside a transaction holding a lock on the
  organization's allowance: the request that loses the last unit is recorded and waits, the assessment is refused.
- **Realizer's *Grant allowance*** is Admin-only, needs a reason, gives at most 100 units and is recorded in the admin audit.
- **The Free allowance shared by a Microsoft organization's workspaces lives only at the control plane** (hosted pricing design HP-89):
  a workspace draws a unit through `POST api/hosted/tenants/{id}/allowance/draw` (the stamp's managed identity, the tenant pinned to its
  stamp), serialized per pool by a concurrency token and idempotent per case, and never grants one itself. Its signed licence says what is
  LEFT of the pool — never which workspaces drew, never a name; no stamp reads another organization's data. A member is told only that the
  allowance is shared; the figures stay with `configuration.manage` (S4-1).
- **A read-only public portal takes no online request** (HP-84): Free and a plan without the Portal add-on pause the portal's intake
  exactly as a lapsed licence does — one rule, "the portal may be written".

#### Hosted pricing: discounts and promotion codes (hosted pricing design HP-90)

- **A discount never changes what an organization may use.** The plan, its modules and its allowance still come from the subscription's
  price — the webhook's one rule — whatever a coupon takes off; a discount is recorded only from Stripe's own record of the subscription,
  read back after a verified webhook or the console's call, never from an event body or a browser.
- **A partner's code is inert data.** `promo` on a sign-up link is length- and character-checked (letters, digits, `-`, `_`, at most 50) by
  the same allow-list at the entry, the stamp and the publisher, shown only as text, and used for nothing but asking Stripe whether it
  exists at the organization's first Checkout; what it gives is what Stripe answers.
- **Console discounts are Admin-only, reasoned and audited.** *Apply a discount* / *Remove discount* need the console's Admin role (the
  publisher's PlatformAdmin), a reason, and write `DiscountApplied` / `DiscountRemoved` to the append-only admin audit for every attempt but
  one without a reason. Each click carries a key: Stripe's idempotency keys derive from it, so a resubmitted form never makes a second
  coupon or applies twice. A coupon the console makes is a percentage, names its organization in its metadata and is never offered to
  another one. Stripe ids are shape-checked before they reach a URL path.
- **A subscription with no card is told in time.** A 100 % code takes no card at Checkout; the app asks an Administrator for one 30 days
  before the first invoice that charges, and an unpaid invoice follows the usual dunning to the Free plan — never a lock-out.

#### Hosted pricing: bundles and extra storage (hosted pricing design P3)

- **A bundle's units arrive only from Stripe's own record of a paid invoice.** The purchase makes one invoice charged to the card on file
  and grants NOTHING itself; after a verified `invoice.paid` the publisher reads the invoice back from Stripe and grants each bundle line,
  for the organization whose Stripe customer it is, through the same ONE writer of allowance — never from the purchase's answer, a
  browser or the webhook's body. A replayed event grants nothing more.
- **One click is charged once.** Each click carries a key the dialog makes; the publisher keeps one purchase row per organization and key,
  and every Stripe call of that click sends an `Idempotency-Key` derived from it — a double click or a retry after a lost answer is the
  same invoice. A new click voids an earlier bundle invoice still open, so two invoices for one need are never both paid later.
- **Only an administrator, only in production.** Buying a bundle or storage needs `configuration.manage`, is refused in Lab mode and has
  its own per-person rate limit (6 a minute); the stamp's tenant is pinned at the publisher. The dialog opens only Stripe's own hosted
  invoice page (`https://invoice.stripe.com/` — never stored), for the bank's 3-D Secure or a declined card.
- **Refunds take back unused units automatically, never used ones.** A Stripe credit note (`credit_note.created`) is read back with its
  invoice; each grant that invoice minted — a bundle's or a plan period's — loses the share the note credits, and the stamp never takes back
  a unit already drawn. Realizer's console gains **Reverse grant** (Admin, a reason required, recorded in the admin audit).
- **Members see whom to ask, never an address.** A member reads the administrators' display names (at most five) where an administrator
  sees the buy button.
- **Bundles are never recurring revenue:** their invoice lines are recorded as `Bundle` and never counted in MRR.
- **Removing extra storage never strands a file** (owner decision 2026-11-10, HP-91). The stored size is measured by the organization's own
  stamp, in its own scope (originals and converted copies, the upload rule's count — tenant isolation unchanged; only the number leaves the
  stamp), and checked twice: a removal the files would not fit is refused (409 `storage-in-use`); the unit is kept, and counted in the
  licence, until the stamp re-checks after the period's end — when the files no longer fit, the storage they need stays (billed) and the
  Administrators are e-mailed. Nothing is deleted or locked. *Remove 100 GB*, *Keep 100 GB* and *Apply* (a promotion code, HP-92) need
  `configuration.manage`, are refused in Lab mode, share the purchases' per-person rate limit and are idempotent per click (the click's key
  on the billing record and in every Stripe `Idempotency-Key`).
- **A promotion code is inert data and one discount at a time** (HP-92): shape-checked at the stamp and the publisher, used only to ask
  Stripe; refused when unknown, expired or used up, another customer's or in another currency; an active discount is replaced only after
  the Administrator confirms; recorded in the organization's audit ledger. The partner the organization came through stays the first.
- **Change plan never hands add-ons to the billing portal** (stage, 2026-11-10): the portal switches the plan only, so on a paid subscription
  Change plan offers no add-on boxes and the publisher refuses a subscriber's Checkout whole, add-ons included.

#### Hosted AccessPoint

- **The global entry keeps nothing, and the stamps answer it without side effects** (multi-region design §4.1 (c), §4.2, RG-10).
  `app.realizer.io` signs a person in with the stamps' own registration and asks each open region's `api/hosted/me` with the token
  that sign-in returned — in that request only: no token cache, no refresh token kept, no session (its one authentication default
  authenticates nobody and refuses any sign-in), no database; its only state is the functional `__Host-ap-region` cookie (the region
  key, no personal data). It sends a person, or a token, only to region hosts on its configured suffix, never follows a redirect,
  and its pages carry no script (`default-src 'none'`, a nonce'd style). On the stamp, `api/hosted/me` is pinned free of side
  effects and a call without the web host's client-address proof is rate-limited per account (`hosted-me`, 30 a minute), never by
  the entry's shared address. The publisher's new anonymous `GET api/hosted/regions` lists only the open regions' keys, names,
  public origins and residency facts — never a stamp's id, principal or Azure region.
- **Hosted AccessPoint: AI that may be processed outside Canada waits for each organization's consent.** The AI models hosted
  AccessPoint uses (gpt-6-luna, gpt-6.1-sol) are offered in Canada only as Azure OpenAI *Global* deployments, which may process
  prompts — case text, document excerpts and the personal information in them — in any Azure region. An organization's AI that uses
  such a deployment is now **off until its Administrator allows it** in Settings → Features & AI → AI Assist, after a brief, dated
  statement: the models are provisioned in Canada, Microsoft may process some prompts and answers in its other Azure regions, and
  what AccessPoint stores stays in Canada. The check is on the server, on every call to a model (403
  `ai-consent-required` otherwise, background work included); a grant and a withdrawal are recorded in the audit history and the
  audit ledger with the disclosure's version and language; a withdrawal stops AI at once; a materially changed disclosure pauses AI
  until it is allowed again. OCR, content search and transcription stay in Canada and need no consent. An AccessPoint you deploy
  in your own subscription never asks (multi-region design RG-3).
- **Hosted AccessPoint: a subscriber can no longer change the operator's notification settings.** In hosted AccessPoint, Settings
  → Setup belongs to Realizer — it sends every organization's e-mail — and was hidden from customers, but the API still accepted a
  customer Administrator's change of the sender mailbox, the Teams switches and the AccessPoint link the organization's e-mails
  carry (`PUT api/settings/notifications`, and the link's self-registration). In hosted AccessPoint those calls, the read of those
  settings and the re-protection of stored secrets now answer 403 `operator-only`; My Day no longer offers *Configure
  notifications and the sender mailbox* there, and no banner, card or link opens Setup. An AccessPoint you deploy yourself is
  unchanged: your Administrator is its operator.
- **A hosted organization's own e-mail settings, never the operator's.** `GET / PUT api/settings/email` (`configuration.manage`;
  the write is production-only — refused in Lab mode) read and write only `Notifications:EmailEnabled` and the Reply-To
  (`Notifications:ReplyToAddress`, one well-formed address — 400 `reply-to-invalid` otherwise). The sender mailbox, the Teams switches
  and the link every e-mail carries stay in Settings → Setup, the operator's in the hosted channel.
- **Hosted AccessPoint: each organization's e-mail has a sending limit** (security review 2026-11-06). Every hosted organization's
  mail leaves from the service's one address, and nothing limited how much an organization — a self-serve trial included — could
  send through it, letters of its own text to any address included. Every message is now counted per recipient before it leaves:
  by default 100 recipients an hour and 500 a day (25 and 100 on a trial, or when the licence cannot be read), and 20 confirmation
  e-mails a day to addresses the organization names (10 on a trial), counted per organization so deleting and re-adding a notice
  contact starts no fresh count. Past it a letter, a confirmation or an invitation is refused, **429** `email-send-limit` with
  `Retry-After`; a notice's e-mail is recorded as not sent and its in-app copy stays. The counts are kept in the database
  (`dbo.EmailSendBudgets`, per organization), never in memory; the operator sets them with `Hosting:Email:*`. The public portal's
  mail — codes an anonymous submission can trigger — has a limit of its own (60 recipients an hour and 300 a day; 20 and 60 on a
  trial), so a flood of submissions can never use up the e-mail your letters and notices need; a portal e-mail held back by its
  limit waits and is sent when the hour turns, without counting as a failed attempt, and the portal itself issues at most 60 codes
  an hour per organization. The hosted Free plan keeps the trial's limits, the public portal's own budget included (PS-2). Lab
  mode's notices are counted too, on a small budget of their own (30 an hour, 100 a day). An AccessPoint you deploy yourself sends
  from your own mailbox and is unchanged.
- **Hosted AccessPoint: a new reply-to address is confirmed before it is used.** A mistyped or hostile reply-to address received
  every reply to the organization's mail. Saving a new one now e-mails a 6-digit code to that address; until an administrator types
  it in Settings → Organization → E-mail (`POST api/settings/email/reply-to/confirm`, `configuration.manage`, production only) the
  mail carries no reply-to address. A code works for that address only, for an hour and five tries — counted atomically, so tries
  sent at once are never compared more than five times — and a new code can be asked for three times per address; both routes
  have a rate limit of their own. The code is stored only as a hash, and sending it counts against the organization's
  confirmation limit. Intake mailboxes are not offered as senders in hosted AccessPoint, and a letter or acknowledgement set to
  send from one goes out with the confirmed reply-to address: an address typed in Settings is never the reply-to until it is
  confirmed. A reply-to address set before this release is kept.
- **The hosted web host answers 404 for a path the app does not have** (it served the sign-in page at any address), and its
  signed-out page sends a visitor who is still signed in back to the app instead of saying they are signed out. Its small pages
  are chosen from a fixed list of eleven languages by `Accept-Language`; nothing from the request is written into them.
- **Hosted AccessPoint: session limits are each organization's, within the service's maximum, and an ended session stays ended
  (ITSG-33 AC-11/AC-12).** The stamp's `Session:IdleMinutes` / `Session:AbsoluteHours` are now MAXIMUMS (30 minutes and 12 hours
  by default; set by the template's `sessionIdleMinutesMaximum` / `sessionAbsoluteHoursMaximum`); an organization's Administrator
  may only shorten them (`api/settings/session`, `configuration.manage`, production only, 400 `session-idle-above-maximum` /
  `session-absolute-above-maximum` above the maximum, written to the audit ledger). The web host holds every request to the
  limits of the organization it is for, on a server-side activity clock — the app's own polls and the session check are not
  activity, and the ticket is no longer renewed; it reads an organization's limits with the person's own token
  (`api/hosted/session-limits`, any member) and, when it cannot, holds the request to the shortest inactivity limit an
  organization can choose (15 minutes), never the maximum. Idle time is the session's longest break so far: after 45 minutes
  away, a request in an organization with a longer limit never lets the session back into one with a 30-minute limit. An end —
  idle, absolute or **Sign out** — ends the whole session and is recorded on the server, so a copied session cookie is refused
  afterwards on every instance and in every organization (before, a sign-out cleared only the browser's cookie); a **Sign out**
  the server could not record is tried again and otherwise reported, never shown as done. A session store that cannot be read
  refuses the request (503 `session-unavailable`) without signing anyone out.
- **Hosted AccessPoint: a report over Microsoft 365-only data can never reach an organization without Microsoft 365.** Every
  Report Studio subject is now classified by edition on the server, and the check runs where every run, export, saved report,
  dashboard, pinned tile and Ask AccessPoint question is compiled (403 `report-subject-not-available`); a subject nobody classified
  counts as Microsoft 365-only there. Today every subject applies to every edition, so nothing changes for anyone — the rule is
  in place for the first subject that does not.
- **Hosted AccessPoint: no storage policy is created or switched on.** Archiving is not offered on the hosted service until it is
  priced: creating a storage policy, switching one on or changing one that is switched on answers 409 `archiving_not_available`
  there (reading, switching off and deleting a policy stay allowed), and a jurisdiction pack imports no storage policy there — the
  import says so. A deployed AccessPoint is unchanged.
- **Hosted AccessPoint: every charge names its currency, and the billing country is checked on both sides** (hosted pricing design
  HP-75). Stripe Checkout is always told the currency to charge in — the organization's, from its billing country — and that Adaptive
  Pricing is off, so Stripe never picks a currency from the visitor's location or converts a price; a plan or add-on without a list price
  in that currency is refused before anything reaches Stripe. The billing country is two letters at the service (400
  `invalid-billing-country`) and one of the ISO 3166-1 codes at the publisher (400 `invalid-request`); once Stripe bills the organization
  its currency cannot be changed through the service (409 `currency-kept`).
- **Hosted AccessPoint sells only what the service can deliver.** A Checkout or *Add a module* that names an add-on the service
  cannot deliver (AI Assist without Azure OpenAI, the Public portal without the portal, Media without a media processor; repository
  connectors on the hosted service) is refused, **409** `add-on-not-available`; the offers leave the Subscription page too.
- **Hosted AccessPoint: adding a module follows Stripe, never the browser.** *Add a module* (Settings → Subscription,
  `configuration.manage`, production only) asks the publisher to add the add-on's configured price to the organization's
  live Stripe subscription, prorated; the publisher reads the subscription back from Stripe and grants the module only
  when Stripe's subscription carries it — the same rule as its webhook. Only a sold add-on of an active subscription can
  be added (409 `no-subscription` on the trial, `subscription-not-active` while a payment is past due,
  `addon-already-held` for a module Realizer already grants).
- **Hosted AccessPoint: removing a module keeps it to the end of the paid period and deletes nothing.** *Remove a module*
  (the same page and permission) asks the publisher, which reads the subscription from Stripe first, records the module's
  end as the end of the period already paid, and only then removes the add-on's Stripe item without proration — no
  refund, and the next renewal no longer bills it; the module stays in the licence until that day. Keeping it again
  before then re-adds the item without a charge. A refusal from Stripe leaves everything as it was; no data is deleted.
- **Hosted sign-up attribution is inert, allow-listed data.** The demo's hand-off keys (`pack`, `lang`, `from`, `demo`,
  `steps`, `size`, `cta`, the `utm_*` tags and `gclid`) are each checked against a pattern and capped at 100 characters in the
  browser, at the stamp and again at the publisher, which stores at most 2,000 characters; nothing else is carried, and the
  values are never used to build a URL or HTML.
- **Hosted AccessPoint: uploads are scanned for malware, and no recording is decoded in the API** (hosted launch, lane A; in
  force from the stamp deployment that adds it). Microsoft Defender for Storage scans every upload; the API reads its verdict
  through a role that holds only `blobs/tags/read`, and the one release gate blocks a Malicious file (403 `malware_detected`),
  holds a Pending one and asks an acknowledgement for a Failed scan — until then a hosted upload was not scanned and passed as
  *Not scanned*. Office, HTML and e-mail conversion, every step that reads a recording, and the release accessibility check run
  in their own workers, each on its own user-assigned identity holding only its container and queues; the media and
  accessibility jobs take one message per execution, so no worker replica goes from one organization's file to another's.
  The workers' storage access still covers every organization's files: a parser compromised by one organization's hostile
  file is contained by its hardening and the scan, not by organization (ITSG-33 profile G-50).
- **Hosted launch: the security review's fixes (2026-11-07, HL-1 – HL-10)** before release:
  - **Each worker writes only what it produces.** Azure role conditions on the workers' blob roles: the media worker writes and
    deletes only under renditions, release exports and its own claim checks; the accessibility worker reads only response
    packages and evidence sets, writes only its reports and deletes nothing; the document worker writes only a job's outputs and
    deletes nothing; the Speech resource reads only the transcription audio. No worker can overwrite or delete an original. A
    condition cannot tie a job to one organization, so the workers still read across organizations (G-50).
  - **The workers' results queues are send-only** (Storage Queue Data Message Sender), so a worker cannot read or clear another
    job's result.
  - **No worker runs by tag.** The stamp's parameter files read the worker digests with no default and the template fails a
    worker without one — production can no longer fall back to `:latest`; `stamp.sh worker-images` checks the release folder's
    `SHA256SUMS` against the pinned release key and each digest file against it before printing anything.
  - **Global AI processing needs a recorded decision.** With Azure OpenAI on, a Global deployment fails the deployment unless the
    stamp's parameter file sets `aiGlobalProcessingAcknowledged`; production names its deployment types and does not set it.
  - **The shared malware scan cap is watched.** An alert on the documents account's daily writes against the cap's pace and one
    when uploads stay unscanned or are tagged *Not scanned* (the API logs both, counts only).
  - **A deletion Realizer records by hand counts its 90 days from the record** — never from the day typed in — and can be undone
    (*Undo the recorded deletion*, audited) until the retention job runs.
  - **HubSpot: only a company the sync created is archived**; one it adopted by domain, found by key or that was merged keeps
    everything but this organization's key.
  - The privacy policy and the PIA now say the hosted backups and stored files are geo-replicated within Canada (Canada Central to
    Canada East), and CI checks that the Microsoft 365 template's documents account stays `Standard_LRS`.

#### The guided welcome and first-time help

- **The guided welcome reads and records only the caller's own facts.** `GET api/welcome` is production-only, answers for the
  signed-in person in their own organization, and writes nothing; the person's answer is the existing `tour.welcome` progress
  item (done or dismissed, and a date — no analytics, which start was chosen is never recorded). Who is greeted is ONE server
  rule that fails closed: an organization whose `Welcome:Since` is not decided greets nobody.
- **The advisor's first-case note on assessments, incidents and complaints reads the server.** Their panels ask the case's
  own collaborator list — which needs view on that case — whether the person is an active advisor there, and only while
  the note has something to show and the person cannot change the case; a removed advisor or an advisor of another case
  is refused the read. Nothing new is granted: advisors stay read-only.

#### AccessPoint Learning

- **A new permission, *Author learning content* (`learning.author`).** It is sensitive, cannot be carried by a dynamic
  role, and Administrators have it. It is required to write, change, reorder and delete your organization's coach notes;
  listing the notes needs it or *Manage training* (`training.manage`); switching a note on or off — your organization's
  or a jurisdiction pack's — needs *Manage training*. A new note starts switched off. A person who holds only *Author
  learning content* now sees Settings → Training, with only its *AccessPoint Learning* section.
- **The coach read shows configuration and coach notes only.** *How we decide* (`GET api/academy/coach/{point}`) is open
  to every signed-in member, in your real work and in Lab mode. It returns the catalogue's descriptions and legal
  references from your configuration (in Lab mode, the training copy's) and the coach notes that are switched on — no
  case data. A scope value that is not a code is refused (400 `coach-scope-invalid`). With *How we decide* switched off,
  it returns an empty panel.
- **Every coach-note write is production-only.** Creating, changing, switching and deleting a note are refused in train
  mode (409 `training-production-only`), like every other AccessPoint Learning write. Coach notes belong to your organization, not to
  the training copy: Lab mode reads them and never copies or changes them.
- **No HTML is stored or shown.** A coach note is structured content — paragraphs, headings, lists, quotes, simple
  formatting and links — checked on every write, again before it is switched on, and again before it is shown; a note
  that fails is refused (400 `content_invalid`) or not shown. Links must be `https:` or `mailto:` without credentials. A
  request body is limited to 1 MB, a note to 20 languages and 400,000 characters, and a coach point to 100 of your
  organization's notes.
- **Jurisdiction pack coach notes are read-only and checked twice.** The importer applies the same content and scope
  rules as the API and does not import a note that fails them (the version an earlier pack shipped under the same id is
  switched off). Before a pack is published, Realizer's pack checks also require plain language with no instructions
  written for an AI model, and links only to official government, legislation and regulator sites on a fixed list —
  never `mailto:`. Re-applying a pack with *Add and update unchanged* keeps your organization's choice to switch a pack's
  note off.
- **The audit ledger records every coach-note change** — created, changed, switched and deleted — with the coach point,
  the scope, the languages, the switch, the order and a SHA-256 of the text, never the text itself.
- **The coach's *Learn more* offers only modules the reader can open, and only in your real work.** `GET api/academy/coach/{point}`
  now also lists the modules the shown notes link to — switched on, published, and open to everyone, the reader's to author, or in a
  learning path the reader is enrolled in — by title; never in Lab mode. A note's *Linked modules* are module codes (at most five),
  written by *Author learning content* like the rest of the note and checked against your organization's modules (400
  `coach-module-links-invalid`); the audit ledger records which modules a note links to.
- ***Ask AccessPoint about this*** opens the existing case assistant with a short starting question and grounds every
  answer of that conversation on the coach's guidance for the decision. The web part sends only which decision it is
  (the coach point, the case's type and the option chosen), never the texts: the API reads the same texts the panel
  shows — the rule and its legal reference, the jurisdiction pack's note and *Our practice* — with the coach's own read,
  in the person's language. The case data the assistant sees is exactly what it already allows that person; AI Assist's
  rules apply unchanged (the `ai` module, the deployment and the assistant's switch, the monthly budget, no
  `temperature`), and the AI log records the call as `AssistantCoach` with prompt version `assistant-coach-v1` —
  metadata only, never the guidance or the answer. Nothing is sent until the person sends it.
- **New AccessPoint Learning APIs, each permission-gated.** Writing modules, files, translations and blocks on pack modules
  (`api/academy/modules…`, `…/assets`, `…/draft/translations`, `…/draft/translate`, `api/academy/page-editor`) needs
  *Author learning content*; publishing, approving and retiring a module, learning path settings (`api/academy/curricula`),
  audience rules (`…/audience`) and the people not enrolled automatically (`…/audience/exclusions`) need *Manage
  training*; switching a block on a pack module needs *Manage training*. What the Studio needs to know of your set-up
  (`api/academy/capabilities` — whether managers can be read from your directory, found by actually reading one) needs
  either permission.
  Completion records (`api/academy/records`) return a person's own records, a training lead's the records of the
  enrolments they assigned, and an Administrator's every record; Team progress's AccessPoint Learning columns need *Manage training*.
  The learner routes (`api/academy/my`, a module version, a step, an acknowledgement, a mentor's confirmation, the
  mentor's list) have no permission attribute — a person with no permission learns too — and each is an object rule in
  the service. The premium parts answer 403 `module-not-licensed` without the AccessPoint Learning module; a downgrade deletes nothing.
- **Every AccessPoint Learning write is production-only, and so are the learner's reads.** In a Lab mode tab they answer 409
  `training-production-only` and write nothing; only the coach read answers in Lab mode.
- **Who may see a module and its files.** An author (*Author learning content* or *Manage training*) sees every version;
  anyone else sees a published version of a switched-on module only when an enrolment of theirs pins it, or the current
  version of a module opened to everyone (*Browse*). Any other request answers 404 `module-not-available` — the same
  answer for a draft or a module that does not exist. A file is readable only when a version the person may see uses it
  and its malware scan passes, checked on every read; authors too open a file only once its scan is clean or a failed scan
  was acknowledged. Draft author notes never reach a learner.
- **Module files are never case documents and never served raw.** Every case-only document route (redaction, release,
  tracking, exports, connectors, suggestions, the case viewers' tokens…) refuses a module file (404); module files are
  never indexed for search, exported, reported or disposed of. Images must be PNG, JPEG, GIF or WebP by their bytes. A web
  page (`.html`, `.htm`) is served only as a PDF and an SVG only as a PNG, converted by the document worker's Chromium with
  JavaScript off and every network request refused (an SVG is drawn as an image, which never runs a script), the PNG
  drawn from that PDF in the API — no SVG parser reads the uploaded file; nothing is served until the conversion is ready,
  and the original is never served. XHTML, MHTML, HTA, compressed SVG, video, audio, scripts and programs are refused, by
  extension and by their bytes. Every file is malware-scanned, and publishing waits for the scan and the conversion.
- **Results learners can't fake.** The steps AccessPoint can check are decided by the server alone: a Practice step from
  the training case's guide (*verified* only when every step with facts was done by its facts), a Do step from your real
  work. A request that claims such a step is done is refused (400 `step-state-server-decided`) and nothing is written. An
  acknowledgement must repeat the step's own statement. Either the learner or the mentor a learning path names marks a Talk to
  step: the learner's mark is recorded as their own statement (*attested*), the mentor's confirmation as *confirmed* — the
  stronger, before or after it; nobody else can confirm (403 `talk-to-not-mentor`). A completion record keeps how each
  step was known to be done.
- **Checks are graded on the server; a decision's model answer comes only after the decision.** A check attempt sends the
  options chosen and nothing else — never a score or a *passed* — and AccessPoint grades it against the answer key of the
  module version the person holds; the questions a learner receives carry no right answer, feedback or right order (the
  server shuffles them for each attempt, and an order question never arrives in the right order). The result, the right
  answers and the feedback come back only after the attempt is stored; once passed, the result stands; a retry cap is
  enforced (409 `attempt-limit`). A Decide step's model answer is sent only in the response that stores the person's
  decision — final for that version (409 `decide-already-committed`) — and afterwards only to that person (409
  `decide-not-committed` before it). A Decide step's case must be fiction: publishing refuses real-looking e-mail
  addresses, telephone numbers and identifiers (`scenario-not-fictional`). Both kinds need the AccessPoint Learning module (403
  `module-not-licensed`) and are production-only.
- **An exercise's model answer comes only once the training case is finished.** An Exercise step may carry a model answer;
  the module a learner receives says only that there is one, never its words. The learner's own read of it is answered only
  when AccessPoint sees their training case finished by its guide in the training copy — a person ticking the scenario off
  themselves completes the step (as their own statement) but never brings the model answer (409 `practise-not-done`) — and
  only to that person, in production. A model answer must be fiction, like a Decide step's case (`scenario-not-fictional`).
  An Exercise step may now name a private pack's (Lab-only) exercise: production shows nothing of it but the step's title and
  *Open in Lab mode* — its card, summary and guide stay in Lab mode, and Get started and learning paths still never suggest it.
- **Who sees check results is your choice** (Settings → Training → AccessPoint Learning → *Who sees check results*; until chosen it
  follows *Show progress to the person who assigned it*): only the learner, plus passed or not yet passed, or plus scores
  and attempts — applied by the server in Team progress, the completion records and both CSV files. A decision, like a
  Reflect note, is returned only to the person who made it.
- **Private notes stay private.** A Reflect note is returned only to the person who wrote it — never in a lead's view,
  a mentor's list, a report, an export or the audit ledger. Step states, Reflect notes and acknowledgements are removed with
  the person's training progress — when the person leaves, and once no enrolment of theirs still kept holds them — while
  the completion record keeps its own retention. Nothing records time on task, clicks, scrolling, how much was seen or any
  ranking (User Guide → *AccessPoint Learning and employee monitoring*).
- **The page editor** is served by the API under the viewers' content-security policy (same origin only, no inline script
  or style), behind a 60-minute ticket bound to the author and the organization that re-checks *Author learning content*
  and the licence. It holds no document of its own and exchanges messages only with the Studio's origin, both ways. A page
  is stored as structured content checked on every save — never HTML; links are `https:` or `mailto:` only.
- **Machine translation of a module** follows AI Assist's rules (the `ai` module, the deployment, your organization's
  automatic-translation switch, the monthly budget, no `temperature`, metadata-only logs). Only words are sent — a text's,
  and an image's alternative text and caption — never a link's address, a file or image id or any other attribute, and an
  answer that changes the structure is refused whole. A text a person wrote is never changed: in a language a person
  wrote, *Translate missing* fills only the empty texts, and marks them as machine translations.
- **Notices and records.** AccessPoint Learning's notices go only through AccessPoint's notification dispatcher (titles stripped of
  control characters before they reach a subject; Teams only where your organization allows it). The completion-record
  retention purge deletes records past their period and writes nothing else. The audit ledger records each module created,
  deleted, sent for approval, approved, published and retired, each change of a module's *Open to Browse* switch, each
  block on a pack module created, changed, switched and deleted (with a SHA-256 of its content, never its text), each
  audience rule created, changed and deleted, and each person allowed again under *Not enrolled automatically*.
- **Certificates: earned on the server, verified inside your organization.** A certificate is issued only from the completion
  record, when every required Check, Practice and Do step was verified by AccessPoint (an attested training case blocks it — 409
  `certificate-not-eligible`); no route takes a claim. Its 128-bit verification code is derived from a key your deployment keeps
  protected by its Data Protection ring and is stored only as a SHA-256; the PDF is made again from the record by the document
  worker (every value HTML-encoded, JavaScript off, no network), pinned so every render is the same bytes, sealed with its SHA-256
  and never stored as a document (503 `certificate-render-unavailable` without a worker). Verification (`GET
  api/academy/certificates/verify/{code}`) is open to signed-in members of your organization only, rate-limited per person
  (`RateLimiting:CertificateVerifyRequestsPerMinute`, 20 by default), returns only what the certificate prints and its state, and
  answers a wrong code only 404 `certificate-not-found`. Downloading and confirming the printed name are the person's own;
  revoking needs *Manage training* (a lead the enrolments they assigned) and a reason. The audit ledger records each certificate
  issued, sealed, re-issued and revoked — never the printed name or the code. Issuing, the PDF and revocation need the AccessPoint
  Learning module; verification does not — it needs only a signed-in member of your organization and keeps its per-person rate
  limit. All of it is production-only.
- **A lead's copy of a certificate.** `GET api/academy/certificates/{id}/lead-pdf` (*Manage training*, the AccessPoint Learning module)
  serves the very bytes the learner gets, only for a certificate the learner issued and only to the leads of that person
  (an Administrator any) — another person's answers 404 — and audits each download like other configuration (the audit
  history and the audit ledger).
- **Recertification and Training coverage follow the server's rules.** A recertification enrolment is opened only by the
  daily enrolment sweep from the completion record — never from a browser — once per completion, never beside an open
  enrolment, for a person a lead withdrew or who left; in it, checks, decisions and acknowledgements count only when made
  after the renewal opened (the one step-state rule decides; no route accepts a claim). *Training coverage*
  (`GET api/reports/training-coverage`) needs *Use reports* and *Manage training*, the AccessPoint Learning module, and answers in
  production only; it shows totals to every such reader and one row per person only for the people the reader assigned
  (an Administrator: everyone), with check results only as far as *Who sees check results* allows. The Report Builder's
  new *Training coverage* subject has one rule — a global *Manage training* and the AccessPoint Learning module — is refused for
  everyone else (403 `report-subject-not-available`), carries no person, and runs saved reports with the viewer's rights.
- **More attempts on a check are a training lead's, with a reason, and never decide a result.**
  `POST api/academy/records/attempt-grants` (*Manage training*, the AccessPoint Learning module, production only) grants one person
  more attempts only on a check whose attempts they used up without passing, only for a person the lead's training
  reaches (an Administrator anyone), never for oneself, and audits the grant and its reason like other configuration —
  the audit history and the audit ledger, the facts only. The check is still graded on the server; nothing is marked passed.
- **Content-quality statistics are anonymous, and the link check reaches public addresses only.** The Studio's Quality tab
  (`GET api/academy/modules/{id}/versions/{version}/quality` — *Author learning content* or *Manage training*, AccessPoint Learning
  module, production only) answers counts, shares and a median only for groups of at least five learners of a version, and
  a filter (a learning path, a period — never a person or an audience rule) shows nothing when it leaves fewer than five or
  leaves out fewer than five; it never returns a person, a name, a decision's reasons or a Reflect note. The weekly link
  check runs only from its production sweep — no route starts it, never on a learner's behalf — and sends a `HEAD` request
  (no body read, no cookie, no credential, nothing of your organization) through the same SSRF-safe handler as e-mail
  preview images, which now lives in one place: it connects only to public addresses, re-checked at every redirect, so a
  link into your network or the cloud's metadata address is never requested. **Check now** (`POST api/academy/modules/{id}/link-check` —
  the same permissions, AccessPoint Learning module, production only) runs that check for one module on demand, the same probe and
  rules, at most once per module every ten minutes (429 `link-check-too-soon` with `Retry-After`) and never on a learner's behalf.
- **The Lab-mode guide's model answer is the learner's own.** `GET api/training/cases/{entityName}/{id}/model-answers` answers only in
  Lab mode, only the training case's own starter (404 for anyone else, as for an unknown case), only once the case's guide is finished,
  and only the model answers the server's own rule releases — the same rule as the module player's read; it reads the person's own
  learning records and writes nothing.
- **Suggested audiences never enrol anyone.** A jurisdiction pack's suggestion is listed for *Manage training* only
  (`GET api/academy/curricula/{id}/audience/suggestions`, AccessPoint Learning module, production only); switching one on is the ordinary
  audience-rule create, with its own permission, ledger entry and go-forward line.
- **The glossary, obligations and training done elsewhere.** `api/academy/glossary` (writes: *Author learning content*),
  `api/academy/obligations` (writes: *Manage training*; both lists: either permission) and `api/academy/external-completions`
  (*Manage training*) need the AccessPoint Learning module and answer in production only; a jurisdiction pack's terms and obligations are
  read-only (409 `pack-row-readonly`). A learning path's *Training done elsewhere* item is met only by a still-valid record a
  training lead wrote from a provider it accepts — no route lets a person tick it, and a stored tick counts for nothing; a
  lead records only for the people whose training they assigned (an Administrator for anyone) and never for themselves.
  A Training Lab certificate's link is checked by the lead by hand: the API never opens it, so no new outbound address.
  Every change to such a record is written to the audit ledger, without its note; the records follow the completion
  records' retention. A glossary definition is plain text or the restricted document format (no image, file or nested
  term), checked like every authored text. The Report Builder's new *Obligation coverage* subject has its own rule — a
  global *Manage training* and the AccessPoint Learning module — is refused for everyone else (403 `report-subject-not-available`),
  carries no person, and runs saved reports with the viewer's rights.
- **Pack glossary terms and obligations can be switched off, and every glossary or obligation change is audited** like
  other configuration (the audit history and the audit ledger, the facts only). A Training Lab certificate recorded as
  training done elsewhere counts toward a learning path only once a lead has ticked *I checked this certificate*.

#### Lab mode

- **Training cases that start approved are written in the training tenant only.** A scenario whose case starts from an approved
  assessment is filled in and approved through the same services, rules and approval gates as any assessment, and only in the
  training twin — the seeder refuses production — and the steps it can tick read only that case's own rows, never another case's
  or another world's. What the start wrote is recorded on the case (a new column, `TrainingCases.StartBaseline`, twin rows only) so
  it can never count as the learner's work. No new route, background job or outbound connection.
- **Simulated people exist only in the training copy.** A scripted colleague is a `Users` row that only a training copy can hold
  (`Users.IsSimulated`; `CK_Users_Simulated`: a `~training` tenant, no sign-in identity, a version-5 id), written by one seeder
  inside one save scope and removed with the training data. Nobody can sign in as one (403 `simulated-person`); it holds no role
  and no permission of its own, is never listed, offboarded, notified or counted, and is never looked up in Microsoft Graph. A
  production row that names one is refused (400 `simulated-person-production`), and in the training copy a row may name one only
  on a training case that casts it (400 `simulated-person-not-cast`).
- **What a scripted colleague may do is one closed table.** A simulated person acts through the same services and rules as a
  person, with what its part's association gives it — or a code of one closed table (`CastCaseGrant`), only in the training copy,
  only on its own training case, only while its team exercise is live — never globally and never in production. Requestor details,
  configuration, people, training administration, holds, deletion, reports and the portal can never be granted. The scripted
  handlers ask the object checks, never the dynamic-role capability test (source scans fail otherwise). A scripted coordinator of
  a Lab mode privacy assessment holds *Modify assessments* only while its own request for an opinion is open or awaits the case
  team's response (or, before it asks, when its start hands the trainee that opinion) and while a refusal for rework is current —
  never merely because the assessment's validation asks for an opinion — and *Activate / transition assessments* only while that
  refusal is current: for its opinion request, its response, its revised answers and its resubmission, and nothing else (each
  tested for refusal first).
- **Act as senior official is fenced.** A scripted senior official's `case.approve` is read through one case-scoped check with
  exactly two call sites (naming the official when the case starts, and the DPIA decider), on its own training case only, while it
  is that case's named senior official; every other `case.approve` check stays global and refuses it. In the training copy, a
  letter the sign-off rule holds on a case whose senior official the script plays waits for that character whoever writes it —
  the *Act as senior official* bypass is withdrawn there by one rule. It only ever makes a send stricter; production never reads it.
- **A colleague who plays someone outside the organization never opens the case.** In a team exercise a participant whose every
  role plays the requestor, a third party, the complainant or the regulator's contact holds nothing of the exercise's case access
  — no view, discussion, list entry or inject record (an unreadable plan fails closed); their desk shows only the letters
  addressed to that person, and their answer goes through the same rules and service as the script's.
- ***Let the script answer* asks the lead's own rights.** Handing a colleague's search, task, review step or advisor place to the
  script moves it as the lead would by hand: before anything is written each item asks the lead the reassignment route's own
  permission on that case (403 `handover-not-permitted`), and on a request that the request is not closed (409 `request_closed`,
  the routes' guard); one refusal refuses the whole handover. A delegated assessment section is given again to the scripted
  colleague only when the lead holds *Assign assessment work* (`assessment.assign`) across the organization, as the delegation
  routes require — a grant on that one case is not enough.
- **Nothing a script writes passes for a person's.** A scripted attestation reads *Scripted attestation* — *Nobody signed this* —,
  records no IP address or browser, and its certificate shows no Entra object id or sign-in name; a certificate approved by a
  simulated person leaves out its identity and says no person approved it. Scripted messages and responses are marked *Scripted
  reply* and *Scripted response*.
- **Nothing leaves the training copy.** The scripted answers are written by one background pass (`ScriptedCastSweepService`) that
  runs only in training copies, on the exercise clock, and sends nothing — no letter, e-mail or Teams message; a team exercise's
  reminder goes through the training notifier (e-mail and the feed, never Teams). No new outbound connection and no new exception
  to tenant isolation. Simulated people and the scripted senior official's `case.approve` each passed a focused security review
  before they merged, and the findings of the review of the scripted colleagues were fixed.
- **The organization's own scripts are written in real work only, by authors.** *Lab scenarios* and the script routes (`api/academy/lab-scenarios`, `api/academy/cast-scripts/*`) answer only outside Lab mode, need the AccessPoint Learning module (403 `module-not-licensed`) and *Author learning content* to write or switch a script (a training manager may read); every script passes the same validator as a pack's, fictional-data rule included (400 `script-invalid`), and runs through the same handlers and rules — a script never grants anything.

#### Requests: rolling releases

- **New release APIs, gated as packages were.** `api/requests/{id}/releases…`: reading, drafting, building and discarding a
  release need *Manage documents* (`document.manage`) on the request; sending one, linking its letter and changing its hold
  need *Send final response packages* (`package.send`); a release schedule needs *Modify requests* (`request.modify`); an
  instalment *Manage fees* (`fee.manage`), its waiver *Waive fees* (`fee.waive`). Letting a release held until paid go before
  payment — and cancelling such a release's open instalment — needs the global *Act as senior official* (`case.approve`)
  and a reason (403 `release-hold-override-forbidden`, 403 `release-instalment-cancel-forbidden`). Every write refuses a request
  outside the Requests module.
- **What went out never changes.** A built release's records, page numbers and packages are written once. Deleting a record
  that a built or sent release decided is refused (409 `document-in-release`), so is deleting a release's package (409
  `release-package-kept`), and housekeeping never removes a package that belongs to a release, that ever became available on
  the portal, or that someone downloaded. To change what went out, build a corrected release; the earlier one stays as
  evidence.
- **Hold until paid has no side door, and follows the payment ledger only.** A release held until its instalment is paid is
  refused by Send release, by the portal delivery — the Export history's *Deliver via secure portal* — and by the public reading
  room's proposal and publication (409 `release-instalment-unpaid`) until the instalment is Paid, which only a provider-verified
  payment, a status query or a payment recorded by hand makes it; a requestor returning from the payment page changes nothing.
  Changing a running request to a type that does not hold releases keeps each unsent release's hold, so letting it go stays a
  senior official's decision with a reason. A release whose secure-portal delivery still waits for its scan is not sent again (409
  `release-sending`), and a letter held for sign-off is offered to Send release only for the release it was composed for.
- **The portal checks the package it delivers.** A secure delivery and a reading-room publication now run the malware and
  hidden-content gates on the package's OWN records, read as they are now — a package whose records are unknown or deleted
  is refused (409 `package-contents-unknown`, `package-record-deleted`) — instead of the request's current records.
- **Letters go through the one choke point.** A release's letter is sent by `CorrespondenceService` like any other; a letter
  that needs the senior official's sign-off holds the whole send, and composing one in Send release needs
  `communication.manage` (403 `release-letter-forbidden`).
- **A letter that names a release.** `GET api/requests/{id}/releases/for-letters` lists a request's built and sent releases,
  each with its open or paid instalment, to someone who works on the request's documents (*Manage documents*) or its
  correspondence (*Manage communications*) — the same rule as the composer's merge of a release's tokens, 403 otherwise.
  Naming a release only fills its tokens: the letter is sent through `CorrespondenceService` with sign-off as before, and only
  Send release links a letter to a release.
- **What the requestor sees.** The portal lists sent releases with their index: exemption codes only, a record withheld in
  full without its name, and a corrected release's reason as one of four categories — never the staff's own words. Release
  letter tokens carry no requestor details.
- **Corrections after closure** are built under `document.manage` with a reason, without reopening the request; marks on a
  closed request stay locked except through the existing unlock for re-disclosure.
- **The audit ledger** records `release.built`, `sent`, `discarded`, `corrected`, `supplemental`, `schedule-changed`,
  `instalment-requested`, `held-unpaid`, `override` and `letter-linked` with the facts in the event data — never a reason, a
  note or a court order's caption. The ledger's hash scheme is unchanged.
- **Report Builder's new *Releases* subject** follows the Requests register: it shows only requests the viewer may see, with
  no requestor field.
- **Lab mode:** a release in a training copy is sent "another way" — the portal and instalments are refused (409
  `training-outbound-refused`) and its letter is simulated.

#### Redaction, exemptions and recordings

- **Advisors and reviewers can flag redactions on their own requests.** Flagging a redaction
  (`POST api/redactions/{id}/flag`) and resolving a flag (`…/resolve-flag`) asked a permission held across the whole
  organization (*Create redactions*, *Edit redactions*), so an advisor or reviewer added to one request was refused, although
  their role grants *Flag redactions* on that request. Both now accept *Flag redactions* on the redaction's own case — an
  advisor or reviewer on that request, or a dynamic role matching it — and still accept the organization-wide permission that
  worked before, so nobody loses access. Resolving a flag is for reviewers (and anyone who may edit the redaction): it also
  needs *Resolve discussion*, which reviewers hold and advisors do not — advisors raise flags and reply, never resolve. Custodians, contributors and readers still cannot flag, an advisor or reviewer still
  cannot flag on a request they are not on, and a redaction the caller cannot see — another request's, another organization's
  or the Lab copy's — is answered as not found.
- **Every redaction action now follows the redaction's own case, and advisors and reviewers can flag from the preview.**
  Drawing a redaction, replying in its discussion, editing, withdrawing, restoring, reverting and approving it, and every bulk
  action asked a permission held across the whole organization, so a role granted on one case — a dynamic role, or a role
  limited to a person's own requests — never reached them. Each now asks its permission on the redaction's own case, and the
  organization-wide permission that worked before still works. Anyone acting on a redaction must also be able to open its
  record; a redaction on a record you cannot open is answered as not found. *Approve redactions* is still needed to approve,
  on the request itself — never a register's manage permission or *Act as senior official*. Advisors flag and reply in a
  redaction's discussion on their requests, reviewers also resolve flags, and neither ever draws, changes or approves one;
  custodians, contributors and readers still have no say. A bulk action skips the redactions you cannot see and is refused
  as a whole if it includes one you can see but may not change. In the read-only document preview, advisors and reviewers
  now get **Discuss redactions**: the document's redactions with their flags and discussions, and Flag, Reply and — for a
  reviewer — Resolve, where the server allows them. Also hardened: a new annotation is created only with a type AccessPoint
  knows, and only a comment names a mark — on the same record — as its parent; a split copies only from a mark on the same
  record and its copied text is hidden from people without access to requestor details; approval refuses a withdrawn
  redaction, a proposal and anything that is not a redaction (409 `redaction_not_approvable`); a section assignee's access to
  their own assessment reference files no longer reaches redactions; a bulk action takes at most 5,000 redactions (400
  `bulk_too_large`); and in Lab mode the records a team exercise's injects filed are read, never marked.
- **An exemption a request may not cite can no longer arrive by a copy.** Importing a prior request's redactions brings across only
  the exemptions the request may cite and says which it left off (the redactions still come across, as suggestions); accepting a
  suggestion, restoring a withdrawn redaction and confirming a duplicate's copied redactions check the exemption again; a suggestion
  or a withdrawn redaction no longer counts as the request already citing an exemption; a suggestion pattern's new matches carry only
  what the request may cite at the time; and the exemptions recorded on a request itself follow the same rule (one it already carries
  stays).
- **Smaller checks.** A suggestion pattern's exemption codes are checked when saved — none empty, at most eight, 200 characters in all
  (Nova Scotia's four-code patterns can now be saved from Settings) — and the extension reasons a request is offered need the
  access-requests module, as the other extension routes do.
- **A media mark's effect must redact something.** Creating or editing a mark on a video or audio record, and the new bulk
  *Change effect*, now refuse (400 `media_effect_not_valid`) an effect with no time span, a Box / Blur / Pixelate with no
  region, and a picture effect on an audio-only record — marks the release would have dropped while listing them as
  redactions. Only changes that touch the effect, the region or the path are judged, so existing marks keep working. Bulk
  *Change effect* stays within a mark's kind, reports the marks it skipped, and sends an approved mark back for approval like
  any edit.
- **Bulk *Change exemption* now sends an approved mark back for approval**, on documents and recordings alike — as editing
  one mark's exemption always did. Before, a bulk change kept the mark approved with a different exemption than the one
  approved. Marks whose exemption does not change keep their status.

#### Correspondence sign-off

- **A former senior official can no longer sign a held letter.** A letter held for sign-off kept the approver it was submitted to, so a
  senior official replaced on the case — who might no longer have anything to do with it — could still approve it or return it. The letter
  now follows the case's senior official, and its named approver can decide it only while the case still names them; anyone who holds *Act
  as senior official* can still decide any held letter, as before. **Reassign or release work** now hands a departing person's letters
  awaiting sign-off only to someone who holds *Act as senior official*, as it already required for the senior official of their cases;
  otherwise the plan is refused before anything changes, and **Clear** (the letters wait for anyone who can act as senior official) and
  **Leave as is** remain. A letter reassigned that way before this release to someone else can no longer be decided by them. The
  letter's text and the send's re-check of its approval are unchanged; each move writes a history row on the case and an audit ledger
  entry with the ids, the purpose and the reason, never the letter's text. A letter approved or returned while its case's senior
  official is being changed stays as it was decided: it is moved only while it is still waiting, in one conditional write, and gets
  no history row or notice otherwise.

#### Jurisdiction packs, dated settings and first setup

- **A request's dated settings are the same for everyone who opens it.** Nova Scotia's new Act (1 April 2027) switches a request's
  exemptions, extension reasons and fees by its received date. With no organization time zone set, that date was read on the calendar
  of whoever opened the request, so a colleague in another time zone could be offered — and apply — the former Act's exemptions and
  fees on a request whose due date ran under the new Act. The date is now read in the organization's time zone, else in the time zone
  the request was entered and its due date last computed in — the same for everyone; only a request never given one (an import, a
  portal submission not yet activated) still falls back to the reader's. The Nova Scotia pack sets the organization's time zone to
  Halifax when none was ever chosen (see *Action required*).
- **Try again on a first setup needs *Manage configuration*.** The new `POST api/config/packs/initial-setup/retry` re-runs the
  organization's first setup (the Universal baseline, Universal learning and, in hosted AccessPoint, the jurisdiction pack the
  owner chose and acknowledged) and is refused in train mode; an Administrator's visit re-runs a failed setup on its own at most
  three times in all. No new outbound connection.

#### Reports

- **Reports menu: a register permission held only through a dynamic role no longer shows that register's analytics row**, which
  the API refused (403) — a dynamic role grants the cases its rule matches, never a register-wide report. Report Studio still
  opens for a role's *Build reports on matching cases*.

#### Platform and dependencies

- **.NET 10.0.14 security servicing.** Every ASP.NET Core, Entity Framework Core and Microsoft.Extensions package the
  API, the portal, the workers, the connectors and the publisher ship moves from 10.0.13 to **10.0.14** (released
  2026-10-25, an out-of-band security release, with fixes for CVE-2026-111497, CVE-2026-70197, CVE-2026-102870 and
  CVE-2026-114148 — https://github.com/dotnet/core/blob/main/release-notes/10.0/10.0.14/10.0.14.md), and the
  `System.Security.Cryptography.Pkcs` pin with them. The other NuGet packages move to their latest patch or minor version
  (among them Microsoft.Graph 6.9.0, PuppeteerSharp 25.15.0, SkiaSharp 4.154.0, MimeKit 4.18.2, AngleSharp 1.9.1 and
  ModelContextProtocol 2.3.1); `dotnet list package --vulnerable --include-transitive` reports nothing for any project.
- **PDFsharp is frozen at 6.2.4,** its last MIT release: PDFsharp 6.5.0 is AGPL-3.0-only, and the document engine takes
  permissive licences only. An exact pin and a build guard keep any later version out of every build.
- **The connector SDK and protocol packages target .NET 10 only.** .NET 8 reaches end of support on 2026-11-09, so the
  `net8.0` builds of `Realizer.AccessPoint.Connector.Protocol` and `…Sdk` are no longer published.
- **Worker images rebuilt on current, digest-pinned bases.** The media and accessibility workers ran .NET 10.0.12 — two
  security releases behind (10.0.13's 44 CVEs and 10.0.14's four); they now run .NET **10.0.14**, and all three workers build
  with SDK 10.0.403 from ONE pinned digest (they carried two). The document worker's Debian trixie-slim base is the
  2026-10-27 image, so its LibreOffice and Chromium packages are current at build time. The accessibility worker's veraPDF
  moves to **1.30.3**, its installer pinned by SHA-256 and its signature checked against the veraPDF release key. The five
  connector images (`src/connectors/*/Dockerfile`) were built on floating `10.0` tags; they are now pinned by digest to the
  same .NET 10.0.14 images, and the repository's build context admits their folders (it did not, so they could not be built
  from the repository root).
- **Viewer and renderer.** The document viewer's PDF.js moves from 6.3.289 to **6.5.438** (vendored byte-for-byte, every file
  hash-checked against the npm registry's integrity; its new opt-in renderer worker is not vendored and never enabled), and the
  engine's PDFium from build 157 to **158** (its pinned SHA-256 updated; same system libraries, no new glibc requirement).
- **Browser packages.** The Working Files editors are rebuilt, reproducibly, with prosemirror-view 1.42.9, prosemirror-transform
  1.12.4 and prosemirror-schema-list 1.6.0. The web part's production dependency `fast-uri` moves to 3.1.9, past two moderate
  advisories (GHSA-w74x-v6f9-j3xg, GHSA-xhq7-xmqj-769h), and two direct dependencies nothing imported — `@pnp/sp` and
  `@fluentui/react-icons` — are removed. `npm audit --omit=dev` reports nothing for the web part, the shared UI, the
  standalone host or the editors. React, Fluent UI, TypeScript and the SharePoint Framework itself are unchanged here: they
  move with the SharePoint Framework 1.24 upgrade.
- **The web part moves to SharePoint Framework 1.24.1 and React 18.3.1.** SharePoint Online loads React for the web part:
  `react`, `react-dom` and `react-dom/client` are SharePoint Framework externals, served by SharePoint at exactly 18.3.1 and
  never carried in the package. The web part, the hosted app, the marketing demo and the Training Lab render through React
  18's `createRoot`; Fluent UI stays on version 8.
- **The property pane no longer bundles a third-party control.** Its version, copyright and Realizer link were drawn by
  `@pnp/spfx-property-controls`' markdown control, which carried `markdown-to-jsx` 6.11.4 into the `.sppkg` — inside
  GHSA-4wx3-54gh-9fr9 (cross-site scripting, moderate). The markdown was built from AccessPoint's own strings and version,
  so nothing a user typed could reach it; the package was filed as a development dependency although it shipped, so the
  production audit and the SBOM did not list it. The pane now uses the SharePoint Framework's own `PropertyPaneLabel` and
  `PropertyPaneLink`, and the package is removed with its whole tree (its own copies of React 17, Fluent UI 8.106 and the
  SharePoint Framework 1.23 runtime, and the toolchain audit's critical `adaptivecards` → `swiper` chain,
  GHSA-hmx5-qpq5-p643). `@uifabric/react-hooks` — never imported, and React 17 only — is removed too.
- **Build toolchain.** Every pipeline builds on Node.js 24 LTS (supported to 2028-04-30; it was Node.js 22, to 2027-04-30), and
  the web part takes the SharePoint Framework 1.24.1 template's dependency overrides (`qs`, `serialize-javascript`, `uuid`).
  `npm audit --omit=dev` reports nothing for the web part, the shared UI or the standalone host. The internal demo tool
  (never shipped) replaced its people picker, so `@pnp/spfx-controls-react` and its one high and five critical advisories
  are gone from the repository.
- **The API's framing rule is one explicit list.** Which API responses SharePoint, Teams or the hosted app may show in a frame
  was decided by a pattern in the path (anything containing `/editor`, and `/viewer` or `/content` under `/api/documents/`),
  which refused the Studio's page editor and allowed a few responses that are never shown in a frame — a working file's editor
  link, a request's content search and an export's list of contents. It is now a list of exact routes — the document viewer
  and the redaction viewer with what they load, the Working Files editors, grid review, the Studio's page editor and the
  downloads started from a hidden frame — and every other response refuses every frame (`X-Frame-Options: DENY`,
  `frame-ancestors 'none'`). The pages in the list are authorized by a short-lived token in their address, never a cookie.

#### The AccessPoint Training Lab (learn.realizer.io)

- **Training Lab (learn.realizer.io): the class code is looked up before anyone joins, and a name never proves who someone is.**
  The join page's new first step, `POST /api/learner/lookup`, sits behind the join's proof-of-work and rate limit and answers
  only an open class's title, learning path, provider, closing time and whether it asks for e-mail; a closed, not-yet-open or
  unknown code answers exactly as a join does. Continuing on another device asks for the resume code (or, in an e-mail class,
  the address and its 6-digit code) and no longer a name; a first-time join whose name is already in the class asks "Is that
  you?" instead of quietly making a second learner. In an e-mail class, a right code for an address that never joined is
  checked but not spent, so only someone holding the code learns that the address is not in the class. An instructor can give
  a learner a new resume code (shown once, audited); the learner's earlier code stops working.
- **Training Lab: one box takes either code, and failed joins have a Lab-wide budget.** A resume code typed where the class code
  goes is matched against the learners of every open class (a guess succeeds with probability learners / 31⁸, behind the
  proof-of-work and the limits); two matches are refused, a closed class's codes match nothing, and a code that matches nothing
  answers exactly as an unknown class code. Every failed lookup, join and continue now counts against one budget for the whole
  Lab: above it the Lab logs one warning (counts only — no code, name or address) for an alert, makes the proof-of-work harder for
  everyone for 15 minutes, and holds an address that keeps failing — never a signed-in learner or a class that address already
  joined.
- **Training Lab: an instructor's resume code is marked.** A code an instructor makes with *New resume code* lets them continue as
  the learner, so its first use is now audited, the learner's course home says once that their instructor gave them a new code on
  that date (on a device of their own when one is still signed in), and the class's *Learners* tab shows when it was used.
- **Training Lab: the warning about an instructor's resume code cannot be dismissed by whoever used the code** (security review
  2026-11-06). The device that continued with an instructor's code — and any code made on it — is never shown the warning and
  cannot mark it seen, so the learner sees it on their own device; a learner with a confirmed e-mail address is also e-mailed once,
  at the code's first use.
- **Training Lab: a signed-in learner passes a cool-down only for their own class.** During a cool-down after many failed join
  attempts, a learner's sign-in no longer exempts every attempt: it passes only to continue or rejoin in the learner's own class,
  and repeated failures carrying one learner's sign-in are held wherever they come from.
- **Training Lab: a resume code still works when very many classes are open at once.** The match no longer fails (or risks
  stopping the Lab) past about 600 open classes: it runs in batches, the same work for a match and a miss.

#### Realizer (the publisher and its admin console)

- **The regions' active-session counts carry two numbers and read no organization's data** (Active now, 2026-11-09; privacy notice
  §4.9.4). Every five minutes each hosted region tells Realizer how many sign-in sessions were active on it in the last 5 and 15
  minutes — two integers and a time, with no name, address, organization or session id (pinned by tests on the stamp's report, the
  publisher's request and its table). The region's API counts its OWN web sessions, never an organization's rows: its startup
  migration creates a view in the web host's session database (`sqldb-…-websession`) that returns only the two counts, and grants
  the API's runtime identity `SELECT` on that view and nothing else there — no right on the session table itself. The counts reach
  the publisher on the region's existing channel (`POST api/hosted/stamp/sessions`, its own `Hosted.Stamp` token; the stamp is
  taken from the token, never the body; implausible values are clamped); the admin console reads them with the `Platform.Admin`
  scope and the `PlatformAdmin` role, and the publisher deletes them after eight days. A Microsoft 365 deployment sends nothing.
- **Realizer's hosted billing reports read Stripe with a read-only key and keep no personal data** (hosted reporting, 2026-11-06).
  Realizer's admin console now reports the hosted app's Stripe revenue: the publisher reads paid invoices, credit notes and payouts
  with GET calls only, to Stripe's fixed host, preferably with a **restricted key whose only scopes are read** (`Stripe:ReportingKey`,
  kept in Key Vault), and stores Stripe ids, statuses, dates and amounts — never a name, address, e-mail or tax id. Hosted customers
  are sent to Realizer's CRM (HubSpot) **with no contact at all** — their deal and company only: nothing proves a hosted owner's
  address belongs to the organization rather than to a person. For Microsoft 365 customers, a contact is sent only when the address
  is proven to be the organization's own: the Microsoft marketplace purchaser's, when the purchase was made with a work or school
  account of the customer's own Microsoft organization (never a personal Microsoft account), and the verified contact only at that
  same domain; a public mail or internet-provider domain never is, nor does it name or match a company. Nothing is read from an
  organization's cases.

### Action required

**Update the SharePoint package with the API (AccessPoint Learning).** Approving a module now sends the revision the approver
previewed; an older web part's approval is refused (409 `revision-changed`) until the package is updated.

**A deployment you run yourself (Microsoft 365): none required. Upgrade in place.** A lapsed subscription is now read-only
instead of blocked; renewing restores everything at the next licence check. The API's database migration, when it starts,
applies every schema change listed below additively — nothing is dropped and no data is lost — and no permission needs
granting. The servicing of .NET and the other dependencies ships inside the packages. The guided welcome needs nothing either:
the upgrade decides each existing organization's `Welcome:Since` on its own (the hosted licence loop, the Microsoft 365 first
sign-in after the update), so nobody already using AccessPoint is greeted.

**Review the requests now in Deemed refusal (optional).** AccessPoint no longer moves a late request into *Deemed refusal*
(see Fixes). Requests it moved there before this release stay there; any where the requestor has not complained can be returned
to their working status.

**A response package is now built through a release.** The *Response package* sub-tab is **Releases**: build Release 1, 2, …
with **Build the next release**, and send each with **Send release…**. Generating a response package from the old menu entry
is refused (400 `response-package-needs-release`), and *Mark as sent* on a package is gone (409
`package-sent-through-release`) — a web part older than the API shows these refusals until the SharePoint package is updated.
Review copies (Redline review, Originals) are generated as before, now numbered from their own `INTERNAL-` counter. Once a
request has a built or sent release, its response date comes from its releases and the Response tab shows it read-only.

**AI Assist moves to new models unless you choose yours (AI Assist deployed by the template).** The template has a new
*AI models* choice (`aiModelChoice`, owner decisions 2026-11-08). An installation from before 2.6.0 has never chosen, so it
follows Realizer's **recommended models**: the upgrade moves the `chat` deployment (summaries, extraction, translation) to
**gpt-6-luna 2026-09-22** and `chat-premium` (AI redaction analysis, drafting) to **gpt-6.1-sol 2026-09-29**; the embeddings
stay text-embedding-3-small.

- **Quota first.** The subscription needs Azure OpenAI quota for both models in the AI account's region, for its deployment type
  — by default 50 and 30 thousand tokens a minute (`aiChatCapacity`, `aiPremiumChatCapacity`). Check it in Azure AI Foundry →
  *Quotas* or with `az cognitiveservices usage list -l <region>`; quota for gpt-5.4-mini and gpt-5.4 does not cover the new
  models. Without it the deployment fails at the model deployments: request the quota, or choose your models (below).
- **UK West and North Europe.** Neither region offers the new models. A **new** AI account there is created in UK South or West
  Europe — the same geography — and later upgrades keep it there. An **existing** account never moves: in North Europe its
  deployments are left as they are and keep their models, and the deployment's output `aiModelsNote` says so (pin them to keep
  them on purpose; to use the new models, delete the AI account and purge it — AccessPoint keeps nothing in it, and a deleted
  account holds its name until purged — and deploy again with
  *Azure OpenAI region* = `westeurope`). UK West offers no Azure OpenAI models at all, so an installation there already names its
  AI region: name it once more on this upgrade — from 2.6.0 the template remembers the AI account's region.
- **To stay on the models you have, pin them.** In the Deploy to Azure form, AI Assist page: *AI models* → **Choose models**, and
  enter the models your deployments run (Azure portal → the `oai-accesspoint-<tenant>` resource → *Deployments*) — for the 2.5
  defaults `gpt-5.4-mini` / `2026-03-17` and `gpt-5.4` / `2026-03-05`. With the script: `-DeployAiAssist -AiModelChoice Pinned
  -AiChatModel gpt-5.4-mini -AiChatModelVersion 2026-03-17 -AiPremiumChatModel gpt-5.4 -AiPremiumChatModelVersion 2026-03-05`.
  Later upgrades keep pinned models (*Keep the current models*, the form's default on an upgrade).
- **Data zone standard** stays EU and US only, as the form says: gpt-6-luna has no Asia Pacific data zone, so an installation
  that chose a data zone in Asia Pacific gets no new model deployments (its existing ones are left as they are) — pin its models.
- **Or use deployments of your own** — new in Settings → Features → AI Assist: an Administrator names an everyday and/or a premium deployment
  created in the same Azure OpenAI resource, AccessPoint tests it and uses it instead of `chat` / `chat-premium` (User Guide →
  *Choosing the AI models*).

**The schema changes the migration applies:**

- **AccessPoint Learning.** New tables: `CoachNotes`, `LearningModules`, `LearningModuleVersions`, `LearningModuleTexts`, `LearningOverlays`,
  `LearningAudienceRules`, `LearningAudienceExclusions`, `LearningAttempts`, `LearningCompletions`,
  `LearningExternalCompletions`, `LearningGlossary`, `LearningObligations` and `LearningLinkChecks` (what the weekly link
  check found; deleted with its module).
  New columns, appended, on `TrainingPaths` (`ValidityMonths`, `CertificateEnabled`, `CompletionRule`, `ObligationTags`,
  `MentorRule`, `DueAfterDays`, `SuggestedAudiences`), `TrainingAssignments` (`Source`, `RuleId`, `PinnedVersions`, `ExpiresOn` — and its status
  check gains `Expired` and `ReviewNeeded`) and `Documents` (`LearningModuleId`, with its owner check widened).
  Two new views: `vw_TrainingCoverageSummary` and `vw_ObligationCoverageSummary` (which reads the first), read by the
  Report Builder's *Training coverage* and *Obligation coverage* subjects.
  One index narrowed: `UX_TrainingAssignments_Open` (one row per learning path and person) now applies only to the
  open statuses (`Assigned`, `InProgress`, `ReviewNeeded`) instead of every status but `Withdrawn`, so a completed or
  expired enrolment can stay beside a new one (each cycle is its own row). Every row the wider index admitted, the
  narrower one admits; the migration drops and re-creates that index and changes nothing else.
- **Releases.** New tables: `RequestReleases`, `RequestReleaseRecords`, `ResponsePackageExportItems`, `RequestReleaseSchedules` and
  `RequestReleaseScheduleDates`; the view `vw_ReleaseStatusSummary`.
  New columns, appended: `Requests` (`RecHighWaterMark`, `InternalBatesHighWaterMark`, `FirstReleaseDate`,
  `FinalReleaseDate`, `NextReleaseDueOn`), `ResponsePackageExports` (`FirstDownloadedOn`, `RequestReleaseId`),
  `PaymentRequests` (`RequestReleaseId`), `RequestTypes` (`HoldReleaseUntilPaid`), `LegalAuthorities` (`ResponseCountsFrom`,
  default `Final`, with the check `CK_LegalAuthorities_ResponseCountsFrom`: `First` or `Final`), `RequestorCategories` (`ElectronicCopyFeeRate`) and `portal.Cases` (`ReleasesJson`); `vw_RequestSummary`
  gains the first and final release dates.
  Checks widened: a payment request's kind gains `Instalment` and its status `Waived` (`CK_PaymentRequests_Kind`,
  `CK_PaymentRequests_Status`, the portal's `CK_PortalPayments_Kind`). A new check keeps `ElectronicCopyFeeRate` at zero or
  more (every existing row is empty).
  `RequestFees.CopyFormat` records how a fee priced the request's pages — `Electronic`, `Paper` or `Inspection`, with the check
  `CK_RequestFees_CopyFormat`; NULL for a fee generated before 2.6.0.
- **Lab mode.** New tables: `TrainingCaseCast` (who plays each person on a training case) and `TrainingScriptedActs` (the scripted answers,
  due and given) — rows in the training copy only — and `TrainingCastScripts` (the organization's own scripts, written in real work).
  New columns, appended: `Users.IsSimulated` (0 for every existing row, with the check `CK_Users_Simulated`),
  `TrainingExerciseRuns.CastPlan` (who plays each role of a team exercise; NULL — every role a person — for existing exercises,
  with an `ISJSON` check) and `RequestorCommunications.CorrespondentType` (whom a complaint letter is to or from, *Complainant* or
  *Regulator*, with its check; NULL on existing rows, whose party is read from their purpose as before).
  Also new: `TrainingCases.StartBaseline` (what a training case's start wrote, as JSON with an `ISJSON` check; twin rows only —
  see *Security*) and `ExampleScenarios.IsTrainingOnly` (a scenario a private pack brought; 0 for every existing row).
  A check widened: `CK_RequestorCommunications_CaptureSource` accepts `Scripted`.
- **Dated settings (Nova Scotia's new Act) and free search hours.** `ChoiceConfigurations.AvailableFrom` and `AvailableUntil`
  (with the check `CK_ChoiceConfigurations_AvailableWindow`), `ExtensionReasons.AvailableFrom` and `AvailableUntil` (with
  `CK_ExtensionReasons_AvailableWindow`), `RequestorCategories.FeeRuleEffectiveFrom` with seven `Prior*` amounts, and
  `AssessmentTypes.MandatoryFrom` — all NULL on existing rows, which behave as before; `RedactionDetectionRules.SuggestedExemptionCode`
  widened to 200 characters; and `RequestorCategories.FreeSearchHoursExact` and `PriorFreeSearchHoursExact` (free search time to
  two decimals of an hour, each with a check of zero or more; NULL on existing rows).
- **Hosted AccessPoint only** (created in every database, used only by the hosted service): the tables `TenantMemberships`,
  `HostedInvitations`, `HostedJoinRequests`, `HostedUsageReportCursors`, `EmailSendBudgets`, `HostedLifecycleNotices`,
  `OrganizationExportJobs` and `portal.TenantHosts`; `Tenants.CreatedByIdentityKey`, `AllowedSignInTenantIds` and
  `MicrosoftTenantId` (NULL on every other row) and `Tenants.IsDiscoverable` (1 by default), with two filtered indexes;
  `UsageLedger.ExpiresOn` and `GrantId` (appended, NULL on every existing row, with a filtered index); and
  `CK_TenantLifecycleLog_Operation` accepts `OrganizationCopy`.

**Optional, after upgrading:**

1. **Re-apply the jurisdiction packs that changed, the Universal baseline first** — Settings → Jurisdiction packs → the pack →
   *Add and update unchanged*. What each brings:
   - **Universal baseline 2.77 and Universal learning 1.11.** AccessPoint Learning's content now ships in its own pack, Universal
     learning, imported automatically beside the baseline (an organization that applied a baseline from 2.67 to 2.74 keeps every
     row, with its people's progress and certificates). Together they bring Realizer's five learning paths (with their glossary
     terms, training obligations and suggested audiences); the PIA course's *PIA practitioner* learning path (since baseline 2.72;
     ten modules of its own with its capstone since 2.74, twenty-one more glossary terms and the training cases *Describing a
     program's information flows*, *Treating a risk* and *Keeping a PIA current*); since 2.74 the learning paths *Your project's PIA*
     and *Signing off a PIA* (with the training case *Answering a section the privacy office delegates to you*); the coach notes and
     their *Learn more* links; AccessPoint Learning's six notification templates (*AccessPoint Learning: training assigned*,
     *training due soon*, *training overdue*, *training to review*, *weekly summary for leads* and *certificate revoked*); the
     notices that say Lab mode; the sample module and learning path (*How we handle a request: the basics*); the scripted people of
     Universal learning's practice cases and team exercise — the team exercise's custodian included — and the access analyst
     path's module on the response, version 2 (Universal learning 1.11); the generic release letters in all eleven languages
     (since baseline 2.66; they say what a release's fee covers since 2.76); and the reminder *Your team exercise is waiting for
     you* (2.77 — until then a colleague who does not answer in time gets no reminder). Until they are re-applied, *How we decide*
     shows your configuration's descriptions and legal references and your own notes, and AccessPoint Learning's notices have no
     template to send.
   - **Canada federal 1.52:** the *ATIP analyst* and *ATIP coordinator* learning paths (with their glossary terms and the Treasury
     Board syllabus's training obligations) and its coach notes' *Learn more* links (and, since 1.48, the coordinator path with the
     analyst modules and *Before you sign a response*, and both paths' suggested audience — the people who coordinate requests); the
     PIA course's federal path (since 1.50; since 1.51 *Signing off a PIA (federal)*; since 1.52 the federal PIA template's version 2);
     the scripted coordinator who reworks a refused PIA, and the case where a scripted senior official decides yours; and the
     corrected wording of 1.50 and 1.52 (*Fixes*).
   - **Ontario provincial 1.34 and municipal 1.37:** the PIA course's Ontario path.
   - **Alberta 1.28** (*Canada — Alberta (ATIA)*)**:** the *Privacy Impact Assessment (POPA)* type (item 10) and, since 1.27, the PIA course's Alberta path.
   - **British Columbia 1.32, Australia — Federal FOI & Privacy 1.34, New Zealand — OIA & Privacy 1.31 and United States —
     Federal (Privacy Act of 1974) 1.25:** the PIA course's path for each (*What's new*).
   - **EU GDPR 1.27 and UK 1.32:** the scripted data protection officers (since 1.26 and 1.31) and a new case that makes you the
     data protection officer (1.27 and 1.32), beside the DPIA course paths of 1.25 and 1.30.
   - **Nova Scotia 1.29**, where installed (*Canada — Nova Scotia (FOIPOP + municipal)*): the new Act's exemptions and extension
     grounds, the suggestion patterns' codes, the fee change and the municipal PIA questionnaire. Nothing needs re-applying on
     1 April 2027 itself. See item 14 for the organization's time zone.
   - **California Public Records Act 1.19** (since 1.18: release letters in English and Spanish, the estimated-date statement, both
     request types holding each release until its instalment is paid, electronic copies free, the response date counted from the
     first release, and a switched-off follow-up rule for the estimated release date; since 1.19: the fee and corrected release
     letters say the pages a fee covers), **Hawaii 1.15**, **Oregon 1.14**, **Delaware 1.15** and **Arkansas 1.15** (release-aware
     wording in their partial-release letters), and **Alabama 1.14**, **Louisiana 1.11**, **New Mexico 1.11**, **Vermont 1.11**,
     **West Virginia 1.12** and **Wyoming 1.12** (with Oregon, Delaware and Arkansas: the statutory notice that was typed as an
     interim response is an ordinary letter now, so Send release offers a release letter instead).
2. **Copy your setup to the training copy again** once the packs whose training content changed are re-applied (Universal
   learning, Canada federal, EU GDPR, UK, and Alberta for its capstone case's new version): Settings → Training → **Copy current
   setup now** — this removes every training case.
3. **Update the SharePoint package** (Settings → Setup → *Update now*, or the app catalog) so the web part offers Releases and
   the media mark card; shows the scripted answers, *Have it arrive now*, simulated people, the party desk and the lead's choices;
   and offers only a request's own Act in the exemption pickers, with the new dates in Settings. The new React and SharePoint
   Framework versions arrive with `accesspoint.sppkg`, and SharePoint Online provides React 18.3.1 to it; for that upgrade nothing
   changes in Teams, the API, the database or the Azure template. SharePoint Framework 1.24 runs on SharePoint Online only —
   AccessPoint has never supported SharePoint Server.
4. **To let people other than Administrators write coach notes,** add *Author learning content* to their role
   (Settings → Roles & Permissions). To let them switch notes on, they also need *Manage training*.
5. ***How we decide* is on by default.** To keep it hidden until your organization is ready, switch off *Show How we
   decide at decision points* under Settings → Training → AccessPoint Learning and select **Save**.
6. **Writing modules needs the AccessPoint Learning module,** which every marketplace plan now lists: your deployment's licence picks
   it up at its next licence check (at most a day, or at the API's next start) — nothing to reissue.
7. **Certificates are made by the document worker:** a deployment without it cannot produce the certificate PDF
   (confirming the name, verification and revocation still work).
8. **To let a second person approve each module before it is published,** switch on *A second person approves each module
   before it is published* (Settings → Training → AccessPoint Learning); at least two people need *Manage training*.
9. **Completion records are kept seven years by default** after the later of completion and the last valid day — set
   *Keep completion records for {n} years* (Settings → Training, 1 to 15) to match your records schedule.
10. **Alberta public bodies:** with the Alberta pack (1.28) re-applied (item 1), you have the *Privacy Impact Assessment (POPA)*
   type. A PIA started on the POPA template from then on needs the head's sign-off (Validation tab → **Record decision**) before it
   takes effect: give the head, or the delegate, *Act as senior official* and name them as the PIA's senior official. PIAs started
   before keep their type and their rules. Then copy your setup to the training copy (item 2) for the Alberta capstone case's new
   version.
11. ***Getting a final response signed off* needs final responses held for the senior official** — Settings → Correspondence
   sign-off → tick *Final response* — and a copy of your setup to the training copy after changing it; its card in **Training
   cases** says when sign-off is not switched on.
12. **Review your legal authorities** (Settings → Legal authorities → *Response date counts from*): the final release by default;
   choose the first release where your statute measures the response by when records start to go out.
13. **Review your fee schedules** (Settings → Requestor fee categories → *Electronic copies*) and **request types** (*Hold releases
   until paid*) for the releases your organization charges for. Where a schedule sets an electronic rate (California 1.18 makes
   electronic copies free), a fee estimate or final fee generated from now on charges the request's pages at that rate unless
   the request's **Response method** is *Mail* (paper) or *In person* (inspection) — set it where copies go on paper. Fees already
   generated are unchanged until regenerated.
14. **Nova Scotia organizations: the organization time zone.** Applying the Nova Scotia pack (1.29) in an organization that has
   never set a time zone and has only Nova Scotia packs installed **sets the organization time zone to America/Halifax**, and records
   the change in the audit log as the pack import's. From then on **every due date, "today" and displayed due day is computed on
   Halifax days**, for everyone — not on the time zone of whoever is working — so the 1 April 2027 switch follows Halifax's days.
   An organization that already chose a time zone, or that also has another jurisdiction's packs, is not changed: set it yourself.
   To check or change it: **Settings → Localization & formats → Time zone**.
15. **The accessibility checker's patience.** The time after which an accessibility check with no result reads *No answer from
   the accessibility checker* is the API setting `Accessibility__NoAnswerMinutes` (minutes; 180 by default, longer than the
   accessibility job's two-hour run limit). Set it only where the job's run limit was raised, and keep it longer than that limit.
16. **Connector authors only:** a connector built on the SDK must target .NET 10 to take the 2.6.0 SDK packages (`net8.0` builds
   are no longer published); a connector already deployed on .NET 8 keeps working against the API, because the protocol, not the
   runtime, is the contract — move it to .NET 10 before .NET 8's end of support on 2026-11-09.

**Hosted AccessPoint and Realizer's services around it — the order.** The hosted items below (every item from here to the end of
this heading but *The AccessPoint Training Lab*) are each work package's record: what it changes and what an older piece does with
it. The ONE order in which Realizer's operators release 2.6.0 to the hosted service — every step below without duplicates, stage
first and then production, with who does each and what to check — is `deploy/hosted/README.md` → *Releasing 2.6.0 (stage, then
production)*; an item below that once gave its own deploy order now points there. In short: in each environment the publisher (its
DacPac, then the app), then the stamp, then the global entry; the stamp's template after its release on stage and before it in
production; `HostedControlPlane:FreeStepDownEnabled` on each publisher slot as soon as every stamp it lists runs the release; the
demo's sign-up switch last.

**Hosted pricing P1 — for Realizer as the operator (hosted pricing design v1.1 §17 P1).** A hosted organization has nothing to do.
Realizer's operators:

1. **Order: the runbook** (`deploy/hosted/README.md` → *Releasing 2.6.0*: in each environment the publisher, then the stamp). The
   API reads the new quota keys (`assessmentsPerMonth`, `storageMb`) and the paid tiers' read-only lists; an older API reads the
   first two as absent — unlimited — and would treat a paid tier as the Free plan for e-mail limits and Lab mode uploads: on stage,
   between the publisher's release and the stamp's (the runbook's rule 1); production has no older API. The publisher DacPac changes
   no table for P1 (the declared covered-population band it once added was removed before release — HP-80); the stamp's DacPac widens
   the CHECK of `HostedLifecycleNotices.Kind` (two allowance notices).
2. **Stripe — the products are done:** `deploy/hosted/stripe/catalogue.py` created **AccessPoint Essentials** (79 / 790 CAD) and
   **AccessPoint Professional** (249 / 2,490), with the rest of the decided catalogue, in the sandbox and the live account on
   2026-11-09, and the live customer portal's plan list; the stage slot holds `Stripe:Prices:hosted-essentials:{month|year}` and
   `…:hosted-professional:{month|year}`, and production takes them with the release. Left (runbook S5): the sandbox portal's plan
   list (`--portal`) once stage runs 2.6.0; archive FOI, Privacy, Complete, the two metered *Overage requests* prices and the meter
   `accesspoint_overage_requests` in the sandbox — never create them live — and remove their settings and
   `Stripe:Meters:OverageRequests` once no sandbox subscription bills them (until then a retired plan's price reads as its
   successor). `docs/hosted/Stripe_Setup.md` §2, §3, §8.
3. **Stage subscriptions on FOI, Privacy or Complete** move to Essentials / Professional by themselves within an hour (audited
   *HostedRetiredPlansMoved*); production has none.

**Hosted discounts and promotion codes — for Realizer as the operator (hosted pricing design HP-90, 2026-11-10).** A hosted
organization has nothing to do. Realizer's operators:

1. **Order: the runbook.** The publisher DacPac appends the discount and partner-code columns to `dbo.HostedBillingAccounts` (all NULLable)
   and `DiscountCouponId` to `dbo.HostedBundlePurchases`. Either order with the stamp is safe: an older stamp ignores the billing view's
   `discount`, `paymentMethodNeededBy`, `promotionCode` and a bundle's `listPrice` (its bundle price is then the discounted one, which the
   purchase charges), and an older stamp drops a sign-up link's `promo` (no partner code reaches Checkout until the stamp's release).
2. **Stripe (`docs/hosted/Stripe_Setup.md` §2 *Discounts and promotion codes*, §8):** give the **restricted** key **Coupons write** and
   **Promotion codes read** beside what it has (runbook S1.1 and L1.2) — without them the publisher still works (a subscription read the
   key refuses is made again without its discounts) but no discount is recorded and the console's coupon list says Stripe refused it.
   Nothing changes on the webhook. Run §9 item 14 on the stage sandbox before live.
3. **Giveaways and partner codes** are made in the Stripe Dashboard (a coupon, then a promotion code with its restrictions and, for a
   partner, `metadata[partner]`); the console's **Apply a discount** puts a coupon on a customer already subscribed
   (`docs/RealizerAdminConsoleRunbook.md` §14).
4. **Decisions taken by the builder** (hosted pricing design §17 *Discounts and promotion codes (HP-90)*, D-1 – D-14 — confirmed by the owner 2026-11-10): Checkout
   asks for a card only when something is due today; a percentage below 100 % discounts bundles and a 100 % one does not unless its coupon
   says `applies_to_bundles=true`; a partner code is recorded once per organization and kept for life; the MRR from the items is counted
   after the discount.

**Hosted pricing P3, bundles and extra storage — for Realizer as the operator (hosted pricing design v1.1 §6.4, §7.3, §7.5, §17
P3).** A hosted organization has nothing to do. Realizer's operators:

1. **Order: the runbook.** The publisher DacPac brings `dbo.HostedBundles` with its seed, `dbo.HostedBundlePurchases`,
   `HostedBillingAccounts.ExtraStorageUnits`, `StripeRevenue`'s `Bundle` role and the `hosted-addon-storage` price row. Either order
   is safe: an older stamp ignores the billing view's bundle fields and offers no button; the new stamp against an older publisher
   shows no bundle offer.
2. **Stripe (`docs/hosted/Stripe_Setup.md` §2, §4, §8):** the bundles and the extra-storage prices already exist in both accounts
   (the catalogue of 2026-11-09); their nine price settings — `Stripe__Prices__bundle-<id>__once` for the seven bundles (the OCR and
   media ones are seeded inactive) and `Stripe__Prices__addon-storage__{month|year}` (`catalogue.py --settings-out` writes them) —
   are on the stage slot (2026-11-10) and go to production with the release (runbook L3); give the **restricted** key **Invoices
   write**, **Invoice items write**, **Credit notes read** and **Payment methods read** beside what it has; add
   **`credit_note.created`** to the webhook endpoint (`catalogue.py --webhook` sets it — runbook S1.2 and L1.2). Run §9's bundle
   checks on the stage sandbox before live (that an invoice item takes `pricing[price]` under the pinned API version was confirmed
   on the sandbox on 2026-11-10).
3. **The admin console** gains Revenue → **Bundles sold (hosted app)** and **Reverse grant** on a customer's allowance grants
   (`docs/RealizerAdminConsoleRunbook.md` §14).
4. **Decisions taken while the owner was unavailable** (hosted pricing design §17 P3, P3-1 – P3-17 — to revisit): Free's unused units carry
   into a paid plan; a Stripe credit note reverses the unused units its invoice minted; the OCR and media-minute bundles stay inactive
   until their pause exists. (P3-10's "removing extra storage is arranged with Realizer" is replaced by HP-91, below.)

**Removing extra storage and a promotion code on a live subscription — for Realizer as the operator (owner decisions 2026-11-10, HP-91,
HP-92; hosted pricing design §17 *Removing extra storage …*).** A hosted organization has nothing to do. Realizer's operators:

1. **Order: the stamp's API first, then the publisher.** The stamp's DacPac lets `HostedLifecycleNotices.Kind` take `StorageKept`; the
   publisher DacPac appends `StorageRemovalUnits`, `StorageRemovalEndsOn` and `StorageChangeKey` to `dbo.HostedBillingAccounts` (NULLable,
   with a CHECK). An older stamp offers no *Remove 100 GB* and never settles a removal — so no removal can exist before the new stamp runs.
2. **Stripe:** nothing new — the restricted key's **Subscriptions write** and **Promotion codes read** already cover the calls
   (`docs/hosted/Stripe_Setup.md` §2). Run §9 item 15 on the stage sandbox before live.
3. **The admin console's customer page** shows the extra storage billed and a removal the organization made, with its end
   (`docs/RealizerAdminConsoleRunbook.md` §14). A removal shown *past that day* waits for the stamp's check (minutes); one that stays past
   it means the stamp is not reporting — check its licence loop.
4. **Codes for customers** are made in the Stripe Dashboard (a coupon, then a promotion code with its restrictions); the customer types it on
   Settings → Subscription → *Promotion code*.
5. **Decisions taken by the builder** (§17, RS-1 – RS-10, PC-1 – PC-6, SP-1 – SP-4 — confirmed by the owner 2026-11-10): the quantity lowered at once without
   proration, the unit held in the licence until the stamp settles it after the end; units kept at the end billed like *Add 100 GB*; the
   *Your extra storage stays for now* e-mail always sent; *Keep 100 GB* only before the end; the 50-unit limit counts units being removed; a
   later promotion code never changes the partner attribution; the promotion code recorded in the organization's audit ledger.

**Hosted pricing P2, the drip and bank — for Realizer as the operator (hosted pricing design v1.1 §5, §17 P2).** A hosted organization
has nothing to do. Realizer's operators:

1. **Order: the runbook.** The stamp's DacPac appends `UsageLedger.ExpiresOn` and `GrantId`; the publisher DacPac adds
   `dbo.HostedAllowanceGrants`. Either order is safe — an older API ignores `allowance`, `nextGrant` and `grants` and counts per
   period as in P1, and the new API with an older publisher keeps the period model; with the publisher first, as the runbook has it,
   a grant minted before the stamp's release is counted at the stamp's first licence refresh. At the first licence refresh after both
   are live, each organization gets its grants: the trial's, the Free year's, and a paid subscription's **current period once** (its
   invoice, when processed later, adds nothing).
2. **Stripe:** a **restricted** key needs **Invoices read** — within §8's **Invoices write** since P3 (the paid invoice is read back
   before anything is granted; without it every `invoice.paid` fails and is retried — the billing sweep then re-processes it). The
   customer portal's *Proration: always invoice* and *downgrades at the end of the period* are what
   `deploy/hosted/stripe/catalogue.py --portal` sets — the live portal's since 2026-11-09, the sandbox's once stage runs 2.6.0
   (runbook S5; `docs/hosted/Stripe_Setup.md` §6).
3. **The admin console** lists each hosted organization's allowance grants and offers **Grant allowance** to its Admin role
   (`docs/RealizerAdminConsoleRunbook.md` §14). Since P3 a refund by credit note takes the unused units back by itself
   (`credit_note.created`), and the console offers **Reverse grant** for a refund made without one.
4. **The public portal (HP-84, HP-85):** the trial no longer includes it (`SeedPlans.sql`); a stage organization whose trial had it
   switched on keeps its portal readable on Free, with intake paused and deliveries kept.

**Hosted pricing HP-89, the Free allowance per Microsoft organization — for Realizer as the operator (hosted pricing design v1.1 §5.4).**
A hosted organization has nothing to do. Realizer's operators:

1. **Order: the runbook** (in each environment the publisher, then the stamp). The publisher DacPac adds
   `dbo.HostedAllowancePools`, `dbo.HostedAllowancePoolDraws` and the `FreePool` source in `CK_HostedAllowanceGrants_Source`. The
   new API draws only when the licence carries the `pool` claim, so it is safe against an older publisher (Free keeps its
   per-workspace 5 + 5); an older API ignores the claim and leaves a Free workspace without units once the new publisher stops minting
   them — its requests wait, its assessments are refused — on stage until the stamp's release lands after the publisher's (the
   runbook's rule 1), while production has no older API. Without the stamp's API reaching the control plane, a Free workspace's
   requests wait and its assessments answer *try again* (503 `allowance-unavailable`); nothing is granted on the stamp.
2. **Switch `HostedControlPlane:FreeStepDownEnabled` on with this release** (decided 2026-11-09 while the owner was unavailable; confirmed by the owner 2026-11-10), by the
   runbook's ONE rule (rule 3): on each publisher slot, as a slot setting, as soon as every stamp that slot lists runs the release's
   API — stage-api right after the stage ring released the release build to `cac-stage`, api.realizer.io right after the production
   ring released `cac-prod`. That keeps O1's condition (item 2 of *Hosted AccessPoint* below): no stamp reads a Free licence with an
   older API. An organization created without a trial (`trial: false` — the account's or its Microsoft organization's trial is used)
   starts on the Free plan whatever the setting says, while a trial that ends only steps down to Free with the setting on.
3. **Stage converts once, by itself:** when a tenant group's pool is made (its first Free licence after the publisher is live), the Free
   grants its workspaces already hold count against the pool's first year (capped at 5 + 5); nothing is taken from a workspace. Production
   has no hosted organizations.
4. **Testers:** `Hosting__Organizations__CreationExemptTenants` on the stamp (stage: Realizer's and Develops' tenant ids, production none)
   now also skips one trial per Microsoft organization — on the stamp and at the control plane. It is the stamp template's
   `organizationCreationExemptTenants` parameter (`cac-stage.bicepparam` lists the two tenants, `cac-prod.bicepparam` none), written
   on every stamp deployment — nothing to set by hand (runbook S4).

**Hosted AccessPoint — for Realizer as its operator.** A hosted organization has nothing to do: a new organization starts with
e-mail notices on and its name in Settings → Organization; an organization created earlier takes its name once (a name already
set is kept). Its administrator sets a **Reply-to address** — and switches **E-mail notices** on for an organization created
earlier — in **Settings → Organization → E-mail**. Realizer's operators:

1. **Session limits.** Everyone signed in before the update is asked to sign in once more (sessions now carry a server-side
   record). The stamp's maximums are the template's `sessionIdleMinutesMaximum` (stage and production: **120 minutes**, owner
   2026-11-06 — the stamp maximum and default; each organization's Administrator can choose shorter) and
   `sessionAbsoluteHoursMaximum` (12): a deployment of the stamp's template writes them to the web host and the API — set them
   there, never by hand on one site. An organization keeps the service default until its Administrator chooses shorter limits
   in Settings → Users & access → **Members** → *Signing out*.
2. **The Free step-down (O1).** Turn on the publisher setting **`HostedControlPlane:FreeStepDownEnabled`** only once EVERY hosted
   stamp the publisher slot lists runs this version's API (owner, 2026-11-06) — an older API reads a Free licence as fully writable;
   the runbook's rule 3 does it with the release (HP-89, item 2 above), each stamp's `/api/health/version` naming the release commit.
   With it off, a trial still ends as before. When it is turned on, the hourly expiry runs `HostedFreeBackfill` once: every hosted
   trial already **Expired** moves to the Free plan (its data becomes readable again); the run is marked in the admin audit and never
   repeats. The publisher DacPac (before the publisher in each environment — `realizer-cd`): `Plans.ReadOnlyFeatures`,
   `Subscriptions.TrialExtendedOn` / `TrialExtendedBy` / `TrialExtensionReason`, `Tenants.SignupAttribution` (all appended,
   NULLable), `Subscriptions.RowVersion` (appended; a `rowversion` SQL Server fills for every existing row — every subscription
   update is now conditional on the version it read, security review 2026-11-07 OB-8), the wider `HostedUsageReports.Period`, the
   four new admin event types and the `hosted-free` plan row (`SeedPlans.sql`, which also makes the trial's request cap record-only).
3. **Lifecycle e-mails, the inactive-Free purge and the data download (O3/O4)** (`docs/RealizerAdminConsoleRunbook.md` §14). Deploy the publisher DacPac (new table `HostedTenantActivity` — dates and counts only)
   before or with the stamp; an older publisher simply ignores the stamp's `activity` field. Set the stamp's
   `HostedLifecycleNotices__ReplyTo` (the stamp template's `lifecycleNoticesReplyTo`, default `support@realizer.io`) — without it
   the notices carry no Reply-To. The stamp's API
   creates `dbo.HostedLifecycleNotices` and `dbo.OrganizationExportJobs` at its migration. The inactive-Free purge stays an operator
   command: `tenant-lifecycle candidates` lists `inactive-free` organizations (with their facts, open requests and warnings);
   suspend one, then `tenant-lifecycle purge --kind inactive-free --tenant <id> --confirm <id again> …` — refused unless it was
   warned at the required notice, is past its date and nobody signed in since (a hold refuses, with no override for this kind).
4. **The AccessPoint Learning add-on and Add / Remove a module.** The add-on — the plan row `hosted-addon-academy`, seeded at CAD
   29 a month or 290 a year (`SeedPlans.sql`, the price the hosted pricing design kept); the hosted trial includes it — needs its
   Stripe prices: the *AccessPoint Learning add-on* product and its prices exist in both accounts (the catalogue of 2026-11-09), and
   `Stripe:Prices:addon-academy:month` and `Stripe:Prices:addon-academy:year` (App Service `Stripe__Prices__addon-academy__month` /
   `__year`) are on the stage slot and go to production with the release (runbook L3). Until they are set, a Checkout that names
   the add-on answers 503 `price-not-configured`, and nothing else changes. *Add a module* adds an
   add-on to a live subscription through the Stripe API (`POST /v1/subscription_items`): a **restricted** Stripe key needs
   *Subscriptions* **write** (it needed read only), and every add-on price must be set at both intervals — a missing one
   answers 503 `price-not-configured` for that add-on only. *Remove a module* deletes the add-on's subscription item
   (`DELETE /v1/subscription_items/{id}`, `proration_behavior=none`) and *Keep* adds it back the same way — the same
   *Subscriptions* write permission; nothing more to configure.
5. **The marketing demo's hosted trial.** `Demo:HostedTrial:SignupUrl` can now point at `https://app.realizer.io/signup` —
   the production release's last step (runbook L11; `docs/DemoDeveloperGuide.md` §5.1).
6. **Deploy each stamp with the workers and malware scanning (hosted launch, lane A).** The stamp template now carries the
   document, media and accessibility workers and Defender for Storage, and both parameter files turn them on — but nothing
   changes until the operator runs the stamp deployment, on stage after the stage ring released the build (with its digests) and in
   production before the production ring (with the promoted release's) — runbook S4 and L5; `deploy/hosted/README.md` → *Workers
   and malware scanning*. Check that `Microsoft.EventGrid` is registered on the subscription (without it the scanner silently stays
   off), deploy as Owner
   of the stamp's resource group (the tag reader is a custom role), export the worker image digests of the build the stamp
   runs — `eval "$(bash deploy/hosted/cd/stamp.sh worker-images accesspoint/<version>)"`, a 2.6.0 build or later (an
   older worker image cannot use the stamps' user-assigned identities; the helper refuses a folder whose signed `SHA256SUMS`
   does not verify, and without the three digests the parameter file does not compile — there is no tag fallback) — then
   `az deployment group create` with the stamp's parameter file, stage first. The deployment rewrites the API's settings and restarts it. Then run the README's checks: a
   Word and an e-mail conversion, a short video, a release's accessibility check, and the EICAR test file reading
   **Malicious** and refused in a release. The hosted CD moves only the API and the web host: when a later release changes a
   worker, deploy the stamp again with that release's digests.
7. **The stamp's alerts, geo-redundant backups, Azure AI and the portal's wildcard domain** (hosted launch lane B, 2026-11-07;
   `deploy/hosted/README.md`). The next deployment of each stamp's template:
   - creates the operations action group and the alert rules, e-mailed to `operationsAlertEmail` (both stamps:
     `support@realizer.io` — change it to the operations mailbox when one exists), and on production Azure Service Health
     (Canada Central, Canada East and Global — `serviceHealthAlert`, in the template since 2026-11-09 instead of a step by hand) and
     availability tests from outside Canada (`availabilityTests`);
   - moves both databases' backups to geo-redundant storage (`sqlBackupStorageRedundancy = Geo`: geo-restore to Canada East; it
     applies to new backups, within 48 hours) and both storage accounts from LRS to RA-GRS in place (a one-time egress charge for
     the first copy; refused while an account holds Archive-tier blobs). Rehearse the geo-restore runbook on stage and write the
     recovery objectives. Long-term SQL retention stays off until the service's retention commitment sets it;
   - creates Azure OpenAI (`chat`, `chat-premium`, `embed`, Global Standard, within the subscription's Canada Central quota:
     gpt-6-luna 250K, gpt-6.1-sol 250K and text-embedding-3-small 1,000K tokens a minute, shared by both stamps), Document
     Intelligence, AI Search and Speech — on **stage**, and on **production** too: decided by the owner on 2026-11-09 (*Azure AI —
     where the data is processed*), production's AI is the same Global GPT-6 deployments behind each organization's consent, turned on
     with this release, which carries the consent gate (`deployAzureOpenAi = true`, `aiGlobalProcessingAcknowledged = true` with the
     date, in `cac-prod.bicepparam`), beside Document Intelligence, AI Search and Speech, which process in Canada Central. Both
     parameter files name the models — **gpt-6-luna 2026-09-22** for `chat`, **gpt-6.1-sol 2026-09-29** for `chat-premium` (owner
     decision 2026-11-08; Realizer manages the hosted models, so hosted organizations have no model choice). In Canada the GPT-6
     models are offered only as Global deployments, which may process prompts outside Canada: the template refuses a Global
     deployment unless the parameter file sets `aiGlobalProcessingAcknowledged = true`. The template writes the API's
     `AzureOpenAI__Processing__*` (`Outside` for a Global deployment), and every organization's AI on such a deployment stays off
     until its Administrator allows it in Settings → Features & AI → AI Assist. Publish the terms, the privacy notice and the
     sub-processor list first (runbook L1). On **stage** each test organization's Administrator allows it once before its AI
     answers (the hosted functional suites carry the step);
   - adds the public portal's wildcard domain `*.{portalHostedDomain}` only once a stamp deploys the portal and names its Key
     Vault certificate (`portalWildcardCertificateSecretId`): import an RSA wildcard certificate into the stamp's vault, deploy,
     then create the wildcard CNAME the output `portalFrontDoorDns` lists.

   The API now logs every write it refuses with 503 `licence-state-pending`, for the new alert; nothing else changes for an
   organization.
8. **Hosted record retention** (`docs/RealizerAdminConsoleRunbook.md` §14). Deploy the publisher DacPac — the `Tenants` columns
   `HostedPurgedOn`, `HostedPurgeReportedOn`, `HostedPurgeKind`, `RecordsDeletedOn`, `HostedPurgeRecordedBy` and
   `HubSpotCompanyCreated` (appended, NULLable; a company synced before is never archived, only released), the table
   `HostedRecordDeletions` and the admin event types `HostedOrganizationPurged`, `HostedRecordsDeleted`, `HostedRetentionHeld` —
   and the publisher before or with the stamps: the stamps report each organization they delete (`POST api/hosted/tenants/{id}/purged`)
   with their licence pass, and one that reaches an older publisher asks again later. The publisher's job is on by default
   (`HostedRetention__Enabled`; `false` stops it — say why on the record); HubSpot and Stripe are settled behind their own settings.
9. **Canada moves to its own host; `app.realizer.io` becomes the global entry** (multi-region design P0, RG-2 / RG-4; before
   production serves anyone). The Canadian stamp now answers at **`ca.app.realizer.io`** (API `api.ca.app.realizer.io`; portals,
   once deployed, `{slug}.ca.requests.realizer.io`) and stage at **`ca.stage-app.realizer.io`** (API `api.ca.stage-app.realizer.io`);
   `app.realizer.io` and `stage-app.realizer.io` are the **global entry app** (`src/AccessPoint.Web` with `WebHost__Role=Entry`,
   `deploy/hosted/entry.bicep`: a site on the stamp's own Linux plan behind the same route on the stamp's web endpoint — no
   new Front Door endpoint, no DNS change for the entry hosts): `/signup` shows the data region before the sign-up continues on
   the regional host, and `/` signs a person in once and opens their region (multi-region design §4.1 (c), built early, owner
   2026-11-09 — it replaces P0's edge redirect, which is not deployed on its own). The demo's trial link and every link that names
   where to sign in keep `app.realizer.io`. Stage first, then production, in the order `deploy/hosted/README.md` → *Releasing
   2.6.0* gives (the entry's own steps: *The global entry*): the publisher with its `HostedStamps__0__RegionKey`, `DisplayName`,
   `ApiOrigin` and `AppOrigin` (the regional host); the new redirect URIs on the hosted registrations (done 2026-11-09); the stamp
   deployment (`regionKey`, `entryOrigin`); the CNAME and `_dnsauth` records of the two new hosts (done 2026-11-09 for both
   environments); the entry deployment (into the stamp's resource group, on its plan) and the entry's federated credential on the
   registration — the hosted CD then releases `AccessPoint.Web.zip` to the entry after each ring's stamp; then the old API host's
   custom domain and, on stage, P0's rule set go (production never had one). The entry's `/signin-oidc` callbacks stay on the
   registrations (the entry needs no sign-out callback). Everyone signs in again once (sessions belong to their host).
   **`emailDataLocation` is now required** and the stamp
   template fails unless it is the geography of the stamp's `location` (both parameter files: `Canada`), so a later region can
   never keep its mail data in Canada by omission.
10. **The currencies** (hosted pricing design HP-75; `docs/hosted/Stripe_Setup.md` §2 *Currencies*). With *Hosted pricing P1*
    above, in the runbook's order: the publisher DacPac brings `HostedBillingAccounts.BillingCountry` and `Currency` (appended and
    NULLable) and the new table `PlanPrices`, seeded by `SeedPlanPrices.sql` with the GBP and EUR list prices the owner decided
    (HP-79). Either order is safe: a 2.6.0 stamp against the older control plane shows no billing-country picker and checks out in
    CAD as before, and a stamp still older sends no billing country — its Checkout charges in its region's currency, CAD on the
    Canadian stamp. **Stripe — done 2026-11-09:** `catalogue.py` gave every plan and add-on price (Essentials, Professional and the
    add-ons; the retired plan prices and the overage prices are archived — runbook S5 — and need none) its **USD** (the CAD numbers),
    **GBP** and **EUR** currency options, each with tax behaviour **exclusive**, in the sandbox and the live account; the price ids
    did not change, so no setting changes. Keep **Adaptive Pricing off** in both accounts (Settings → Payments). Add **USD, GBP and
    EUR** to HubSpot's currencies beside CAD before the first sync after the release (runbook L1.3): a hosted deal is now sent in its
    subscription's currency. Then run the setup's checklist item 11 on stage.
11. **Active now** (`docs/RealizerAdminConsoleRunbook.md` §15). Nothing to set: deploy the publisher DacPac (the new table
    `HostedStampSessionSamples`) and the publisher before the stamps take 2.6.0 (the runbook's order) — a 2.6.0 stamp's API then
    creates its session-count view at start (its log says *Stamp session counts: … holds SELECT on it and nothing else there*) and
    reports every five minutes. A stamp that reaches an older publisher logs one warning (HTTP 404) and tries again with each pass.

**The AccessPoint Training Lab (learn.realizer.io) — for Realizer as its operator.** The Lab's AI drafting moves to
**gpt-6.1-sol 2026-09-29** (Global Standard) for every provider (owner decision 2026-11-08). Its deployment `drafting` held
gpt-4.1-mini as a regional Standard deployment: delete it once, then deploy `deploy/classroom/classroom.bicep` with its parameter
file (`docs/TrainingLabRunbook.md`, *AI drafting*). The Classroom's model client now sends room for the model's reasoning and a
reasoning effort (`Classroom__Ai__ReasoningEffort`, `low` by default).

**Realizer (the publisher and its admin console) only — hosted reporting** (2026-11-06; `docs/RealizerAdminConsoleRunbook.md` §13):

1. **Stripe read key.** Create a Stripe **restricted key** with Invoices, Credit notes, Payouts and Balance — **Read** only, store it
   in Key Vault `kv-realizer-api` as `Stripe-ReportingKey` (stage `Stripe-Stage-ReportingKey`), reference it from the publisher's
   `Stripe__ReportingKey`, then set `StripeRevenue__Enabled` = `true` (default off). The live key is in Key Vault since 2026-11-09;
   its reference and the switch go on the production slot with the release (runbook L3; on stage optional, S5). Without the
   reporting key the import reads with the billing key, which then needs those four read scopes too.
2. **QuickBooks accounts for the Stripe journal.** Create (or pick) a *Hosted revenue* income account, a *GST/HST payable* liability, a
   *Stripe clearing* other current asset (CAD), a *Stripe fees* expense and the CAD bank account Stripe pays out to, and map them in
   **Accounting → Account map** (Hosted revenue, Sales tax payable, Stripe clearing, Stripe fees, Stripe bank). Have the accountant
   confirm the journal's tax treatment before the first posting.
3. **HubSpot: add CAD** — and, with the currencies (item 10 above), USD, GBP and EUR. A hosted deal is sent in its subscription's
   currency (`deal_currency_code`): add them to the HubSpot account's currencies before the next sync (runbook L1.3), or every
   hosted customer's sync fails visibly on the Worklist. The first sync after the update re-sends every customer once.
4. **Deploy order:** the publisher DacPac (three new tables; one CHECK widened), then the publisher, then the console — `realizer-cd`
   deploys the first two in each environment; approve *DeployAdminConsole* after *DeployProduction* (runbook L2).

**Deploy script: `-AiDeploymentSku` now keeps your AI deployment type** (bug review 2026-11-12 F-77). `Deploy-AccessPoint.ps1
-DeployAiAssist` used to pass `GlobalStandard` whenever `-AiDeploymentSku` was left out, which moved a Data zone standard
installation's AI deployments to Global (or failed the upgrade). It now reads the type your deployments have and keeps it; name
`-AiDeploymentSku` only to change it. Deployments of mixed types, a list it cannot read, an AI account with no deployments and
no recorded type, or the retired regional `Standard` type stop the script with a message asking you to name `-AiDeploymentSku`;
naming `-AiDeploymentSku` without `-DeployAiAssist` is refused. The template now records the type it used in the API's app
settings (`AzureOpenAI__DeploymentSku`, managed by the template).

**A public portal behind your own gateway or WAF: set the forwarded-header settings.** The portal shares each hour's intake codes
per client address; behind your own proxy every requester arrives from the proxy's address unless the portal's `ForwardedHeaders`
settings (`KnownProxies` / `KnownNetworks`, `ForwardLimit`) name it (`docs/features/NotificationSystem.md`). The default
deployment (Front Door) needs nothing.

### What's new

#### Hosted AccessPoint: creating organizations, colleagues and one trial per Microsoft organization

- **Create another organization, two kinds.** The organization menu and *Choose an organization* ask what to create: **a new
  organization with its own subscription** — your account's first organization starts with the 30-day trial, any other starts on the
  Free plan and opens at Settings → Subscription to choose a plan — or **a new workspace sharing this subscription**, shown as coming
  as an add-on with Practice. One account can have created at most 10 organizations that still exist.
- **One trial per Microsoft organization.** When someone signs up with a work account of a Microsoft organization that already uses
  AccessPoint, the sign-up page shows *People from your organization already use AccessPoint: {name}* with **Ask to join**; its
  administrators approve (an invitation) or decline in Settings → Users & roles → *Requests to join*. A separate workspace starts on
  the Free plan. **Colleagues can find this organization** (on by default) turns this off. The rule holds across regions: a workspace
  created in another region of AccessPoint starts on the Free plan too when its Microsoft organization already has a live one.

#### Hosted AccessPoint: the Free allowance belongs to your Microsoft organization (hosted pricing design HP-89)

- **One Free allowance per Microsoft organization, shared by its workspaces.** The Free plan's 5 requests and 5 assessments a year belong
  to your Microsoft organization (a personal Microsoft account has its own), not to one workspace: each Free workspace of the organization
  takes a request or an assessment from the shared allowance when it needs one. Nothing is lost when a workspace is abandoned or deleted —
  and deleting one never gives the year's allowance back.
- **What you see.** Settings → Subscription says *Shared by your organization's workspaces: {n} left this year, until {date}.* beside the
  requests and assessments; everyone's Free banner says the allowance is shared. A request that arrives when none is left is still recorded
  with its due date and waits, as before; an assessment that cannot reach the shared allowance for a moment says *try again in a few
  minutes*.

#### Hosted AccessPoint: Essentials, Professional and Enterprise (hosted pricing design P1)

- **Two plans to buy, one to talk to us about.** **Essentials** — CA$79 a month or CA$790 a year: 10 requests and 1 assessment a month,
  complaints and appeals, fees, privacy breaches and assessments, no audits. **Professional** — CA$249 a month or CA$2,490 a year: 40
  requests and 10 assessments or audits a month, every register and the privacy program. **Enterprise**, for organizations of 500
  employees or more, priced by the people they serve with unlimited volume in an annual contract: *Talk to us*. The FOI, Privacy and
  Complete plans are retired. Members are unlimited on every plan.
- **Annual billing: 15 months of allowance for the price of 10, all on day one** (150 requests and 15 assessments on Essentials, 600 and
  150 on Professional).
- **At the limit a received request is still recorded — and waits.** Past the period's requests a new request is recorded with its due
  date and its automatic acknowledgement; its case work waits for the next request from the allowance, which goes to the waiting request
  due first. Moving from the trial or Free to a plan unlocks every waiting request at once. An assessment cannot be started past the
  allowance; an update assessment never counts, a deleted Draft request gives its request back, and an imported request that was already
  closed is not counted. Nothing is billed as overage.
- **No size question:** *Choose a plan* asks nothing about the organization's size — the allowances do the work; below the plans,
  and beside **See plans** when an allowance is used up, *Need higher volume?* suggests Enterprise with **Talk to us** (HP-80).
- **Storage:** Free 2 GB, the trial 10 GB, every paid plan 100 GB — a staff upload past it is refused, what arrives with a received
  request is always stored, and nothing is deleted.
- **Warnings at 80 % and 100 %:** a banner for administrators (and one line for everyone at 100 %), the Subscription page's meters with the
  next arrival, the waiting requests and storage, and e-mails — *running low* following *E-mail notices*, *used up* always sent.
- **Read-only, never hidden:** a register outside the plan (audits, risks and the program on Essentials) stays readable where it holds
  records and leaves the tab bar where it holds none, and says so in the plan's own words (*Read-only on your plan…*, **Change plan**);
  on Essentials an assessment works end to end, and maintaining the inventory is Professional's — on Free and Essentials the privacy
  program's banner says vendors and systems are Professional features (HP-81). An add-on outside the plan is read-only on every plan,
  Free included (HP-82). A refusal that reaches you from the server says it in the same words — on a paid plan never "Free plan".

#### Hosted AccessPoint: discounts and promotion codes (hosted pricing design HP-90)

- **Promotion codes at checkout.** The payment page takes a promotion code Realizer or a partner gave you. A code that makes the plan
  free starts it without a card.
- **Partner sign-up links.** A link such as `app.realizer.io/signup?promo=ASSOC20` carries a partner's code to your organization's first
  checkout, where it is applied for you; *Choose a plan* says so beforehand — or that the code could not be applied, and the payment page
  still takes one.
- **Your discount on Settings → Subscription:** *Discount: 20 % off.*, *Discount: 100 % off until 1 March 2027.* or *Discount: 50 % off your
  next invoice.*
- **Add a payment method in time.** When your subscription has no payment method on file and its next payment is due within 30 days, an
  administrator reads *Add a payment method before {date}* with **Manage billing**.
- **Bundles at your discount.** A partner's percentage discount also applies to bundles: the dialog shows the discounted price and *Includes
  your discount: 20 % off the list price of CA$49.00.* A 100 % discount on your plan does not make bundles free.
- **For Realizer** (the admin console): *Apply a discount* / *Remove discount* on a hosted organization (an existing coupon, or a percent
  coupon made on the spot; Admin, a reason, audited), the discount and the MRR after it on the customer page, and Revenue → **By partner
  code** with its CSV.

#### Hosted AccessPoint: bundles and extra storage (hosted pricing design P3)

- **Add requests or assessments in one click.** When a paid plan's requests or assessments run low or out, an administrator adds a bundle
  — 10 requests for CA$49, 50 for CA$199, 5 assessments for CA$49, 25 for CA$199 (the same numbers in US dollars; euro and pound prices
  in Europe and the UK) — from the banner, the request page, the New assessment panel or Settings → Subscription → *Bundles and storage*.
  The dialog says what it charges and to which card (*We'll charge CA$49.00 plus tax to the card ending 4242.*); the units arrive within
  seconds, waiting requests are covered at once, earliest due first, and bundle units are kept 12 months, used after the month's
  allowance.
- **If the bank asks to confirm, or the card is declined,** the dialog opens Stripe's invoice page to finish there; requests keep waiting
  with their due dates until it is paid.
- **More AI Assist tokens:** an organization with the AI Assist add-on can add 1,000,000 tokens for CA$19, used after the month's
  allowance.
- **Extra storage:** *Add 100 GB* (CA$19 a month, or CA$190 a year on annual billing, prorated) from the storage banner or Settings →
  Subscription. The media add-on now brings its own 100 GB too.
- **Members see whom to ask** — *Ask an administrator to add more: Ada Lovelace, Grace Hopper.* — and an organization with only one
  administrator is reminded to add a second.
- **The step-down e-mail names the public portal only if you had one.**

#### Hosted AccessPoint: removing extra storage, promotion codes and the Subscription page (owner, 2026-11-10)

- **Remove 100 GB** beside *Add 100 GB*: the storage leaves at the end of the period you have paid for — nothing refunded, no file deleted —
  and **Keep 100 GB** keeps it until then without a charge. If your files would not fit in what is left, the page says how much to free
  first. If they grow past it before that day, the storage they need stays on your subscription (billed with your plan) and every
  administrator is e-mailed *Your extra storage stays for now*.
- **A promotion code on your subscription.** Settings → Subscription → *Promotion code*: type a code Realizer or a partner sent you and
  choose **Apply** — it takes effect from your next invoice. One discount at a time: a code replaces the current one after you confirm.
- **Change plan on a paid subscription** changes the plan and the billing interval only; it no longer shows add-ons to tick (Stripe's billing
  page dropped them) and takes you to **Add a module** or **Your add-ons** instead.
- **The Subscription page's order:** your plan, *Add a module*, *Your add-ons*, *Bundles and storage*, *Promotion code*, the usage, and
  *Download all of your organization's data* last.
- **Settings opens with Subscription.** Settings → **Subscription** (your plan, its status, the meters and bundles) is now the first row
  of the Settings panel, above *Jurisdiction packs*, so an administrator finds billing first; the search and the arrow keys follow the
  new order. An AccessPoint you deploy yourself has no Subscription row and is unchanged.
- **Learn more** links to Realizer's website for each add-on, each kind of bundle, promotion codes, the plans and where AI processing
  happens — in French for a French interface — opened in a new tab.

#### Hosted AccessPoint: the drip and bank (hosted pricing design P2)

- **Monthly allowance is kept for 12 months.** Each paid month's requests and assessments arrive when the month is paid and stay for 12
  months, the oldest used first: a quiet month banks its allowance for a busy one. Annual billing still brings the year's allowance on day
  one, until the year ends. A month that is not paid brings nothing new until it is.
- **Upgrades take effect at once:** moving to a bigger plan charges the prorated difference now and brings the matching share of the
  bigger allowance now; moving down takes effect at the end of the period. When a paid plan ends (the move to Free), its unused allowance
  ends with it.
- **The trial and Free use the same rule:** the trial's 3 assessments at the start and 10 requests for each 30 days, Free's 5 and 5 at the
  start of each Free year.
- **Settings → Subscription says what comes and what goes:** under each meter, *The next 10 arrive on 1 December.* and *7 of what is left
  expire on 10 February 2027.* A request waiting for a unit is covered within minutes of one arriving, the earliest due first.
- **Realizer can add requests or assessments at once** — for example while a card is being replaced.
- **The trial no longer includes the public portal** (HP-85): it needs a paid plan and the Public portal add-on; every other add-on stays in
  the trial. **A read-only portal pauses online requests** (HP-84): on Free, or on a plan without the add-on, the portal says online
  requests are paused with your contact details, while requests already received stay in AccessPoint and releases already delivered stay
  downloadable until they expire; the add-on reopens it within minutes. Settings → Public portal says which applies.

#### Read-only licences and the hosted Free plan (hosted onboarding)

- **Hosted AccessPoint: the trial ends on the Free plan, never a lock-out.** At day 30 — or when a cancelled paid plan ends — a
  hosted organization moves to the **Free plan**: everything stays readable and exportable, every received request is still
  recorded and 5 requests and 5 assessments a year are worked in full (past that a request is *recorded* — closable and
  withdrawable, its case work waiting for a plan — and a 6th assessment cannot be started), the other registers are read-only, media
  and AccessPoint Learning only read (what the trial made with them stays readable — HP-82; the public portal, never part of the trial
  since HP-85, only for an organization that held one, with its online intake paused — HP-84; none can be bought on
  Free), members are unlimited and Lab mode stays on. An administrator can **Extend 30 days for procurement** once,
  from day 20 of the trial until 30 days after the move to Free. Settings → Subscription shows each state — the trial; the trial after its
  extension (*Your trial ends on {date}. This was your one extension.*); Free (what you have and what a plan adds, *{n} of 5
  requests worked this year*); Free past the cap (the requests waiting for a plan); active; ending (the plan ends with the period,
  then the organization moves to Free); and past due or unpaid — and **Change plan** names the read-only registers each plan makes editable again. A read-only
  register keeps its tab with a slim banner, its New and change actions disabled with the reason; a request past the cap says
  *Recorded. The Free plan includes 5 requests a year; choose a plan to work on this one.* The trial banner turns to a warning in
  its last ten days and offers **Extend 30 days** (administrators, once per organization).
- **Hosted AccessPoint: e-mails that say what is happening to the subscription** (O3). Administrators get fixed, short e-mails in
  their own language: the trial ends in 7 days, in 3 days and today; the trial was extended; the organization is now on the Free
  plan (always sent); the Free plan's 5 requests this year are used. *E-mail notices* (Settings → Organization → E-mail) governs
  all but the step-down. After a real success — a first letter sent, a redaction applied, a package released, a second member
  joining, the 4th and 5th Free request — an administrator may see one small, dismissible suggestion a day under the page title,
  never in Lab mode and never over a dialog.
- **Hosted AccessPoint: an unused Free organization is deleted only after warnings, and you can download everything first** (O4).
  Nobody signing in and no new case for 12 months (90 days for an organization never really used) leads to e-mails 30 and 7 days
  before the deletion (90 days first while a received request is open); any member's sign-in cancels it, and a preservation hold
  stops it. Settings → Subscription now offers **Download all of your organization's data**: one ZIP of every case, document,
  setting and the audit trail, downloadable once within 14 days.
- **Read-only registers open in the Reader view** (O1 follow-up): a case of a register your plan makes read-only opens without its
  editing controls, under the one-line read-only notice. In the privacy program hub, **New** is disabled with the reason when assessments are
  read-only too, or the licence has lapsed; on the Free plan **New subject** (which follows the assessments rule) and **New
  vendor** (the vendor register stays writable) stay available.
- **A lapsed subscription is read-only, not a stop (both editions).** A **Microsoft 365 deployment** whose subscription has
  expired beyond its grace period, or that Realizer revoked, now becomes **read-only, indefinitely** instead of stopping: reads,
  search, reports, exports and Lab mode keep working, every other change is refused (`403 licence-read-only`), and sending, the
  portal's intake, connectors and AI pause until it is renewed. Everyone sees *AccessPoint is read-only: your subscription expired
  on {date}…* (or Realizer's revocation); administrators get **Renew the subscription** and **Check again** (a live licence check,
  at most once a minute), and everyone else the names of the Administrators to ask. The public portal says the organization is not
  accepting online requests right now, with its contact details. With no subscription at all, the page now explains how to finish
  setting up (Microsoft Marketplace, Finish Setup, Retry) instead of a sales page.

#### Hosted AccessPoint

- **Hosted AccessPoint: you decide whether AI may be processed outside Canada.** Settings → Features & AI → AI Assist shows
  **AI processing outside Canada**: the disclosure, its version and date, and who allowed it and when. An Administrator ticks that
  they have read it and selects **Allow AI processing outside Canada**; **Withdraw consent** stops it again for everyone. Until it
  is allowed, the AI switches read *Off — your Administrator has not allowed AI processing outside Canada* and the Ask AccessPoint
  toolbar button explains why. Lab mode follows the organization's choice.
- **Hosted AccessPoint: signing out, your organization's way.** Settings → Users & access → **Members** → *Signing out* sets how long members
  may be inactive (15, 30, 60, 120 or 240 minutes) and the longest a session may last (1 to 24 hours) — only the choices the
  service allows, with *Use the service default (…)* naming its own. Two minutes before an inactivity sign-out a dialog counts
  down — *You'll be signed out in 1:59 because you've been inactive* — with **Stay signed in** and **Sign out**; five minutes
  before the session's end it says *For security, you'll need to sign in again in 4:59. Save your work now.* Working in any tab
  keeps every tab signed in and closes the warning everywhere. Afterwards the dialog — and the sign-in page after a reload — says
  why (*You were signed out after 30 minutes of inactivity.*), and **Sign in again** comes back to the same page. An organization
  can only shorten the service's limits, never lengthen them. A deployed AccessPoint is unchanged: its sign-in is Microsoft 365's.
- **Hosted AccessPoint polish.** Settings follow the service, by ONE rule that decides each row and part — no Setup, no
  Repository connectors, and the Public portal, Payment providers, Document conversion, AI suggestions and Jurisdiction playbook
  only where the service runs what they configure, with the Microsoft 365 parts of the other panels left out (a deployed
  AccessPoint shows exactly what it showed); **Settings → Organization → E-mail**, where a hosted organization sets its own e-mail
  (notices on or off, and where replies go), and notice contacts and the automatic acknowledgement work without a sender mailbox;
  **Subscription** sells only the add-ons the service can deliver, meters only what it runs and names the annual saving; the
  trial banner says when the trial ends, with **Choose a plan**; one header (the wordmark, the organization and the account menu
  in the app's own title row); a branded sign-in page whose footer offers the free trial, privacy, terms, pricing and help; a
  real *Page not found*; the signed-out page in the visitor's language; a grouped, faster jurisdiction list on *Create
  organization*, whose name is asked only once; *Members* and *organization* throughout. The organization's name given at
  creation fills Settings → Organization's name and the `{InstitutionName}` field. A deployed AccessPoint is unchanged.
- **Hosted AccessPoint: Add a module.** On an active paid subscription, Settings → Subscription lists the add-ons the
  organization does not have yet — AI Assist, Public portal, Media, AccessPoint Learning — at the subscription's own price; **Add**
  adds one to the subscription, the rest of the current period prorated on the next invoice, and the module works as
  soon as Stripe confirms it. User Guide → *Subscription and members (hosted AccessPoint)*.
- **Hosted AccessPoint: Remove a module.** *Your add-ons* lists the add-ons you pay for; **Remove** ends one at the end of
  the period you have paid for — nothing is refunded, nothing is deleted, and the module works until that day, shown as
  *{module} — leaves on {day}* with **Keep** to change your mind without a charge.
- **Hosted AccessPoint: one address to sign up and sign in** (multi-region design §4.1 (c)). `app.realizer.io/signup` first shows
  **where the organization's data will be kept** — what is stored and processed in the region, where Realizer keeps the account
  data, and how AI is processed there — in the visitor's language, the region suggested by the visit's jurisdiction; today Canada,
  with one button, **Continue in Canada**, after which the sign-up continues at `ca.app.realizer.io`, where **Create organization**
  shows *Data region: Canada* with **Choose another region**. `app.realizer.io` signs a person in once and opens their region; a
  person in several regions chooses, and a region that cannot be reached is named with its address. The browser remembers the last
  region (`?choose=1` brings the choice back); older links (`/invite/…`) still arrive. The admin console shows each hosted
  organization's data region.
- **Hosted sign-up from the demo.** `app.realizer.io/signup` is the demo's trial link: the sign-in page says **Start your free
  trial** in the demo's language, **Create organization** opens with the demo's pack and language chosen (the pack notice is still
  yours to tick), the welcome offers **Continue where you left off** at the demo's example, and the admin console shows where a
  customer came from.
- **Hosted AccessPoint: reports that apply.** Every report was checked against the hosted service, and one rule decides them: the
  Reports menu, pinned tiles and links follow what the service runs: *Intake quality* needs the public portal and *AI governance*
  needs AI Assist (each with the plan that includes it); a tile pinned before reads *Not available in this edition.* and a link
  says the report is not available. *Departed members* has no directory column, *Storage* shows sizes, tiers and what the policies
  would move without a cost (the hosted service is priced by plan), and Document access, Report Studio's sharing and the built-in
  statistical summary say *organization* and *members*. Archiving is not offered until it is priced: Settings → Storage and
  archiving is not listed (a policy switched on before keeps it, to switch the policy off) and the Storage report leaves out what
  the policies would save.
- **Hosted AccessPoint: Office, e-mail and web pages convert to PDF; recordings and accessibility checks too** (once Realizer
  deploys its service with them). Word, Excel and PowerPoint files, e-mails and saved web pages preview as PDFs and join
  releases; video and audio records are prepared for playback, redaction and release; every response package gets its
  PDF/UA-1 accessibility check; and every upload is scanned for malware, with *Scanning for malware…* on a file until its
  verdict arrives. Settings → Document conversion and the release accessibility parts appear as soon as the service runs them.
- **Hosted AccessPoint is sold in four currencies** (hosted pricing design HP-75). *Choose a plan* asks the organization's **billing
  country** — pre-filled with the service's own country, Canada on `ca.app.realizer.io` — and shows every plan and add-on in its currency:
  **CAD** for Canada, **USD** for the United States (the same numbers), **GBP** for the United Kingdom, Jersey, Guernsey, the Isle of Man and
  Gibraltar, **EUR** for the euro area, the microstates that use the euro and the places with their own code that use it (Åland and
  the French overseas departments and collectivities), and USD everywhere else. Checkout charges in that currency,
  whatever country the browser is in. Once the organization subscribes, its country and currency are fixed and shown as such; paying in
  another currency later is a new subscription at renewal, arranged with Realizer. Realizer's reports show each organization's revenue in
  its own currency and add them up in CAD at the Bank of Canada's monthly averages.

#### The guided welcome and first-time help

- **The guided welcome (both editions).** Once per person, on a plain landing on My Day, to newcomers only (first sign-in on or
  after the organization's start of the welcome, within 30 days — never people already there when it arrived, never over a link
  to a case, a notice or a Teams activity):
  - **Hosted owner:** *Welcome to AccessPoint, {name}.* · *Your 30-day trial includes every register and add-on except the public portal. No card needed.* — and, while the
    organization's first setup runs, its steps in the welcome (the banner stays quiet). The setup no longer reloads the page over
    the welcome or an invitation being typed: it says *Ready — refresh to see your configuration*, and refreshes once that closes.
  - **Microsoft 365 first Administrator:** *You are its first Administrator.*, the trial line only on a Marketplace trial, and
    **What's left to set up** — My Day's *Finish setting up* list (done rows ticked) plus the Microsoft 365 permissions and the
    Teams app.
  - **Later members:** a short welcome with Lab mode and their role's first step (log a request, start an assessment, open your
    reviews, find a case); hosted, who invited them.
  - **Custodians, contributors and respondents:** no dialog — a *Here's your task* card on the assignment, task or survey, with
    the Get started steps, **Show me** and **Got it**.
  - **The starts:** **Try it on example cases** (Lab mode at the training cases for your role, without a second introduction),
    **Log your first real request** (New request, or New assessment), **Invite your team** (hosted: Settings → Members → Invite
    people; Microsoft 365: a SharePoint / Teams sharing guide). Get started then opens the matching topic with its next step.
  - **Help → Show the welcome again** shows it on demand.
- **Guide me on three more first-time screens.** A contributor's first task, an advisor's first case and a senior
  official's first letter waiting for sign-off now offer a *Guide me* tour of that screen — the task's instructions,
  each repository's outcome, the records and submitting; what an advisor can read, the records shared and the case's
  discussion; the letter, **Approve** and **Request changes** — beside the first-time learning paths they already named.
  User Guide → *Tips on first-time screens*.
- **The advisor's note on every case.** The first-time note for advisors — its tour and its learning paths — now shows on an
  assessment, incident or complaint the person advises, as it did on a request.

#### AccessPoint Learning

- **The names: AccessPoint Learning and Lab mode.** The learning product is now called **AccessPoint Learning** — the
  Studio, modules, learning paths with audience rules, checks, certificates, completion records and the *How we decide*
  coach — in SharePoint, Teams and the hosted app, Billing included (the add-on is *AccessPoint Learning*). **Train mode**,
  practicing on fictional training cases in your own AccessPoint, is now **Lab mode**, and its fictional records are the
  **Lab library**, in all eleven languages; the AccessPoint Training Lab, the online simulation for classes, keeps its name.
  Learn in AccessPoint Learning, practice in the Lab. When you record training done elsewhere, a Training Lab certificate is
  recognized at the Lab's address, `https://learn.realizer.io/verify/…` (only there: a link to one of the Lab's earlier
  addresses is read like any other provider's link). The help pages of the renamed screens have new addresses on realizer.io —
  *Lab mode*, *Learning paths*, the Studio, *Our practice*, audience rules and completion records — and the old addresses
  redirect to them. The Universal baseline (2.68) brings the new names into the notices. Nothing else changes: permissions,
  reports, exports and the API keep working as before.
- **One vocabulary for training: learning paths and exercises.** What 2.5.0 called a *training path* and AccessPoint Learning a
  *curriculum* is now a **learning path** everywhere — the Training Lab's word, in all eleven languages: *Learning paths
  and progress*, the Studio's *Learning paths* tab, *Your learning paths* in My learning, the certificate (*has completed the
  learning path*), Training coverage and the two Report Builder subjects, the notices and the pack's item names (the
  Universal baseline 2.67). AccessPoint Learning's *Practice* step is now an **Exercise** step — a task worked on a training case,
  as in the Training Lab; team exercises keep their name. Nothing else changes: links, reports, exports and the API keep
  working as before.
- **How we decide.** Beside twelve decisions — a request's scope, an extension, an exemption, a fee, a consultation or
  third-party notice, the response and its outcome, the assessment screener, risk rating, the validation decision, a
  breach notification, a complaint finding and signing off a letter — a closed panel opens on request with *The rule*
  (the description of the option chosen, or a jurisdiction pack's plain-language note, with its legal reference) and
  *Our practice* (your organization's notes for that decision and kind of case). It loads nothing until it is opened,
  offers *Ask AccessPoint about this* when AI Assist is on — answers that draw on that same guidance as well as on the
  case — and works in Lab mode. A person can hide it at one
  decision (*Hide coaching here*) and bring it back with *Show Get started tips again*; an administrator can switch it
  off for everyone. User Guide → *How we decide*.
- **Our practice: coach notes.** The Studio's *Coach* tab (also reached from Settings → Training → AccessPoint Learning): write your organization's guidance for
  each coach point, narrowed by request, assessment, incident or complaint type, legal authority and the point's own
  options (an extension reason, an exemption, an outcome…); your organization's languages side by side, with the ones
  not yet written marked; a block editor for paragraphs, headings, lists and links, reordered with *Move up* and *Move
  down*; a preview; switch on and off; reorder; delete once switched off. User Guide → *Our practice: coach notes*.
- **Learn more in How we decide.** A coach note can now link to the modules that teach its decision (*Linked modules* in the note's
  editor, up to five), and *How we decide* lists them under **Learn more**: open one in the module player, see how long it takes and
  whether you have done it. The Universal baseline's notes on a request's scope, closing a request, the assessment screener, rating a
  risk and notifying a breach link to its new modules.
- **Learning paths: notes, links and a role brief.** A path can now hold up to twelve items (from ten), including notes
  of your own (ticked when read) and links to `https://` pages (ticked when opened), and a role brief shown above the
  items. User Guide → *Learning paths and progress*.
- **Coach notes in the jurisdiction packs.** The Universal baseline 2.63 ships six notes in all eleven languages — a
  request's scope, closing a request, the assessment screener, risk rating, breach notification and the complaint
  finding. The Canada federal pack 1.44 ships eighteen in English and French — its six extension reasons, six
  exemptions and the Cabinet confidences exclusion, the fee rule of each Act and its three consultation types — each
  linking to its section on the Justice Laws website.
- **The Studio** (Training hub → *Learning content*; AccessPoint Learning module). Write your organization's own **modules** — up to
  twenty steps each, from a template (*Role primer*, *Decision lesson*, *Policy acknowledgment*, *Annual refresher*) or
  blank. Ten step kinds: Read (a page written in the new page editor — headings, lists, callouts, tables, images and links
  to files), Look, File, Link, Guide me, Practice (a training case), Do (a real first task), Acknowledge, Talk to (a mentor)
  and Reflect (a private note). Autosave with a clear refusal when someone else saved first; *Check* with each finding on
  its step, field and language (alternative text, link words, `https:`, files still scanning or converting, partial
  translations); *Preview as learner* in any language; *Publish* with a change note and *material change*; immutable
  versions; *Retire*. User Guide → *The Studio: writing modules*.
- **Images and files for modules,** uploaded in the Studio, malware-scanned, with publishing waiting for the scan; web
  pages and SVG images accepted and shown only as PDF and PNG — a page rendered offline (the images and styles it links to
  are not fetched), an SVG drawn on white, as the Studio says when one is uploaded. A module's copy brings its images and
  files.
- **Translations.** Write each of your organization's languages yourself, or translate the missing and outdated ones
  with AI Assist; machine translation changes only the words — an image's alternative text and caption included — and
  never a text a person wrote: in a language a person wrote it fills only the texts not written yet, marked as machine
  translations. A partly written language stops publishing; a missing one only warns.
- **Publish review.** Optionally, a second person who manages training approves each module before learners see it —
  never the person who sent it.
- **Pack modules and Our practice.** Jurisdiction packs can now ship modules and learning paths (the Universal baseline 2.64:
  *How we handle a request: the basics*); add your organization's practice around a pack module's steps — your own steps
  before or after them and notes inside a Read step — kept through pack updates, live on save. User Guide → *Pack modules
  and Our practice*.
- **Learning paths.** A learning path can hold modules and gains a due-after, how long a completion stays valid, how it
  counts as done (every required item, or a number of them) and a mentor (the learner's manager, a named person or the
  learning path's owner); only people who manage training change them. User Guide → *Learning paths*.
- **Audience rules.** Enrol people automatically by role, Microsoft 365 group (nested groups count), kind of work, the
  first time someone is a custodian, contributor, reviewer, advisor or senior official (offered at once on that screen),
  everyone or a named person — from today, or including the people already there. A daily sweep (hourly for first times)
  adds and withdraws; a lead's withdrawal holds, and *Not enrolled automatically* lists who, with *Allow again*. User Guide
  → *Audience rules*.
- **Suggested audiences.** A jurisdiction pack's learning path can suggest who it is for — a role, a kind of work or everyone. The Studio
  lists the suggestions above a learning path's audience rules; **Switch on** adds one as an ordinary rule, starting today — nothing is
  enrolled until a training lead does. The Universal baseline (2.70) suggests an audience for each of its learning paths, the Canada federal
  pack (1.48) the people who coordinate requests for both of its. User Guide → *Audience rules*.
- **My learning and the module player.** Everyone's learning paths with due and *Valid until* dates, each module at the
  version they were given (*Start*, *Continue*, *Review*), earlier cycles, *Browse* for the modules your organization opens
  to everyone (each module's *Open to Browse* switch in the Studio — off for your own modules until an author opens one),
  and — for mentors — *Waiting for you*, the conversations to confirm (a learner may also mark a Talk to step done
  themselves). The player resumes where you left off,
  never moves on by itself, ticks the steps AccessPoint checks (a training case finished in Lab mode, a real task done)
  by itself, and opens a Practice step's training case in Lab mode. People who hold no role open AccessPoint straight
  on My learning. User Guide → *My learning and the module player*.
- **A module done once counts everywhere.** A module someone already finished in one learning path — still valid, at the same version —
  counts in every other learning path that lists it and is not asked again; My learning and the player say where it counts from, and the
  completion record names it. A renewal still asks its checks, decisions and acknowledgements again. If the completion a module came
  from is revoked, every completion record that counted it is marked *Review needed* for the training lead to decide on — nothing is
  revoked or removed by itself, and each mark is in the audit history. User Guide → *My learning and the module player*.
- **Completion records, reminders and the CSV.** A record when a learning path is completed — versions, days, validity,
  acknowledgements, how each step was known to be done, who assigned it — and a new one for each renewal or review; Team
  progress shows overdue, expires and certified; **Export completion records** downloads a CSV with fixed columns
  learning-management systems import; notices on assignment, three days before the due date and once when overdue, and a
  weekly digest for leads. User Guide → *Completion records, reminders and Team progress*, and — for works councils and
  monitoring policies — *AccessPoint Learning and employee monitoring*.
- **Checks and decisions.** Two new kinds of step (AccessPoint Learning module). A **Check** asks one to ten questions — one right
  answer, several, true or false, or putting things in order by number (never by dragging) — with your feedback on each
  option, a pass mark (80% by default), optional limits on attempts and no timer; AccessPoint grades it and shows the
  right answers after each try, and a passed check counts the step done. A **Decide** step gives a short fictional case;
  the learner records a decision — a choice, their reasons, or both — and only then sees your model answer beside it.
  The *Decision lesson*, *Policy acknowledgment* and *Annual refresher* templates now fill in their checks and decisions.
  **Who sees check results** (Settings → Training → AccessPoint Learning) shows leads nothing, passed or not yet passed, or scores and
  attempts too, in Team progress and the CSV files. User Guide → *Checks and decisions*.
- **Model answers for exercises, and private packs' exercises in modules.** An Exercise step can carry a **model answer** —
  what a good case looks like, step by step — that the learner sees once their training case is finished, beside **Open my
  training case in Lab mode**, whose timeline is their own step-by-step account. It is translated with the module's other texts.
  An Exercise step may also name a **private pack's** exercise (marked *Lab only* in the Studio): learners see only its title
  and *Open in Lab mode* in their real work. Every Exercise step now names its scenario by its title. User Guide → *The Studio: writing modules*
  (*Exercise steps*) and *My learning and the module player*.
- **Certificates.** A learning path with *Offer a certificate on completion* now gives one: in **My learning → Your
  certificates**, a person who completed it with every required check, practice case and task verified by AccessPoint
  confirms the name to print (once, filled in from the directory) and downloads a PDF — learning path, versions, day, *Valid
  until*, your organization's name or letterhead, and a verification code. **Verify a certificate** (My learning, or the
  address the certificate prints) lets anyone in your organization check a code: valid, expired, revoked on a day, or no
  longer held once the record's retention has ended. A training lead revokes a certificate from Team progress, with a
  reason; the person is told. Team progress's *Certified* column now lights up. User Guide → *Certificates and
  verification*.
- **Recertification.** A learning path with a validity now renews its completions: 30 days before a person's completion
  expires they are enrolled again (the *recertify* notice), due on its last valid day; the day after, an unrenewed
  completion shows *Expired*. In the renewal, checks, decisions and acknowledgements are asked again while what the person
  read carries over on modules that did not change. It works from the completion record, so it also reaches people whose
  enrolment was removed from the progress table — and so does the review after a material change. My learning names the
  renewal and its date; Team progress marks the row *recertifying*. User Guide → *Recertification*.
- **Training coverage.** A new report under Reports → *Training and preparedness*: the learning paths of AccessPoint Learning as of today —
  enrolled, completed, in progress, overdue, expired and recertifying — by learning path and by the audience that enrolled
  each person, and one row per person for the people you assigned, with check results as far as your setting allows. It
  pins to My Day, and the Report Builder has it as the *Training coverage* subject (no person in it). AccessPoint Learning module.
  User Guide → *Training reports*.
- **Content quality.** The Studio has a Quality tab: for each module version, how many learners completed it, the share
  who got each question right at the first and at the latest attempt, which options they chose, and which options a
  decision's learners chose — only for five or more learners, never naming anyone — with a learning path and a period filter.
  It lists the dead links a new weekly link check found in your modules (their current version, the draft and your
  additions to pack modules) and the languages that are missing or outdated. AccessPoint Learning module. User Guide → *Content quality
  and the link check*. **Check now** checks a module's links at once after you fix one (at most once every ten minutes per module).
- **A glossary and obligations.** The Studio's Glossary tab holds terms a page can explain: mark the words with the page
  editor's *Glossary term* button, and a learner sees the term's definition when they move to or tap the words. The
  Obligations tab lists the training obligations your learning paths cover — a jurisdiction pack's syllabus items and your own —
  which modules and learning paths name by code; Report Studio's new *Obligation coverage* subject shows which obligations your
  learning paths cover and how many people are certified for each. Jurisdiction packs can now ship glossary terms and
  obligations (two new item types). AccessPoint Learning module. User Guide → *Glossary and obligations*.
- **Training done elsewhere.** A learning path can include a course taken outside AccessPoint Learning — in the AccessPoint Training
  Lab, at a public-service school, in a workshop — met when a training lead records the completion from Team progress
  (*Training done elsewhere*); for a Training Lab certificate the lead opens its link, checks the name and course, and ticks
  *I checked this certificate*. AccessPoint Learning module. User Guide → *Training done elsewhere*.
- **The AccessPoint Learning module.** Authoring, audience rules and your blocks on pack modules need the new `academy` module; it is
  on every marketplace plan, and on hosted AccessPoint it is the *AccessPoint Learning add-on* (the hosted trial includes it, as it does every add-on but the public portal). Learning,
  pack learning paths, records, reminders and the CSV are part of the core product.
- **AccessPoint Learning: the owner's decisions after checks, certificates and recertification.** A training lead can grant a person
  more attempts on a check they used up without passing (*More attempts* in Team progress, with a reason); download a
  person's certificate for an audit or a personnel file — each grant and download in the audit history; and a
  re-assignment after a completion expired now asks the checks, decisions and acknowledgements again, like an automatic
  renewal, and tells the person with the *recertify* notice. *Training coverage* shows revoked completions
  in their own column, apart from expired ones (also in the Report Builder subject). Someone who manages training can
  switch a module's *Open to Browse*; editing one text of a machine translation keeps the *Machine translation* mark on
  the texts you did not touch; a pack's glossary terms and obligations can be switched off one by one; a module naming an
  obligation code your list lacks gets a publish warning; an Administrator can record training done elsewhere for anyone
  from Team progress, and the completion records note the items met that way. Certificate verification works without
  the AccessPoint Learning module. User Guide → AccessPoint Learning sections.

#### Realizer's learning content

- **Realizer's first learning paths.** The Universal baseline (2.69) ships five learning paths for every jurisdiction, in all eleven
  languages: *Searching for records* (for custodians), *Signing a response* (for senior officials), *PIA practice* (how a privacy
  impact assessment works in AccessPoint), *Responding to a breach* and *Your access and privacy duties* (for everyone, renewed every
  12 months). Their six modules mix short pages, checks, decisions on fictional cases with a suggested answer, exercises in Lab mode
  with a model answer, a step done in real work and an acknowledgement; nine glossary terms and five training obligations come with
  them, and three of the paths offer a certificate.
- **The access analyst path.** Universal learning (1.3) adds *Access analyst*, in all eleven languages and for every jurisdiction: the
  basics of a request, then twelve modules on the method — the right of access, scope and clarification, the search, reviewing records,
  exemptions and discretion, severance, third parties, time limits, fees, the response and complaints — with a capstone, decisions on
  fictional cases, checks, product tours and four exercises in Lab mode on the fictional Town of Harbourview's requests, each with a
  model answer. The exercises start on your organization's default request type, so *Practice a request* in Get started can now be done
  in every jurisdiction. A certificate is valid for 24 months.
- **The PIA course begins: *PIA practitioner*.** The Universal baseline (2.72) ships the first learning path of the PIA course — how to
  approach, do and manage a privacy impact assessment — for privacy analysts, in all eleven languages and for every jurisdiction:
  *PIA practice* as its first module, then *Does it need a PIA?*, *Scope, plan and team*, *Describe it: inventory and flows* and *Test
  it: authority, necessity, principles*, with pages, product tours, decisions on fictional cases with a suggested answer, checks and an
  exercise in Lab mode on a fictional meals-at-home program, *Describing a program's information flows*, whose steps tick themselves
  when AccessPoint sees the personal-information section complete, the data flows drawn and every flow to an outside party labelled. It
  is due 60 days after enrolment, offers a certificate valid for 24 months, suggests the privacy officers and the people who
  coordinate assessments, and brings twenty-one glossary terms of PIA practice; *How we decide* beside the screener offers *Does it need
  a PIA?* under **Learn more**. Since 2.73 the path continues with *Find and rate the risks*, *Treat the risks*, *Consult*, *Report and
  sign-off* and *Keep it current*, and two more exercises: *Treating a risk* (a housing authority's contractors who see too much) and
  *Keeping a PIA current*, which starts from an approved PIA and asks for its update after a vendor's new AI feature. Since 2.74 it ends
  with its capstone, a PIA carried end to end in Lab mode with a model answer.
- **The PIA course for project leads and senior officials.** The Universal baseline (2.74) adds *Your project's PIA* — for project leads:
  why and when a PIA starts, what the privacy office needs from you (with an exercise on answering a section it delegates to you) and the
  measures and changes you own, due 14 days after enrolment — and *Signing off a PIA* — for senior officials: what an approval accepts and
  how to read a PIA and record a decision with conditions, due in 7 days and renewed every 24 months. Each suggests a **just-in-time**
  audience: the first time a section of an assessment is delegated to someone, and the first time someone is named an assessment's senior
  official. A first-time audience rule can now name an **assessment section delegate**, and the delegated section offers the learning path to
  its assignee at once. *How we decide* adds guidance beside the decision on an assessment.
- **The PIA course for program leads.** Universal learning (1.2) adds *Running a PIA program*, in all eleven languages: nine modules on
  the PIA policy and decision rights, intake and triage, the inventory, templates and quality review, tracking measures to closure,
  keeping the portfolio current, metrics for leadership, publishing summaries, and training and assurance, with decisions on fictional
  cases, checks, product tours and three exercises in Lab mode — a program nobody recorded, an approved PIA whose measures slipped and a
  privacy compliance audit — each with a model answer. It is due 90 days after enrolment, offers the *PIA program lead* certificate,
  valid for 24 months, and suggests the people who run the privacy program and the privacy officers.
- **Canada federal's ATIP learning paths.** The Canada federal pack (1.46) ships *ATIP analyst (federal)* and *ATIP coordinator (federal)*, in
  English and French, on the Treasury Board's training syllabus (Appendix B of the directives on access to information requests and on personal
  information requests): eleven modules with checks, decisions on fictional cases, an exercise in Lab mode on a third-party consultation and an
  extension, steps done in real work and links to the Acts, the Treasury Board's guidance, the commissioners and the Canada School of Public
  Service's courses; twenty federal glossary terms; the syllabus's 33 items as training obligations for the *Obligation coverage* report; and a
  certificate on each path, valid for 24 months. *How we decide* offers the matching module under **Learn more** beside each federal coach note.
  Since 1.48 the *ATIP coordinator* path holds the analyst path's eight modules with its own four and the baseline's *Before you sign a
  response* — one enrolment, one certificate covering both syllabuses. A learning path can hold up to twenty items (it was twelve).
- **The PIA course in Ontario.** The Ontario provincial (1.34) and municipal (1.37) packs ship *PIA practitioner (Ontario)*, in English and
  French: the universal path's ten modules, then the written PIA FIPPA s. 38 and MFIPPA s. 28 require and the IPC's four steps on the
  Ontario template, the update before a significant change, and a capstone in Lab mode on the Town of Harbourview's online recreation
  registration; a certificate valid for 24 months, nine Ontario terms, the eight PIA duties as training obligations and Ontario guidance
  in *How we decide*. Both packs carry the same add-on: the first applied keeps it, nothing is duplicated.
- **The PIA course for federal institutions.** The Canada federal pack (1.50) adds *PIA practitioner (federal)*, in English and French: the
  universal path's ten modules, then the Treasury Board's privacy checklist (with what a multi-institutional PIA needs before it starts),
  the Standard on Privacy Impact Assessment (its template, the two approvals, every completed PIA to TBS and the Office of the Privacy
  Commissioner and the answer to their recommendations, the published summary and the yearly review) and a capstone in Lab mode on the
  federal template; a certificate valid for 24 months, six more glossary terms, eleven duties of the Standard as training obligations and
  federal guidance in *How we decide* beside a PIA's checklist, risk rating and approval.
- **Signing off a PIA, for federal institutions.** The Canada federal pack (1.51) adds *Signing off a PIA (federal)*, in English and French,
  for the official responsible for section 10 and the senior officials who approve PIAs: the universal *Signing off a PIA* modules, then
  the two approvals the Standard on Privacy Impact Assessment asks of you (the privacy checklist and the PIA) and an exercise in Lab mode
  where you are the case's senior official — a complete PIA on the federal template arrives for your decision, and recording it on the
  Validation tab ticks the step. A certificate is valid for 24 months. In Lab mode, a practice case can now make you its senior official:
  it is for people who can act as senior official, and the training gallery marks it for them.
- **The PIA course under the GDPR.** The EU GDPR pack (1.25) adds *DPIA practitioner (GDPR)*, in English: the universal path's ten
  modules, then when Article 35 requires a DPIA (the three cases, the supervisory authorities' lists, the WP248 criteria), the data
  protection officer's advice, the views of the people concerned and prior consultation under Article 36, and a capstone in Lab mode on
  the EDPB template; a certificate valid for 24 months, eleven GDPR terms, six duties of Articles 35 and 36 as training obligations and
  GDPR guidance in *How we decide* beside a DPIA's screener, risk rating and decision.
- **The PIA course in the UK.** The UK pack (1.30) adds *DPIA practitioner (UK)*, in English: the universal path's ten modules, then
  when a DPIA is required (the ICO's screening checklist and list), the ICO's seven steps with the DPO's advice and the reasons when it
  is overruled, the views of individuals and prior consultation of the ICO, and a capstone in Lab mode on the ICO's sample template; a
  certificate valid for 24 months, ten UK terms, the duties of Articles 35 and 36 as training obligations and UK guidance in *How we
  decide* beside a DPIA's screener, risk rating and sign-off.
- **The PIA course in Alberta.** The Alberta pack (1.27) adds *PIA practitioner (Alberta)*, in English and French: the universal
  path's ten modules, then when the Protection of Privacy Act requires a PIA and when it goes to the Commissioner, the OIPC's mandatory
  template, the privacy management program and the submission, and a capstone in Lab mode on the Alberta template; a certificate valid
  for 24 months, eight Alberta terms, the duties of POPA ss. 25 and 26 as training obligations and Alberta guidance in *How we decide*.
- **The PIA course in British Columbia.** The British Columbia pack (1.32) adds *PIA practitioner (British Columbia)*, in English and
  French: the universal path's ten modules, then when FIPPA section 69 and the PIA Directions require a PIA (every initiative, significant
  changes, sensitive information outside Canada), the privacy office's review, early notice to the Commissioner and the Personal
  Information Directory, and a capstone in Lab mode on the BC Standard template; a certificate valid for 24 months, nine BC terms, the
  section 69 duty as a training obligation and BC guidance in *How we decide*.
- **The PIA course for Australian Government agencies.** The Australia — Federal FOI & Privacy pack (1.34) adds *PIA practitioner (Australian
  Government)*, in English and French: the universal path's ten modules, then the APP Code's PIA duty (high privacy risk projects, the
  threshold assessment, the PIA register, the Privacy Officer), the OAIC's ten steps and a capstone in Lab mode on the Australian
  Government template; a certificate valid for 24 months, seven terms, the Code's duties as training obligations and guidance in
  *How we decide*.
- **The PIA course in New Zealand.** The New Zealand — OIA & Privacy pack (1.31) adds *PIA practitioner (New Zealand)*, in English and
  French: the universal path's ten modules, then when a PIA is expected and the brief privacy analysis, the Privacy Commissioner's toolkit
  (the information privacy principles, the risk and mitigation table, the report and checkpoints) and a capstone in Lab mode on the New
  Zealand template; a certificate valid for 24 months, seven terms and guidance in *How we decide*.
- **The PIA course for US federal agencies.** The United States — Federal (Privacy Act of 1974) pack (1.25) adds *PIA practitioner (US
  federal)*, in English and Spanish: the universal path's ten modules, then section 208 of the E-Government Act and the privacy threshold
  analysis, Privacy Act systems of records, SORNs and routine uses, and a capstone in Lab mode on the federal template; a certificate valid
  for 24 months, seven terms, the section 208 duty as a training obligation and guidance in *How we decide*.
- **Two more PIA practice cases.** Universal learning (1.1) adds *Tracking a PIA's measures to closure* — an approved PIA whose measures
  slipped: give one a new owner, check in on another, close the one that is done, escalate the one nobody kept and decline a
  recommendation, each step ticking itself — and *Signing off a PIA: approve with conditions*, which starts where the senior official comes
  in (the analysis and the privacy review done, the last review step yours) and is *Reading a PIA and deciding*'s optional exercise.

#### Lab mode

- **Lab mode is ready minutes after a new organization's setup.** When the first setup finishes, the training copy is refreshed
  at once with the organization's real configuration, instead of waiting for the daily pass.
- **People who answer you in Lab mode.** In a practice case the people around you answer as the scenario scripts them, a while
  later in *exercise time*: the requestor writes back to a clarification letter, an extension notice or the response; a consulted
  third party responds to its notice with its position and representations; on a complaint the complainant answers your
  acknowledgement and your response, and the regulator's contact plays the regulator's side of the timeline — the notice, the
  request for records, preliminary findings, a finding — each step waiting for what you do. What they say can depend on what you
  did. A scripted message is marked *Scripted reply*, a scripted consultation response *Scripted response*.
- ***Waiting for*, and *Have it arrive now*.** The training case's guide lists whose answer you are waiting for and when it is due,
  announces each arrival and lists it under *Answers received*, and says in words why one will not come. In a practice case
  **Have it arrive now** brings an answer at once, dated now, and moves nothing else; in a team exercise answers follow the lead's
  exercise clock, and *To the next deadline* stops at the next one. A scripted answer never ticks a step for you.
- **Colleagues who answer you: simulated people.** The colleagues a scenario scripts exist only in Lab mode, and no directory
  account is needed for them; nobody signs in as one, they never appear in your real work, and the pickers list them first, tagged
  *Simulated*. Give them work as you would a colleague: a custodian searches and submits (with a *Scripted attestation* when your
  organization requires one), a contributor completes a task, a reviewer approves a step or sends it back, an advisor flags the
  redactions the scenario names, a section assignee answers a delegated section, a complaint's investigator reports findings on a
  workstream, an audit's evidence provider hands over evidence, a breach's action owner reports progress and a risk's
  treatment-task owner completes a task. Send their work back and they answer again. They act through the same rules as a person,
  never with more than their part allows.
- **Practice a colleague's side.** Some practice cases put you in another seat: a scripted coordinator hands you a search as its
  custodian, a section of an assessment, a complaint workstream, an audit's evidence request or a breach action when the case
  starts, then approves your work or returns it with a comment. A practice assessment can also make you the one whose opinion is
  asked — the scripted coordinator asks for it and responds to it — and a scripted coordinator revises and resubmits a PIA you
  refuse with *Rework*. In the Canada federal pack's two sign-off cases you either decide a PIA a scripted coordinator reworks or
  have a PIA decided by a scripted senior official; in the EU GDPR and UK packs you can be the data protection officer whose
  advice a scripted project lead asks for.
- **A senior official and a data protection officer, by script.** Universal learning (1.9) adds *Getting a final response signed off*,
  in all eleven languages: the fictional Town of Harbourview's Town Clerk is the request's senior official from the start; you redact a
  log of festival noise complaints, build the package and submit the final response for her sign-off, and about two hours later in
  exercise time she returns it once with a note — redact first when no redaction cites an exemption, otherwise say why the bylaw
  officer's name is released — then approves it when you submit it again, and you send it. The case needs final responses held for the
  senior official's sign-off (*Correspondence sign-off*; its card says when sign-off is not switched on). In Lab mode, when a case's
  senior official is a character the scenario plays, such a letter waits for that character whoever writes it — someone who holds *Act
  as senior official* too, who in your real work sends it directly — so an Administrator can practice it; your real work is unchanged.
  The access analyst path's module on the response offers the case as an optional exercise. In the EU GDPR (1.26) and UK (1.31) DPIA capstones the data protection officer now
  gives her advice when you ask for it — **Request opinion** on the Validation tab — as the requested provider, with her memo as the
  advice document; you record how it was taken into account, and asked again she advises on the reworked DPIA. When a scripted
  colleague cannot act, the guide says their part on the case does not allow it; when an outside party's answer cannot be recorded, it
  says the permission to record it is no longer held — neither blames the case's owner.
- **Team exercises: a colleague or the script for each person.** When the lead plans a team exercise, *People in the scenario*
  offers, for each person the scenario plays, **A colleague** or **Scripted — {name}**. A colleague who plays the requestor, a
  consulted third party, the complainant or the regulator's contact never opens the case: they work at **Your desk** — the letters
  that person received, what is waiting for their answer and the records they hold — and their answer arrives on the case as a
  scripted one would. Someone who does not answer in time gets one reminder — and none once they have done the work by hand; the
  lead's console offers **Remind** and, where the person has a script, **Let the script answer** — for a colleague in the product
  (a custodian, contributor, reviewer, advisor, section assignee, senior official, opinion provider, investigator, evidence provider,
  action owner or treatment-task owner) it moves their open work to the scripted colleague, as the lead could by hand — a delegated
  section is delegated again to the scripted colleague and the colleague's cancelled, their draft answers kept on it; a letter already held for the
  colleague's sign-off goes with the senior official's role. Each of those people can be scripted from the plan, too.
- **Your own scripts (AccessPoint Learning module).** The Studio's **Lab scenarios** lists the installed practice cases and team
  exercises with their people; an author writes the organization's own script for any person — every kind of answer, a person the
  organization adds, records from the Lab library, *Answer differently when…* — checked as a pack's would be, and *Try it in Lab
  mode*. When a lead plans a team exercise they can write a script for that exercise alone. The organization's script replaces the
  pack's for that person; switching it off brings the pack's back. Running scripted people is part of the core product; writing
  your own scripts needs the AccessPoint Learning module.
- **A complaint letter remembers whom it was for.** A complaint's letters and logged messages store their party — *The
  complainant* or *The regulator* (*Correspondence with*) — so a general letter to the regulator counts as the regulator's.
- **Realizer's training content.** Universal learning 1.4 – 1.11, in all eleven languages: the four request practice cases'
  requestors and contractors, their scripted custodians, advisor and reviewer; the complaint practice case's complainant and
  investigator; a practice regulator review; *Team exercise: the contractor's objections*, built for the desk and with a custodian — Nora Lindgren of Public Works — whom a colleague or the script plays, so a lead can try **Let the script answer** on a colleague's search; *Answering a search
  as a custodian*; *Investigating one line of a complaint* (whose findings and approval steps tick themselves); and *Getting a final
  response signed off*. A training provider's
  private pack exported from the AccessPoint Training Lab carries its people's scripts too (an earlier AccessPoint imports its
  scenarios without them), and its *Who's who* step says which of its people answer as simulated people.
- **Assessment exercises are checked by AccessPoint.** A training case's steps can now tick themselves on more of an assessment's
  work — the screener's determination, a completed section, a drawn and labelled data-flow diagram, a risk or commitment raised from a
  finding, commitments added, checked in, closed or declined, opinions and the validation decision, a regulator consultation, an
  update assessment created and approved, and a new version of the privacy subject's diagram — so more exercises count as
  verified. A training case can also start from an **approved** assessment, In Effect with its data flows, risks and measures, for
  exercises about what comes after approval; what it started with never ticks a step.
- **The model answer in the Lab-mode guide.** When a training case is an AccessPoint Learning exercise, its guide shows the module's
  model answer the moment every step is done, beside the case — the same answer, by the same rule, as the module player. User Guide →
  *Training cases*.
- **The guide says what ticks each step, in plain words.** A training case's step that ticks itself now says what it waits for —
  *Ticks itself once someone on this case… sends the letter “Acknowledgement”* — and, once ticked, *What was checked*; an AccessPoint
  Learning Exercise step and the Studio's Exercise editor list what the training case checks, step by step (the Studio with each
  check's code for the author). Learners never see a code. The words are the Training Lab's, in all 11 languages. User Guide →
  *Training cases*.

#### Requests: rolling releases and copies

- **Releases.** Documents → **Releases**: **Build the next release** opens a picker on the records *In the response*, ticking the
  ones ready and not yet released; choose to release or withhold each in full, the kind, the cuts, and build. Each release
  records its records, page numbers (Bates numbers run on across releases; a corrected record gets new ones), packages and
  figures; its **Index** lists every record it decided. The Documents tab gains a **Release** column and filter (*Not yet
  released*, *Changed since released*, *Corrected in a release*). User Guide → *Releases*.
- **Send release.** One action: deliver through the secure portal or another way, send or link the letter (with sign-off when
  your organization requires it) and see what it does to the response date. Release letter tokens — `{ReleaseNumber}`,
  `{ReleaseIndex}`, `{ReleaseIndexToDate}`, `{PagesReleasedToDate}` and more — and `{NextReleaseDate}` / `{RemainingEstimate}`.
- **On the portal,** the requestor's records are grouped by release with each release's index; a corrected release says what
  it corrects and why (after an appeal decision, a complaint or a regulator's order, an error found, a third-party
  consultation). Requestor-facing words for a release are everyday words in each language (*entrega*, *udlevering*,
  *Lieferung*, *envoi* …).
- **Statistics.** The response date comes from the releases — the final release, or the first where the legal authority says
  so — with **First release sent** and **Final release sent** in Key dates and the Report Builder; pages disclosed are the
  pages of sent releases.
- **Release schedules.** Fixed dates, every N days or N pages per period, from an estimate, an agreement or a court order; the
  next release due in Key dates and My Day; missed dates recorded; a **Status report** (CSV or Excel) with the figures a court
  status report asks for; the Report Builder subject **Releases**, with net figures that add up across corrections; the
  follow-up case date *Next release due*.
- **Instalments and hold until paid.** Ask for a release's own instalment from the fee engine's suggestion — paper,
  electronic or inspection, with the fee schedule's new **Electronic copies** setting (free, as paper, or their own rate) —
  never more than the fee leaves; hold a release until it is paid, waive it, or let it go with a senior official's reason.
  **Each record is charged once:** a record the requestor already received in a release that was sent — released again
  unchanged, or re-issued by a corrected release — or that another release's instalment already asks for is free when a later
  release sends it as copies the fee schedule charges at the same rate, and the instalment dialog says so (*3 pages already sent
  in Release 1 — not charged*); a copy the schedule charges at another rate is a new copy, and a cancelled or waived instalment's
  pages are charged again. The Universal Baseline's release letters (2.76) and California's fee and corrected release letters
  (1.19) say the pages a fee covers and the pages already sent (`{InstalmentPages}`, `{ReleasePagesAlreadySent}`).
- **One rule for copies.** The request's fee estimate and final fee price pages the way each release's instalment does:
  electronic copies at the schedule's electronic rate, paper copies at its duplication rate, inspection nothing per page — read
  from the request's **Response method** (*Email* and *Portal* electronic, *Mail* paper, *In person* inspection; none =
  electronic). The fee panel says how the pages are priced. A fee remembers how it was priced: once an estimate is issued, the
  panel keeps explaining that amount, and says when the response method has changed since and what applies now.
- **A letter that names a release.** In **Send correspondence**, any letter to the requestor can pick one of the request's
  releases under **Release**, so its number, pages, records, index and instalment fill in — a payment request before a held
  release goes out, say.
- **Corrected and supplemental releases,** on a closed request too, without reopening it.
- **A draft request takes no release** until it is activated: *Build the next release* is unavailable and says why.
- **Mark as the final release.** A request answered in interim releases and closed without a final one: mark the last release
  sent as the final release, once, with a reason — the final release date and, where your jurisdiction counts it, the response
  date follow.
- **Settings.** Legal authorities → *Response date counts from*; Requestor fee categories → *Electronic copies*; Request types →
  *Hold releases until paid*.
- **Jurisdiction packs.** California Public Records Act 1.18 (release letters, the estimated-date statement of Gov. Code
  § 7922.535(a), hold until paid, free electronic copies, the response from the first release, the estimated-release-date
  follow-up rule switched off); Hawaii 1.15 (incremental disclosure as a release schedule); Oregon 1.14, Delaware 1.15 and
  Arkansas 1.15. The Universal Baseline 2.66 brings generic *Interim release*, *Corrected release*, *Supplemental release* and
  *Fee for a release* letters in all eleven languages, offered where a request's own pack has no letter of that kind; the
  statutory notices of Alabama, Arkansas, Delaware, Louisiana, New Mexico, Oregon, Vermont, West Virginia and Wyoming that were
  typed as interim responses are ordinary letters now (Alabama 1.14, Louisiana 1.11, New Mexico 1.11, Vermont 1.11, West
  Virginia 1.12, Wyoming 1.12).
- **Training.** Guide steps can be ticked by `release:sent`, `release:sent:{n}` and `release:corrected`.

#### Redaction and recordings

- **Video and audio marks are managed in the side panel's card, like a document's.** A mark's effect (Box, Blur or
  Pixelate for the picture; Mute, Bleep or Distort for the sound), its exemption and its alternate exemptions are chosen in
  its card — and a new mark's in a *New mark* card at the top of the panel — with a line saying what each effect does and
  your organization's default marked; only the effects that fit the mark are offered. The mark bar under the picture keeps
  timing and placement, so the frame stays larger while a mark is selected, and its first button opens the card. *Bulk
  actions → Change effect* changes the effect of many marks of one kind at once.

#### Jurisdiction packs and dated settings — Nova Scotia's new Act switches itself on 1 April 2027

- **Settings that change on a date.** An exemption option can carry the days it is offered (*Available from* / *Available
  until*), a fee schedule can carry a *Fee change on a date* — the day its amounts take effect and the amounts before it — and an
  assessment type a *Mandatory from* day. A request is offered the exemptions, and charged the fees, of the date it was received
  (in your organization's time zone, the same day its due date counts from), so a request received before a new statute takes
  effect stays under the former one. Exemptions already applied never change: a mark keeps its exemption, its label and its
  colour. Extension reasons can carry the same dates, and **Add extension** offers a request only the reasons of its date; an
  extension already taken never changes. A suggestion pattern can name several exemption codes, and a suggestion takes the first
  one the request is offered. An assessment type counts as mandatory from its day, in your organization's time zone.
- **Nova Scotia (1.29).** The Freedom of Information and Protection of Privacy Act (S.N.S. 2025, c. 13) takes effect on 1 April
  2027, and requests made before then stay under the former Act or MGA Part XX (s.146). The pack now switches everything that
  changes by itself, by each request's received date: the due date (already), the exemptions — the new Act's ss.30–49 for a
  request received from 1 April 2027 (Executive Council records become a mandatory refusal, legal privilege includes settlement
  privilege), the 1993 Act's ss.12–21 and MGA ss.472–481 before — the new Act's extension grounds (s.21) in place of FOIPOP s.9 /
  MGA s.469, suggested redactions tagged with the personal-information exemption of the request's own Act (municipal requests
  included), three free hours instead of two, and the privacy impact assessment becomes mandatory (s.53). A new municipal PIA questionnaire follows the Commissioner's *Privacy Impact Assessment —
  Municipal Government Act* template. The regulations under the new Act (fee amounts, what a privacy assessment must contain,
  data-linking, storage outside Canada) are not yet published; a pack update will follow when they are.
- **An Alberta PIA type.** The Alberta pack (1.28) gives its POPA PIA template its own assessment type, *Privacy Impact Assessment
  (POPA)*, governed by the Protection of Privacy Act — so a PIA started from it follows the Act, and *How we decide* shows its Alberta
  guidance, even where another pack set up your *Privacy Impact Assessment* type. Its decision is the sign-off of the head of the public
  body, or a delegate named in writing under section 55, as the OIPC's completion guide says; the submission to the Commissioner that the
  Ministerial Regulation s. 7(5) requires is recorded as a review the OIPC answers with a closing letter. *How we decide* adds a note
  beside the sign-off, and the Alberta capstone records the sign-off and the submission before the PIA takes effect.
- **Quieter pack imports.** When two jurisdiction packs ship the same row — the Ontario provincial and municipal packs' PIA add-on — the
  second pack's import no longer warns that the code is already used when its row is identical to the one kept; a real difference still
  warns. *Configuration packs* → *Installing & re-importing*.

#### Reports

- **The Reports menu lists only the reports you can open (every edition).** A report row whose data the API would refuse you is
  no longer in your menu — for example *AI governance*, *Document access*, *Storage* and *Retention review* without *Manage
  configuration*, *Departed users* without *Manage users*, *Requestor volume* without *View requestor PII*, the register
  analytics without that register's view, and *Report Studio* without *Use Report Studio*. A tile pinned before says *You don't
  have access to this report.* (remove it from its menu) and a link to it says the same. Permissions held while covering for a
  colleague count. **In an AccessPoint you deploy (the Microsoft 365 web part) this is the only change: it hides rows people
  could not open anyway** — each of them answered with an error before.

#### Accessibility and the interface

- **One set of status colours, by meaning.** A status's colour now says what it means, the same in every register: *In
  Review* is purple and *On Hold* amber on the chips and on the summary cards that filter them. Notices, banners, check
  results and report figures use the same colours — a warning is the attention gold, a success the done green, a figure
  between a warning and an error amber — with dark and high-contrast versions (in Teams high contrast, bright text on the
  colour's dark fill). Settings → statuses → *Colour* and the audit scales offer the colours by name, in your language —
  Grey (new), Blue, Purple, Amber, Gold, Red, Green, Teal and Muted. A colour chosen before keeps its colour: *Brand*,
  *Success* and *Yellow* are Blue, Green and Gold, and a colour no longer offered (Magenta) stays until you choose another.
- **Names that match what you see.** The summary cards, the file name at the top of the document preview and the
  redaction viewer, and the rows of the redaction list — a document's marks and a recording's — are named by the words
  they show, starting with them, so a voice-control user can say what is on the screen (WCAG 2.5.3). A redaction row now
  also tells a screen reader its status, who marked it and when, its comments, and whether it is locked or flagged — and
  shows every badge: in a narrow panel they wrap to a second line instead of being cut off. The Risks register's source
  chips are named by their source and count.

#### The AccessPoint Training Lab (learn.realizer.io)

- **The Training Lab, polished (learn.realizer.io).** The Lab now looks like AccessPoint — the white header with the wordmark,
  the brand's blue and greys, cards, a footer with privacy, terms and help — and joining is one form: the class code first,
  then *This is my first time* or *I've joined before*, with the e-mail field up front in a class that asks for it, *Change
  email* and *Send the code again*. Codes are upper-cased and dashed as they are typed, and a pasted link fills them in.
  Signing out warns a learner who has no way back and offers their resume code first. The course home shows *Next up* and
  overall progress; exercises on a phone scroll as one page and say they are best on a larger screen; the guide has one
  primary action and announces each step's state; Enter submits every form. Instructors get **Show to the class** (the code,
  a QR code of the join link and the address, full screen), **New resume code** for a learner, settings in cards with one
  Save each, and destructive actions in red. All eleven languages. One box now takes the class code or a resume code: a class
  code goes straight to joining (with *Joined before?* below), a resume code straight back to the learner's work, and a device
  that joined before says *Welcome back*. The Live grid shows each step as a coloured chip with a word and a legend, Results
  start with a summary before the numbers, and the New class wizard has numbered steps, a ready title, date checks on the field
  and *Change* beside each review line.

#### Realizer (the publisher and its admin console)

- **Active now: who is signed in to each hosted region, and when the week is quiet** (Realizer only; owner, 2026-11-09;
  `docs/RealizerAdminConsoleRunbook.md` §15). *Operations → Active now* shows, for each region, the sign-in sessions active in the
  last 5 and 15 minutes and when the region measured them; the last 7 days by hour — each hour's highest 15-minute count, with a
  data table — and the quietest 3-hour windows of the week, in UTC, to plan maintenance for a quiet time. A region that has not
  reported for 15 minutes says *Not reporting*. A session is active when its person did something in the service, not while a tab
  sits open. The counts are kept eight days.
- **Realizer's admin console reports the hosted app beside the Microsoft Marketplace** (Realizer only; hosted reporting, 2026-11-06).
  A Stripe revenue import, the SaaS metrics, monthly snapshots and their CSV split into Marketplace (USD), Hosted (CAD) and a Total
  that adds customers and shows a combined total in CAD — the USD converted at the Bank of Canada monthly average of the same month,
  labelled so; a month the Bank has not averaged yet (the current one) keeps the channels separate and says why; the hosted funnel of the onboarding design (trials, extensions, the Free
  plan, paid plans and add-ons, trial → paid, Free → paid, retention, demo-sourced) on Home and Growth; a monthly Stripe journal for
  QuickBooks beside the Microsoft payout journal; hosted customers in HubSpot with their channel, plan and state; Stripe ids and the
  MRR in CAD on the Customers pages. Hosted trials are no longer counted as marketplace trials. With O3 the funnel's activation tiles
  light up from the stamps' activity summaries — activation (a real request or an assessment within 14 days), Lab engagement, team
  (a second member within 30 days), time to first value and Free organizations active in the last 30 days — and the demo-sourced
  funnel reads the sign-up attribution.
- **Realizer's admin console for the hosted onboarding** (Realizer only; `docs/RealizerAdminConsoleRunbook.md` §14). **Extend
  hosted trial** on a hosted subscription moves the trial's end 1 to 90 days later, with a reason, any number of times — an
  organization on the Free plan goes back to the trial until then — and never uses up the organization's own *Extend 30 days*;
  the customer list's *Channel* filter and **Free** badge, the subscription's procurement-extension facts and the customer
  page's *Sign-up* line; and four new notification event types: *Hosted trial moved to the Free plan*, *Hosted subscription
  moved to the Free plan*, *Hosted trial extended for procurement* and *Free plan converted to paid*.
- **Hosted record retention** (Realizer only; `docs/RealizerAdminConsoleRunbook.md` §14). A hosted organization's subscription ends
  when its stamp deletes it (an inactive Free organization, an abandoned trial, one that leaves), and 90 days later the new hourly
  job *Hosted record retention* deletes Realizer's licence records, notes and contact for it and anonymizes the rest — the plan,
  billing, usage and Stripe revenue stay, under the placeholder *Deleted hosted organization* — writes a hash-only evidence row,
  archives its HubSpot company (its deals keep stage and value, without the name) and removes its Stripe customer's e-mail address and
  name (the customer and its invoices stay for accounting). Three new notification events: *Hosted organization deleted on its
  stamp*, *Hosted organization's records deleted* and *Hosted records deletion held* (while Stripe still bills the organization —
  cancel it in Stripe and the next pass deletes). For an organization whose stamp no longer runs (the former development stamp), the customer page's
  **Record a hosted deletion** (Admin; a reason, the kind, the day and the hosted id typed again) records the deletion the stamp can
  never report — refused while the stamp runs, the organization was in use within 30 days, or Stripe still bills it. Its 90 days
  count from the record, and **Undo the recorded deletion** (Admin; a reason and the hosted id typed again) reverses it until the
  retention job runs: the subscriptions come back and the stamp's control plane answers again.

### Fixes

#### The release's bug review (2026-11-12)

The review of every change since 2.5.0 (`docs/code-reviews/2026-11-12-bugs.md`) found one severe and ten serious defects and a set
of smaller ones; all are fixed in this release. The ones you can notice:

- **Public portal while a licence is read-only** (F-3): verification codes are still sent, so a requester can open a delivery made
  before the lapse, or the case status; a code that waited past its lifetime is dropped instead of arriving late.
- **AccessPoint Learning** (F-9, F-10, F-12 – F-17, F-58 – F-66): a required step your organization adds to a pack module now holds
  the completion record and the certificate; the Studio keeps each Read step's page in its own step and saves what is waiting
  when you change tab or leave; line breaks typed in a paragraph are kept; *Save the items* keeps a path's other settings; moving a
  coach note never undoes another author's edit; paths finished before 2.6.0 get their completion records without a visit to My
  learning; the completion-records CSV includes every record (it stopped at 20,000).
- **Rolling releases** (F-20, F-21, S4-10 – S4-12): two people sending the same release at once send one letter; under
  count-from-first a response date recorded before the first release is kept; a schedule change never fails a send whose letter
  already left; the status report's running totals never go down the page.
- **Fees** (F-76): a waiver on a final fee that carried an estimate's waiver now adds to it — the amount owed never rises.
- **Documents** (F-85): saved views save, restore and clear the Release filter.
- **Offboarding** (F-32): a leaver's letter held for sign-off reaches the person the plan reassigns it to.
- **Lab mode** (F-22 – F-24): one clash between two scripted people no longer stops every new reply in the training cases; a
  scripted custodian waits for open contributor tasks instead of never answering.
- **Hosted AccessPoint** (F-5, F-7, F-26 – F-31, F-35, F-36, F-67 – F-69): a session whose sign-in has expired goes back through
  Microsoft instead of looping; a failure to read the organization's session limits no longer signs anyone out; members of a
  region closed to new sign-ups find their organization; the app picks up a new plan or module at once; a refusal caused by a
  read-only licence says so; a storage refusal says whether the plan is full or the file does not fit; an organization export
  survives a restart and a failed progress check; the trial line counts to the trial's end.
- **Smaller fixes** (S4 observations): coded refusals instead of English sentences or generic errors across AccessPoint Learning
  and releases; the read-only banner no longer flickers after a deployment; a response package cover no longer cuts "s. 13" in
  half; a DPIA consultation stores the regulator's own name; and more — every one is in the review report's *Remediation* table.

#### Requests and cases

- **A late request is no longer moved into Deemed refusal.** Practitioners told us that a late request is not a deemed refusal
  until the requestor complains about it — until then it is simply late. A request past its due date now keeps its status and is
  shown as overdue, as before, in the request list, on its Key dates card, in My Day and in the reports' late counts; My Day's
  overdue item now suggests a delay notice and a letter on the right to complain (the delay notice alone once the request is in
  Deemed refusal). When the requestor complains to the
  Commissioner (or your oversight body) about the late response, set the request's status to *Deemed refusal* yourself; the
  change is recorded in the Activity feed like any status change. The jurisdiction packs no longer set an overdue status on their
  request types (28 packs, each with a new version). When AccessPoint 2.6.0 first runs, it clears the overdue status of every
  request type — one a jurisdiction pack set up or one of your own — whose overdue status is a deemed-refusal status a
  jurisdiction pack shipped, renamed or not, without changing any request's status: requests already in Deemed refusal stay
  there until you change them, and they no longer return to their previous status by themselves when you grant an extension. A
  pack re-applied later never sets a deemed-refusal status as an overdue status again. If your organization chose an overdue
  status it created itself for a request type (Settings → Request Types → Overdue status), it keeps working as before — except
  that AccessPoint never undoes a status a person picks: once someone picks a status for an overdue request with its status
  picker, it is left alone until its due date moves (activating, resuming or reopening a request is not a pick, nor is a linked
  case's status change). One case keeps moving: a pack's request type that the pack linked to a status your organization had
  created by hand under the same code (for example `DEEMED-REFUSAL`) — clear its overdue status in Settings → Request Types.
  The compliance report now shows late responses once, as *Late*, instead of repeating the same number as "Deemed refusals".
- **The Releases sub-tab no longer reads the releases over and over.** With Documents → Releases open, the page re-read the
  request's releases several times a second for as long as it stayed open. It now reads them when the sub-tab opens, after a
  change, and every five seconds only while a release with a recording is being built.
- **The request shows its requestor's details as soon as they are saved.** Editing the requestor through Requestor → **Open
  contact** (for example, adding an e-mail address to a draft request) now refreshes the request: *Requestor email* and the
  **Activate** button follow at once, without reopening the request.
- **Close request says why the request did not close.** When the request was changed elsewhere while the dialog was open,
  **Close request** did nothing visible. The dialog now says so, loads the latest version and keeps what you entered — select
  **Close request** again. Other refusals (a review in progress, an already closed request) are said in the dialog too. A
  refused close no longer leaves a *closed* entry in the request's history.
- **Export history offers Delete only where a package can be deleted, and says why one is kept.** A package of a release that
  is built or sent is kept as the release's evidence, and one whose release is being built waits for the build. Export history
  offered **Delete** on them anyway and, when refused, said the package was in the reading room. **Delete** no longer appears on
  those packages, and a refused delete now gives the real reason.
- **No raw error under Response & fees for people who cannot see portal deliveries.** Someone without access to a request's
  documents saw *API error: 403* where the secure portal deliveries are listed. The section is now hidden for them, as it is when
  a request has no deliveries.
- **A role that may create requests, or see only its own, has the Requests tab.** A role whose *View requests* is limited to
  own requests (or assigned requests), or that can only create requests, had no Requests tab: no **New access request** and no
  way to find a request. The tab now shows, and its list holds exactly the requests the role may open — those the person
  created (own requests) or works on (assigned requests). A request's named senior official also finds it in the register.
- **Advisors, readers and senior officials can open the assessments, incidents and complaints they are on.** A person added as
  advisor or reader on an assessment, incident or complaint — or named its senior official — without a role that shows that
  register got *This item could not be opened*. The register's tab now shows for them, listing only those cases.
- **A request number is never issued twice.** When the default numbering's sequence reached a number a request already had —
  after a second jurisdiction pack's numbering on the same prefix took the default, or a sequence was reset — activating a
  request failed on the duplicate. AccessPoint now skips a number that names a request, or one deleted under retention, and
  continues after the highest number already given with that pattern. Assessment, incident and complaint numbers skip a number
  already taken the same way.
- **The Activity names a fee's currency as the fee card does.** On an organization whose currency is the US dollar, a request
  whose fee schedule is in Canadian dollars showed *Fee estimate generated — Estimate $65.18* in its Activity while the fee card
  read *CA$65.18*. Every fee and payment entry in the Activity and the audit ledger — estimates, final fees, lines, waivers,
  payments, refunds and instalments — and the fee messages beside the fee card now write a currency that is not the
  organization's as CA$, US$, A$, NZ$ or MX$ (SEK, DKK, NOK for the kronor), and the organization's own currency with its usual
  symbol.
- **The public portal tells a complainant that their complaint was received, not a request.** A complaint or a privacy-concern
  report sent through the public portal got the e-mail written for requests — *We have received your request … Your request has
  reached the access team* — wherever the *Public portal: request received* template was in place (the Universal baseline
  ships it), and the *not accepted* notice said *… was not registered as a request* the same way. Those notices now read *We
  have received your complaint* (or *your report*) *… has reached the privacy office* and *… was not registered as a complaint*
  (or *as a report*), in the language the person used. The *Public portal* correspondence templates still word the notices
  about requests.
- **A refund takes its place in the portal's history.** On the public portal's case page, a refund was listed before everything
  else that happened on its day — ahead of that morning's submission, fee requests and payments. It is now listed when it was
  recorded, after what came before it that day; the history still shows only its date.

#### Correspondence sign-off

- **A letter waiting for sign-off follows the senior official.** A letter held for sign-off stayed with the senior official it was
  submitted to: when a request or a complaint named someone else — on its details, by reassigning a departing colleague's work, or when
  a Lab mode team exercise's lead let the script play the senior official — the new official was not asked and the former one still
  could sign it. Every letter still waiting now moves to the new official, who gets the usual *Correspondence awaiting your sign-off*
  notice; it leaves the former official's queue and My Day, and shows *Now with {name} — the senior official changed*. With nobody
  named, or a new official who cannot act as senior official, it waits for anyone who holds *Act as senior official*; a new official who
  wrote the letter gets it only when they could have sent it without sign-off. Approved, returned, withdrawn and sent letters never move,
  and the letter itself never changes. Each move is in the case's Activity (*Letter for sign-off reassigned*) and the audit ledger.
- **The senior official asked to sign a letter can sign it.** *Letters awaiting sign-off* on the request's Requestor tab showed
  only to people who send correspondence, so a senior official holding only *Act as senior official* was asked in My Day to
  sign a letter they could not find. It now shows to the request's senior official and to anyone who can act as senior official.
  My Day asks a person to sign only a letter their case shows them.

#### Documents, redaction and recordings

- **The redaction viewer on a phone gives the record the screen.** On a screen narrower than 640 pixels (a phone, a narrow Teams
  column), the side panel beside the record took most of the width and left the page a few pixels wide. The panel now starts
  closed there and comes up over the lower part of the record when you select text or draw a box (the exemption form is in it),
  or with **Show panel**; **Hide panel** closes it again. The viewer's header wraps instead of scrolling sideways. A hidden panel keeps the record's redactions loaded and painted, on every screen size.
- **A package whose accessibility check gets no answer says so.** Where the accessibility checker is configured but does not
  answer (it is not deployed, or it stopped), a release package no longer shows *Accessibility: checking…* for hours. After
  three hours it reads **No answer from the accessibility checker**: AccessPoint's own checks are still shown and no PDF/UA-1
  claim is made. A release rule that requires a passing check holds such a package as *needs review*, as it does a package no
  checker could see — an acknowledgement releases it. An answer that arrives later still counts. **Check again** now runs a
  fresh check at any time; it was unavailable while a check was waiting. (Before, an unanswered check became an error after six
  hours and the package read *Failed*.)
- **R in the media viewer focuses the selected mark's region again.** The side panel and the viewer could disagree about
  which mark was selected: choosing another mark in the panel did not always reach the viewer, and the mark bar's
  **Done** left the mark selected in the panel. The viewer's keys (R, S, Shift+I, Shift+O) then acted on another mark, or
  on none. The panel and the viewer now show and use one selection.
- **Folders a background collection creates appear at once.** With *Mirror folder hierarchy*, the folders a repository
  collection created appeared in the Documents tab only after the page was reloaded. They now appear with the collected
  records when the collection finishes.
- **Repository details show a removed location at once.** After **Edit this section** removed a repository's link to a
  connector folder, the panel kept showing the old folder, with **Browse here** and **Search here**, until it was reopened. It
  now shows what was saved.
- **A response package's contents page no longer prints one column over the next.** In *Records included*, a long page or
  Bates range ran into the *Exemption* column, and a document name was cut at 28 characters yet could still reach *Pages*. Every
  column of the contents' tables, and of the Redaction Index, now has a fixed width in which its text wraps onto as many lines
  as it needs: the full document name, the whole page range and every exemption are printed, a name or label with no spaces
  breaks inside its column, and the row grows to its tallest cell. A row that does not fit moves to the next page, which
  starts with the column headings again. On *Other records*, a long record ID wraps beside its details the same way.
- **A package's contents page, Redaction Index and *Other records* page are in the package's language.** A German package
  headed its records table *Document*, *Pages* and *Exemption*; in every language but English and French the Redaction
  Index's recording column read *Timecode* and *Other records* and its sections were titled in English; a record with no
  exemption read *(none)*; and a recording's or file's disclosure (*Disclosed in full*, *Withheld in full*…) was English on
  the contents page. All of these are now translated in every language. A page or Bates range reads *first – last* in every
  language (it read *first to last*), on the contents page and in the cover letter's {BatesRange}.
- **A response package's cover letter no longer reads *Provisions relied on: .*** With nothing redacted, the Universal
  baseline's *Response package cover* said *Where information has been withheld, 0 redaction(s) have been applied … Provisions
  relied on: .* That paragraph is now left out when the package has no redaction, and with redactions but no exemption cited, only
  the *Provisions relied on* sentence is. It holds for covers already imported, in every language, and for a cover of your own
  that uses {TotalRedactions} and {ExemptionsSummary}.

#### AccessPoint Learning

- **The Studio's page editor opens.** On every **Read** step (and wherever a step's text is written as a page) the Studio said
  *The page editor could not be opened*: the API refused to be shown in the Studio's frame. It opens now.
- **Preview as learner shows a check's questions and a decision's options.** A check showed only its number of questions, and
  a decision its scenario and prompt without its options. The preview now shows both as a learner sees them, read-only, still
  without the right answers, feedback or model answer.
- **My learning shows a new or finished learning path without a reload.** A learning path an audience rule assigned, or one
  finished by reading its last note, appeared in My training only after the page was reloaded. My learning now reads afresh
  each time it opens and after each item you complete there.
- **Completion days are the day you completed.** A learning path completed in the evening in a time zone behind UTC showed the
  next day — the UTC day — in the completion records and their CSV export, My learning, the certificate (*Completed on* and
  *Issued on*), its verification and a revocation. They now show the day in your organization's time zone when one is set
  (**Settings → Localization**), else in your own. A certificate keeps the days it was issued with, whoever downloads it;
  certificates issued before this release keep the days they print.
- **A certificate is the same file on every download.** A certificate made with your organization's letterhead came out
  slightly different on every download (only an internal checksum changed), so its SHA-256 never matched the seal and every
  download recorded a new seal in the audit ledger. Every download is now the same file, sealed once. A letterhead
  certificate downloaded before this release is sealed once more on its next download, then stays the same. The web part can
  now read the seal a download carries (`X-Certificate-Sha256`).
- **The completion-records CSV carries scores and attempts.** With *Who sees check results* set to *scores and attempts too*,
  the `CheckScores` and `CheckAttempts` columns were empty for a learning path completed while the setting showed less, though
  Team progress showed them. The export now carries what the setting in force lets you see, read from the results the path was
  completed with while AccessPoint keeps them.

#### Lab mode

- **Training says *email*.** The training guide's sentence for bringing in a message from Outlook now reads *brings in an email
  from Outlook*, and assigning a learning path, planning a team exercise and a scripted person's address in the Studio say
  *email* too — the spelling used everywhere else in English.

#### Jurisdiction packs and first setup

- **Applying a jurisdiction pack no longer stops after a minute in hosted AccessPoint, and trying again no longer fails as a
  "deadlock".** On the hosted service, applying a large pack (*Canada — British Columbia (FIPPA)*, 2026-11-10) took longer than the
  minute Front Door waited for an answer: Front Door ended the request, AccessPoint took that for the person leaving and undid the
  import, and **Apply pack** showed an error; applying it again a minute later failed with *Transaction … was deadlocked … Rerun the
  transaction*. Now:
  - a pack import that has started finishes on the server even when the browser stops waiting — still all or nothing, within ten
    minutes;
  - one pack import runs at a time in an organization: a second one (another tab, or the first setup applying a pack at the same
    moment) is refused at once with *Another jurisdiction pack is being applied to your organization right now* (409
    `pack-import-in-progress`) instead of failing part-way;
  - a passing database error (a deadlock, a failover) is retried by AccessPoint and not shown; only when every retry fails does the
    import say the database was busy, with nothing changed (503 `pack-import-busy`);
  - an import reads the database in bulk: the British Columbia pack's first application went from about 1,100 database round
    trips to about 220, applying it again from about 600 to about 200;
  - when the connection ends before the import answers (a gateway timeout, a dropped connection), **Settings → Jurisdiction packs**
    says the import may still be finishing, looks at *Applied packs* again on its own over the next few minutes and says when the
    pack is applied — instead of *API error*.

  The hosted service's Front Door now waits up to 240 seconds for an answer (Realizer's setting). An AccessPoint you deploy yourself
  has all of the above too; its API is behind Front Door only with `frontDoorForApi`, which has always waited 240 seconds. Nothing to
  do.
- **New hosted organizations are set up again — and a setup that fails says so.** Every hosted organization created since the
  hosted app opened stayed on *Setting up your workspace…*: the organization is given its own system statuses and types at
  creation, and the Universal baseline then tried to add a second *Law enforcement* incident notification type, which the database
  refuses, so no pack was applied (the jurisdiction pack failed on the same leftover row). A pack now takes over the
  organization's own system row of the same code instead of adding one — and the same for incident and complaint statuses and the
  incident and record-of-processing option lists — while a row your administrators made or another jurisdiction pack shipped is
  kept and named in a warning. A failed setup is recorded: the banner says it is taking longer than expected after five minutes,
  or that the workspace could not be set up completely, and offers an Administrator **Try again** and **Open Jurisdiction packs**;
  when an Administrator opens the app, a failed setup runs again on its own. Organizations already stuck are set up the first time
  their Administrator opens AccessPoint after this release (the Universal packs; a jurisdiction pack chosen at creation was not
  kept and is applied from **Settings → Jurisdiction packs**). In an AccessPoint you deploy yourself, a first setup that fails
  shows the same banner and **Try again**, instead of waiting for the API's next restart.
- **The Vermont and Utah packs can be applied again, and free search time can be part of an hour.** Vermont gives the first
  half hour of a search free and Utah the first quarter hour, but AccessPoint read free search time as whole hours, so applying
  either pack stopped with an error and changed nothing (since September 2026). A fee category's free search hours now take a
  fraction of an hour — to two decimals, entered in quarter-hour steps in Settings → Requestor categories — and the fee estimate
  and final fee subtract exactly that. AccessPoint 2.5 is given the hours rounded up to a whole hour, never fewer than the law
  grants, so both packs apply there too.
- **Organizations still on AccessPoint 2.5 are served the packs as 2.5 can use them** (publisher; it applies as soon as the
  publisher is deployed, whatever AccessPoint version an organization runs). Since the Universal baseline moved the practice cases
  and training paths into Universal learning (baseline 2.75), a new organization on 2.5 — which imports only the baseline — started
  with none, and the baseline and the California and Hawaii packs offered release letters 2.5 sends with blanks. An organization on
  2.5 now gets the baseline with the eight practice cases and six training paths 2.5 shipped with, the 2.5 wording of the training
  notices, the 2.5 California disclosure and Hawaii increment letters, and no release letter, Lab mode notice, scripted practice case
  or AccessPoint Learning content; it no longer sees Universal learning. On 2.6, Universal learning takes those practice cases and
  paths over — no second copy, assignments and progress kept. An organization on 2.5 that took the earlier content can recover by
  re-applying the Universal baseline and switching off the four release letters (*Interim release*, *Fee for a release*, *Corrected
  release*, *Supplemental release*).
- **Jurisdiction packs no longer offer items they dropped.** The Realizer catalogue now removes from a pack the items its file
  no longer contains: the Universal Baseline pack stops offering the learning content that moved to the Universal Learning pack.
  Nothing to do in a customer deployment.
- **The British Columbia pack can be applied on AccessPoint 2.5 again** (publisher; it applies as soon as the publisher is
  deployed, whatever AccessPoint version an organization runs). Since early November, applying *Canada — British Columbia (FIPPA)* on 2.5
  stopped with *An item with the same key has already been added. Key: ExampleScenarios* and changed nothing: the Realizer catalogue
  held its practice cases twice and sent both. The catalogue now holds and sends each item once, and repairs such a repeat on its
  own. AccessPoint 2.6 also accepts a pack that carries an item twice: it imports it once and adds up the counts of two different
  items of one kind, instead of refusing the pack. Nothing to do in a customer deployment: apply the pack again.
- **The Canada federal pack follows the Standard on Privacy Impact Assessment's wording (1.50).** The pack said that the approved PIA
  must go to the Treasury Board of Canada Secretariat and the Office of the Privacy Commissioner *before implementation*; the Standard
  (Appendix C of the Directive on Privacy Practices) asks for every completed PIA, with any related information either of them requests,
  and sets no deadline. The Directive on Privacy Practices authority, the federal PIA template's filing reference and guidance, and the
  learning content now say so. They also name the approvers as the Standard does — the executive or senior official who manages the
  program and the official responsible for section 10 of the Privacy Act — and the template's validation decision reads *Approval by the
  official responsible for section 10 of the Privacy Act*. The federal template still asks for both copies before a PIA is marked in
  effect, as your organization's workflow rather than a Treasury Board deadline. The *Privacy Impact Assessment* type now cites
  Appendix C for the personal information bank — prepared before implementation and registered through the Treasury Board of Canada
  Secretariat — instead of section 71 of the Privacy Act alone. Re-apply the Canada federal pack (*Add and update unchanged*) to receive
  the corrected texts.
- **The federal PIA template's section 10 question names the official responsible for section 10 (Canada federal 1.52).** Its Section E
  question asked whether *the head of the institution or the delegate* approved the assessment; it now asks whether *the official
  responsible for section 10 of the Privacy Act* did, as the Standard on Privacy Impact Assessment (C.2.2.14), the template's decision
  and the learning content say, and it is in French too. The template moves to version 2: assessments already started keep version 1.
  Re-apply the Canada federal pack (*Add and update unchanged*) to receive it.
- **Applying a second jurisdiction pack keeps your request numbering.** A pack's default numbering took the default from the
  numbering already in use: an organization on Ontario MFIPPA (FOI, at 651) that applied British Columbia FIPPA had its next
  requests numbered FOI-2026-0001, FOI-2026-0002… from the new pack's sequence. A pack's numbering now becomes the default only
  when there is none, when it replaces the Universal baseline's own default (the first jurisdiction pack, as before) or when the
  same pack is applied again; otherwise it is added beside yours, not the default, and you can choose it in Settings → Numbering.
  An organization whose default was already taken over can make its own numbering the default again there; no number already
  given is reissued either way. Ontario FIPPA 1.35 and MFIPPA 1.38 also name their numbering apart — *Ontario FOI (provincial,
  FIPPA)* and *Ontario FOI (municipal, MFIPPA)* — so an organization with both packs no longer sees two numberings called
  *Ontario FOI*.
- **Applying another jurisdiction's pack no longer renames a type you edited.** The types every jurisdiction shares — the
  privacy breach incident type, the PIA assessment type — are one row in your organization. When an administrator had edited
  one, a later pack left the row alone but still wrote its own names and descriptions over the row's translations: an Ontario
  organization that applied the Quebec health and social services pack saw its breach type called *Confidentiality incident
  (R-22.1)*, with the Quebec description. A type, status, option, attestation or assessment template that a pack leaves alone
  now keeps its own names in every language; applying the pack it came from again still refreshes them, as before. A name
  already replaced this way stays until an administrator corrects it in Settings → Incident types or Assessment types.
- **Statutory search fees are charged in their own unit, not by the whole hour.** Ten packs stored a rate set per 15 minutes,
  per half hour or per minute as its hourly equivalent, and the fee engine counts part of an hour as a whole hour, so an estimate
  of an hour and a half under Ontario MFIPPA came to $60 instead of $45. Their fee schedules now carry the statute's own unit
  and rate: by the quarter hour — Alberta ATIA 1.29 ($6.75), Northwest Territories 1.26 ($6.25), Nunavut 1.26 ($6.75), Ontario
  FIPPA 1.35 and MFIPPA 1.38 ($7.50); by the half hour — Manitoba FIPPA 1.27, Nova Scotia FOIPOP 1.30 and Saskatchewan FOIP
  1.25 ($15), New Zealand OIA 1.32 ($38); by the minute — Vermont 1.12 ($0.45). Yukon ATIPP 1.25 charges $30 for each processing
  hour or part of one (ATIPP Regulation s.14(1)(a)) instead of $25 an hour. Settings → Requestor categories now shows a
  schedule's unit as it is billed (it showed *Per Hour* for every pack unit but its own *Per 15 Minutes*) and offers *Per 30
  Minutes* and *Per Minute*. Re-apply each pack (*Add and update unchanged*) to receive its schedule; a schedule you edited is
  kept. AccessPoint 2.5 is served the units in the words its fee engine reads (publisher), so a quarter-hour rate is never billed
  as an hourly one there — which also corrects the British Columbia, Prince Edward Island, Queensland and Hawaii schedules that
  already carried a unit.

#### Hosted AccessPoint

- **A hosted organization's sign-up attribution reaches Realizer.** The stamp collected where an organization's first owner came
  from (the demo, a campaign — the sign-up context's allow-listed keys) and the publisher stores it, but the stamp's registration
  request left it out, so `Tenants.SignupAttribution` stayed empty and the admin console's demo-sourced funnel counted no one
  (multi-region design §6.7). The registration now sends it, and a contract test fails if any field of the request ever goes
  missing from what is sent. Organizations registered before carry none and count as not demo-sourced; the console's definition
  says so.
- **People search and names work in hosted AccessPoint.** Every people and group search (the pickers) and every lookup of one
  person (an incident's owners, a reviewer's name) answered *Directory search unavailable* on a hosted organization: the check that
  admits the caller asked first for the deployment's own Microsoft 365 tenant, which a hosted service never has. It now admits the
  caller's organization, and the search reads that organization's own members, as designed; an incident no longer shows
  *Assigned incident owners could not be loaded*. Microsoft 365 deployments are unchanged.
- **The trial banner and Settings → Subscription show the same end date.** The banner rebuilt the date from a rounded number of days
  left and could show the day after the trial's real end; it now shows the trial's own end and counts the calendar days to it in
  your time zone.
- **A register your plan does not make available shows its switch off.** On a plan that has audits and risks read-only, an
  organization that holds no audit and no risk has no Audits or Risks tab — yet Settings → Features showed *Audits tab* and *Enable
  the Risks dashboard* on, and switching them changed nothing. A register switch your subscription does not make available now shows
  off and cannot be changed, with the reason under it: *Not included in your subscription.*, or *Read-only on your plan: the tab
  appears once your organization holds a record in this register.* The *Audits board* switch in Settings → Audits follows the same
  rule. Your own setting is kept as it was, and applies again when the plan changes. An AccessPoint you deploy yourself is unchanged
  unless its licence leaves a register out.

#### Languages

- **Every screen reads in the language you chose.** A final review of all ten translations of 2.6.0's text — the product,
  the Training Lab, the hosted entry and sign-in pages, the public portal and the e-mails — corrected some 3,800 strings: one
  word for each idea in each language (a privacy subject is never named like a person, a senior official has one title), the
  same level of formality throughout each language, counts that read correctly for one and for two to four, and labels that
  were still in English. Nineteen texts that showed English whatever the language (tag and category suggestions, proposals on
  a subject's safeguards, the sign-off settings' save error) are now translated, and page counts, report row counts, the
  calendar capture, the audit ledger and the packs' install dates follow your AccessPoint language rather than the browser's.
- **The public portal's embed widget is version 2.6.0.** It carries the Finnish complaint form's corrected title. A site that
  loads the stable `/widget/v1/` address gets it with the upgrade; a site that pins `/widget/2.4.0/accesspoint.js` keeps
  working unchanged.

#### Accessibility

- **Narrow screens no longer cut off three controls.** At 320 CSS px (a phone, or 400 % zoom) the hosted edition's organization
  switcher lost its arrow past the page's edge; an incident's notification obligation pushed **Dismiss** off the panel; and
  Settings → Features & AI pushed **Change monthly budget** and **Per-feature breakdown** off the screen. The switcher now goes
  under the AccessPoint name, a panel's buttons wrap to a second line, and the AI usage line wraps.
- **Guide me keeps keyboard focus on the step.** When a tour opened a panel — the privacy program's subjects, for
  example — focus went to the panel's own **Help** button instead of the step's title, so Tab never reached the
  highlighted control; and a tour started from the Help panel left focus on the page when it was closed with Escape. Focus
  now stays on the step's title until you move it, Tab goes through the step to the highlighted control, and Escape
  returns focus to where the tour started, or to the highlighted control — never to the page.

#### The AccessPoint Training Lab (learn.realizer.io)

- **Training Lab: `HEAD /health` answers 200** (an uptime monitor probing with HEAD saw 405), a past class's settings no longer
  say when its learners' data will be deleted, message bars name their close button, the page starts at its top after joining
  or signing out, and the Lab's pages no longer log the product's "SPFx bundle" line.

#### The marketing demo (demo.realizer.io)

- **The marketing demo's *Book a live demo* button no longer covers what you are working on.** The button that stays at the
  bottom left of the interactive demo (demo.realizer.io) could sit on the last row of a list, so that row could not be opened.
  It now shows only when the demo bar's own **Book a live demo** cannot be used — the bar has scrolled away, you are on a phone,
  or a request, the viewer or another panel covers it — and whatever it sits over can always be scrolled clear of it: over a
  request or the viewer it moves inside that window's bottom-left corner, above any Save and Cancel buttons.

### Verification

- **Automated tests.** CI run 3339 built the released commit, `bcd82aa15`, and its build and test legs passed. On the reviewed
  commit, `7904c7564` — the released commit differs from it only under `docs/` — the suites passed: API
  (`dotnet test tests/AccessPoint.Api.Tests/`) 22,737 passed, 103 skipped, none failed; publisher 5,975; Training Lab 470;
  demo host 150; shared UI (`heft test --clean` in `src/AccessPoint.Web.UI`) 5,591; SPFx 95; the web host's client 1,061
  (1 skipped); the editors' own tests. The portal (543), document engine (423, 49 skipped), admin console (829), web host (396)
  and connector (453) suites passed on 13 November on the same line of fixes (`6857a13d8`).
- **Functional run.** The core run of 11 – 12 November on the development tenant (`docs/test-runs/2026-11-11-core.md`, gate
  `docs/test-runs/gates/v2.6.0.json`): of the 392 smoke and core checks of `docs/FunctionalTestPlaybook.md`, 390 passed and
  none failed; POR-28 and POR-36, the portal checks that need an e-mailed sign-in code, were accepted without a run while
  Microsoft 365 incident MO1550821 stopped e-mail. The 34 defects the run found (none of severity 1 or 2) are fixed; the
  report records how each was re-checked.
- **Code reviews.** The security review and the bug review of the whole 2.6.0 cycle, from 2.5.0's `da1559a9e`
  (`docs/code-reviews/2026-11-12-security.md`, `docs/code-reviews/2026-11-12-bugs.md`): every finding of severity 1 or 2 is
  fixed, and fresh reviewers read the fixes in the delta reports of 12 and 13 November (`docs/code-reviews/2026-11-12-*-delta*.md`,
  `docs/code-reviews/2026-11-13-*-delta*.md`). Both gates, `docs/code-reviews/gates/v2.6.0-security.json` and
  `docs/code-reviews/gates/v2.6.0-bugs.json`, are bound to `7904c7564`.
- **Accessibility.** The Accessibility Conformance Report's 2.6.0 edition (2026-11-12): the owner's NVDA pass over the 2.6.0
  surfaces and Hosted AccessPoint on the hosted stage, the 320 CSS px reflow pass, axe-core in the demo's Playwright run, and
  the audits `docs/test-runs/2026-11-10-ux-a11y-audit-2.6.0-surfaces.md` and `docs/test-runs/2026-11-10-ux-a11y-audit-hosted.md`.
- **Languages.** The 2.6.0 language sweep (`docs/test-runs/2026-11-10-l10n-sweep-2.6.0.md`); the locale parity check and the
  English-spelling overlay check run in CI.
- **Lab mode.** `TrainingIsolationEndToEndTests` (every new production surface classified), `CastCaseGrantRowsTests` and the
  rest of the training suites green; functional suites TRN and ACA on the development tenant.
- **Hosted AccessPoint.** The hosted stage stamp (`ca.stage-app.realizer.io`) runs this build: hosted CD run 3344 verified the
  signed packages against the pinned release key, released them through the staging slot and a warm swap, and passed its
  smoke checks.
- **Artifact hashes and signatures.** `SHA256SUMS`, `SHA256SUMS.sig` and `cosign.pub` beside the packages, signed with the
  release key pinned in `src/AccessPoint.ReleaseVerification/PublisherReleaseKey.cs` — unchanged since 2.5.0. The media,
  accessibility and document worker images are named by digest (`media-worker.digest`, `accessibility-worker.digest`,
  `document-worker.digest`), signed like the packages.

### Known issues

- **Carried from 2.5.0.** The known issues listed for 2.5.0 below still apply, except where this section's *What's new* or
  *Fixes* says otherwise.
- **An API scaled out to two or more instances can record one audit-ledger entry twice on its first run of 2.6.0** (bug
  review 2026-11-13, B4-1, severity 3; to be fixed in 2.6.1). When 2.6.0 first runs, it stops the automatic move into
  *Deemed refusal* that a jurisdiction pack had set on a request type, and records each such change on the audit ledger. Two
  instances doing this at the same moment can both record the same change; if their two writes interleave, the ledger's
  verification then reports a break for your organization at that entry. It happens at most once per organization and
  changes no request or other record. The templates deploy one instance; if you scaled the API out, run it on one instance
  for the first hour after the upgrade.
- **Hosted AccessPoint: a member let back in can still open the cases of work they finished before** (accepted). Removing a
  member ends their roles, case grants, delegations, Lab-mode grants and open case assignments; finished work stays as
  history, so a member removed and later let back in with no role can still open the cases of that finished work.
- **AccessPoint Learning: quality readings taken at different times** (accepted). A content-quality figure shows its
  filtered readings only when every group they separate holds at least five learners, all of them or none. Two readings taken
  at different times — after learners left a group, or after a learning path was edited — can still be compared, and the
  difference can say more about a small group than either reading does (AccessPoint Learning design §9.8, D21).
- **No penetration test or performance run was recorded for 2.6.0.** Both are optional evidence for a release and were not
  run for this one.
- **Not exercised in the functional run:** a portal sign-in with an e-mailed code (POR-28, POR-36) and the corrected e-mail
  sent for a complaint or concern report made through the portal (DEF-33) — Microsoft 365 incident MO1550821 stopped e-mail
  during the run. Their code is covered by automated tests.
- **Screen-reader evidence.** The rows of the Accessibility Conformance Report that rest on code review and automated tests
  rather than a screen-reader pass say so.
- Small display observations from the functional run (severity 4, not filed as defects) are listed in its report.


---

