InnoRouter 6.0.0 ships the validated package state from the tagged commit.
Documentation
Changes
-
Inspector provides 66 interface strings in English and 15 translated
languages, with semantic context for translators. Mounted views follow
SwiftUI locale changes, including existing failure/status messages and
timestamps; unsupported languages fall back to English. Stable diagnostic
values and app-owned content are not translated. -
Inspector also reads the unchanged string catalog on SwiftPM toolchains
that copy rather than compile it, preserving localization for Swift 6.3
command-line consumers without a generated translation copy. -
Inspector refreshes its native form and split-view boundaries when layout
direction changes, preventing stale mirrored content and hit regions while
retaining parent tab identity, captured data, selection, filters, scenario
state, URL input, and ownership of in-flight execution. -
Inspector recording controls remain individually operable in narrow sidebars.
Timeline filtering clears hidden selections, shows explicit empty results,
and never restores a stale detail when a filter is removed. -
Immersive hosts keep a stable native lifetime boundary while their canonical
content changes. Disappearance callbacks retain the token from appearance, so
a closing old space cannot dismiss a newly accepted space with the same ID. -
Generated deep-link traversal consumes a one-shot child-entry permit instead
of nesting an extra TaskLocal scope at every level. This reduces stack use
while preserving the depth-64/work-1,024 limits, cycle detection, and isolation
of roots started by application conversions or their child tasks. -
A restored regular window now closes from its own mounted scene context if
its canonical route disappeared before native reopening finished. This
prevents a blank native window surviving an approved deferred close even
when the driver's value-based dismissal ran before reattachment completed. -
Restoration activation, snapshot writes, removals, and stop now share one
status-publication owner. Late completions cannot hide a newer loading state
or persistence failure. Initial-restore lifetime, durable command ordering,
and each operation's caller result remain independent of displayed status;
automatic saves acquire status ownership only after their debounce ends. -
Independent deep-link lookups inside custom parameter conversions no longer
inherit a feature's traversal admission, including lookups made by tasks
created during conversion. Feature cycles and per-traversal limits remain
enforced. Late snapshot removals no longer overwrite a newer save's progress
or failure status, while still completing their durable work and reporting
storage errors to their original caller. -
Durable commands now run in the order the driver accepted them, so a removal
accepted after a save can no longer be overtaken by that save and leave the
deleted snapshot or pending link back on disk. A command that never reaches
storage, such as one whose encode failed, no longer blocks the commands
behind it, and ordering is per driver: unrelated drivers still write
concurrently. Retrying an unfinished initial restore no longer depends on the
displayed status, so a concurrent save — successful or failed — cannot
consume the restore attempt that never ran. Recursive@FeatureRoutegraphs
now terminate in every generated deep-link entry point instead of recursing
until the stack overflows; a cyclic edge contributes no catalog entries and
resolves to nothing, while independent branches and a child shared by two
parents keep working. Generated feature traversal now includes the root and
enforces per-call depth and work budgets, so endlessly growing generic
specializations fail closed instead of crashing. Incomplete catalogs expose
no partial entries and report a traversal-limit explanation. An explicitly
stopped initial restore also remains observation-only across later
detach/attach cycles instead of replaying an old snapshot over newer state.
A generic router declared inside another type now keeps
its generic arguments in the generatedPresentationandScenehelpers.
@Routerno longer reports E016 or E048 for a same-named instance property
or for a declaration inside inactive conditional compilation; real
collisions with the generated static catalogs and nested types are still
rejected. -
Restoration activation now establishes observation and its starting revision
when the shared lifetime is reserved, rejects stopped workers and late manual
claims, and preserves newer navigation across restore completion. Deferred
expiration tasks are bound to one registration lifetime, so a cancelled
timer cannot expire a newer request that reuses the same deferral ID.
@FeatureRoutenow preserves enclosing-routeSelfpayloads in direct,
nested, and generic routers and permits an associated-value case named
routerFeatureCatalogwhile retaining E067 for a parameterless conflict. -
History-owned checkpoint moves now finalize from their own terminal event,
preserve newer navigation, wake record-count waiters, and transfer queued
deferral ownership before an immediate resume or cancellation can complete.
Shared restoration activation now follows all mounted or manual owners, so
cancelling one host cannot stop another live host's automatic saves. Removed
scene drivers no longer execute immersive effects that were still waiting in
the shared queue. Presentation factories allocate collision-free local
bindings and resolve recursiveSelfin the route context. Feature metadata
moves fromRoute.Feature.catalogtoRoute.routerFeatureCatalog, leaving
natural feature cases such ascatalogand same-named instance properties
available while diagnosing direct generated-member conflicts precisely. -
Restoration cancellation now removes its complete deferred request family;
immersive restoration serializes native effects and compensates obsolete
successful opens; partial scene reconciliation preserves each window's
completed Store ownership. MultipleRouterHistoryobservers now follow
one another's successful navigation without duplicating their own moves.
Case-path generation avoids associated-value binding collisions, resolves
recursiveSelfpayloads in the enclosing enum, and preserves conditional
availability. Scenario source generation rejects the discard identifier
anywhere a Swift declaration or qualified factory name is required. -
Macro-first hosts and scene/restoration drivers now follow replacement
application-owned stores and driver leases without retaining stale SwiftUI
state. History and restoration stop/reset operations cancel their complete
request families;RouterHistoryFailure.cancelleddistinguishes a superseded
move from a permanently stopped history. Restoration cleanup correlates the
exact initial transition or resumed deferral, so an unrelated restoration
event cannot release another driver's cancellation ownership. -
Generated deep links now return a URL only when it resolves to the original
route, including static-path collisions and composed Feature ambiguity, and
required path values reject empty segments. Conditional@Routableand
@CasePathablecases preserve compiler branches, conditional presentation
diagnostics inspect syntax instead of source text, and scenario source
factories share strict Swift identifier validation. -
Feature, window, and immersive scopes now carry Store-owned logical lifetime
tokens through queueing, policy suspension, and deferral rebasing. Stale
scopes cannot mutate a same-ID replacement Scene or complete another
Feature's presentation. -
Native Scene failure repair now uses a bounded, lifetime-deduplicated Store
lane that is not dropped by the application request queue limit and does not
evict, interrupt, or bypass serialization for ordinary requests. -
Scenario fixture format v7 preserves ownership for ordinary Feature actions,
presentations, completions, and plans. Older formats fail closed instead of
replaying a Feature request as an unscoped root action. -
Feature plans containing window or immersive inventory are rejected before
root extraction, policy admission, or partial mutation. -
@PresentationResultfactories preserve conditionally compiled availability
clauses, including nested compiler conditions, and downstream consumers now
verify both guarded success and unguarded availability diagnostics. -
Feature plans now revalidate their complete nested macro feature ownership at
executor and resumed-commit boundaries. Scenario fixture format v6 records
that mapping path; replay and generated tests require resolvers built from
the same typed mappings and fail closed on missing or duplicate resolvers. -
Pending-link cancellation now follows one logical Store request through
queueing and arbitrarily repeated policy deferrals, including a resumed
non-cooperative policy. Cancelling the slot returns the serialized lane
without allowing a late commit. -
Immersive restoration now distinguishes opened, user-cancelled, failed, and
stale native results. Failed opens repair only the current canonical
lifetime, release reservations, and bypass application admission policies. -
@Routerdiagnoses conditional@FeatureRoutedeclarations consistently,
including conditional attributes and nested qualified spellings.
@PresentationResultfactories preserve all case availability attributes. -
Changelog phase checks now share one Bash-only implementation that can run
in the Ubuntu release-contract job without Swift or ripgrep. -
Feature plans now retain scoped intent through queueing, policy deferral,
scenario capture, and replay. Rebased plans replace only their owned subtree
and preserve current sibling navigation and application scene inventory. -
Cancelling a pending-link slot now cancels its owned Store request and blocks
late commits. Deferred native scene closes restore the authoritative scene,
dead scope cache entries are weak and bounded, and programmatic requests no
longer force unrelated native binding reconciliation. -
Pending-link persistence now gives every restore/save/submit/cancel/resume
operation explicit generation ownership. Caller or driver cancellation
prevents a late storage load from resurrecting a gated link or overwriting a
newer operation's status. -
Scenario fixture format v5 records each request's revision precondition and
cancellation origin. Replay translates revisions relative to its own
baseline, reproduces queued stale-history outcomes, and distinguishes an
explicit request cancellation from a deferral.canceldecision or an
unrepresented history lifetime. -
Scenario recording now observes actual active and queued request cancellation
at the store boundary instead of inferring controls from cancelled terminal
events. Generated external fixtures cover stale history plus action and
history deferral-resume cancellation. -
Restoration stop and caller cancellation now cancel the exact owned restore
request, release its serialized execution lane, and prevent a late policy
result from committing without cancelling unrelated or newer work. -
Scenario history validation now distinguishes the navigation-only intent from
its merged exact action. Existing scenes can precede history submission,
while tampered resumed actions and unrepresented stopped-history lifetimes
fail preflight before any production request executes. -
Bound caller-driven presentation cancellation and native immersive-space
disappearance to the exact presentation UUID or scene lifetime that
originated the request. Deferred/resumed presentation work now cancels its
active policy race, releases the serialized lane, and rechecks ownership
before a late non-cooperative policy can commit or defer again. -
Native sheet, cover, and popover dismissal callbacks retain the UUID that
created their binding, so a delayed system callback cannot remove a newer
replacement presentation. Presentation detent callbacks use the same guard. -
History rebase now reconstructs its navigation-only plan at executor entry,
preserving current windows, immersive spaces, badges, and non-conflicting
presentations even when the resumed request waited in the queue. Conflicting
presentations and incompatible topology return structured rejections. -
Scenario replay and generated tests now validate the complete request and
deferral control graph before production execution, rejecting duplicate
logical submissions, invalid event indices, missing terminals, and invalid
deferral ownership. -
Scenario replay now registers every actual deferred outcome before
validation or cancellation can fail, so failure cleanup cannot leave
replay-owned work able to commit later. -
Macro-generated deep-link catalog witnesses qualify
Swift.String, allowing
application route enums to own a payload type namedStringwithout
changing its conversion semantics. -
Closed third-review races by propagating cancellation into queue-promoted
executor tasks, binding typed presentation completion to the exact UUID and
completion owner, and draining scenario-replay-owned work before failure or
cancellation returns. -
Scenario replay now rejects a mismatched complete initial state before the
first request. Inspector scenario failures expose localized payload-free
categories instead of arbitrary error descriptions or stale raw exports. -
Macro catalog purity now uses runtime type identity, so shadowed standard
names cannot invoke application converters during read-only analysis.
Feature URL rendering preserves each parent or child declaration's own
origin allowlist and round-trips through composed routers. -
Closed the 6.0 review races around feature-scope execution, partial restoration
cancellation/fallback, synchronous history checkpoints and deferred cursors,
and test waiter shutdown. -
Scenario fixture format v3 adds route/environment/dependency preflight,
logical-to-live deferral identity mapping, request-owned terminal validation,
rejection categories, and separate Swift/JSON generated artifacts. -
Macro catalogs now compose child-feature declarations and matchers under
stable feature namespaces, reject ambiguous feature instances, and keep the
default Inspector explanation path free of application conversion code. -
The Inspector deep-link workbench now shares only payload-free structural
summaries by default and offers an opt-in scenario recording, progress,
stop/cancel, raw export, and native raw-import workflow.
Breaking
- InnoRouter is now macro-first:
@Routerunlocks oneRouterStore, one
recursiveRouterState, and oneRouterActionvocabulary. - The selectable library products are now only
InnoRouter,
InnoRouterTesting, andInnoRouterInspector. The former granular runtime,
macro, effects, scene, and spatial libraries are removed from the external
dependency contract. - The independent
NavigationStore,ModalStore,FlowStore,AppShellStore,
AdaptiveSplitStore, andSceneStoreauthorities and their intent/plan
families are removed from the public API. See the 6.0 migration guide. - Coordinator callback lifecycles are replaced by exact, result-bearing
presentations onRouterStoreandEnvironmentRouter. - Deep-link authentication is now actor-safe:
isAuthenticatedis async and
RouterLinkPipeline.decide(for:)must be awaited. - Snapshot encoding is now off the main actor, so
RouterStore.snapshot(using:)must be awaited. TerminalRouterEventcases
also carry theirRouterTransitionContextdirectly. RouterTestStore.finish()is async so it can diagnose and then await
cancellation of store-owned requests, timers, waiters, and deferrals.- Native scene actions are available only when the route conforms to
RouterSceneRoute; unsupported scene styles and mismatched immersive IDs
are rejected instead of entering canonical state. - The retired 5.x implementation and regression tree is no longer shipped in
the checkout. Migration evidence remains available in Git history only. - Custom split-column identifiers and initial native split state now use the
throwingRouterTwoColumnSplitLayoutandRouterThreeColumnSplitLayout
contracts instead of raw host parameters. - Deep-link hosts and explicit store handling now share
RouterLinkExecution; the duplicateRouterLinkEventvocabulary is removed.
Added
-
Macro-first feature composition now uses
@FeatureRoute,
RouterFeatureMapping, andRouterFeatureHostto project independent route
modules through one parent store without child authorities. -
RouterTestRuntime, virtual time, correlated request handles, and strict
pending-work diagnostics make timeout, queue, cancellation, and deferral
tests deterministic. -
App-validated partial restoration keeps valid sibling state, reports every
removal or replacement, and rejects stale validation commits. -
inspectorCatalog: truegenerates a payload-free deep-link catalog and
explanation path consumed by the Inspector URL workbench. -
Explicit scenario capture separates observations from developer-authored
expectations and emits realRouterTestStoreSwift Testing source only for
complete, bounded fixtures. -
RouterHistoryadds bounded navigation-only back/forward and named
checkpoints while preserving modal, badge, and scene lifetime state. -
Public API extraction now includes every module re-exported by the umbrella,
including Apple system integrations, and a separate per-product symbol
budget prevents baseline regeneration from silently expanding the surface. -
Fixed-seed state-machine, malformed-input, event-stream, and object-lifetime
suites now back the canonical invariants. Release publication also requires
independent Thread Sanitizer and Address Sanitizer jobs. -
The performance workflow now records seven release-mode samples: reducer,
snapshot, deep-link, Inspector, scenario capture off/on, history-capacity,
and catalog-size throughput, in a validated JSON trend artifact. -
Coverage keeps the portable 85% gate and now also uploads a comprehensive
all-library LCOV report plus per-component JSON visibility for native hosts,
macro bootstrap code, and every previously floor-excluded source. -
A real downstream migration gate now builds the exact published 5.2.1
NavigationStorescenario and its macro-first 6.0RouterStorereplacement,
then fails if their expected final navigation behavior differs. -
RouterObservability.signpostsexposes payload-free transition intervals to
Instruments, andInnoRouterVersion.currentsupplies one release identity
for application and support diagnostics. -
RouterSnapshotMigration.codableturns adjacent snapshot upgrades into
compiler-checked old-payload-to-new-payload transforms. -
Inspector can export a deterministic
RouterInspectorDiagnosticBundlewith
platform and framework identity around its redacted timeline; bookmark order
is stable across runs. -
RouterActionSequenceadds versioned, deterministic action fixtures that
replay through the production reducer, policy, and event pipeline in
RouterTestStore. -
RouterActionSteppreserves per-action provenance, animation, request keys,
and deferral context during serialization and policy-aware sequential replay. -
Inspector reopens diagnostic bundles in the Recorder and native view,
rejects unsupported formats and duplicate envelope keys, enforces import
limits before entry decoding, and clears stale timing on session replacement. -
Snapshot validation rejects nonpositive schema versions and out-of-range
migration definitions without integer overflow. Signpost intervals close
exactly once on all terminal outcomes, replacement, and adapter teardown. -
RouterStatemodels stacks, presentations, nested tab/split branches,
selections, badges, regular windows, and immersive state in one validated
value.RouterScopeprovides stable read-only subtree projections. -
RouterStoreruns a pure reduce → async policy prepare → atomic commit
pipeline with typed busy, rejection, cancellation, and stale outcomes. -
RouterPlanis the shared exact-state value for transactions, deep links,
and restoration. -
RouterSnapshotCodecadds deterministic versioned snapshots, adjacent
migrations, typed failures, and explicit fallback provenance. -
Result-bearing presentation distinguishes returned values, interactive
dismissal, caller cancellation, and policy rejection. -
RouterLinkPipelinemaps admitted URLs directly to complete plans and can
retain an authentication-gated plan without partial navigation. -
RouterTabHostkeeps independent tab histories inside the same store.
@Routersupports mixed@TabItemroots and ordinary destinations and
generates stable case-name scope identifiers. -
RouterTestStoreasserts the production transition lifecycle host-lessly. -
InnoRouterInspectorrecords a bounded correlated timeline with structural
before/after summaries and route-payload redaction by default. -
The pre-release candidate includes the planned 6.1 capability set: FIFO
request scheduling, atomicRouterPlanBuildertransactions, semantic
transition source/animation metadata, popovers and presentation options,
macro-generated typed presentation requests, and system-binding
reconciliation after rejected transitions. -
@Scenenow forms a partial window/immersive catalog on the same@Router
enum, andRouterSceneDriverreconciles committed scene state with native
SwiftUI scene actions. Regular windows preserve their exact UUID through
value-basedWindowGroupopen and dismissal actions; scene lifecycle
modifiers feed interactive closure back into the store and reopen a scene
whose system-originated dismissal is rejected by policy. -
App Intent URL generation and universal-link-only Handoff continuation share
the canonical deep-link plan pipeline. UIKit and AppKit hosting bridges reuse
the application-ownedRouterStore. -
The optional Inspector adds search, payload-redacted state trees, structural
diffs, JSON export, and non-mutating pure-reducer replay previews. -
The pre-release 6.2 capability set adds
@EnvironmentRouterStateand its
narrow read-only projection, explicit pending-link replacement/cancellation/
continuation, and an opt-inRouterRestorationDriverwith atomic file
storage and scene-phase flushing. -
Inspector sessions can now be imported, stepped, and compared without a live
store.RouterTestStoreaccepts transition context and exact plans and adds
snapshot, restoration, unchanged-event, and complete-state assertions. -
The best-effort 6.3 capability set adds payload-safe
RouterObservability
adapters for unified logging or app-owned metrics and a typed
RouterShortcutCatalogshared by concrete application App Intents. -
Regular windows and immersive spaces now retain their own recursive
navigation nodes in canonical state.@Scenegenerates typedRoute.Scene
requests, whileRouterWindowHostandRouterImmersiveSpaceHostrender the
exact scene-local stack and presentation lifetime. -
RouterSplitStateandRouterThreeColumnSplitHostadd validated two- and
three-column topology, independent column histories, visibility, and compact
column preference. -
Atomic
pushIfNeeded,backOrPush, andreplaceTopactions avoid common
read-then-write races. Semantic request keys add keep-first and
replace-pending coalescing without disturbing unrelated FIFO requests. -
Policies can defer any transition, release the execution lane, and resume,
reject, or cancel explicitly. Resume is revision-safe by default, with an
opt-in rebase strategy, and awaited presentation results survive deferral. -
Presentation state now includes selected detent, background/content
interaction, and corner radius.@TabItemadds selected images and native
search-tab roles. -
RouterPendingLinkPersistenceDriveradds versioned, atomic persistence for
the exact pending authentication continuation at an app-selected location. -
Inspector sessions now preserve bookmarks and correlated timing, compare
arbitrary captured states, pause on terminal rejection, and import JSON
snapshots through the native file importer. -
RouterPlatformCapabilitiesdeclares the exact native feature contract for
every supported Apple platform. Presentation and tab fallbacks emit
deduplicatedplatformAdaptedevents that observability and Inspector expose
without route payloads. -
Platform runtime tests now execute the same capability and adaptation
contract on iPhone, iPad, Mac Catalyst, tvOS, watchOS, and visionOS. -
Request admission is now explicitly bounded: callers can choose queue
overflow behavior, set a policy timeout, and bound or expire unresolved
deferrals with typed eviction, capacity, and expiry outcomes. -
RouterTabCatalogandRouterSceneCatalogadd throwing structural
validation for advanced manual conformances while keeping@Routeras the
default catalog producer. -
Inspector JSON import now preflights encoded bytes and top-level entry count
before full decoding. Platform CI emits and verifies library-evolution
interfaces for all three public products on every floor, including Mac
Catalyst.
Fixed
- Slow restoration loads cannot overwrite a newer committed revision, failed
activation can be retried, stale debounce tasks cannot discard newer saves,
and snapshot encoding no longer blocks the main actor. - Regular-window UUIDs cannot be reused for a different route. Scene dispatch
rechecks revision ownership around native async operations and rolls back a
failed open through a non-rejectable, revision-checked system repair instead
of leaving an unrepresented canonical scene. @EnvironmentRouterStatetracks its narrow path, presentation, selection,
badge, window, and immersive projections instead of invalidating every
reader for every router mutation.- Default Inspector exports redact scope identifiers, native window UUIDs, and
immersive identifiers while using collision-free structural node IDs. - Cancellation no longer retains arbitrary unknown request identifiers, and
observability adapters report the real source of terminal transitions. - Slow pending-link loads cannot overwrite a newer in-memory submission, and
concurrent saves converge on the latest slot generation. - A typed presentation deferred by policy now keeps its original result waiter
alive through approval and completes it on deferred rejection or cancellation. - Split hosts no longer force-unwrap custom three-column topology, and platform
adaptation deduplication keeps a bounded recent-event history. - Policy deferral diagnostics are informational instead of being classified as
rejections. Scope refresh invalidates only the exact system-reconciled
subtree, and AppKit-only hosting code no longer leaks into Mac Catalyst. - Caller cancellation now terminates timed policy preparation immediately even
when the policy itself does not cooperatively observe cancellation.
Full Changelog: 5.2.1...6.0.0