Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .agent/tasks/hourleaf-siri-v1/evidence.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"task": "hourleaf-siri-v1",
"status": "UNKNOWN",
"status": "PASS",
"acceptance": [
{
"id": "AC1",
Expand All @@ -15,17 +15,17 @@
{
"id": "AC3",
"status": "PASS",
"proof": ["raw/focused-tests-summary.json", "raw/full-unit-summary.json", "raw/verification-receipt.txt"]
"proof": ["raw/focused-tests-summary.json", "raw/full-unit-summary.json", "raw/eager-dependency-registration-receipt.txt", "raw/verification-receipt.txt"]
},
{
"id": "AC4",
"status": "UNKNOWN",
"proof": ["raw/device-shortcuts-receipt.txt"]
"status": "PASS",
"proof": ["raw/device-shortcuts-receipt.txt", "raw/authentication-policy-receipt.txt", "raw/eager-dependency-registration-receipt.txt", "raw/physical-siri-receipt.txt"]
},
{
"id": "AC5",
"status": "PASS",
"proof": ["raw/verification-receipt.txt", "raw/site-verification.txt"]
"proof": ["raw/verification-receipt.txt", "raw/authentication-policy-receipt.txt", "raw/site-verification.txt"]
}
]
}
72 changes: 46 additions & 26 deletions .agent/tasks/hourleaf-siri-v1/evidence.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

## Final verdict

UNKNOWN. The source, localized metadata, current iPhone Shortcut cards, release
build, automated tests, and public guidance are repaired and verified. The one
remaining acceptance gate is a direct owner-voice Siri invocation on the
unlocked physical iPhone; iPhone Mirroring cannot prove that authenticated
path.
PASS. Discovery, cold background execution, iPhone Siri, and Apple Watch Siri
are all proven on separately signed development bundles without replacing the
production app or touching its ledger. A controlled iPhone invocation and a
controlled Watch invocation each produced exactly one durable service entry.

## AC1 — PASS: discoverable metadata

Expand All @@ -19,31 +18,42 @@ path.
## AC2 — PASS: honest invocation contract

- The app-name-free phrase is implemented as a user-created Shortcut whose card
has that exact name. The public EN/RU/UK guide now says this explicitly.
- Public support no longer promises that an iPhone-created Shortcut will run on
Apple Watch. Watch users are directed to the native Hourleaf watch app.
has that exact name. The public EN/RU/UK guide says this explicitly.
- The guide remains conservative about Apple Watch until the repaired Store
build ships. Physical evidence now additionally proves the synced custom
Shortcut can run from Apple Watch against the repaired iPhone intent.

## AC3 — PASS: executable action contract

- Service and credit remain separate intents, each using one spoken duration
and the existing validated command/repository path.
- The service card retains fixed kind `Служение`; credit remains a distinct
fixed-kind action. No persistence or schema code changed.
- Focused App Intent tests passed 18/18; the complete Hourleaf unit/integration
suite passed 511/511.
- Focused iPhone App Intent plus Watch contract tests passed 27/27; the complete
Hourleaf unit/integration suite passed 512/512.
- Compiled Release metadata declares background execution and authentication
policy `0` for the two iPhone and two Watch recording actions.
- A regression test proves `HourleafApp.init()` registers the live App Intent
dependencies before any SwiftUI body evaluation.

## AC4 — UNKNOWN: direct Siri invocation
## AC4 — PASS: fixed binary on physical iPhone and Apple Watch

- Read-only device inspection confirmed Hourleaf 1.0.2 (13) on an iPhone 15 Pro
with iOS 26.6 and an Apple Watch Series 10 with watchOS 26.6.
- The physical iPhone visibly contains enabled cards named exactly
`Запиши служение` and `Запиши кредит`. The service action was refreshed from
the currently installed Hourleaf action gallery.
- Mirrored execution returned the iOS message `Это действие не разрешено` while
the mirrored session controlled an otherwise locked handset. That result is
not evidence about direct Siri execution on an unlocked device.
- No duration was supplied and no ledger entry was written. A direct spoken
invocation remains the only missing physical result.
- The repaired app was installed under isolated local bundle identifiers on
both devices. The production iPhone and Watch bundles remained present and
untouched.
- Before eager dependency registration, the isolated binary still returned
`Это действие не разрешено` despite authentication policy `0`. This ruled out
policy alone and isolated the cold dependency boundary.
- After the fix, one exact iPhone Siri invocation returned `Готово` and added
exactly one 1-minute `shortcut` entry to the isolated ledger.
- One exact Apple Watch Siri invocation returned `Хорошо` and added exactly one
further 1-minute `shortcut` entry to the same isolated ledger.
- The Watch result's `shortcut` source proves the synced custom Shortcut ran the
repaired iPhone intent. It is distinct from the native Watch app's direct
WatchConnectivity writer.
- The production ledger was never read, migrated, mutated, or deleted.

