Repository navigation
Conversation
740f7b9 to
d78b76d
Compare
d78b76d to
d27a835
Compare
d27a835 to
6a04f77
Compare
> _Posted by an AI agent on kve's behalf._
## Summary
Add typed horizontal and vertical size classes to Broadway. UIKit roots
observe changes live; SwiftUI roots map their environment into the same
traits. Scoped overrides let component styles resolve the container's
layout policy.
This is foundation only. It preserves the current main toolchain and
screen behavior.
## Primary APIs
`BHorizontalSizeClass` and `BVerticalSizeClass` expose only compact and
regular values. Both default to compact. UIKit unspecified/unknown
values and SwiftUI missing/unknown values normalize to compact at the
bridge, so stylesheet switches need only two cases. `BTraits.system`
registers both, and `bHorizontalSizeClass` / `bVerticalSizeClass`
provide scoped SwiftUI overrides.
```swift
content
.bHorizontalSizeClass(.regular)
.bVerticalSizeClass(.regular)
```
Stylesheets read `context.traits.horizontalSizeClass` and
`verticalSizeClass` during slicing. Measured geometry remains a view
input. The fallback is an explicit styling policy; known system traits
and scoped overrides are preserved without inferring size classes from
device identity or bounds.
Independent review found one downstream test matrix using the removed
enum case. PR #378 now tests all nine raw UIKit size-class combinations
through the Broadway bridge, preserving single-pane fallback coverage.
## Stack
1 of 5, based on `main`. The snapshot foundation follows this PR;
reusable navigation and geometry come next. [The final app
PR](#372) describes the complete
experience and remaining native release checks.
## Testing
- At current stack tip `2fd6f699853ac4fa592a90d3928f83e836bca635`,
`./test --all` passed on Xcode 27.2: 2,975 iOS unit tests, 28 host macro
tests, and 31 architecture tests. SwiftFormat passed. The root PR also
passed 141 Broadway tests from an isolated build; an earlier
shared-cache build hit stale LifecycleKit deployment-target metadata.
- The earlier full integration at
`e9236bb54771a1e144ffbc35ea9076e8f2c4569f` passed both CI gates,
including all image suites. The current change normalizes unavailable
Broadway size classes to compact and updates the downstream UIKit-input
regression matrix; reference PNGs and renderer settings are unchanged.
New full gates are running on the current tip: [GitHub
Actions](https://github.com/kyleve/Stuff/actions/runs/43064578603) and
[CircleCI pipeline
2166](https://app.circleci.com/pipelines/circleci/HfkN3cJ2hk23YfG42g3oS1/E7hn5FALiSX67sknpk9SZu/2166).
- Visual review covers every changed reference, including full-height
content, accessibility annotations, large text, and theme panels.
Reference PNG metadata and comparison tolerances are preserved.
- Independent review covered all five stack slices and the final
capture, navigation, and inset changes. Focused mutation tests
demonstrate that stale-inset delivery and off-screen accessibility
regressions fail without their fixes.
- Two tall Year accessibility images retain a pre-existing marker offset
and incomplete native-toolbar legends. The capture follow-up is
documented below; it is tracked in
[STU-325](https://linear.app/kve/issue/STU-325); these images do not
prove live VoiceOver behavior.
- Native Duo 27.2 geometry re-measurement and interactive device checks
remain pending. Synthetic regular-simulator coverage does not establish
native system-bar geometry or spoken VoiceOver behavior.
## Backlog reconciliation
The 13 preserved Duo records are tracked in Linear.
[STU-318](https://linear.app/kve/issue/STU-318) owns adoption and its
six implementation sub-issues. This slice relates to
[STU-318](https://linear.app/kve/issue/STU-318). Unmerged implementation
remains In Review.
Remaining Backlog work: native Duo release validation
([STU-316](https://linear.app/kve/issue/STU-316)), intermittent
Locations settling diagnostics
([STU-317](https://linear.app/kve/issue/STU-317)), and tall Year
accessibility annotations
([STU-325](https://linear.app/kve/issue/STU-325)). Existing
[STU-114](https://linear.app/kve/issue/STU-114) and
[STU-252](https://linear.app/kve/issue/STU-252) now distinguish the
partial fixes from their remaining requirements; both retain their
priorities, labels, and open state.
b55080d to
6695ad8
Compare
| import SwiftUI | ||
|
|
||
| /// Named synthetic configurations from SnapshotKit's measured Duo profiles. | ||
| enum AdaptiveHistoryPose: String, CaseIterable, Identifiable { |
There was a problem hiding this comment.
If this is only for testing, maybe we should move it into SnapshotKit itself?
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Moved the seven synthetic configurations into SnapshotConfiguration.Pose in cb30be5. They reuse the existing frames and traits and carry typed reserved-region geometry plus activation state. WhereUI keeps the localized lab labels and its geometry adapter. Frame names, dimensions, snapshot IDs, and measurement provenance are unchanged; native 27.2 re-measurement remains pending.
| } | ||
| } | ||
|
|
||
| var regions: [AdaptiveHistoryReservedRegion] { |
There was a problem hiding this comment.
Similar question; is this duplicated with anything in SnapshotKit?
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Removed the separate pose geometry definitions in cb30be5. SnapshotKit now owns each synthetic pose and its reserved regions; WhereUI adapts those values to the production geometry API. AdaptiveHistoryGeometry remains in WhereUI because it interprets the container and system geometry for application layout.
| import SwiftUI | ||
| import WhereCore | ||
|
|
||
| /// Retains the calendar's scroll anchor and requested planning presentation across remounts. |
There was a problem hiding this comment.
Does "remount" here mean as the UI moves around as the device is folded, unfolded, rotated, etc?
I wonder if there's a more general way to support this for scrollable areas that have anchors for content; I gotta imagine this is more common than just calendars.
There was a problem hiding this comment.
Eg, imagining something like:
- At the level of a stable container, place a ScrollPosition cache in the Environment
- The positions are cached by the view type, and some identifier (eg, like the region)
- Upon remounting the view, look up a scroll position value / write it up on scroll.
This would be a more general solution to the mount/remount problem than making a model for each view type.
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Yes—replacement as a fold or layout branch changes. Implemented your stable-ancestor environment approach in cb30be5 and 9b386b5: .bScrollRestorationScope() owns a BScrollRestorationStore, and @BScrollPosition supplies a native binding keyed by view type and typed pane role. Region/year is a separate context token that replaces the current entry, so there is no history of old contexts. Without a scope it stays view-local. Mounted tests cover replacement, independent scopes/roles, delayed readiness, obsolete callbacks, and bottom alignment. #372 uses it for calendar detail, timeline, and Locations browsing.
|
|
||
| /// Explicit selections connect history panes. Scroll observations never write this selection. | ||
| @MainActor @Observable | ||
| final class HistoryNavigationModel { |
There was a problem hiding this comment.
Yeah similar comment to CalendarNavigationModel; this feels much more generalizable than we've made it here.
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Agreed. cb30be5 removes scroll storage from the history coordinator. HistorySelectionModel now holds only the selected interval and explicit reveal requests, with distinct request IDs and independent consumption by each destination. Ordinary scrolling does not change the linked selection. The shared Broadway utility owns restoration; #372 integrates it and tests delayed data and repeated reveals.
|
|
||
| /// Scroll observations retain a local anchor. Only explicit selection requests reveal a row. | ||
| @MainActor @Observable | ||
| final class TimelineNavigationModel { |
There was a problem hiding this comment.
Yeah another one where IMO at least the scroll position stuff can be generalized.
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Generalized in cb30be5 / 9b386b5 and integrated in #372 (cde4ff4). Timeline uses the same @BScrollPosition as calendar and Locations, with its own typed role and year context. The remaining timeline-specific code resolves explicit history selections against loaded domain items; it also retries when an existing stay extends without changing its ID.
| /// Session-scoped presentation state. Resizing changes containers, never this owner or its | ||
| /// children. | ||
| @MainActor @Observable | ||
| final class SceneNavigationModel { |
There was a problem hiding this comment.
I don't 100% love this approach; what exactly is it solving? Why do we need this state when we didn't need it before; can the view itself not keep our navigation state like it did before?
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Removed the aggregate SceneNavigationModel approach. cb30be5 supplies the reusable groundwork; cde4ff4 in #372 keeps paths, selection, search, sheets, and presentation helpers in stable owning views above adaptive branches. Models interpret data and access preferences. Editors keep their drafts locally, and an active pushed Locations stack remains mounted while resizing; tabletop waits until returning. Hosted guards cover pushed-controller identity, search, presented editors, unsaved drafts, and load continuity. Native keyboard/focus and physical folding validation remain pending.
6695ad8 to
2e1f0d2
Compare
2e1f0d2 to
e02b3d9
Compare
> _Posted by an AI agent on kve's behalf._ ## Summary Add explicit frame layout traits and recorded Duo profiles to the Xcode 27.2 baseline from main. Apply requested content clearance after UIKit finalizes containment and native geometry. This layer retains the existing Where navigation. Its image references establish the new capture baseline before the adaptive app changes. Calendar month sections, day rows, and Timeline rows measure eagerly so full-content captures include the final rows; the selection and tabletop changes remain in the app PR. Eager Timeline measurement removes blank tails caused by lazy height estimates in a bottom-anchored scroll view. Settings waits for native search chrome to settle before measuring its full height. Existing scrolling onboarding and Devices fixtures use full-content frames. Theme choices also fall back to a vertical layout when narrow, and large-text Logged Days rows retain their dates, notes, and labels. ## Screenshots Developer Overlay, light iPhone full-content capture. Retaining the scene restores uniform native glass without changing the menu's styling, dimensions, or content. | Before | After | |---|---| | <img alt="Detached-scene menu with bright bands and a hard material cutoff" width="260" src="https://media.githubusercontent.com/media/kyleve/Stuff/9e759fc8b0ac8db6569bfb03d49cdafd54c7ad2c/Where/WhereUI/SnapshotTests/__Snapshots__/DeveloperOverlaySnapshotTests/developerOverlay.MenuTopLeading_iPhone.png"> | <img alt="Scene-backed menu with uniform glass and complete content" width="260" src="https://media.githubusercontent.com/media/kyleve/Stuff/f05ca62400c415631e21c5e649ce655700d9f18a/Where/WhereUI/SnapshotTests/__Snapshots__/DeveloperOverlaySnapshotTests/developerOverlay.MenuTopLeading_iPhone.png"> | Before: `9e759fc8`. After: `f05ca6240`; all six overlay captures reproduced byte for byte. ## Primary APIs - `SnapshotConfiguration.Frame.LayoutTraits` owns horizontal and vertical size classes and interface idiom. Configuration-level layout traits remain supported and take precedence over frame defaults. Phone and iPad presets carry truthful traits without changing their filenames. - `Frame.scenePolicy` controls capture scene retention without renaming references. Both configured assertions and hosted PNG export honor it. - `Frame.viewport` captures bounded shell composition. It must be paired with full-content captures of scrolling panes. - The four Duo profiles use measured native geometry. The module README retains the measurement date, runtime/build, collection method, and validation limits; the unused raw JSON dump is removed. `.narrowWindow` covers a synthetic multitasking container. ```swift let configuration = SnapshotConfiguration(device: .duoInnerPortrait) configuration.applyTraits(to: host) ``` Previews and UIKit capture use the same mapping. Conversion from configuration traits to frame traits uses exhaustive switches for both size classes and idiom, so new enum cases require an explicit mapping. Custom frames can supply `layoutTraits`; component frames inherit the host's traits. ## Capture and tooling boundaries All capture entry points acquire one lock before host discovery, validation, and preparation. Fixed, regular-width phone captures retain their scene so native bar geometry stays stable. Other synthetic captures detach the marked window by default, preserving compact title space and anchoring full-content search to expanded content. Capture and measurement hosts reconcile their effective insets after containment and layout, with another reconciliation after settling. The predicate uses content-controller traits, not pixel width or simulator identity. Frames can explicitly retain the scene when native chrome requires it. Periscope and Developer Overlay use this option without changing their configured traits, insets, or sizing. Developer Overlay's native glass otherwise develops bright bands and a hard material cutoff. Retention can expose physical reserved regions, so general presets keep the automatic policy. Both paths restore scene and presentation state on success or failure. A nil inset override retains native geometry. Only the captured root overrides its safe-area getter, during final pixel rendering. Native getters remain active during containment, measurement, and settling so inset changes propagate to children. Root pinning protects translated tiles. Overriding ancestors doubled asymmetric insets after measurement rehosting. Annotation padding has zero safe-area insets to avoid moving centered content. Tall tiled Year annotations retain the pre-existing limitation listed below. Regressions cover these boundaries, already-mounted inputs, compact and regular title readability, native bar stability, tiling, and failure cleanup. Full-content captures reset restored scroll offsets after readiness; viewport captures preserve them. Accessibility subjects stay mounted during readiness and settling. Ordinary captures retain their controller parent during parsing; only upstream tiling temporarily detaches it. Annotation wrappers grow only after the final accessibility parse. Synthetic viewports recover native navigation-bar metadata synchronously, restore window geometry before parsing, and restore the original getters on every exit. Pixel settling retains main’s normalized pixel comparison and retry policy. Final reference-comparison tolerances remain unchanged. Hosted resize, restoration, full-content, PNG export, and cancellation checks cover the shared pipeline. Snapshot shard discovery accepts literal multiline source arrays with shared support files. Unsupported declarations fail without borrowing a following target's sources. The existing shard assignments stay unchanged. ## Compatibility and review focus - The stack requires iOS 27.1. Development and CI use Xcode and simulator 27.2. The native macOS deployment target is unchanged. - Review the capture isolation and frame-trait API changes before the references. The fix addresses stale inset compensation: requested top/bottom values of 5/9 previously reached native children as 0/0. - The app integration in #372 fixes a separate stale developer-overlay inset delivery. Native accessibility capture corrections belong to this foundation layer; later app layers own their navigation and search behavior. - The Duo profiles retain their recorded 27.1 measurements. Re-measurement on the native 27.2 Duo runtime remains an explicit release-validation item. - Theme descriptions retain three lines of minimum space and grow for large text. The shared picker no longer truncates the Flat description at AX5. ## Testing - At `42ab5b40e`, `./test --review --only SnapshotKitTests --only WhereUISnapshotTests/DeveloperOverlaySnapshotTests` passed all 56 SnapshotKit tests and the Developer Overlay image suite (all six captures matched byte for byte). Architecture and SwiftFormat passed. Review fixes preserve the existing mappings and presets; no references changed. - Full gates on the current head `42ab5b40e`: [GitHub Actions](https://github.com/kyleve/Stuff/actions/runs/43081928022) and [CircleCI pipeline 2195](https://app.circleci.com/pipelines/circleci/HfkN3cJ2hk23YfG42g3oS1/E7hn5FALiSX67sknpk9SZu/2195). - At `f05ca6240`, the full run passed 2,922 iOS unit tests and 28 host macro tests. All 71 snapshot tests are covered by the full run plus focused assertions after review; 679 affected WhereUI tests also passed after the eager Timeline change. - `./test --no-generate --review --timings --only WhereUITests` with the seven affected snapshot suites verified the refreshed references. A final `./test --no-generate --no-build --review --only WhereUISnapshotTests/DeveloperOverlaySnapshotTests` repeated all six overlay captures byte for byte. Architecture checks and SwiftFormat passed. - Full gates for the capture-repair baseline (before the exhaustive-conversion refactor and documentation cleanup): [GitHub Actions](https://github.com/kyleve/Stuff/actions/runs/43079785790) and [CircleCI pipeline 2188](https://app.circleci.com/pipelines/circleci/HfkN3cJ2hk23YfG42g3oS1/E7hn5FALiSX67sknpk9SZu/2188). The capture fixes and reference migration are verified at this PR's own layer. A green stack tip cannot establish that an earlier PR's renderer and references agree. Layer-specific Timeline, Settings, and Year references retain the behavior present here rather than borrowing later adaptive UI semantics. - Independent source review covered capture containment, final annotation sizing, native-bar getter restoration, Settings measurement, and eager Timeline layout. Visual review covered the refreshed references and preserved comparison-sheet metadata; comparison tolerances are unchanged. - Two tall Year accessibility images retain a pre-existing marker offset and incomplete native-toolbar legends ([STU-325](https://linear.app/kve/issue/STU-325)). - Native Duo 27.2 geometry re-measurement and interactive device checks remain pending. Synthetic regular-simulator coverage does not establish native system-bar geometry or spoken VoiceOver behavior. ## Stack First active layer, based on main after [#376](#376) merged. This supplies the capture foundation for #378 and #372. Capture corrections and their references land here; adaptive corrections and references land with the app integration. ## Backlog reconciliation The 13 preserved Duo records are tracked in Linear. [STU-318](https://linear.app/kve/issue/STU-318) owns adoption and its six implementation sub-issues. This slice relates to [STU-319](https://linear.app/kve/issue/STU-319), [STU-320](https://linear.app/kve/issue/STU-320), [STU-327](https://linear.app/kve/issue/STU-327). Unmerged implementation remains In Review. Remaining Backlog work: native Duo release validation ([STU-316](https://linear.app/kve/issue/STU-316)), intermittent Locations settling diagnostics ([STU-317](https://linear.app/kve/issue/STU-317)), and tall Year accessibility annotations ([STU-325](https://linear.app/kve/issue/STU-325)). Existing [STU-114](https://linear.app/kve/issue/STU-114) and [STU-252](https://linear.app/kve/issue/STU-252) now distinguish the partial fixes from their remaining requirements; both retain their priorities, labels, and open state.
e02b3d9 to
19fb4a9
Compare
Keep all nine UIKit size-class combinations in the pane-policy regression while mapping through the two-case Broadway API. Unspecified inputs must still select a single pane. Validation: SwiftFormat and diff checks pass. Full unit integration runs at the rebased stack tip before publication; the root Broadway suites passed 141 tests.
19fb4a9 to
68bd35e
Compare
Share synthetic pose geometry through SnapshotKit. Keep explicit history selection separate from view-owned presentation state. Add native hosted restoration, context replacement, delayed initialization, and scope isolation guards.
| @Environment(\.bScrollRestorationStore) private var sharedStore | ||
| @State private var localStore = BScrollRestorationStore() | ||
| private let key: BScrollRestorationStore.Key | ||
| private let context: () -> AnyHashable |
There was a problem hiding this comment.
Confirming we want this and not a more specific type?
There was a problem hiding this comment.
|
|
||
| private var attachment: Attachment { | ||
| guard let resolvedAttachment else { | ||
| preconditionFailure("BScrollPosition must be read from a mounted view") |
There was a problem hiding this comment.
I think this should be an assert so it doesn’t crash in prod
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Addressed in 4acf65c. Unmounted access uses assertionFailure in debug and returns a stable, isolated attachment in release. That fallback never resolves the environment store, so it cannot replace a mounted entry. Mounted/context-isolation tests pass; the release-only fallback was source-reviewed rather than executed by the debug suite.
| extension SnapshotConfiguration { | ||
| /// Synthetic container geometry for adaptive previews, captures, and hosted tests. | ||
| /// These profiles do not change the simulator's native folding pose. | ||
| public enum Pose: String, CaseIterable, Identifiable, Sendable { |
There was a problem hiding this comment.
Maybe we name this duo pose?
Also, one case per case statement please?
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Addressed in eb9dd29: renamed the type and matching files to SnapshotConfiguration.DuoPose, with one enum case per declaration. The frames, traits, reserved regions, activation state, and snapshot identifiers are unchanged.
| import SwiftUI | ||
|
|
||
| extension SnapshotConfiguration.Pose { | ||
| var title: String { |
There was a problem hiding this comment.
any reason to not put these strings in snapshotkit too?
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Addressed in eb9dd29. SnapshotKit now owns the seven localized pose labels and its resource catalog. WhereUI retains only the production geometry adapter; the label text is unchanged.
|
|
||
| /// Connects explicit selections to displayed history data. It owns no scroll or presentation state. | ||
| @MainActor @Observable | ||
| final class PresenceSelectionModel { |
There was a problem hiding this comment.
I wonder if we could simplify this by just giving each element we want to scroll to a more regular id? This feels very complicated to me
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Simplified in 7aa3146 and the #372 integration commit 4c0cd0a. Removed PresenceSelectionModel, per-pane consumption tracking, the timeline resolver, and the unused linked presentation. Timeline now owns its recorded/flight/planned row IDs. Locations owns a small CalendarMonthReveal value passed through @Binding; its request identity remains distinct from the month identity so selecting the same month again works after loading. Mounted tests cover delayed/repeated requests and browsing restoration without replaying a consumed request. Those tests caught a plain-binding observation gap during the refactor; registering the value with @Binding fixes it. Five annotation references in ca09946 remove the obsolete recorded-row Button trait; their screen pixels are unchanged, and planned-stay buttons remain.
| } | ||
| } | ||
|
|
||
| /// Shares the native/injected coordinate mapping with custom chrome above the destinations. |
There was a problem hiding this comment.
What exactly is custom chrome? Why do we need it?
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Clarified in fd1fd30, with the Settings simplification in #372 commit 0790712. The geometry reader is reused by the welcome and developer overlays to find clear space. It does not draw navigation bars or toolbars. Settings now uses native split navigation and stylesheet compact policy directly; Locations retains the pane resolver for its tabletop composition. Native Duo geometry validation remains pending.
Summary
Add scoped scroll restoration and shared Duo pose fixtures for adaptive UI. Stable views own navigation, presentation, and explicit reveal requests. This PR supplies groundwork; #372 integrates it into Where.
Ownership and APIs
SnapshotConfiguration.DuoPoseBScrollRestorationStoreand.bScrollRestorationScope()BScrollPosition<ID, Context>AdaptivePaneGeometryandAdaptivePaneArrangementThe store retains semantic content identity and alignment, without pixel restoration, persistence, application navigation, or pane synchronization. Without a scope, positions remain view-local. Consumers choose readiness, initial positioning, validity, and fallback behavior.
A pending initialization cannot replace a later user position. Old bindings and outgoing views retain detached entries after context replacement. Reading an unmounted wrapper asserts in debug; release access uses an isolated attachment that cannot claim a scoped entry.
Where has no shared selection coordinator. #372 keeps a small month-reveal value in Locations and gives Timeline its own row IDs.
RegionStint.IDis a typed Hashable/Sendable region/start-date identity; this source API change does not alter persisted data.AdaptivePaneGeometryReaderalso supports the welcome and developer overlays. It does not implement navigation bars or toolbars. Native containers retain that responsibility. Broadway supplies column-card styling, and the architecture rule confines system reserved-region reads to the geometry adapter.Duo fixtures retain their frame names, dimensions, traits, snapshot identifiers, and measurement provenance. SnapshotKit owns the labels; WhereUI adapts its reserved-region values to production geometry.
Composition
The consumer in #372 places
.bScrollRestorationScope()on a stable ancestor and binds the scroll view to$detailPosition. Once content is ready,initialize(id:anchor:)restores the saved target or applies that view's initial policy.Review focus
Testing
BScrollPosition,SnapshotDuoPose, andAdaptivePaneContainer../test BroadwayUITests SnapshotKitTests WhereUITestspassed all 29 BroadwayUI and 58 SnapshotKit tests. Its 711 WhereUI tests found four calendar binding-observation failures and one new timeline test waiting on a transient command; all five were corrected and the rebuilt 19-test mounted regression set passed.--record never --review. This review follow-up updates five reviewed accessibility legends in feat(WhereUI): adapt Where for iPhone Duo #372 and removes one obsolete linked-timeline capture; screen pixels in those five updated captures are unchanged../swiftformat --lint,./xcstrings --lint, and complete PR diff checks passed.Native Duo 27.2 geometry measurement remains pending. Synthetic layouts and hosted state tests do not establish native folding, system-bar placement, keyboard behavior, or spoken VoiceOver behavior.
Stack
First active layer, based on main after #377 merged. #372 adds consumer integration. Both PRs remain open for review.
Backlog reconciliation
The 13 preserved Duo records are tracked in Linear. STU-318 owns adoption and its six implementation sub-issues. This slice relates to STU-321, STU-324. Unmerged implementation remains In Review.
Remaining Backlog work: native Duo release validation (STU-316), intermittent Locations settling diagnostics (STU-317), and tall Year accessibility annotations (STU-325). Existing STU-114 and STU-252 now distinguish the partial fixes from their remaining requirements; both retain their priorities, labels, and open state.