<feed xmlns='http://www.w3.org/2005/Atom'>
<title>domain-dig.git, branch v4.8.2</title>
<subtitle>local-first ios domain inspection toolkit. dns, tls, rdap, audit.
</subtitle>
<id>http://git.krz.sh/krz/domain-dig.git/atom?h=v4.8.2</id>
<link rel='self' href='http://git.krz.sh/krz/domain-dig.git/atom?h=v4.8.2'/>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/'/>
<updated>2026-07-20T20:54:10+00:00</updated>
<entry>
<title>v4.8.2: Bump version and mark shipped in roadmap</title>
<updated>2026-07-20T20:54:10+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:54:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=28f6ed976a3397e794371e5587c85e5207c62b63'/>
<id>urn:sha1:28f6ed976a3397e794371e5587c85e5207c62b63</id>
<content type='text'>
Bump AppVersion/marketing version to 4.8.2 and build number to 42 across the
app, widget, and share extension targets. Mark v4.8.2 (delivery visibility for
disabled integrations, forced queue retries, unreachable-domain reporting,
Swift 6 concurrency warnings, synced StoreKit configuration) shipped in
RELEASE_ROADMAP.md and record the UAT follow-ups as resolved.
</content>
</entry>
<entry>
<title>fix: report unreachable domains instead of 'No meaningful changes'</title>
<updated>2026-07-20T20:52:46+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:33:50+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=7b880ea410f37a7df22594ed9b268448621db4d8'/>
<id>urn:sha1:7b880ea410f37a7df22594ed9b268448621db4d8</id>
<content type='text'>
Closes #10.

resolvedSnapshotAfterFallback replaces a failed lookup's snapshot with
the previous one, so alertDescriptor compared the old snapshot against
itself, found matching hashes, and the run reported 'No meaningful
changes' for a domain that was never actually reached. Nothing in the
UI or the monitoring log distinguished that from a genuine no-change.

MonitoringDomainResult now carries unreachableReason, set when the
fallback fires. It is Optional so already-persisted monitoring logs
still decode. The run summary reads 'Could not check — kept the previous
result' with the underlying error, and monitoringEvents emits a warning-
severity monitoringFailure so configured integrations hear about it
rather than seeing silence.
</content>
</entry>
<entry>
<title>fix: make disabled targets and forced queue processing visible</title>
<updated>2026-07-20T20:52:42+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:31:51+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=8b661d9f36381ee432ece5e77a17d5ae6357d327'/>
<id>urn:sha1:8b661d9f36381ee432ece5e77a17d5ae6357d327</id>
<content type='text'>
Closes #8, closes #9.

enqueue(events:) filtered to enabled targets before writing any
DeliveryRecord, so events routed to a disabled integration disappeared
with nothing in the Delivery Log. Disabled targets now record a .skipped
entry with a reason, matching how filter mismatches are already surfaced.

sendTest bypassed the isEnabled check entirely, so a test event
delivered against a target that silently dropped every real event —
exactly the wrong signal when someone is verifying their setup. It now
skips with the same reason.

processQueueNow only restarted the processing task; it never moved
nextAttemptAt, so an item in retry backoff stayed undue and the fresh
task went straight back to sleep. Backoff reaches an hour, so the button
appeared inert for the one case it exists to handle. It now pulls every
queued item forward, and reports when the queue is empty instead of
returning silently.
</content>
</entry>
<entry>
<title>chore: rename StoreKit configuration to SyncedProducts.storekit</title>
<updated>2026-07-20T20:52:38+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:47:24+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=d9bd61cc745b3f1d6ff481fd300abf3216d07d48'/>
<id>urn:sha1:d9bd61cc745b3f1d6ff481fd300abf3216d07d48</id>
<content type='text'>
DomainDig.storekit sat beside the DomainDig/ source folder, and Xcode
treated the two as conflicting when creating the synced configuration —
the resulting confirmation dialog offered to replace the folder. Naming
the file SyncedProducts.storekit removes the collision entirely and
matches the convention Xcode uses for synced configurations elsewhere.

Updates the project file reference and the scheme's
StoreKitConfigurationFileReference to match.
</content>
</entry>
<entry>
<title>chore: adopt synced StoreKit configuration</title>
<updated>2026-07-20T20:52:38+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:44:36+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=aeb671a8152c51c710f82d07cddc8f50c49f39d2'/>
<id>urn:sha1:aeb671a8152c51c710f82d07cddc8f50c49f39d2</id>
<content type='text'>
Xcode synced DomainDig.storekit against App Store Connect, replacing the
hand-authored placeholders with real values: the app's internal ID
(6760368004), the real subscription group ID (22051301), a synchronized
timestamp, and group localizations.