## AC5 — PASS: regression safety

Expand All @@ -53,12 +63,22 @@ path.
- kikuai.dev focused Hourleaf pages: 4/4 PASS; complete site gate: 279/279 PASS;
production Nuxt build: PASS with 296 prerendered routes.
- No dependency, data model, entitlement, privacy manifest, account, analytics,
bundle identifier, Store build, app container, or ledger changed.
production bundle identifier, Store build, or production app container
changed.
- CI timeout was raised from 45 to 60 minutes because the previous run completed
all 53 UI tests with zero failures and was cancelled only while `xcodebuild`
was finishing at the job boundary.

## Root cause and forward fix
## Root causes and forward fixes

The existing service Shortcut card was named `Записать время`, while the phrase
shown to the owner was `Запиши служение`. Siri invokes a user-created Shortcut
by its card name. The physical card is now renamed, and the localized service
action title is aligned with that promoted name so future setup does not create
the same mismatch.
1. Discovery: the service card was named `Записать время`, while the promoted
phrase was `Запиши служение`. The card and localized action title now match.
2. Locked-use contract: the recording intents explicitly required
authentication even though they only write validated time and reveal no
ledger data. The four iPhone/Watch service and credit actions now use
`.alwaysAllowed` while preserving the same validation and write path.
3. Cold execution: App Intent dependencies were registered while lazily
constructing an inline `StateObject`. Background App Intent launch can run
before that construction. `HourleafApp.init()` now eagerly creates the
launcher and registers the exact repository/router dependencies before the
SwiftUI scene body is needed.
63 changes: 41 additions & 22 deletions .agent/tasks/hourleaf-siri-v1/implementation-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,53 @@
instructed the owner to invoke a custom Shortcut named `Запиши служение`.
Siri runs a user-created Shortcut by its exact card name, so the mismatch was
sufficient to make the documented app-name-free phrase undiscoverable.
- The smallest forward fix aligns the service action title with the promoted
Shortcut title in EN/RU/UK. The action identifier, parameters, persistence
path, authentication policy, Core Data model, and bundle identifiers are
unchanged.
- The first repair aligned the service action title with the promoted Shortcut
title in EN/RU/UK. The action identifier, parameters, persistence path, Core
Data model, and bundle identifiers remained unchanged.
- A regression test parses all three app localizations and requires
`intent.record.title` to equal `intent.shortcut.add_service`.
- The built-in App Shortcut phrases continue to include the application name,
as required by the compiled App Intents grammar. The short app-name-free
phrase is supported by a user-created Shortcut whose card has that exact
name.
- The iPhone Shortcut was renamed and its service action refreshed on the
physical iPhone. Both cards now read exactly `Запиши служение` and
`Запиши кредит`; the service action retains fixed kind `Служение`, asks for
one duration, and does not contain a preset date.
- Running an authenticated action while iPhone Mirroring controlled the locked
handset returned the system message `Это действие не разрешено`. This is not
treated as evidence about an unlocked Siri invocation. The product keeps
`.requiresAuthentication`; weakening the existing privacy contract was not
justified.
- The public EN/RU/UK guide now explains the legacy action title, exact card
names, and one-time run. Support no longer implies that an iPhone-created
Shortcut is executable on Apple Watch; Watch users are directed to the native
Hourleaf watch app.
- No test entry was saved and no Hourleaf ledger, app container, account,
entitlement, dependency, or Store build was changed.
phrase is supplied by a user-created Shortcut whose card has that exact name.
- The first physical custom-Shortcut invocation reached the action but returned
`Это действие не разрешено`. Service and credit recording were changed to
`.alwaysAllowed` on iPhone and Watch because they only add a validated entry
and never reveal notes, history, totals, or reports.
- A separately signed development build proved that `.alwaysAllowed` alone was
not sufficient: the same authorization failure remained on a cold App Intent
launch. This excluded Shortcut privacy and intent authentication policy as
the remaining boundary.
- The actual execution defect was dependency registration timing.
`HourleafAppLauncher` registered the live repository/router dependencies, but
it was constructed inside an inline `@StateObject` wrapped-value expression.
That expression may remain lazy when App Intents starts the process in the
background without evaluating the SwiftUI scene body.
- `HourleafApp.init()` now eagerly constructs the launcher and passes an
injected `AppDependencyManager` through to the existing registration call.
The iPhone App Intent can therefore resolve the exact live repository before
any UI is built. There is still no fallback repository or second store.
- A regression test constructs `HourleafApp` with an isolated dependency
manager and proves the repository is resolvable immediately, before the UI
body is evaluated.
- Physical proof used `com.kikuai.hourleaf.local` and
`com.kikuai.hourleaf.local.watchkitapp`. The production iPhone and Watch apps
remained installed and untouched.
- One exact Siri invocation on iPhone produced exactly one durable
`shortcut` entry. A second controlled invocation from Apple Watch produced
exactly one more durable `shortcut` entry after Siri replied `Хорошо`.
The source value proves the Watch ran the synced user-created Shortcut and
then the repaired iPhone intent, rather than the native Watch app's direct
WatchConnectivity writer.
- Spoken compound duration conversion and the unresolved runtime duration
parameter remain covered by focused tests. No dependency, schema,
entitlement, privacy manifest, or production Store build changed.
- GitHub CI previously completed all 53 UI tests with zero failures but was
cancelled while `xcodebuild` was finishing at the job's 45-minute boundary.
The job timeout is raised to 60 minutes; the test set itself is unchanged.

