diff --git a/doc/share-extension-configuration-audit.md b/doc/share-extension-configuration-audit.md
new file mode 100644
index 00000000..be8526a6
--- /dev/null
+++ b/doc/share-extension-configuration-audit.md
@@ -0,0 +1,188 @@
+# iOS Share Extension Configuration Audit
+
+**Generated:** 2026-06-25 15:33:39 PST
+
+## Scope
+
+Static inspection of the `TimeSafariShareExtension` target configuration to determine the extension entry point, principal view controller, storyboard vs. code-based setup, and whether `ShareViewController.viewDidLoad()` is guaranteed to execute. No code was modified.
+
+### Files Inspected
+
+| File | Role |
+|------|------|
+| `ios/App/App.xcodeproj/project.pbxproj` | Target, build settings, file membership |
+| `ios/App/TimeSafariShareExtension/Info.plist` | NSExtension configuration |
+| `ios/App/TimeSafariShareExtension/ShareViewController.swift` | Principal class implementation |
+| `ios/App/TimeSafariShareExtension/TimeSafariShareExtension.entitlements` | App Group access |
+
+---
+
+## Direct Answers
+
+### 1. What class is configured as the extension entry point?
+
+`ShareViewController`, resolved via `Info.plist` key `NSExtensionPrincipalClass`:
+
+```xml
+NSExtensionPrincipalClass
+$(PRODUCT_MODULE_NAME).ShareViewController
+```
+
+`$(PRODUCT_MODULE_NAME)` resolves to `TimeSafariShareExtension` (derived from `PRODUCT_NAME = $(TARGET_NAME)`), so the runtime entry point is `TimeSafariShareExtension.ShareViewController`.
+
+### 2. Is ShareViewController actually the configured principal view controller?
+
+**Yes.** `ShareViewController.swift` declares:
+
+```swift
+class ShareViewController: UIViewController {
+```
+
+within the `TimeSafariShareExtension` target. The class name, module, and `UIViewController` base class match the `NSExtensionPrincipalClass` reference. There is no competing storyboard-designated initial controller, so `ShareViewController` is unambiguously the principal view controller.
+
+### 3. Is the extension storyboard-based or code-based?
+
+**Code-based.**
+
+- `Info.plist` contains `NSExtensionPrincipalClass` and does **not** contain `NSExtensionMainStoryboard`.
+- The extension folder contains no `.storyboard` file (only `Info.plist`, `ShareViewController.swift`, and the entitlements file).
+- The only storyboards in the project (`Main.storyboard`, `LaunchScreen.storyboard`) belong exclusively to the **App** target's resources, not the extension.
+
+This deviates from the default Xcode Share Extension template (which ships a `MainInterface.storyboard` + `NSExtensionMainStoryboard`). The deviation is intentional and internally consistent.
+
+### 4. Does the configuration guarantee that ShareViewController.viewDidLoad() executes when the extension launches?
+
+**Yes, under normal launch.** Because:
+
+- The principal class is a `UIViewController` subclass, the extension host instantiates it and installs its view into the extension's window. This triggers the standard view lifecycle: `loadView()` → `viewDidLoad()`.
+- `ShareViewController` overrides `viewDidLoad()` and calls `super.viewDidLoad()`, then immediately runs `processAndOpenApp()`. The startup marker (`shareExtensionLastStart`) and `[ShareTarget] viewDidLoad started` log execute before any other logic.
+- The Swift source is compiled into the extension target via the Xcode 16 **file-system synchronized group** (`PBXFileSystemSynchronizedRootGroup` for `TimeSafariShareExtension`), so the class is guaranteed to be present in the built `.appex`.
+
+**Caveats (not failures, but worth noting):**
+- The guarantee holds only if the OS successfully resolves and instantiates the principal class. If `$(PRODUCT_MODULE_NAME)` ever diverges from the actual Swift module name (e.g., a custom `PRODUCT_MODULE_NAME`), runtime class lookup would fail and the extension would not launch. Currently they match.
+- `viewDidLoad()` executing does not, by itself, guarantee the *share* succeeds — the asynchronous `loadItem` work in `processSharedImage` happens after `viewDidLoad` returns.
+
+### 5. Are there any mismatches between Info.plist, storyboard, and ShareViewController?
+
+**No blocking mismatches.** Details:
+
+| Check | Result |
+|-------|--------|
+| `NSExtensionPrincipalClass` ↔ Swift class name | Match (`ShareViewController`) |
+| Principal class module ↔ target module | Match (`TimeSafariShareExtension`) |
+| `NSExtensionMainStoryboard` ↔ storyboard file | Consistent — neither exists (code-based) |
+| Activation rule ↔ implementation | Consistent — `NSExtensionActivationSupportsImageWithMaxCount = 1` matches first-image-only handling |
+| `NSExtensionPointIdentifier` | `com.apple.share-services` (correct for a Share extension) |
+| Source file membership | `ShareViewController.swift` compiled via synchronized group |
+
+See "Observations / Non-Blocking Notes" for environment-specific items.
+
+---
+
+## Detailed Configuration
+
+### NSExtension (Info.plist)
+
+```xml
+NSExtension
+
+ NSExtensionAttributes
+
+ NSExtensionActivationRule
+
+ NSExtensionActivationSupportsImageWithMaxCount
+ 1
+
+
+ NSExtensionPointIdentifier
+ com.apple.share-services
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).ShareViewController
+
+```
+
+| Key | Value | Meaning |
+|-----|-------|---------|
+| `NSExtensionPointIdentifier` | `com.apple.share-services` | Registers as a Share sheet extension |
+| `NSExtensionPrincipalClass` | `$(PRODUCT_MODULE_NAME).ShareViewController` | Code-based entry point |
+| `NSExtensionActivationRule` | `…ImageWithMaxCount = 1` | Activates for shares containing at least one image; processes one |
+| `NSExtensionMainStoryboard` | *absent* | Confirms code-based (no storyboard UI) |
+
+### TimeSafariShareExtension Target (project.pbxproj)
+
+| Attribute | Value |
+|-----------|-------|
+| `isa` | `PBXNativeTarget` |
+| `productType` | `com.apple.product-type.app-extension` |
+| `productReference` | `TimeSafariShareExtension.appex` |
+| `CreatedOnToolsVersion` | `26.1.1` |
+| File membership | `fileSystemSynchronizedGroups` → `TimeSafariShareExtension` (auto-membership) |
+| Sources build phase | Empty explicit list (handled by synchronized group) |
+| `Info.plist` membership | Excepted from synchronized group (`PBXFileSystemSynchronizedBuildFileExceptionSet`) |
+| Embedded into | App target's "Embed Foundation Extensions" copy phase |
+| Target dependency | App target depends on `TimeSafariShareExtension` |
+
+### Extension Build Settings (Debug / Release)
+
+| Setting | Debug | Release |
+|---------|-------|---------|
+| `INFOPLIST_FILE` | `TimeSafariShareExtension/Info.plist` | same |
+| `GENERATE_INFOPLIST_FILE` | `YES` | `YES` |
+| `PRODUCT_NAME` | `$(TARGET_NAME)` → `TimeSafariShareExtension` | same |
+| `PRODUCT_BUNDLE_IDENTIFIER` | `app.trentlarson.timesafari.TimeSafariShareExtension` | `app.timesafari.TimeSafariShareExtension` |
+| `CODE_SIGN_ENTITLEMENTS` | `TimeSafariShareExtension/TimeSafariShareExtension.entitlements` | same |
+| `IPHONEOS_DEPLOYMENT_TARGET` | `14.0` | `14.0` |
+| `DEVELOPMENT_TEAM` | `7XVXYPEQYJ` | `GM3FS5JQPH` |
+| `SWIFT_VERSION` | `5.0` | `5.0` |
+| `SKIP_INSTALL` | `YES` | `YES` |
+
+`PRODUCT_MODULE_NAME` is not overridden, so it defaults to `PRODUCT_NAME` = `TimeSafariShareExtension`, making the principal class resolve to `TimeSafariShareExtension.ShareViewController`.
+
+### ShareViewController Linkage
+
+```swift
+import UIKit
+import UniformTypeIdentifiers
+
+class ShareViewController: UIViewController {
+ ...
+ override func viewDidLoad() {
+ // writes shareExtensionLastStart, logs, then super + processAndOpenApp()
+ }
+}
+```
+
+- Subclass of `UIViewController` → eligible as a code-based principal class.
+- Lives in the `TimeSafariShareExtension` target via the synchronized group.
+- No `@objc(...)` annotation is required because the principal class is referenced with the fully-qualified Swift name (`module.Class`).
+
+### Scene / Lifecycle Configuration
+
+- **No** `UIApplicationSceneManifest` / `UISceneConfigurations` in the extension `Info.plist`.
+- **No** `SceneDelegate` in the extension target.
+- The extension relies entirely on the principal `UIViewController` lifecycle (`viewDidLoad` → `processAndOpenApp` → `processSharedImage` → `completeRequest`).
+- The main app (`AppDelegate`) is a `UIApplicationDelegate` and is unrelated to the extension's lifecycle except via the shared App Group.
+
+### App Group Linkage
+
+`TimeSafariShareExtension.entitlements` grants `group.app.timesafari.share`, matching the App target's entitlement. This is what allows `viewDidLoad()`'s `shareExtensionLastStart` write to be visible to the main app's `getShareExtensionDiagnostics()`.
+
+---
+
+## Observations / Non-Blocking Notes
+
+1. **Config-dependent bundle IDs & teams.** Debug uses `app.trentlarson.timesafari*` with team `7XVXYPEQYJ`; Release uses `app.timesafari*` with team `GM3FS5JQPH`. Within each configuration the extension bundle ID is correctly nested under the app bundle ID. Ensure provisioning profiles for both teams include the App Group capability.
+
+2. **`GENERATE_INFOPLIST_FILE = YES` alongside an explicit `INFOPLIST_FILE`.** Xcode merges auto-generated keys into the supplied `Info.plist`. This is supported and the explicit `NSExtension` block is preserved; no conflict observed.
+
+3. **Deployment target gap.** Extension targets iOS 14.0 while the App target targets iOS 15.5. Valid (an extension may target lower), and not a launch concern.
+
+4. **Principal-class resolution dependency.** The launch guarantee depends on `$(PRODUCT_MODULE_NAME)` matching the compiled module. If `PRODUCT_MODULE_NAME` is later customized or the target renamed without updating expectations, the OS would fail to instantiate `ShareViewController` and `viewDidLoad()` would never run. Currently consistent.
+
+5. **Code-based template divergence.** Since there is no `MainInterface.storyboard`, any future tooling or documentation that assumes the stock storyboard-based Share Extension template will not apply here.
+
+---
+
+## Conclusion
+
+The `TimeSafariShareExtension` is a **code-based** Share extension whose entry point is `ShareViewController` (a `UIViewController` subclass) via `NSExtensionPrincipalClass`. The Info.plist, (absent) storyboard, and Swift implementation are mutually consistent. Under normal extension launch, `ShareViewController.viewDidLoad()` is guaranteed to run, executing the startup marker and the share-processing pipeline. No blocking misconfiguration was found; only environment-specific items (signing identities, principal-class resolution dependency) warrant ongoing attention.