Also registers the file in the project so Xcode can find and re-sync it,
but without target membership. Xcode's default added it to the Resources
build phase of all three targets, which would ship the test configuration
inside the app, widget, and share extension bundles. The scheme
references it by path for the Run action; it does not need bundling.
</content>
</entry>
<entry>
<title>fix: correct StoreKit configuration file format</title>
<updated>2026-07-20T20:52:38+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:36:52+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=4da7adabc63876fb5f38b93af9b6466f47d974e8'/>
<id>urn:sha1:4da7adabc63876fb5f38b93af9b6466f47d974e8</id>
<content type='text'>
Compared against a known-good Xcode-generated configuration
(hutch/SyncedProducts.storekit) and corrected the hand-authored file:

- version bumped 4.0 -&gt; 5.0, the format Xcode 26 writes
- added the appPolicies block Xcode always emits
- added the missing settings keys (_askToBuyEnabled,
  _billingGracePeriodEnabled, _billingIssuesEnabled, _disableDialogs,
  _renewalBillingIssuesEnabled, _timeRate)
- _developerTeamID set to ZCNAX3VL9D, matching DEVELOPMENT_TEAM in the
  project rather than being left empty
- _applicationInternalID cleared. It previously held 6763610682, which
  is the Apple ID of the Pro+ (Annually) subscription, not the app's
  internal ID. That value is now on the subscription's internalID where
  it belongs; the app ID is left empty rather than wrong.
</content>
</entry>
<entry>
<title>fix: StoreKit config path and Swift 6 concurrency warnings</title>
<updated>2026-07-20T20:52:38+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:29:50+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=f834c8a8223c40bd17b90be8f6ab7db843d0914c'/>
<id>urn:sha1:f834c8a8223c40bd17b90be8f6ab7db843d0914c</id>
<content type='text'>
The StoreKitConfigurationFileReference added in #11 used one '../' too
many, resolving outside the repository. Xcode resolves it relative to
the .xcodeproj's xcshareddata directory, so two levels reaches the repo
root.

SweepActivityAttributes is now explicitly nonisolated. The app target
sets SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor while the widget target
does not, so a type shared by both inferred a main-actor-isolated
ActivityAttributes conformance that ActivityKit cannot use from its
concurrent contexts.

LocalAPIService's logger closures captured self strongly while their
inner Tasks declared [weak self]. The weak capture is now on the outer
closure and bound before the Task, so the concurrently-executing closure
references an immutable strong local rather than the weak capture.
</content>
</entry>
<entry>
<title>docs: record the IAP fixes in the v4.8.1 roadmap section</title>
<updated>2026-07-20T20:12:24+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:10:44+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=b4147fe8f14d900c5c87f5fc4129f79884bb92b1'/>
<id>urn:sha1:b4147fe8f14d900c5c87f5fc4129f79884bb92b1</id>
<content type='text'>
PR #11 merged after the v4.8.1 version bump, so the roadmap's v4.8.1
section omitted the product ID correction and the StoreKit configuration
file. Both are in the 4.8.1 tree; document them alongside the other
fixes.
</content>
</entry>
<entry>
<title>test: add StoreKit configuration for local IAP testing</title>
<updated>2026-07-20T20:07:40+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T19:08:09+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=b5d67f42b7f7e009eb60a80857a306414117969f'/>
<id>urn:sha1:b5d67f42b7f7e009eb60a80857a306414117969f</id>
<content type='text'>
Adds DomainDig.storekit mirroring the App Store Connect setup: one
subscription group with Pro+ at level 1 and Pro at level 2, using the
corrected product IDs.

Wires it into the Run action so purchases resolve locally against
StoreKit instead of the App Store, and disables the
DOMAIN_DIG_FORCE_PRO_PLUS launch argument, which bypasses StoreKit
entirely and would mask whether the purchase path works.

Prices in the configuration are local-testing placeholders and do not
need to match App Store Connect.
</content>
</entry>
<entry>
<title>fix: match IAP product IDs to App Store Connect</title>
<updated>2026-07-20T20:07:40+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T19:03:36+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=024f611fbbf4d2405a10d649a59968617321732a'/>
<id>urn:sha1:024f611fbbf4d2405a10d649a59968617321732a</id>
<content type='text'>
The four product ID constants did not match the auto-renewable
subscriptions configured in App Store Connect, so Product.products(for:)
returned an empty array and tier(for:) resolved every purchase to .free.

Product IDs are permanent in App Store Connect, so the code is corrected
to match the configured values rather than the reverse:

  domaindig.pro.monthly      -&gt; domaindig.pro.month
  domaindig.pro.yearly       -&gt; domaindig.pro.annually
  domaindig.dataplus.monthly -&gt; domaindig.proplus.monthly
  domaindig.dataplus.yearly  -&gt; domaindig.proplus.annually
</content>
</entry>
</feed>
