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
20 changes: 20 additions & 0 deletions .agents/skills/agent-guidelines-audit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Review the actual change rather than only checking whether files exist:
- Perform the mandatory [native-component and presentation decision check](#audit-native-components-and-presentation) for changed SwiftUI controls and presentation behavior.
- Perform the mandatory [system-control placement check](#audit-system-control-placement) for changed navigation, toolbars, dismissal controls, and window chrome, including affected UIKit/AppKit wrappers.
- Perform the mandatory [animation and image-rendering check](#audit-animation-and-image-rendering) for changed visual transitions, reusable control styles, and dynamic image paths, including directly affected consumers.
- Perform the [Reduce Motion check](#audit-reduce-motion) for affected motion and for Reduced Motion support declarations.
- Check tests for the required framework, mirrored paths, shared tags, Given/When/Then structure, deterministic seams, and coverage of changed behavior and failure paths.
- Trace every new or changed stateful, asynchronous, fallible, or lifecycle-oriented behavior and verify that its owning artifact emits privacy-safe AppLogger events for the meaningful success, failure, cancellation, recovery, and state-transition outcomes needed to diagnose it. Dependency declaration and target linkage alone do not establish logging coverage. Accept silence for pure values or utilities only when there is no meaningful event boundary and the implementation handoff records that deliberate decision.
- Check logging ownership, subsystem, categories, emoji, privacy, severity, metadata stability, noise controls, and focused formatter or sink tests when logging changed.
Expand Down Expand Up @@ -87,6 +88,25 @@ Use these scenario walkthroughs when evaluating the check:
| Prepared derivative preserves originals and rejects stale results | Accepted with applicable tests and interaction evidence |
| Zero hitches recorded without actual interaction | Insufficient performance evidence; applicable verification remains blocked |

## Audit Reduce Motion

Apply the canonical [Reduce Motion policy](../../../Guidelines/Swift/SwiftUI.md#reduce-motion) and its [support declaration requirements](../../../Guidelines/Swift/SwiftUI.md#declaring-support):

1. For changed motion and directly affected components, identify each potential trigger, its owner, and its chosen adaptation or evidence that no adaptation is needed. Inspect custom styles and surrounding transactions as well as native controls. Do not require removal of harmless feedback or a separate task request for an applicable adaptation.
2. Verify the source of the preference, response to changes during use, and preserved information, functional state, and native accessibility behavior. For an in-app alternative, inspect the consumer's rationale and criteria coverage. Reject blanket suppression that loses meaningful feedback and unresolved problematic motion.
3. Require runtime actions and outcomes with Reduce Motion on and off, plus a preference change while running. Record platform/OS, app revision, scenarios, results, and verification limits. Static screenshots, compilation, an environment read, or the use of a native component alone do not prove support. Accept recorded manual verification when automation cannot exercise the setting; missing applicable evidence blocks completion of the affected work.
4. For an app-wide support declaration, expand the evidence scope to all common tasks on the declared platform, following the linked Apple criteria for content and advertising. Check the consumer evidence and current release scope; withhold or correct unsupported claims. A local component check or guideline adoption is insufficient. Re-evaluate existing declarations during app updates; do not demand an unrelated whole-app audit for an isolated motion change when no declaration is in scope.
5. Documentation-only policy work uses scenario walkthroughs rather than simulator testing. Report the exact trigger, missing evidence, or unsupported declaration that prevents audit completion; do not claim this central audit establishes any consumer app's support.

| Scenario | Audit outcome |
| --- | --- |
| Decorative depth effect ignores the enabled preference | Blocked until adapted and exercised |
| Informative movement becomes a fade and retains its meaning | Accepted with on/off and live preference-change evidence |
| Native control already adapts correctly | Accepted with interaction evidence; no duplicate guard required |
| Every animation is removed and a status change becomes imperceptible | Blocked until meaningful feedback is restored |
| No problematic motion across evaluated common tasks | Support declaration may pass with platform-specific evidence |
| One compliant component or guideline adoption used to claim app-wide support | Declaration blocked pending common-task evaluation |

## Audit Xcode project settings

For every checked-in `.xcodeproj`, read and apply the shared [Xcode project-settings guide](../../../Guidelines/Xcode/ProjectSettings.md):
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to this project are documented in this file.

## [0.0.42] - 2026-10-20

### Changed

- Replaced the explicit-request restriction on Reduce Motion adaptations with Apple-aligned evaluation of individual motion triggers, responsive preference handling, and preservation of useful feedback.
- Required platform-specific common-task evidence before declaring Reduced Motion support, with re-evaluation on app updates and a link from App Store metadata guidance.
- Added focused Reduce Motion audit checks, scenario walkthroughs, and validator regression coverage for policy, evidence, and support claims.

## [0.0.41] - 2026-10-20

### Added
Expand Down
4 changes: 4 additions & 0 deletions Guidelines/AppStore.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Omission means unmanaged. Add only fields and domains the project intends to rec

Ordinary metadata, screenshot, commerce, provisioning, or signing synchronization does not authorize submitting a version for review or releasing it. Use the MCP's explicit readiness and submission workflow only when the owner has separately placed submission in scope.

## Accessibility support claims

Before adding or retaining a Reduced Motion support declaration, apply the shared [Reduce Motion support evaluation](Swift/SwiftUI.md#declaring-support). Keep the platform-specific consumer evidence current; adopting these guidelines alone does not establish support. Include any requested metadata change in the inspected synchronization plan above rather than inferring publication authority from a policy or implementation change.

## Screenshots

Treat each localization's `screenshots.json` as the ordered manifest for its selected display sets. Paths are relative to `AppStore/`, and the explicit array order is the storefront order. Preserve reusable originals in the repository; do not silently resize, transcode, substitute another locale, or derive ordering from filenames.
Expand Down
16 changes: 15 additions & 1 deletion Guidelines/Swift/SwiftUI.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,24 @@ Use these decisions when auditing an implementation:
- Change enabled state, hit-testing, accessibility state, and action availability immediately. Animate appearance; never delay functional state until an animation finishes. Immediate press, focus, or selection feedback remains appropriate when it improves responsiveness; record an intentional immediate transition and its reason.
- Preserve stable view identity when only appearance changes. Prefer changing fill, opacity, or shadow values over replacing equivalent view branches.
- Scope animation to the intended state and visual attributes. Preserve responsive controls, stable layout, and uninterrupted user interaction; animating surrounding layout must not accidentally animate every control inside it. The presence of `.animation` does not prove correct scope: value-triggered animation can affect other changes in the same transaction. Use narrower modifier or closure scope where necessary and supported by the deployment target.
- Do not introduce app-level Reduce Motion guards unless the task prompt explicitly requests them. This includes reading `accessibilityReduceMotion` to replace animation with `nil`, remove symbol effects, or otherwise suppress app-authored animation. Preserve any accessibility behavior provided automatically by native system components; this policy governs additional app-level overrides.
- Apply the [Reduce Motion policy](#reduce-motion) alongside these animation defaults, including in reusable custom-styled controls.

Consult Apple's [Explore SwiftUI animation](https://developer.apple.com/videos/play/wwdc2023/10156/) for transaction propagation and scoped animation behavior. The reusable-control defaults above are repository policy.

### Reduce Motion

Follow Apple's [Reduced Motion evaluation criteria](https://developer.apple.com/help/app-store-connect/manage-app-accessibility/reduced-motion-evaluation-criteria/) and [motion design guidance](https://developer.apple.com/design/human-interface-guidelines/motion). Evaluate individual animations; do not disable all animation indiscriminately.

- Respect the user's reduced-motion preference as part of normal implementation; no separate task request is required. Preserve native accessibility adaptations and verify custom styling and surrounding animations do not defeat them.
- Use SwiftUI's [accessibilityReduceMotion](https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityreducemotion) environment value when app-authored motion needs adaptation. Follow preference changes during use. System preference integration is the repository default; document any equivalent or more granular in-app alternative and verify it meets Apple's criteria rather than requiring a redundant setting.
- Identify potentially problematic scaling, spinning, peripheral motion, depth simulation (including parallax or animated blur), and multi-axis or multi-speed movement. Remove decorative triggers or replace them with lower-motion feedback when reduced motion is requested. For ongoing motion such as an auto-advancing carousel, stop it or provide a discoverable stop control.
- Preserve information and usability: replace meaningful motion with suitable alternatives such as a dissolve, highlight fade, or color change. Retain harmless feedback, immediate functional state, and system-owned behavior. A reduced-motion preference does not justify losing status, navigation context, or action availability.
- Exercise affected flows with the preference on and off, including changing it while the app is running. Record the platform/OS, app revision, actions, outcomes, and limitations. Test custom and native behavior rather than assuming an environment read or native control proves support.

#### Declaring support

Claim Reduced Motion support only after evaluating all common tasks for the platform being declared against Apple's criteria. Follow Apple's [Accessibility Nutrition Labels guidance](https://developer.apple.com/help/app-store-connect/manage-app-accessibility/overview-of-accessibility-nutrition-labels) for task coverage, required third-party or user-generated content, and advertising. Record the evaluated tasks, evidence, remaining limitations, and declaration scope in consumer documentation. An app with no problematic motion can qualify; a guideline update or a single compliant component cannot establish app-wide support. Re-evaluate support with each app update, and withhold or correct a claim when relevant evidence is missing or a regression invalidates it. Updating App Store Connect remains a separately scoped metadata operation under [App Store metadata](../AppStore.md).

## Image rendering

- Use retained, display-appropriate derivatives for large dynamic images in small, frequently updated views instead of repeatedly rendering the original bitmap. This applies to photos, downloaded images, generated images, and other bitmap sources; an expensive rendering path does not by itself establish a provider defect.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ From the consumer repository root, install a tagged release:
git subtree add \
--prefix=AgentGuidelines \
https://github.com/thatfactory/agent-guidelines.git \
0.0.41 \
0.0.42 \
--squash
```

Expand Down Expand Up @@ -148,7 +148,7 @@ Review the target release's changelog, then pull it deliberately:
git subtree pull \
--prefix=AgentGuidelines \
https://github.com/thatfactory/agent-guidelines.git \
0.0.41 \
0.0.42 \
--squash
```

Expand Down
40 changes: 39 additions & 1 deletion Scripts/validate_guidelines.swift
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,21 @@ func validateInteractionRenderingPolicy(_ errors: inout [String]) {
"Preserve stable view identity when only appearance changes",
"value-triggered animation can affect other changes in the same transaction",
"Use narrower modifier or closure scope",
"Do not introduce app-level Reduce Motion guards unless the task prompt explicitly requests them",
"[Reduce Motion policy](#reduce-motion)",
"### Reduce Motion",
"https://developer.apple.com/help/app-store-connect/manage-app-accessibility/reduced-motion-evaluation-criteria/",
"no separate task request is required",
"do not disable all animation indiscriminately",
"Follow preference changes during use",
"document any equivalent or more granular in-app alternative",
"Remove decorative triggers or replace them with lower-motion feedback",
"stop it or provide a discoverable stop control",
"replace meaningful motion with suitable alternatives",
"Claim Reduced Motion support only after evaluating all common tasks for the platform being declared",
"required third-party or user-generated content, and advertising",
"An app with no problematic motion can qualify",
"Re-evaluate support with each app update",
"withhold or correct a claim",
"## Image rendering",
"retained, display-appropriate derivatives",
"display scale, aspect-fit/fill requirements, orientation, fidelity, and bounded intermediate/cache memory",
Expand Down Expand Up @@ -767,6 +781,25 @@ func validateInteractionRenderingPolicy(_ errors: inout [String]) {
"| Scenario | Audit outcome |",
"| Appropriate native control already supplies feedback | Accepted without additional animation |",
"| Zero hitches recorded without actual interaction | Insufficient performance evidence",
"[Reduce Motion check](#audit-reduce-motion)",
"## Audit Reduce Motion",
"Guidelines/Swift/SwiftUI.md#reduce-motion",
"Guidelines/Swift/SwiftUI.md#declaring-support",
"Require runtime actions and outcomes with Reduce Motion on and off",
"plus a preference change while running",
"missing applicable evidence blocks completion of the affected work",
"expand the evidence scope to all common tasks on the declared platform",
"withhold or correct unsupported claims",
"do not demand an unrelated whole-app audit for an isolated motion change",
"Documentation-only policy work uses scenario walkthroughs",
]
),
(
appStoreGuideline,
[
"## Accessibility support claims",
"Swift/SwiftUI.md#declaring-support",
"adopting these guidelines alone does not establish support",
]
),
]
Expand All @@ -775,6 +808,11 @@ func validateInteractionRenderingPolicy(_ errors: inout [String]) {
for value in required where !contents.contains(value) {
errors.append("\(file.lastPathComponent): missing interaction/rendering requirement: '\(value)'")
}
if contents.contains(
"Do not introduce app-level Reduce Motion guards unless the task prompt explicitly requests them")
{
errors.append("\(file.lastPathComponent): obsolete Reduce Motion opt-in restriction")
}
}
}

Expand Down
Loading
Loading