Open Questions
Grouped by who answers, not by priority, so each group can be sent as it stands.
Covers Logged In Experience (15), Identity & Authentication (12), Content pages (4), Universal Finder (6), Identity, Profile & Account (12, both layers), Certifications & eCard (7, both layers), Dive Log (10, both layers), Learning & Course Progress (11) and Engagement (12). Each question names the items it blocks.
IDs are stable. PADI-n needs PADI. SCOPE-n is a product or scope decision for Tashrik and Hetal. INT-n is ours.
PADI — Ralph Lai, Kanikar Phan, Kevin Braun
Thirty-three questions, one of them now answered and kept for the record. The first three are escalations rather than questions: they have been asked before and not answered. PADI-11 and PADI-26 are the cheapest high-value questions in the set — a configuration lookup that unblocks two Q1 identity items, and a schema lookup that decides whether reliable dive-log sync is server-guaranteed or a client-side approximation. PADI-18 remains the most urgent — two items are confirmed for Q1 against pages that do not exist.
PADI-1 · Which of the existing endpoints survive the legacy sunset?
Blocks: every "Existing" verdict in this study — sixteen of them: ten in Logged In Experience, five in Identity & Authentication, one in Content pages.
Ralph and Kanikar, WS 26 — Technical Workshop #3 (2026-03-31): "APIs are undergoing an active transition", "several endpoints are being rebuilt due to the legacy system sunset", existing Postman documentation reflecting "only a subset."
No list of affected endpoints has been shared. Every verdict in this document describes what works today. An unknown subset is being replaced, and the exposure is worst where the app leans hardest — the auth facade, the eCard family, the learning endpoints.
This ranks above everything else. A buildable verdict is only as good as the answer to this.
Partial answer, 18 September 2026 — and it is ours, not PADI's. The PADI Personalised Home — API Reference (OpenAPI 3.1.0, 20 operations) names a target-state API surface for the MyPADI dashboard. Against the SwaggerHub spec analysed in the API inventory §11 it carries 12 operations forward, adds 8, and drops 3.
That is the closest thing to a list this study has. It is not an answer, for three reasons:
- It is Axelerant-authored and self-declared as inferred — the same evidence class as everything else here.
- It covers one screen, so absence from it carries no information. Only presence does.
- Nobody at PADI has said these replace anything. The reference is a design-to-API mapping, not a deprecation notice.
The question to put to PADI is now sharper, and it is a better question than the original: of the 20 operations in that reference, which are the ones you intend the app to use in Q1 2027 — and which of the 34 in our inventory do they retire?
PADI-2 · Is there an aggregate endpoint for the dashboard, and will mobile get it?
Blocks: MYP-01.
Asked in #eng-padi-web on 2026-06-17 — "is a single API being proposed to fetch the diver profile, learning-related info, and club-related data? Also, will it be accessible as a REST API for mobile as well, like the LMS API?" — and never answered. Asked again 2026-07-13. Confirmed absent by the 2026-08-12 component review.
Axelerant owns a BFF layer and can compose. The question is whether PADI is also building one, so the work is not done twice.
PADI-3 · What is the system of record for profile, and does a write propagate to it?
Blocks: MYP-02.
No web front end writes to Salesforce. Every documented write goes to Cognito (PUT /user/update/{email}) or the learning profiles API. Salesforce write-back exists only as unbuilt scope — PADI-68, endpoint listed TBC, owner PADI.
If Salesforce is authoritative, nothing currently writes to it from any client. That is a platform question, not a mobile one.
PADI-4 · Which client and scope do the Cert and Photo endpoints require?
Blocks: MYP-03, MYP-06.
From the live-tested access matrix: "Cert / Photo reject the SSO token (401) — need a different client/scope/key from the API owners."
The current app reaches these with its own client. A unified app minting tokens through the SSO flow may not. This is a small question with a large consequence — it sits under the card's most commit-ready item.
PADI-5 · Does the LMS expose per-course completion percentage over API?
Blocks: MYP-04.
Confirmed absent from every source. GET /v2/courses/{packageId}/details returns "course + status details"; nothing names a percentage or a last-accessed date. It appears only as a requirement in PADI-70, whose acceptance criterion is unmet and which depends on PADI-67 ("API credentials and documentation for LMS", status Pending).
If the answer is no: is the reduced form acceptable — in-progress list with a Continue deep link, no percentage? (See SCOPE-4.)
PADI-6 · Is there an endpoint for membership renewal date, tier and billing history?
Blocks: MYP-05.
Status and entitlements are live-tested. The MyPADI OpenAPI spec's member query on POST /pros/graphql adds renewalStatus, autoRenewEnabled, memberSince, memberStatus and primaryCredentialName — more than this study previously credited.
Renewal date, tier and billing history are named on nothing we have inspected. Verify before asking. pros/graphql is GraphQL and its schema has never been introspected, and the response bodies of /c/club/member/subscription and /c/credentials/{id} were never recorded — any of the three could already carry these fields (the API inventory §12).
Asked directly in #eng-padi-web on 2026-06-23 — "how much data can be exposed through this api like status, tier, renewal date, billing summary?" — unanswered.
PADI-7 · When will the in-app purchase decision be made, and by whom?
Blocks: the purchase half of MYP-05, and PAY-09 in the Commerce card.
Owner is PADI business/legal, point person Kevin Braun. Raised 2026-04-14, escalated 2026-06-03 and again 2026-08-11 ("This is a PADI readout item & PADI team was supposed to get back to us on this"). Still open 2026-09-03.
Five months, no committed date. The ask is a date, not a decision.
PADI-8 · Is there an endpoint returning email-category labels?
Blocks: MYP-07, PREF-02 — quality, not capability.
From the source: "The recipient/preference API returns only numeric preferenceId + status; no endpoint returns the email-category labels or descriptions."
Without it the app hardcodes seven labels and breaks the moment PADI adds a category.
PADI-9 · What system holds consent and privacy records?
Blocks: MYP-09, PREF-03, AUTH-08, AUTH-10, LEGAL-04.
The source is explicit: "Privacy (data export/delete, consent) → Privacy systems not documented." Nothing in any repo, capture or live test serves data export, deletion, consent records, policy versions, or acceptance records.
This is the single most load-bearing gap in the study — five items across three cards rest on it. See SCOPE-13; it should be scoped once as a platform capability, not five times as features.
PADI-10 · What is the system of record for language?
Blocks: PREF-01.
"Language is stored in 3 places — Cognito custom:language, preference communicationLanguage, and profile languageCommunicationPreference — written by different endpoints, so an edit on one platform doesn't propagate."
The source raises it as an open question itself: "can a single write propagate to Cognito + Salesforce + SFMC + LMS?" Until answered, a diver changing language in the app may still receive email in the old one — the exact failure MyPADI promises to fix.
PADI-11 · Is token revocation enabled on the app client, and is the aws.cognito.signin.user.admin scope granted?
Blocks: AUTH-03, AUTH-05 — and it is a settings lookup, not development work.
The app already calls Cognito's own API directly with the user's accessToken — AWSCognitoIdentityProviderService.GetUser at cognito-idp.us-west-2.amazonaws.com (UserAttributeApi.swift:21-27). That makes GlobalSignOut, RevokeToken and ChangePassword reachable by the same proven path, which is why AUTH-03 and AUTH-05 are not gaps.
Both depend on app-client configuration PADI controls:
- Token revocation enabled?
RevokeTokenfails on an app client without it. aws.cognito.signin.user.admingranted?GlobalSignOutandChangePasswordneed it.
Also confirm which app client id the unified app should use — clientId is a field on SignUpRequest, and the idToken's aud must match the target.
Ask this first. Two Q1 items turn on it and the answer costs PADI a console lookup.
PADI-12 · Is POST /password/change live on the auth facade?
Blocks: nothing — AUTH-05 is buildable without it. Affects which route is preferred.
The endpoint appears in the MyPADI inventory on the same auth base as login and refresh, but no mobile app calls it and it is not in the live-tested matrix. If it is live, all auth traffic stays on one host with one error vocabulary, which is preferable to a direct IdP dependency in the client.
PADI-13 · Does POST login return Cognito challenge responses?
Blocks: the MFA portion of AUTH-06.
The facade's login returns a Token (Swapi.kt:31-33). Cognito MFA works by returning a challenge (SMS_MFA, SOFTWARE_TOKEN_MFA) plus a session, which the client answers with RespondToAuthChallenge. If the facade collapses that to a token-or-error, MFA has nowhere to go and either the facade must change or the unified app must call InitiateAuth directly.
The app already handles two adjacent Cognito states — FORCE_CHANGE_PASSWORD and RESET_REQUIRED (UserStatus.swift:22-23) — so some challenge information does survive. Whether that extends to MFA challenges is the question.
PADI-14 · Is there a user-scoped path to the SLO session registry?
Blocks: the cross-property half of AUTH-03.
https://slo.global-prod.padi.com/graphql offers getSession, createSession and deleteSession and is the only cross-PADI logout plumbing in the estate (slo_session_client.dart:6-54). It authenticates with a static x-api-key hardcoded in the client and addresses sessions by Cognito sub — so anyone holding the key can delete any diver's session.
A shipped consumer app cannot embed that key. Is there an idToken-authenticated path, or should the unified app reach this only through a server-side component?
PADI-15 · What is the intended account-deletion mechanism, and who owns cross-system erasure?
Blocks: AUTH-08.
Today the app emails privacy@padi.com asking an operator to "deactivate their SSO, remove them from all marketing communication lists, and send a confirmation email" (EmailTransactServiceImpl.swift:63-90). Cognito DeleteUser would remove the user-pool record only — diver data also sits in Salesforce, SFMC, the LMS, commercetools and Travel, so deleting Cognito alone breaks the erasure guarantee rather than fulfilling it.
A real deletion is an orchestrated flow across every system holding diver data, plus a defined recovery window ("recover account" has no mechanism anywhere). That is PADI-side. See also INT-5 — the current path is defective independently of this decision.
PADI-16 · Does any waiver storage or consent-scoped document sharing exist?
Blocks: AUTH-11.
No waiver, signature, or document-storage endpoint appears in any repo, capture or live test. AUTH-11 needs a signed document stored against a parent account and released to authorised dive centres on consent. If nothing exists, the Low effort estimate is wrong (see INT-6), and the dependency on E12 (Portable Waiver) is the real sequencing constraint.
PADI-17 · What is the mechanism for migrating an identity's records?
Blocks: AUTH-12.
The age-18 transition moves certification and eLearning history from a child profile to a new independent account. AUTH-12's own scope text puts LMS certification records outside Axelerant's scope, so the migration is PADI's to build. Confirm it exists or is planned, and on what timeline — the client's share is only the consent screen and notification.
PADI-18 · Will a Terms of Use and a Cookie Policy exist at the November launch, and at what URLs?
Blocks: LEGAL-02, LEGAL-03 — both marked confirmed for Q1 2027.
Probed live on 2026-09-10. Every candidate path 404s on the main property: www.padi.com/terms, /terms-of-use, /terms-conditions, /legal-notices, /de/terms, and store.padi.com/terms. The only Terms page in the estate is travel.padi.com/terms/ (200) — PADI Adventures, a different property with different commercial terms, and not a substitute.
No cookie policy resolves anywhere (/cookie-policy, /cookies → 404).
So two items are committed for Q1 against documents that do not yet exist. This is a web-side prerequisite, not a mobile estimate — mobile's share is one row in a list each, closable within a day of a URL existing.
Also worth confirming in the same breath: www.padi.com/zh-hans/privacy now returns 200, so is the separate assets.padi.com.cn static-file path still required, or can China consolidate onto the main property? Two documents are currently maintained in two places.
PADI-19 · Will Japanese and Hebrew privacy policies be published?
Blocks: LEGAL-01 localisation — the app ships both languages.
Localised policies are live at www.padi.com/{lang}/privacy for ar, de, es, fr, it, ko, nl, zh-hans (plus pt and th, which the app does not use). ja and he both 404.
The app supports twelve languages (Language.swift:27-38) including Arabic and Hebrew. Ten are already served and simply not requested by the client — that half is our defect to fix. Japanese and Hebrew are PADI's to publish.
Japanese is worth calling out: it is the only language the current app's URL resolver branches on, and it is one of the two with no localised policy.
PADI-20 · ~~Is there a content API for legal and compliance pages?~~ — ANSWERED
Was blocking: a native rendering of LEGAL-04.
Yes. The November 2026 front end reads Drupal over JSON:API at ${BASE_URL}/{locale}/jsonapi/{path} (padi.com/src/shared/services/drupal.ts:19-21). Published content requires no authentication — the only Authorization header is an optional HTTP Basic for Shield-protected non-prod environments.
So it is live, locale-aware and anonymously readable. Any content type the web team models is readable by the unified app, in every Crowdin language, the day it ships — legal pages included.
Kept in the register rather than deleted, because it changes two recommendations: native rendering of legal pages is now an option rather than a blocker (SCOPE-17), and FIND-01/02/03's Drupal content types come with a mobile-readable API for free.
PADI-21 · Is there a policy version identifier and a record of what a diver accepted?
Blocks: LEGAL-04, and it is the same missing platform as PADI-9.
Today nothing records which version of a policy a diver agreed to, when, or in which language. The only consent captured at registration is optIn: Boolean on SignUpRequest. So "which privacy policy version did this diver accept" is unanswerable — which is exactly the question that matters the moment a policy changes and re-acceptance is required.
This makes five items resting on one absent consent platform: MYP-09, PREF-03, AUTH-08, AUTH-10, LEGAL-04. See SCOPE-13.
PADI-22 · Is a shared search index planned across Drupal and Travel?
Blocks: FIND-06, the only real gap on the Universal Finder card.
Cross-object search exists within families but not across them: Diviac's dive-guide/autosuggest/ spans place types, search/shop_autosuggest/* spans shop types, dsl/courses/autosuggest/ covers courses, and Drupal JSON:API serves one content type at a time. Diviac is Elasticsearch-backed; Drupal is not indexed with it.
A universal finder needs one ranked result set across Destinations, Dive Sites, Dive Centres, Courses and content. That is either a shared index PADI builds, or a server-side fan-out with a ranking policy that Axelerant's BFF builds. Ranking heterogeneous sources without a shared index is where these features usually disappoint, so the answer changes the design, not just the estimate.
PADI-23 · Radius search and server-side course/certification filters do not exist.
Blocks: FIND-05 — and this is not an inference, it is a POC result.
The dive-shop locator spike ([PAM-18]) rebuilt the web /dive-shops view in Expo against the live Travel APIs and reached LOCATOR: WORKING. Two things it could not do server-side:
RADIUS SEARCH: OPEN (new API)— the client can hold apoint(device coords + distance), but no endpoint filters by radius. Scope line 3 of FIND-05 asks for exactly this.SERVER-SIDE COURSE/CERT FILTERS: OPEN (new API)— filtering shops by course offered or certification is client-side today, which does not scale to a full directory.
Both are small, well-specified additions to an API that already exists, and both are needed before FIND-05 is more than a map.
PADI-24 · Is there any API for a diver's medical / fitness-to-dive record?
Blocks: the medical third of ID-05.
Nothing models it on mobile — searched medical|fitness_to_dive|rstc|waiver|liability_release across all four apps; no model, no field, no endpoint.
On the web there are two things, and neither is a medical record API:
- TrueVault is a compliance document store (
GET /Search/Diver·/Search/Member·/Search/blob/{id}·/Search/document/{id},POST /Truevault/Data). Its list response carriesmedicalRequiredas a boolean on a generic signed-form record — there is no form-type field at all, andprogramis hardcoded with a// Placeholder for now(learning.padi.com/src/store/modules/forms/actions.js:26). Our own POC reached the same conclusion independently: "there is no real program field on this response. Do not invent one." - Diviac has a real model —
MedicalInformationwithblood_group,allergies,other_conditions,medical_certificate(account/models/setting_models.py:160-178) — but it is not exposed through anytravel_v2serializer, so no client can read it.
So: is the intended home TrueVault (in which case a form-type field is needed), Diviac's model (in which case it needs exposing), or neither?
PADI-25 · Does any PADI system issue an Apple or Google Wallet pass?
Blocks: CERT-05.
Nothing in the estate produces one. Searched pkpass, walletobjects and Google's save link across all eleven web repositories — account.padi.com, club.padi.com, pro.padi.com, learning.padi.com, padi.com, diviac, customer-padi and the Drupal trio. Zero source matches.
The only wallet code anywhere is a consumer: the iOS app intercepts application/vnd.apple.pkpass in its webview and presents PKAddPassesViewController (PDWebViewController+Helpers.swift:72-77, +Delegate.swift:121-136). It can add a pass; it cannot make one.
A client cannot mint a pass. An .pkpass is signed with an Apple-issued Pass Type ID certificate; a Google Wallet object is a signed JWT against an issuer account. Both need PADI-held credentials and a signing service. So the questions are:
- Does such a service exist anywhere PADI has not shown us?
- If not, is PADI prepared to obtain the Apple certificate and Google issuer account, and to run a pass-issuing endpoint?
- Pass updates — a wallet pass is a live object. A renewed, expired or revoked credential needs a push through APNs' pass-update channel. Is that in contemplation, or is a pass a one-time snapshot?
Question 3 is the one that gets missed, and it is the larger half of the build.
PADI-26 · Does logbook_logs expose a version (or ETag) and an idempotency key?
Blocks: LOG-03, and it is the cheapest high-value question in the Dive Log card.
The logbook schema exposes no client_id, no version and no deleted column — only update_date. Our own POC records this in its adapter header and works around it: it uses update_date as a version proxy, recovers a lost-ack create by re-reading to find the row it already made, and guards update and delete by reading the current row before writing.
Its own assessment of that workaround: "this is a read-then-write check with a small TOCTOU window, acceptable for the POC." Server-enforced optimistic concurrency exists only against the POC's mock. On the real backend two devices writing at once can still interleave.
So the sync engine is built and tested; the contract it writes against is a proxy. Three things would close it:
- a monotonic
version(or ETag) onlogbook_logs, returned on read and required on write; - an idempotency key the client can set on create — the POC generates a stable client UUID already;
- delete semantics — hard delete or a tombstone column, and whether the list query supports a changes-since cursor.
Until then, "reliable sync" is reliable to the limit of a client-side check.
PADI-27 · Are these six the complete set of log_course values?
Blocks: the training half of LOG-02. Now a confirmation, not a discovery.
log_course is a server-side enum of PADI course codes, not the free-text course titles the client holds from entitlements — passing a title is rejected with a data exception. This question previously said the values were unknown. They are not: both shipped apps declare them.
iOS — padiww/ios-padi-app PADI/feature/logbook/trainingdivecourses/model/LogBookTrainingCourseType.swift:11-16 |
Android — padiww/android-padi-app app/src/main/java/com/duns/padiapp/domain/BaseAppSettingsIpm.kt:1041-1053 |
|---|---|
Open |
Open |
Advanced |
Advanced |
Rescue |
Rescue |
DSD |
DSD |
Reactivate |
Reactivate |
Specialty/Distinctive |
SpecialtyAndDistinctive |
Five agree, and the sixth is an iOS defect rather than an ambiguity: a GraphQL enum value cannot contain /, and iOS's own read and write paths use SpecialtyAndDistinctive (PADI/model/view/LogBook.swift:260). Only its log-number query sends the malformed one, via TraingDiveCourseViewModel.swift:83.
So the ask is narrow: confirm that these six are the whole enum and that SpecialtyAndDistinctive is the correct sixth. Still a one-line introspection for whoever owns the schema, and it lets the unified app write a field the POC currently holds back.
PADI-28 · Where does dive media live, and does anything else consume logbook content?
Blocks: LOG-09 — and, less obviously, a committed item in another area.
Nothing stores dive photos. No image, media or attachment field on any dive-log model on either platform, no attachment table in the six-table nested insert, and no upload path. The vendor's own KT documentation describes LogbookExperience as holding "Notes, marine life observations, photos, rating"; the shipped model holds feelingType, notes, buddies and diveCenter. Three of those four do not exist.
For contrast, PADI AWARE already models per-survey medias with coordinates — so PADI has built diver-facing media capture, on a different backend.
Ask the second half in the same breath. DEST-01 — a committed item with a full requirement — has scope reading "a 'latest sightings' feed pulled from divers' logbooks" and "pulls the details of the marine life spotted at a destination from the dive logbook of the divers." There is no marine-life field on a dive log either. A committed item depends on logbook content nobody has asked this area to produce, so "where does media live" and "what else reads the logbook" are one question.
PADI-29 · Does PADI accept platform commission on in-app digital goods?
Blocks: CRS-02 — and it is the same decision as PADI-7 and CERT-05.
The current apps have already answered this by avoiding it. Neither app contains any in-app purchase code: iOS imports StoreKit only for the App Store review prompt (padiww/ios-padi-app PADI/data/repository/impl/RatingRepositoryImpl.swift:8,182), Android has no BillingClient in source or Gradle, and neither references Adyen, Stripe or Braintree. Courses are bought by handing off to the external browser — PADI/feature/common/CourseDetailViewController.swift:33-43 into UIApplication.shared.open, and compose/course/CoursesNavigation.kt:69-73 into Intent.ACTION_VIEW. A link-out to a browser sits outside the platform-commission regime entirely.
The moment the unified app puts a native "buy this course" affordance on screen, Apple's and Google's digital-goods rules apply to it. So this is not a checkout-engineering question; the client work behind either answer is small.
Three items now wait on the same decision — CRS-02, CERT-05 and the eCard purchase path disabled at every call site in today's iOS app. Answer it once.
And correct one thing before asking it. PADI does take payment inside an app: diviac/travel-rn (PADI Adventures) has a native Stripe checkout — card tokenisation at app/screens/AddCreditCardScreen.js:53 and app/services/Api.js:226-228, orders at checkout/orders (app/screens/CheckoutScreen.js:597), 3-D Secure through a web view (app/screens/ConfirmCreditCard.js:4,48,51).
That is permitted because Adventures sells trips — real-world services are exempt from Apple's and Google's digital-goods rules. Courses are not exempt. So the Adventures integration is not a precedent for course checkout, and "we already do this in Adventures" is the wrong argument to bring to this decision. What it does establish is that PADI holds a Stripe merchant relationship and has shipped a working native payment UI in React Native. Note also that PAM-72 (In-app purchase — Club, eCard, course bundles) sits at fix version Later - Release 2027 while CRS-02 sits in the Q1 lane.
PADI-30 · Who owns a diver-signed form, and what makes a consumer-app signature legally sufficient?
Blocks: LRN-06. Answer alongside AUTH-11, which is already blocked on PADI Legal.
The capability exists, but only on the instructor's surface. PadiWW/pro.padi.com captures a real touch signature (src/main.js:15,102, src/components/training/FingerSign.vue:1-49) against a full RSTC medical questionnaire (MedicalForm.vue:1-50) and a liability release (NonAgencyForm.vue:1-45). Those are reached from the instructor's flow, where the student signs in the instructor's presence.
What a diver gets today is a PDF. PadiWW/account.padi.com src/lang/translations/en-US.json:99 tells a parent to download the RSTC Medical Statement from apps.padi.com, print it and bring it along. Mobile carries only static prose (padiww/android-padi-app app/src/main/res/values/strings.xml:1075) — no form widgets, no capture, no submission.
So a diver-facing, self-service signing flow does not exist on any PADI surface. Building one needs answers this team cannot give: what binds a signature to an identity, what the minor-consent path is when a parent signs, who stores the executed document, and what evidentiary standard a medical declaration has to meet. The engineering follows from the answers; it does not precede them.
PADI-31 · Is course progress reachable at all — via percentRemaining, progressPercent, or per-section results?
Refines: MYP-04. Replaces the broader check that stood open from Section 1.
The old check was answered too strongly, and is restated here. GET /v2/courses/{packageId}/details — the LMS course-detail call at https://learning-prod.padi.com/learning/v2/courses/{courseId}/details (padiww/ios-padi-app PADI/data/api/impl/LanguageCourses/LanguageCoursesApiImpl.swift:26) — has an iOS decoder (PADI/model/view/OfflineLearning/LanguageCourse.swift:10-29) declaring packageId, hasAnalytics, heroUrl, title, isSampleCourse, dateStarted, status, template, hasLegacy, availableLanguages[]. No percentage, no last-accessed date.
That proves non-consumption, not absence. A Decodable declares only the fields the client uses, so the server may well return more. Three sources now expect progress data to be reachable and none has been observed:
CourseDetails.progressPercent— asserted by the MyPADI Personalised Home API Reference, which declares its own response shapes inferred rather than confirmedUserCourse.percentRemaining(PADI/model/view/OfflineLearning/UserCourse.swift:25) — declared, never read, absent from AndroidAssessmentResult{sectionId, title, isCompleted}fromGET /learning/v2/courses/{customCourseId}/assessmentresults— per-section booleans, from which a percentage is derivable
The third is the most useful, and an earlier draft of this question described it as the least verified — "no client has ever called it". That was wrong, and the correction makes the question easier to answer.
PadiWW/pro.padi.com src/store/modules/course/actions.js:48-70 calls /assessmentresults in production to render the eRecord, branching on affiliateId between the learner's own record and the instructor's view of a student. The accurate statement is narrower: no mobile client calls it, and neither does axelerant-padi/mobile-poc or PadiWW/padi.mobile.app.
That matters because a live web consumer proves the endpoint exists, is reachable with an ordinary user token, and returns a shape a front end can render. What is still unverified is only the response body — the MyPADI reference declares its shapes inferred rather than confirmed, and nobody on this study has made the call.
PADI Engineering said in the 15 September session that section progress is "not determinable"; the same session records that APIs doing it were found and need confirming. Both can be true — PADI does not serve a percentage, and one may be derivable from the per-section booleans its own Pro portal already receives.
But a second model raises a narrower question. PADI/model/view/OfflineLearning/UserCourse.swift:25 — the offline-learning course payload from CultureCourseApi/CourseApi — declares percentRemaining: String? and complete: Int?. Neither is read anywhere in the app, and Android declares no equivalent at all.
A field reaches a Codable model because someone once saw it in a response, so this is a hypothesis worth one live call, not a finding. If the server populates it, MYP-04's reduced form gets easier and the three-state badge is a floor rather than a ceiling. If it does not, the gap closes for good.
PADI-32 · Which push platform does the unified app use?
Blocks: ENG-01 and ENG-05 — and nothing in either moves before it. Also decides SCOPE-48.
Three stacks exist in PADI's own estate and they do not agree.
- The PADI apps use Salesforce Marketing Cloud —
padiww/ios-padi-appPodfile:24(MarketingCloudSDK 9.0.3),padiww/android-padi-appgradle/libs.versions.toml:64(8.1.5). The device token goes straight to the vendor (PADI/data/repository/impl/PushNotificationHandlerImpl.swift:175-178); PADI has no device-registration API of its own. - PADI Adventures uses Firebase Cloud Messaging with a real registry —
diviac/travel-rnapp/containers/App.js:59-84andapp/containers/AuthWrapper.js:34-47, posting{registrationId, name, deviceId}toaccount/devices/(:93). - The unified app has neither. No
expo-notifications, no push code at all.
So a PADI-owned device registry exists — on the Travel realm, behind JWT rather than Bearer. Three answers are possible and they have very different costs: stay on Marketing Cloud and inherit its registry; adopt the Adventures FCM stack and its realm; or have PADI build a first-party registry.
No client-side estimate for ENG-01 means anything until this is settled, because the client's share is small under every answer and the platform's share is not.
PADI-33 · Is Club membership a segmentation attribute in Marketing Cloud, and can we see the configuration?
Blocks: ENG-05.
The audience data is served — GET /c/club/member/subscription, plus renewalStatus and autoRenewEnabled (see MYP-05). Knowing who to notify and when a renewal is due is not the problem.
The problem is that the sending half cannot be inspected. Targeting would be configured in Salesforce Marketing Cloud, and Axelerant has no SFMC access. So the segment structure, the available audience attributes, and whether membership status is synced into SFMC at all are unverifiable from here.
Any estimate produced without this answer covers the app's share only, and silently omits the part that actually sends the message.
SCOPE — Tashrik and Hetal
Product and scope decisions. None needs PADI; all need answering before estimation.
Thirty-seven of the forty-nine items studied arrive with no stated requirement. Only twelve carry substantive scope text:
| Card | Items | With a requirement |
|---|---|---|
| Logged In Experience | 15 | 6 — MYP-01 to MYP-05 and MYP-09 (MYP-11's drawer is an empty stub) |
| Identity & Authentication | 12 | 2 — AUTH-11 and AUTH-12, both items not in Q1 |
| Content pages | 4 | 0 — four items confirmed for Q1 2027, each arriving as a title and a flag |
| Universal Finder | 6 | 4 — FIND-01, 02, 03 and 05 |
| Certifications & eCard | 2 | 0 |
| Dive Log | 10 | 0 — the whole area, both lanes, arrives as titles and flags |
Most of what follows is a consequence of that. The pattern worth noticing: the cards with the firmest Q1 commitments have the thinnest requirements.
SCOPE-1 · Is Purchase History in mobile Q1 scope?
MYP-01 requires it as a dashboard section, but the item that delivers it — PAY-09 — sits in the Commerce and Payments card, IAP-parked. Completing this card in full still does not deliver MYP-01.
The endpoint exists (POST cart/getOrders) but sits in a separate auth realm needing a commercetools session bridge. Worth noting the store's own UI never calls it.
SCOPE-2 · What does "field-level permissions" mean?
In MYP-02's title and nowhere else. No such system exists in any repo or endpoint. Per-field visibility rules would be a substantially larger build than the six scope lines imply.
SCOPE-3 · What is the conflict rule for offline profile edits?
PLT-01 (offline foundation) is committed for Q1. The web requirement says writes are "real time". Both cannot hold, and two devices editing offline need a rule. Last-write-wins, first-write-wins and prompt-the-diver are all defensible and produce different builds.
Genuinely new — created by the unified app, not inherited.
SCOPE-4 · Is a reduced eLearning progress section acceptable?
If PADI-5 comes back negative: in-progress course list with per-lesson status and a Continue deep link, no percentage.
This is no longer a proposal. The eLearning POC built precisely that — a 3-state LessonStatusBadge (not-started / in-progress / complete) rather than a progress bar, because the server serves a status and not a percentage. It is working, with offline playback and progress commit. The question is only whether the reduced form is acceptable to PADI, not whether it can be built.
SCOPE-5 · Is "profile photo" an avatar or the moderated certification photo?
The only photo pipeline is the certification photo — reviewed, rejectable, printed on the eCard. Using it as an avatar means a diver's picture can be rejected by PADI review.
Affects MYP-02 (display) and MYP-06 (upload). Answer once for both.
SCOPE-6 · Are MYP-07 and PREF-02 the same item, or does PREF-02 mean per-channel?
Same endpoints, same area, neither has a drawer. If they are the same, the card is 14 items and the pair is estimated once.
But "contact preferences" may mean channels — email / SMS / push — where "email communication preferences" clearly does not. The preference API serves seven flat categories with no channel dimension, while PADI Adventures already models per-channel flags across five categories. At the channel reading this is not a duplicate and the existing endpoint is the wrong shape.
SCOPE-7 · How wide is "unified login"?
The endpoints exist. The work is that unified login means three auth realms: PADI gateway (idToken), store (commercetools session via a store-client token), Travel (Travel JWT). Tokens expire in 60 minutes and cannot be reused across realms.
Does Q1 include the store and Travel realms, or the PADI gateway only? The difference is a token-broker architecture versus a sign-in screen.
SCOPE-8 · What is a "certification path"?
An ordered prerequisite graph, or a flat next-course list? {PRO_API}/journey/routing/othercourses exists and may serve one but not the other — its name suggests routing, not progression.
SCOPE-9 · Are MYP-10 and MYP-12 the same item?
Technically they are not — MYP-10 resolves to {PRO_API}/journey/routing/othercourses (progression) and MYP-12 to /v2/courses?tag=recommended (recommendation). Different APIs, different builds.
They read as a pair only because the requirement wording overlaps. Merging them would be a product decision to show one surface instead of two, not a recognition that they are the same thing. Ask deliberately rather than letting the resemblance decide it.
SCOPE-10 · Is "personalized" CDP-driven or rules-based?
GET /v2/courses?tag=recommended exists and is already called by a web front end. If that is sufficient, MYP-12 is buildable today. If "personalized" means CDP next-best-action, no endpoint serves it on either platform.
SCOPE-11 · Split AUTH-06 into its five features.
AUTH-06 is "Login using biometrics, passkeys, MFA, magic links and federated login" — five features with three different answers, parked as one item.
| Feature | Needs |
|---|---|
| Biometric unlock | expo-local-authentication over a securely stored refresh token — no API at all |
| MFA | Cognito supports it; depends on PADI-13 |
| Passkeys | PADI configuration, likely hosted UI |
| Magic links | Custom auth flow with Lambda triggers — PADI build |
| Federated login | Hosted UI plus IdP configuration |
Biometric unlock is what divers mean by "log in with Face ID", is cheap, and has no backend dependency. It is currently parked alongside magic links. Recommend splitting it out for Q1 and leaving the rest parked.
SCOPE-12 · Does B2C registration still need the legacy M2 triage?
POST user/exist/legacy returns {m2User, cognitoUser, travelUser, status} — three onboarding paths from one call. Whether the unified app still needs the M2 branch depends on how far the legacy sunset has progressed, which is PADI-1 territory. Affects AUTH-01's flow complexity, not its feasibility.
SCOPE-13 · Scope the five consent items as one platform capability.
MYP-09, PREF-03, AUTH-08, AUTH-10 and LEGAL-04 all resolve to the same missing system: consent capture, policy versioning and acceptance records, privacy records, data export and erasure. The source says "Privacy systems not documented."
Five separate estimates would be five guesses at one unknown. Estimate the platform once and let the five items draw on it. LEGAL-04 is the newest arrival and the clearest illustration: it needs to know which policy version a diver accepted, and nothing records that.
SCOPE-14 · Which trigger model for the age-18 transition?
AUTH-12's own scope asks PADI Legal and Engineering to choose between fully automatic on the 18th birthday, diver-triggered from a notification, or parent-initiated. Three different builds. Post-Q1, so not urgent — but it should be answered before the item is estimated rather than during.
SCOPE-15 · Does B2B account creation belong in the consumer app?
AUTH-13 is post-Q1 and has no drawer. B2B onboarding involves credential verification and commercial terms. Affiliate type is already a first-class Cognito claim (custom:affiliate_type_id) and pro reads are mobile-proven, so pro identity is modelled — but creating a dive centre or resort account from a consumer app flow may be the wrong surface entirely.
SCOPE-16 · Does "Cookie Policy" mean anything on a native app?
LEGAL-03 is confirmed for Q1. Cookies are a browser storage mechanism; a React Native client has no cookie jar in the sense a cookie policy describes.
What the app does owe disclosure for is different: the IDFA and App Tracking Transparency on iOS (the current app already ships a PrivacyInfo.xcprivacy manifest declaring NSPrivacyCollectedDataTypeTracking), the advertising ID and Play Data Safety declaration on Android, and SDK telemetry — where Datadog is initialised with TrackingConsent.GRANTED hardcoded (PadiApplication.kt:318), asserting analytics consent in code rather than asking for it.
Three options, and it should be a decision rather than parity by default:
- Recast the item as a tracking-and-telemetry disclosure, and scope the ATT/Data Safety work explicitly.
- Link whatever cookie policy the web publishes, as one row in the legal list — cheap, and honest enough if the app embeds any webviews (it does).
- Drop it from mobile scope.
The hardcoded tracking consent is the real issue underneath and belongs with the consent platform (PADI-9), not with a cookie page.
SCOPE-17 · Legal pages: webview list, or native rendering from a content API?
- Webview list — a Legal screen where each row opens
www.padi.com/{lang}/{doc}in an in-app browser. Cheap, always current, inherits the web's localisation and its right-to-left handling for Arabic and Hebrew. Loses offline access, which matters becausePLT-01(offline foundation) is committed and divers are routinely offline. - Native rendering — now possible: Drupal JSON:API is live and anonymously readable (PADI-20, answered). Gains offline caching and consistent styling; costs nothing PADI has to build, but the legal pages must first be modelled as Drupal content.
Recommendation: webview list for Q1 with the locale template, and a content API treated as a later improvement rather than a Q1 dependency.
SCOPE-18 · Drupal or Diviac as the source of place data?
Governs four of the six Universal Finder items — FIND-01, 02, 03, 04. Our own POC hit this and left it open as its Q11 CANONICAL BACKEND question.
FIND-01/02/03 are scoped as new Drupal 11 content types (Destination, Dive Site, Dive Centre) with Crowdin translation. Meanwhile a production equivalent already runs on travel.padi.com / Diviac: a Django + Elasticsearch platform with a place hierarchy (continent|region|country|area|location|world), dive-site and dive-centre search, map endpoints, autosuggest and a marine-life service. The PADI app's Dive Shop Locator already links into it.
FIND-01's own scope says "Any travel.padi.com integration is deferred to Phase 2" — without saying why.
Both are defensible. Drupal content is editorial, translated and marketing-owned; Diviac's is operational, indexed and commerce-owned. What is not defensible is leaving it implicit: reading both means reconciling two place taxonomies in the client, which is the outcome nobody wants.
Decide per surface, and state it before any of these four are estimated.
SCOPE-19 · Is the monthly marine-life calendar in scope, and from where?
Named in both FIND-01 and FIND-02 scope text. Diviac has a marine-life/ service (travel_v2/urls.py:35). If the Drupal path is chosen it becomes new editorial content to model and translate; if Diviac, it is a read. Small item, but it swings on SCOPE-18.
SCOPE-20 · Which FIND-03 lines are web-only?
Two of the Dive Centre scope lines do not belong in a native app:
- Salesforce lead capture — routing contact-form enquiries into Salesforce as leads. No Salesforce write path exists from any client (the same finding as PADI-3). If this is mobile scope it needs an endpoint nobody has.
- SEO structured markup — Dive Centre schema for local Google results. Meaningless in a native app. Carrying it as parity is the same category error as the Cookie Policy in LEGAL-03 (SCOPE-16).
Recommend marking both web-only before this item is estimated for mobile.
SCOPE-21 · Confirm the FIND-05 filter set.
Map search, proximity, typed-location autocomplete and tab switching between search types are already implemented in PADI Adventures. The gap is filter breadth: the existing map call carries activity_type, a bounding box and date. Course and price filters exist elsewhere on Diviac; instructor specialty is not evidenced anywhere.
Confirm which filters are actually required — that is the whole remaining scope of this item.
SCOPE-22 · What does "cross-object" mean in FIND-06?
The item the card is named after, and the only true gap on it. Does it mean:
- Places — the existing
dive-guide/autosuggest/already does this; or - Shops and sites — a fan-out over three existing autosuggests; or
- Everything — destinations, sites, centres, courses and editorial content in one ranked result set?
Only reading 3 is a build, and it depends on PADI-22. Readings 1 and 2 are days, not weeks.
SCOPE-23 · Does the unified app adopt Travel's diver-profile model, or does PADI build its own?
Governs three items at once — PROF-01, the gear half of ID-05, and ID-06.
All three resolve to the same structure, and it already exists on PADI Travel:
- diver sizes —
height,weight,shoeSize,wetsuitSize,bcdSizeplus unit fields, written toaccount/preferences/account-detail(travel-rn/app/components/form/ProfileAdvancedInputs.js:172-211) - the same fields server-side in a section diviac names "Equipment info" (
account_profile.py:90-116), atPOST/PUT /account/profile/ - a buddy is the same record — Personal details, Diving experience, Equipment info (
account_buddy.py:21-103) — with full CRUD onaccount/buddies/
The PADI gateway has none of it; the apps' only equipment data is per-dive-log, and suit_type/weight_type are exposure type and subjective weight, not sizes.
The cost of adopting Travel's model is that diver preferences then live in a different auth realm (Travel JWT, not the Cognito idToken) from profile, certifications and membership — so one settings screen pulls the second realm of SCOPE-7 into scope. The cost of building PADI's own is duplicating a working model.
Answer once and three items resolve together.
SCOPE-24 · Can FAM-01 be built before FAM-06?
FAM-01 — "Create a child account linked to an adult account" — is targeted at Q1 and carries SPK. FAM-06, in the same card, is titled "Parent–Child Data Model Fix" and is post-Q1.
The only family primitives that exist today are guardianEmail on SignUpRequest and the custom:guardian_email Cognito claim — enough to email a guardian, not to link two accounts. So the artefact sequences create the thing ahead of fix the model that holds it.
Also note FAM-01 drags in two other gaps: a minor's account needs consent handling (AUTH-10) and a signed waiver (AUTH-11).
SCOPE-25 to SCOPE-29 and PADI-24 concern
ID-01–ID-06, which sit in the artefact's Post Q1 2027 lane. They are listed because they are genuinely open and the evidence is gathered, not because they are Q1 asks. SCOPE-27 is the exception worth reading now — the item it turns on,PLT-01, is committed for Q1, so its design has to anticipate these consumers.
SCOPE-25 · Is onboarding state local, or resumable across devices?
ID-02 is buildable either way, but the two are very different jobs. Local state is client work. Resumable-across-devices needs a server-held "has this diver completed onboarding" flag, and the only precedent in the estate is AWARE's show_initial_pop_up boolean, flipped via PUT /users/profile — on a different backend.
SCOPE-26 · Which surfaces are ungated for a signed-out diver?
ID-03 is POC-proven — ADR 0002 already decided the model ("the Locator is never gated", logged-out tabs push Login rather than blocking), and the gate map is live at mobile-poc/app/(tabs)/_layout.tsx:11-52: ungated Dive Sites, Trips, Dive Log, Certifications, Account; gated Learning and Membership.
That is a defensible first pass, not a ratified product decision. Confirm the list — it is the whole remaining scope of the item.
SCOPE-27 · Are ID-04 and ID-06 just acceptance cases for PLT-01?
Both fail for the same reason: no app has a general-purpose mutation queue. Android drops an offline language write entirely (LanguageScreen.kt:49-68); iOS saves locally and lets the server disagree; Adventures' buddy writes are disabled without connectivity.
The POC's Realm outbox (mobile-poc/src/dive/diveSync.ts:85-145) is conflict-aware and restart-durable but hardcoded to dive-log fields. Generalising it is PLT-01 — "Shared offline foundation (save + sync + conflict handling)" — which is committed for Q1.
Recommend scoping both as consumers of PLT-01 rather than as standalone items, so the queue is built once.
SCOPE-28 · Is a diver's medical record in scope at all?
ID-05 bundles certifications, medical and gear sizes. Certifications and gear are buildable; medical is the only hard gap in the device-side half of this area, and per PADI-24 nothing currently models it.
The honest ceiling today is what the POC already renders: a "Medical Required" chip derived from a boolean. If that is enough, ID-05 is buildable now. If a real fitness-to-dive record is meant, it is a platform build and should be separated from the rest of the item before anyone estimates it.
SCOPE-29 · Are dive buddies for checkout, or for dive logging?
Adventures' buddy roster exists to autofill participant details at checkout (travel-rn/app/containers/DiveBuddies.js:114-118) — which is why a buddy record carries certification data and gear sizes.
A dive-logging buddy roster is a different product intent over the same data, and the PADI apps currently model a buddy as a free-text string on a log entry. Decide the intent before the model, because it changes whether ID-06 and the logbook's buddies field should converge.
SCOPE-30 · For CERT-01, does "offline access" mean every card automatically, or cards the diver downloads?
The two implementations that exist disagree, and both are defensible.
- The current iOS app is opt-in. There is a Download eCard control on the detail screen (
ECardDetailV2ViewController.swift:18-19) and the repository speaks of "downloaded" cards throughout (DatabaseRepository.swift:24-42). Offline availability is something the diver arranges in advance. - The POC is automatic.
padi-cert-offline-poccaches every card on launch and on reconnect, and guarantees the cache survives a failed pull.
Opt-in is less storage and fewer surprises; automatic is the only version that helps a diver who did not think to prepare — which is the case the feature exists for. CERT-01 is flagged Now, so this needs answering before Q1 estimation, not during it.
SCOPE-31 · Is the eCard a product PADI sells, or an artefact issued with the certification?
Somebody has already hit this. The eCard purchase path in the current iOS app is built and deliberately switched off: the link-out to Constant.ECardBuyCertUrl (WebViewInputType.swift:130) is commented out at every call site (ECardsViewControllerV2+Delegate.swift:26-31, CertificationDetailViewController.swift:47-52, ECardDetailV2ViewController+Actions.swift:52, AllECardsListViewController.swift:361-363), and the button is hidden even where it is still added (ECardDetailV2ViewController+SetUp.swift:165-171).
Disabling a working flow rather than deleting it is the signature of a store-policy problem — the same one PADI-7 has left open since April.
The answer decides whether CERT-05 is a feature or a purchasable item, and whether a wallet pass is issued free with a credential or sold. It cannot be settled inside mobile scope.
SCOPE-32 · Who owns instructor verification — the unified app, or PADI Training?
Blocks: LOG-04, and it reshapes PRO-01.
The two shipping apps now disagree. iOS has removed in-app verification: LogbookSubmitVerifyViewModel no longer submits anything and its only action deep-links to the separate PADI Training app, with the file header still carrying its previous name. Android still implements it in-app — manual instructor-number entry and QR scan, both wired to a submit action.
Disabling a working flow rather than deleting it is usually deliberate. If verification is migrating to PADI Training, LOG-04 shrinks to almost nothing and PRO-01 (the instructor's side) changes shape entirely. If it is not, iOS has a regression.
Related and worth fixing either way: there is no verification audit trail. The log records an instructor member number and nothing else — no verifier identity beyond the number, no timestamp, no method. The KT documentation describes a record with an email, a date and a verification method; no such record exists in code. For a training record that feeds certification, that is thin.
SCOPE-33 · One key strategy for training and recreational dives.
Blocks: LOG-02, and it is a sync correctness question rather than a UI one.
The current apps reconcile the two dive types on different keys — training on log_number, recreational on log_id. Our POC records that this "is unconfirmed at the schema level, so the POC models it as a single tag on one shared log shape."
Two reconciliation keys on one table is how duplicate rows and lost edits happen. The unified app needs one strategy, decided before the sync engine is wired to the real backend rather than after.
SCOPE-34 · Is the Dive Log area committed for Q1 2027, or is it parked?
Blocks: estimating any of it — and it is a question about the records, not the engineering.
The scope artefact flags all ten dive-log items PRK or PQ1. Not one is Now, none has a Jira id, an epic, an Impact, an Effort or a detail drawer.
Everything else says the opposite:
- Jira carries epic
PAM-8Dive Log at fix version Q1 - Release 2027, withPAM-28,PAM-29,PAM-51,PAM-68andPAM-77open against the same release. - Two feasibility spikes are Done —
PAM-16Offline logging + conflict-safe sync andPAM-20Offline-first data layer. - The unified app has already built the encrypted dive store (
PAM-113,PAM-114). - Area 04 Pro is parked "until the dive log capability document is finalised."
Whatever the answer, the artefact and the backlog should be made to agree before anyone estimates — a parked area with a funded epic and production code is a reporting problem that will surface as a scope dispute later.
SCOPE-35 · What is "Course Tile Enrichment"?
Blocks: CRS-01, which is otherwise the most de-risked item in its area.
The catalogue itself is settled: native lists on both platforms and the web storefront all query one commercetools backend (padiww/ios-padi-app PADI/data/api/impl/CourseCatalogueServiceImpl.swift:144; padiww/android-padi-app app/src/main/java/com/duns/padiapp/data/api/NewCourseApi.kt:9-18; PadiWW/customer-padi packages/frontend/backend/commerce-commercetools/actionControllers/ProductController.ts:45-46). Rebuilding a list against a known contract is ordinary work.
"Enrichment" is the entire delta and it has no definition. Which fields, and — the part that decides the cost — whether commercetools already carries them. If the enrichment is price, title and imagery, this is nearly free. If it is ratings, live availability or instructor proximity, it stops being a catalogue item and becomes an integration with whatever system owns those.
SCOPE-36 · Does CRS-03 mean Discover Scuba Diving, or a PADI Scuba Diver on-ramp?
Blocks: CRS-03.
Everything built today is DSD: deep-link entry (padiww/ios-padi-app PADI/data/repository/impl/FirebaseDynamicLinkRespositoryImpl.swift:142,216-230), a native affiliation API (PADI/data/api/impl/LearnAPIImpl.swift:20-30), an in-app web view to learning.padi.com/dsd (PADI/application/Constant/Constant.swift:194), Android parity (PadiApplication.kt:149-171), and the same CheckPoint backend behind the web page (PadiWW/learning.padi.com src/store/modules/checkpoint/actions.js:4-8,20-24,46-50).
But PADI Scuba Diver is a certification level and Discover Scuba Diving is not a certification at all. If the item means DSD, it is nearly free. If it means a genuine Scuba Diver enrolment on-ramp, the affiliation plumbing transfers and the enrolment and payment path does not — which lands it straight back on CRS-02 and PADI-29.
SCOPE-37 · What does "native" mean in LRN-01?
Blocks: LRN-01. No estimate for this item means anything until this is settled.
Today there are two eLearning experiences in the same app. Online is a remote web view into PADI's own Vue app (padiww/ios-padi-app PADI/feature/learn/LearnViewController.swift:80,108; padiww/android-padi-app compose/learn/LearnScreen.kt:94-114). Offline has a genuinely native shell — a full UIKit tree under PADI/feature/offlineLearning/, and Compose screens at compose/elearning/ELearningNavigation.kt:18,26-105 — but the course content still renders in a local-file web view (SCORM Reader/SCORMReader.swift:11-41; PersistentWebView.kt).
Reading A — in-app rather than link-out. Already true offline on both platforms and re-proven in Expo by the POC. Modest work.
Reading B — natively rendered rather than web view. SCORM is an HTML-and-JavaScript packaging standard; rendering it without a web view means replacing SCORM as the content format or writing a native runtime for it. This exists nowhere at PADI, including the web — PadiWW/learning.padi.com src/components/training/PadiCourse.vue:160-184 simply calls window.open.
The two readings differ by an order of magnitude.
SCOPE-38 · What is the storage eviction policy for downloaded courses?
Blocks: nothing — but it is unbuilt work inside a committed item, LRN-02.
Download itself is settled: shipping on both platforms (padiww/ios-padi-app PADI/data/api/impl/AssetsApiImpl.swift:32-290; padiww/android-padi-app compose/elearning/DownloadManagerViewModel.kt:1-121) and re-proven in React Native by the POC, which records pause/resume working.
What nobody has built is what happens when the device fills up. The POC states it plainly: EVICTION POLICY: NOT IMPLEMENTED (axelerant-padi/mobile-poc docs/elearning-poc-features.md:304-310). Course packages are large. A policy is needed — least-recently-used, completed-courses-first, or never-without-asking — and each implies different UI.
SCOPE-39 · Was dropping the always-available offline tier intended?
Affects: how LRN-02 is described at readout.
The artefact's LRN-02 names the on-demand tier specifically, and PAM-34 (On-Demand Download Tier) is at Q1 - Release 2027. Its sibling PAM-33 (Always-Available Tier, Auto-Cached) has no fix version at all.
PAM-33 describes what that removes: "outlines, quiz questions, knowledge-review text, and safety checklists… automatically downloaded when I enroll… without taking any extra action." That is the tier a diver gets without knowing to ask for it.
The artefact and the backlog agree only because the second tier has fallen out of both. "Offline eLearning is in Q1" will be heard as covering both, so either restore PAM-33 or say explicitly that auto-caching is out.
SCOPE-40 · What is the conflict policy for learning progress?
Blocks: the second half of LRN-03 — the half named in its title.
The sync half ships. Both platforms commit to POST /learning/lms/commit on api.padi.com (padiww/ios-padi-app PADI/data/service/AutoSyncDataService.swift:101-103; padiww/android-padi-app app/src/main/java/com/duns/padiapp/data/api/PADIApi.kt:9-13) with a durable queue and retry (AutoSyncDataService.swift:32-155; SyncAllWorker.kt:14-40).
The conflict half does not exist anywhere. Android's OnConflictStrategy.REPLACE (ActivityDao.kt:15) is a database primary-key rule, not a business policy about whose progress wins. The POC is explicit (docs/elearning-poc-features.md:312-322): two-device merge NOT PROVEN, "last-writer-wins on drain order… KD7 has no server status at all… two devices genuinely diverge with no merge point."
Last-writer-wins, highest-progress-wins and per-lesson merge have materially different costs, and only the first is free. This feeds PLT-01 with a different write shape from the dive log's — see 18-learning-course-progress.md.
SCOPE-41 · Does the app carry any of the access-code issuing side, or only redemption?
Blocks: scoping LRN-05, though not its feasibility.
Redemption is well served and already called by a web front end — PadiWW/learning.padi.com src/store/modules/redemption/actions.js covers listing unredeemed codes (:4-6), redeeming (:75-77), specialty redemption (:119-124), direct enrolment (:162-176) and sharing (:178-201).
Issuing is a different surface. PadiWW/pro.padi.com src/api/smp/code.js:49-56 assigns a code to a PADI ID and SKU, with resend at :4-15 and unassign at :35-44. That is an instructor and dive-centre action. If LRN-05 is redemption only, it is ordinary work; if it includes issuing, it pulls Pro workflows into a consumer app and belongs with FAM-08.
SCOPE-42 · Is LRN-07 the diver's read-only view or the instructor's authoring surface?
Blocks: LRN-07.
eRecord and Performance are first-class surfaces on PadiWW/pro.padi.com (src/components/training/PadiERecord.vue:1-60, PadiPerformance.vue:1-20, src/components/smp/AssignedCourse.ViewERecord.vue), and the string "eRecord" appears nowhere in either mobile app.
A diver-facing read-only view is tractable and useful — and the app already produces part of the record, since SCORM completion syncs from both apps into the knowledge-development half. The write side is an instructor attesting that a skill was performed, which is not a consumer action.
One trap. The mobile apps have a training-dive logbook with skills and instructor verification against logbook.global-prod.padi.com. It is a different system from the Pro eRecord — different backend, different model, different owner. Conflating the two produces an estimate for neither.
SCOPE-43 · Which communication channels does PADI commit to platform-wide?
Blocks: COMM-01, and ENG-02 cannot be written without it.
Email works. Push works, on two incompatible stacks (PADI-32). SMS has never been observed sending anything.
diviac/travel-rn app/components/form/NotificationsPreferencesForm.js offers an SMS column across all five preference categories, so the Adventures model stores an SMS flag. But searching all five PADI web repositories and both PADI mobile apps for a sending integration returns nothing — the only sms matches are Apple Developer 2FA references in fastlane/Fastfile.
A checkbox is not a channel. ENG-02 is a policy arbitrating between channels; it cannot be written until it is known how many there are.
SCOPE-44 · Adopt the Adventures preference model, or extend PADI's preference centre?
Blocks: ENG-03.
PADI's preference centre has no channel dimension at all. The same API is called from three web front ends (PadiWW/account.padi.com src/api/auth/index.js:35-57, PadiWW/learning.padi.com src/store/modules/auth/actions.js:259,289,317, PadiWW/pro.padi.com src/store/modules/auth/actions.js:274,310,335-337) and the payload is a flat set of interest topics — padiCommunications, environmentConservation, diveAbroad, events, localDiving, diveCentricTrips, thirdParty, communicationLanguage. Every label reads "email me…".
Adventures has exactly the model the item describes — a 5 categories × 3 channels matrix at /account/preferences/notification/ (diviac/travel-rn app/components/form/NotificationsPreferencesForm.js:200).
So this is not re-plumbing an existing field; it is new work either way. The choice is whether to inherit a working model along with the Travel realm, or to add a channel dimension to PADI's own.
SCOPE-45 · Does the transactional / marketing split move into the data model?
Affects: ENG-03, and it is a correctness question rather than a preference one.
Some PADI communications are non-optional — training bulletins, quality-management notices, renewal notifications. Today that is encoded as static markup: PadiWW/pro.padi.com src/components/preferences/ProPreferences.vue:8-24 renders them as checked items with no toggle. Nothing in the data model marks a topic transactional.
A second client re-implementing that list from scratch will eventually disagree with the first. Worse, on web consent and preference share one payload — thirdParty (consent to share data with partners) sits beside marketing topics in the same flat object (src/components/preferences/DiverPreferences.vue:69-92), while mobile keeps legal consent separate (p/personalization/api/Personalization/attributes/{key}).
Whichever model the unified app adopts, it inherits one of those two positions. This bears directly on MYP-09 and PREF-03.
SCOPE-46 · Are reminders local, or server-scheduled?
Blocks: ENG-04 — and the two answers are different items.
Nothing schedules anything, on any surface. No UNCalendarNotificationTrigger in padiww/ios-padi-app; no AlarmManager or notification-posting WorkManager job in padiww/android-padi-app; and no localNotificationSchedule in diviac/travel-rn either — its one localNotification call renders a foreground FCM message (app/containers/App.js:99-107), it does not schedule a future one.
The triggers that exist are event-driven, not date-driven. Adventures notifies on "bookings, vouchers and cancellations" and "cart activity, payment, reviews, referrals" — things that happen. A reminder fires because a date is approaching.
| Approach | Where it runs | What it needs |
|---|---|---|
| Local, from cached data | The device | Nothing from PADI. Works offline. |
| Server-scheduled campaign | PADI | A service that knows every diver's trip and dive dates. Not observed anywhere. |
13-post-q1-certifications-ecard.md reached the identical fork for certification-expiry reminders. The local form should be offered explicitly, because it is cheap and unblocked.
SCOPE-47 · Is ENG-07 a social feature, or notifications over someone else's buddy model?
Blocks: ENG-07, and the answer changes its size by an order of magnitude.
A buddy is not an entity. On both platforms it is a single free-text string on a dive-log entry — padiww/ios-padi-app PADI/model/view/LogbookExperience.swift:44-57 and padiww/android-padi-app compose/logbook/createlogbook/CreateLogbookViewModel.kt:216. No buddy list, no connection model, no linkage between a typed name and a PADI account, anywhere in the estate.
A typed name is not a person, so there is nobody to notify. Delivering this means building identity resolution, an invitation or confirmation flow, a relationship store and privacy rules — and then a notification, which is the smallest part.
The lane disagreement is sharpest here: the artefact places it in Q1 2027, PAM-50 sits at Later - Release 2027. The backlog looks right.
SCOPE-48 · Which in-app inbox does PAM-49 build on?
Blocks: PAM-49, which is funded for Q1 and appears in no feasibility sub-task. Answer together with PADI-32.
The artefact's area blurb promises "push as a channel and the in-app inbox", and no ENG- item is the inbox — ENG-06 is missing and the capability is missing with it. Jira funds it anyway.
It is not greenfield. Three implementations exist:
| Implementation | Where | Evidence |
|---|---|---|
| AWS AppSync GraphQL — query, mark-read, delete, live subscriptions | PadiWW/learning.padi.com, PadiWW/pro.padi.com |
src/components/notification/GlobalNotification.vue; schema at PadiWW/pro.padi.com src/graphql/header/index.js:3-49 |
| Paginated REST message list | diviac/travel-rn |
app/screens/NotificationsScreen.js:83-84 — GET account/messages/ |
| Salesforce MobilePush inbox — deliberately disabled | padiww/ios-padi-app |
PADI/data/repository/impl/PushNotificationHandlerImpl.swift:32 — let inbox = false |
Answering this separately from PADI-32 would produce an app whose notifications and notification history live in different systems.
SCOPE-49 · Who owns the training-dive curriculum?
Blocks: nothing. Shapes: LOG-02, and every future curriculum change.
The logbook server stores log_course and log_number. It does not store what they mean. The names of the training dives, which dives belong to which course, and the skills required on each are hardcoded in the client — in all three of them:
| Client | Where |
|---|---|
| Android | padiww/android-padi-app app/src/main/java/com/duns/padiapp/domain/BaseAppSettingsIpm.kt — six courses, their dives, and each dive's required and checkable skills; names at app/src/main/res/values/strings.xml:1216-1241 |
| iOS | padiww/ios-padi-app PADI/feature/logbook/trainingdivecourses/model/TrainingDiveCourse.swift:11-70 — a 13-case enum with the same names and the same logNumber mapping |
| The POC | axelerant-padi/mobile-poc src/dive/trainingCatalogue.ts — the same pattern, and it says so at :76 |
This is not recorded as a gap, because it is the established design and no client has ever had an API for it. But it has a cost worth stating once: a curriculum change today requires an app release on every platform, and three copies can drift — which is exactly what has happened, since the POC's bundled list is already a different curriculum from the shipped apps'.
And it carries a hard build requirement regardless of the answer. Training dives reconcile on log_number, and the shipped apps bind 1–13 to specific dive names. The unified app must adopt that mapping, or a diver's existing training dives render under the wrong names after migration.
INT — Axelerant internal
INT-1 · MYP-09 is estimated Low impact / Low effort. Challenge it.
It describes cross-system consent orchestration across Salesforce and Marketing Cloud. The systems it would orchestrate are documented as "not documented". Flag before it reaches a commitment.
INT-2 · Manual account deletion is a compliance exposure
The current app emails privacy@padi.com asking an operator to deactivate the account by hand. Whatever is decided about PREF-03's scope, a manual step in a GDPR deletion path is worth raising on its own.
INT-3 · Security findings in the client repos
Committed secrets across kms-android-padi, kms-ios-padi and travel-rn — Marketing Cloud tokens, release keystore passwords, inline OAuth2 and Cloudinary credentials, real Cognito JWTs in an iOS test fixture — plus session tokens in plaintext storage.
Separately: prefapi.scubadiving.com was verified in #eng-padi-web (2026-08-17) to accept calls "without credentials and without IP restrictions".
And the most severe of the set, found 2026-09-10 while formalising the endpoint spec (the API inventory §11): the SwaggerHub spec's login operation carries two working-looking credential pairs in its request examples — usernames with plaintext passwords, one of them a @padi.com account — plus two Cognito clientId values. The spec is publicly readable: it was retrieved over plain HTTPS with no authentication and no API key. Anyone who finds the org has those credentials.
That one is not a repo-hygiene issue and not a scope finding. It is an active exposure on a third-party host, and it is the item to lead with.
Building a new app does not retire any of this. Route to Tashrik, then to PADI in writing, on its own timeline rather than attached to a scope readout. Credentials are deliberately not reproduced in any of these documents.
INT-4 · No PADI-authored API contract exists
Every endpoint in this study is Axelerant discovery — browser capture or live testing. Documentation was requested 2026-04-24 and again 2026-07-13.
The SOW assumes otherwise: "the APIs necessary for the unified mobile application shall be provided, stable, and adequately documented by PADI." That assumption is unmet, and it is a contractual position worth stating deliberately rather than absorbing.
INT-5 · The account-deletion path is defective in production
Three faults in one code path (EmailTransactServiceImpl.swift:35-90), and it is a GDPR erasure flow:
- A manual step in an erasure path — deletion depends on a human reading an email.
- Admin client credentials hardcoded in source — client id and secret inline at lines 35-36, exchanged via an
oauth2/tokenclient-credentials grant. - Staging hosts in release code —
api-stage.global-np.padi.comandmessaging-stage.global-np.padi.com. Production deletion requests go through staging messaging. This is a functional bug, not only hygiene.
Fault 3 is worth a ticket today regardless of what happens to AUTH-08. Faults 1 and 2 belong with INT-3.
INT-6 · AUTH-11 is estimated High impact / Low effort. Challenge it.
"Low effort" would be fair for a signing UI over an existing document service. There is no document service, no signature capture, no consent-scoped sharing model, and no family-linking data model — and PADI Legal sign-off is a stated non-negotiable prerequisite.
Same pattern as INT-1 on MYP-09: a low-effort label on a capability whose substrate does not exist. Flag before it reaches a commitment.
INT-7 · Legal text is compiled into the app, and the consent links are dead
Three defects in the current apps' legal handling. None is a scope question; all three are worth tickets whatever happens to the Content pages card.
- The consent copy links nowhere.
strings.xml:637reads "By creating a PADI account, you are agreeing to our<a href="#">Privacy Policy.</a>"— andstrings.xml:1152, the China PIPL agreement, uses the samehref="#"placeholder. A diver is asked to agree to a policy behind a dead link, at the moment of account creation. The most raiseable defect in the card. - ~4,000 words of legal text are compiled into the binary.
strings.xml:1074(padi_term_condition) holds the eLearning parent/guardian Terms and Conditions — COPPA language, an acceptance clause, the lot — as one Android string resource. Changing a word requires an app release and store review. For a document PADI Legal owns, that is the wrong medium. - The privacy URL is hardcoded English. Ten of the app's twelve languages already have a localised policy live on the web (PADI-19); the app requests none of them. The URL is a template and the client ignores it.
Fix 1 before anything else. Fix 3 as part of LEGAL-01, which is buildable now. Fix 2 by moving the document to the web and linking it, which is the same change LEGAL-04 needs anyway.
INT-8 · The full PADI instructor roster ships inside both app binaries
Both current apps carry the entire PADI instructor directory — member number, first name, last name — bundled in the application package and unpacked to unencrypted local storage on first run. On iOS it is a zipped resource expanding to an ~81 MB JSON under Documents/; on Android a ~14.9 MB CSV parsed into a Room database with no SQLCipher.
It is there to make LOG-04's instructor lookup work offline, which is a legitimate requirement. The delivery mechanism is the problem: every installed copy of the app contains the roster, extractable from the package without running the app.
Our own POC independently found the ceiling from the engineering side — holding the replacement set in memory "at the native apps' ~678k rows … risks OOM / a UI freeze" — and names the production-safe design as bounded, disk-backed, generation-tagged paging.
The unified app must not reproduce this. Route the exposure the same way as the other security findings — Tashrik first, then PADI in writing, on its own timeline rather than attached to a scope readout. The engineering constraint (the approach does not scale) is stated in the Dive Log card; the data-exposure framing is held here.
INT-9 · Android's dive-log sync fails silently and can discard an instructor's verification
Two defects in one worker, both independent of any scope decision, both worth a ticket now.
- Every failure is swallowed.
SyncLogbookDataWorkerwraps its whole run incatch (ex: Exception) { //do nothing }and then returnsResult.success()unconditionally. No retry, no backoff, no telemetry — a failed sync is invisible to the diver and to us, and only recovers when something else happens to re-enqueue the worker. - A verification can be dropped. If the local row has an unsynced edit, the server row is not applied — so a dive an instructor has just marked
Verifiedcan sit atpendingon the diver's phone indefinitely. iOS handles exactly this case, giving the server priority when it carries a verification outcome. Two apps on one backend with different merge semantics.
Both are fixed by construction in the POC's engine, so they are arguments for the rebuild rather than work to carry across. Raise 1 regardless — a silent-failure sync path in the feature divers already complain about losing data is the wrong combination.