·
6 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
InnoRouter 6.1.0 ships the validated package state from the tagged commit.
Documentation
Changes
Changed
- Release publication checks the runtime identity and both installation
READMEs against the candidate version, with separate GA and prerelease
changelog rules. GA publication also verifies the remote package's exact
resolved version and commit before publishing the release. - Inspector UI preparation uses explicit, acknowledged Hold/Resume commands
instead of a nested native switch. A dedicated regression verifies held,
cancelled, and resumed execution; localization and interaction checks remain. - Platform CI runs the native iPadOS and visionOS scene policy probes and
preserves their logs. Independent visionOS policy cases run in fresh
processes; the combined rapid-reopen stress mode remains available separately. - Repository CI now tracks exact SwiftPM resolutions. The integration workflow
delegates its duplicate DocC site build and source lint pass to the existing
required sibling jobs; standalone and release principle gates still run the
complete contract. DeepLinkMatcher.diagnosticsis computed on demand instead of stored.
Reading it is unchanged — the same diagnostics are reported, including on a
matcher configured with.disabled, which continues to suppress emission
rather than availability. No migration is required. Computing the value
compares every pattern pair, and@Routerbuilds a matcher inside each
generatedresolveDeepLinkcall, so storing it charged that quadratic pass
to every deep-link resolution and then discarded the result. Resolution is
now linear in catalog size: on a 60-case catalog, 627µs before and 50µs
after. The property is recomputed per access, so bind it to a local when
inspecting it repeatedly.
Fixed
- Revoking automatic restoration saves now reaches the storage actor. An old
save queued behind a slow load can no longer run after stop, last detach,
superseding navigation, or removal and overwrite a replacement driver's
file. Explicit saves retain their accepted durability contract. - Scene lifecycle persistence no longer replaces an unreadable, oversized, or
otherwise failed initial snapshot with the Store's pre-restore state. It
waits for an accepted restore or an independent navigation commit; explicit
save()andremoveSnapshot()calls keep their existing app-controlled
behavior. - Snapshot migrations once again wrap every application transform failure in
migrationFailed, including a transform that throwsRouterSnapshotError.
This preserves the 6.0 recovery contract while codec-generated migration
payload limit failures remain distinct typed errors. - Explicit tab restoration captures its starting revision before decoding,
preventing a late snapshot from overwriting newer navigation. Reconciliation
validates mutable state before indexing branches and rejects non-stack nodes
used by current tabs. The orphan-tolerant host rejects an orphan selection
and invalid current stack shapes before rendering. RouterTabHost(store:)no longer aborts the process when the store's tab
branches do not match the router's catalog. That initializer is a SwiftUI
Viewinitializer, re-run on every parent body pass, and the branches are
not always what the application chose: restoration applies a decoded snapshot
through.apply, which replaces the root wholesale, and partial restoration
preserves branch identifiers as written. A snapshot taken before a tab was
renamed or removed therefore reached a host whose catalog no longer matched,
and the assertion fired on the next render. The host now renders its catalog
and leaves an orphaned branch unused, and a restored selection naming a tab
that no longer exists falls back to the first tab. Bumping
RouterSnapshotCodec.currentVersionremains the way to reject or migrate an
old snapshot deliberately.@Routableand@CasePathableno longer crash the compiler on a case whose
argument label is a keyword, such ascase detail(in: Int). The label was
reused as the extract binding, which emittedlet inand failed to parse
inside the expansion. Labels keep their own spelling and bindings are escaped
independently.@Routerwas never affected.- Generated argument labels no longer carry an author's backticks, which made
case foo(default: Int)emit an "does not need to be escaped" warning
inside the expansion that the author could not silence. DeepLinkMatcher's documentation no longer shows aFlowPlansample, a 5.x
type that no longer exists, and now states that a bare matcher compares path
and query only and never checks the URL origin.@DeepLinkand
RouterLinkPipelineremain fail closed and are the surfaces to prefer.- The documentation metadata gate parses explicit implementation and
publication states, version, commit, and date fields. Negated and future
publication prose cannot satisfy a publication claim; duplicate fields and
contradictory metadata fail, while unpublished work remains representable. - The documentation consistency gate reads the release identity from
InnoRouterVersion.swiftinstead of requiring the literal6.0.0, so a
later version no longer fails the gate for being accurate. It validates that
the runtime version is SemVer and that both READMEs install it. A
publication run can passRELEASE_VERSIONto require that the candidate,
the runtime, and a dated changelog section all agree. - The sanitizer smoke filters now run
RouterTabHostTests,
RouterDeepLinkHostTests, andNativeHostRuntimeTests, which cover the
SwiftUI host boundary that restoration commits through, and
RouterDeepLinkBehaviorTestsnow runs under the address sanitizer as well as
the thread sanitizer.
Added
- Applications can opt into finite snapshot envelope, payload, migration, and
file-I/O byte limits. Existing snapshot codec and file-storage initializers
retain their unbounded 6.0 behavior. - Automatic restoration can opt into route-level partial validation with an
optional current tab topology. It exposes the initial report separately from
the transition and persists only accepted normalized state. @TabItemaccepts an optional literalid:so a tab's persisted scope can
remain stable across route case renames. Duplicate effective IDs fail during
macro expansion; existing annotations keep their case-name identity.- A complete macro-first tab restoration example demonstrates file persistence,
catalog changes, restore outcomes, and reopening a saved session. The public
DocC catalog links a focused restoration guide and distinguishes the existing
6.0 surface from APIs added in 6.1.0. - Partial restoration reports include payload-free
topologyChangesfor
inserted scopes, scope order, and selection changes. Older encoded reports
decode with an empty change list; the transition outcome still determines
whether the reported candidate was applied. RouterTabRestorationTopologyrestores a snapshot into the tab catalog an
application renders now. Restoration stays exact by default, so a snapshot
written before a tab existed leaves that tab unreachable. Passing a topology
toRouterStore.restore,RouterStore.restorePartially,
RouterRestorationDriver.init, orRouterTestStoreadds the missing scopes.
Build it withinit(of:)from a@Routerenum orinit(catalog:)from a
manual catalog. The value carries ordered scope identity only — no routes,
presentations, badges, store, or view — so reconciliation creates empty
scopes and cannot move payload into a restored state. A scope the snapshot
carries is kept exactly; a branch the topology does not name is preserved
after the current scopes for a later catalog; a selection it no longer names
falls back to its first scope. Partial restoration reconciles before
validating, so the application validates the candidate that will be applied.
A state returned byRouterSnapshotRecoveryPolicy.useis never reconciled.
Render a store restored this way with
RouterTabHost(store:catalog:allowingOrphanedBranches:); the existing
init(store:catalog:)keeps its exact set match.- Fix-its for redundant
Route/DestinationRouteconformances and for
duplicate@TabItem,@Scene,@DeepLink,@FeatureRouteand
@PresentationResultmarkers.
What's Changed
- Fix macro keyword-label compiler crash, deep-link resolution cost, and unrunnable gates by @Ethan-IS in #47
- Fix RouterTabHost abort on restored tab drift, extend fix-its, and tighten perf budgets by @Ethan-IS in #48
- Fix queued restoration writes after driver cancellation by @Ethan-IS in #51
- Prepare 6.1.0 release with identity and native verification gates by @Ethan-IS in #53
Full Changelog: 6.0.0...6.1.0