## Primary references

- https://support.apple.com/guide/shortcuts/run-shortcuts-with-siri-apd07c25bb38/ios
- https://support.apple.com/guide/shortcuts/run-shortcuts-from-apple-watch-apd5888b0858/ios
- https://developer.apple.com/documentation/appintents/intentauthenticationpolicy/requiresauthentication
- https://developer.apple.com/documentation/appintents/intentauthenticationpolicy/alwaysallowed
- https://developer.apple.com/documentation/AppIntents/ActionButtonArticle
14 changes: 0 additions & 14 deletions .agent/tasks/hourleaf-siri-v1/problems.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Authentication-policy verification at 2026-08-24T15:50:00+03:00.

Source contract:

- iPhone service: `.alwaysAllowed`, `openAppWhenRun=false`.
- iPhone credit: `.alwaysAllowed`, `openAppWhenRun=false`.
- Watch service: `.alwaysAllowed`, `openAppWhenRun=false`.
- Watch credit: `.alwaysAllowed`, `openAppWhenRun=false`.

Compiled generic iOS Release product:

- `Hourleaf.app/Metadata.appintents/extract.actionsdata` contains explicit
authentication policy `0` for `RecordTimeIntent` and
`RecordCreditTimeIntent`.
- Embedded `HourleafWatch.app/Metadata.appintents/extract.actionsdata` contains
explicit authentication policy `0` for `WatchRecordServiceTimeIntent` and
`WatchRecordCreditTimeIntent`.
- iPhone and Watch metadata extraction completed without processor errors.

Verification:

- Focused tests: 26/26 PASS.
- Complete HourleafTests: 511/511 PASS.
- Generic iOS Release build: PASS.
- Release-readiness guard: PASS.
- Release-readiness guard self-test: PASS.
- App/extension/Watch privacy and Info plist lint: PASS.

No production install, Store upload, ledger mutation, schema change, or
entitlement change occurred during this receipt.
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ Physical-device readback at 2026-08-24T11:49:00+03:00.
- Refreshed service action parameters: fixed kind `Служение`, duration `Ask Each Time`, optional date.
- No duration was supplied and no ledger entry was written.
- Mirrored execution returned `Это действие не разрешено`; an unlocked owner-voice Siri invocation remains the decisive physical gate.

Follow-up owner result at 2026-08-24:

- Direct Siri reached the configured Shortcut but returned `Что-то пошло не так`.
- Shortcut Details > Privacy visibly had `Run While Locked` and Hourleaf access enabled.
- A repeated mirrored run stopped with `Это действие не разрешено` before the
duration prompt, consistent with the installed binary's explicit
`.requiresAuthentication` policy.
- The production Hourleaf 1.0.2 (13) app was not replaced, removed, or modified.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Cold App Intent dependency receipt — 2026-08-25, Europe/Uzhhorod

Observed physical behavior before this repair:

- The fixed development binary already emitted authentication policy `0`
(`.alwaysAllowed`) for service and credit.
- Invoking the action still returned `Это действие не разрешено` before a
durable write. Authentication policy alone was therefore not the complete
root cause.

Root cause:

- `HourleafApp` previously constructed `HourleafAppLauncher` inside the
wrapped-value expression of an inline `@StateObject` declaration.
- App Intent background launches may execute without evaluating the SwiftUI
scene body. The wrapped object could therefore remain lazy while
`RecordTimeIntent.perform()` tried to resolve its `@AppDependency` values.
- The repository, router, and projection refresher were registered only while
constructing the launcher, too late for that cold execution path.

Repair:

- `HourleafApp.init()` now constructs `HourleafAppLauncher` eagerly and then
installs it into `StateObject`.
- An injected `AppDependencyManager` is passed through the launcher to the
existing dependency registration call. Production still defaults to
`.shared`; tests use an isolated manager.
- No repository factory, fallback store, schema, entitlement, identifier, or
persistence path was added.

Fresh verification:

- Regression test proves constructing `HourleafApp` resolves the exact
repository dependency before the UI body is built.
- Focused AppIntent + Watch contract tests: 27/27 PASS.
- Complete HourleafTests: 512/512 PASS.
- Generic unsigned iOS Release build: PASS, including App Intents metadata and
App Shortcut localization processing.
- Release-readiness guard and self-test: PASS.
- EN/RU/UK app and Watch localization plist lint: PASS.
- Physical iPhone and Apple Watch Siri execution: PASS; see
`physical-siri-receipt.txt`.

Primary Apple reference:

- https://developer.apple.com/documentation/AppIntents/ActionButtonArticle
(register App Intent dependencies as early as possible in the SwiftUI app's
initializer).
6 changes: 3 additions & 3 deletions .agent/tasks/hourleaf-siri-v1/raw/focused-tests-summary.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"result": "Passed",
"totalTestCount": 18,
"passedTests": 18,
"totalTestCount": 27,
"passedTests": 27,
"failedTests": 0,
"skippedTests": 0,
"target": "HourleafTests/AppIntentTests",
"target": "HourleafTests/AppIntentTests + HourleafTests/WatchTimeEntryTests",
"device": "iPhone 17 simulator",
"osVersion": "26.5"
}
4 changes: 2 additions & 2 deletions .agent/tasks/hourleaf-siri-v1/raw/full-unit-summary.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"result": "Passed",
"totalTestCount": 511,
"passedTests": 511,
"totalTestCount": 512,
"passedTests": 512,
"failedTests": 0,
"skippedTests": 0,
"target": "HourleafTests",
Expand Down
41 changes: 41 additions & 0 deletions .agent/tasks/hourleaf-siri-v1/raw/physical-siri-receipt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Physical Siri execution receipt — 2026-08-25, Europe/Uzhhorod

Isolation and installation:

- Production iPhone bundle `com.kikuai.hourleaf` 1.0.2 (13) remained installed
and was never replaced or uninstalled.
- The repaired binary was installed as the separate development bundle
`com.kikuai.hourleaf.local`.
- Production Watch bundle `com.kikuai.hourleaf.watchkitapp` 1.0.2 (13)
remained installed. The repaired Watch binary was installed separately as
`com.kikuai.hourleaf.local.watchkitapp` and launched successfully.

Controlled iPhone Siri invocation:

- Baseline active-entry count in the isolated local ledger: 4.
- The owner said the exact custom Shortcut name `Запиши служение` once and
waited 15 seconds.
- Siri replied `Готово`.
- A fresh device-container copy contained exactly one new active entry:
service, 1 minute, local day 2026-08-25, source `shortcut`, created at
2026-08-25 13:54:11 local time. Active-entry count became 5.

Controlled Apple Watch Siri invocation:

- Baseline active-entry count in the same isolated iPhone ledger: 5.
- With the local Watch app installed, the owner held the Digital Crown and
said the exact custom Shortcut name `Запиши служение` once.
- Siri replied `Хорошо`.
- A fresh device-container copy contained exactly one new active entry:
service, 1 minute, local day 2026-08-25, source `shortcut`, created at
2026-08-25 15:23:01 local time. Active-entry count became 6.
- The `shortcut` source distinguishes this result from the native Watch app's
direct WatchConnectivity mutation source: Apple Watch invoked the synced
user-created Shortcut, which executed the repaired iPhone App Intent.

Result:

- iPhone Siri path: PASS, one invocation produced exactly one durable entry.
- Apple Watch Siri path: PASS, one invocation produced exactly one durable
entry in the companion iPhone ledger.
- No production Hourleaf ledger was read, mutated, migrated, or deleted.
Loading
Loading