Skip to content

InnoDI 6.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 29 Sep 02:11
Immutable release. Only release title and notes can be modified.
249e267

Highlights

  • 6.0 introduces explicit @Input and container roles, typed assisted child
    factories, injectable multibindings, graph contract gates, owned async
    preparation, on-demand services, and SwiftUI container lifecycle helpers.
    See the breaking changes and upgrade actions below before updating from 5.x.

  • Release-note extraction handles long Unicode sections on macOS's system
    Bash without repeated full-string whitespace substitution. Exact content,
    missing-section, and empty-section contracts are covered by subprocess tests.

  • Apple trace owners amortize OS random generation in a bounded, lazy 1 KiB
    batch while retaining random UUID v4 instance IDs. The owner lock protects
    batch refill and consumption; disabled tracing allocates no batch. The
    existing trace workloads and budgets are unchanged. See
    profiling evidence.

  • Runtime trace timing moves from mandatory CI/release gating to optional,
    exact-SHA manual diagnostics. Raw measurements and rejection checks remain;
    the reference budgets are not a 6.0.0 performance guarantee. Functional trace
    tests, sanitizer checks, and the separate macro-performance gate are unchanged.

  • Trace sinks execute outside on-demand cell locks. Initializing state is
    installed before a start callback, and waiters recheck it after callbacks
    to avoid lost wakeups. Same-thread, same-cell reentry from any trace callback
    now diagnoses immediately; callbacks may safely resolve a different cell.

  • Host phase observers may synchronously start or retry without losing the new
    generation's cancellation handle or overwriting its phase. Cleanup barriers
    are installed before notifications; replacements started from an idle or
    ready notification wait for the previous container's close hook.

  • Independent macro-performance workloads now cover an assisted factory with
    8 static and 8 assisted inputs, 64-contributor multibinding, and 32-method mock
    generation. Run Tools/measure-macro-features.sh; CI archives all samples,
    dimensions, workload versions, compiler and SHA provenance separately.
    These v1 workloads are report-only until independently calibrated. They do
    not replace, update, or count toward the composite-v2 release/trend baseline.

  • On-demand Sendable safety: unrestricted deferred cells no longer claim
    Sendable, even for a Sendable result, because arbitrary factory captures may
    be unsafe. Keep ordinary on-demand containers on their isolation domain;
    use eager storage or an explicitly main-actor container when appropriate.
    For nonisolated async factories, generated code now uses a separate checked
    handle requiring both a Sendable payload and an @Sendable factory, including
    transitive on-demand dependencies. Overrides preserve the same checks and
    still skip unused factories. Compiler-negative and runtime controls cover
    unsafe captures, payloads, regular/actor-isolated use and async dependency chains.

  • Public collection metadata now uses checked Sendable conformance and accepts
    AnyKeyPath & Sendable at every construction boundary. Canonical member
    literals remain source-compatible; callers building arrays explicitly must
    preserve that intersection instead of erasing to AnyKeyPath. Mutable,
    non-Sendable subscript captures are compiler errors, not silently transferable
    metadata. The @Provide(collection:) canonical-member grammar is unchanged.

  • Post-acceptance contract hardening:

    • Async waiter cancellation no longer retains completed-request IDs across
      scope resets. Caller cancellation is checked during actor-isolated
      continuation registration; late handlers only remove live waiters.
    • Public API baseline schema 9 additionally records typealias RHS identities,
      structure, actor isolation, Sendable and function effects. Compiler/consumer
      mutation tests distinguish source breaks from qualification/format changes.
      Generic RHS references use compiler-declared depth/index slots so direct
      symbol-graph emission and serialized-module extraction compare identically.
      Swift 6.2 omits function @Sendable from symbol graphs. The gate exports a
      compiler interface from each built module and records Sendable positions
      within alias type structure, including nested parameter/return/tuple
      functions. It never infers a missing effect from source text or the baseline.
      Nominal-scope lookup prevents same-named aliases from being conflated;
      missing or ambiguous compiler-interface declarations fail closed.
      Unknown nominal identities and ambiguous parameter metadata still fail
      closed. Tests exercise both compiler paths and distinct nested generic slots.
      This schema update changes no public declarations.
    • Release exact-revision consumers preserve preflight's annotated-tag/main
      ancestry contract after normal main progress. Untagged initial dispatches,
      rewritten history and mismatched checkouts still fail closed.
    • All seven READMEs now use the 6.0.0 package dependency and versioned
      documentation, with a source-migration link for existing 5.x consumers.
  • Follow-up hardening of the c7 review candidate:

    • Validation reads and hashes source bytes before reusing any AST digest,
      including metadata-identical edits. Digest-cache version 7 invalidates old
      records; metadata-hit now means matching metadata and verified bytes.
    • Public API baseline schema 6 retains named actor attributes, isolation,
      public setter availability, mutating methods/getters and nonmutating
      setters (including subscripts). Real compiler/consumer fixtures cover
      breaking changes and formatting-only controls; no public symbols were
      added or removed by this baseline update.
    • Detached transient resolvers share typed dependency-only factory code
      instead of recursively duplicating diamond dependency paths. Each call
      still creates fresh transient values; overrides, lazy resolution and
      escaped-handle ownership remain unchanged.
    • Async preparation uses iterative traversal for deep valid/cyclic graphs,
      preserving declaration-order traversal and reverse close order.
    • Permanent async-scope close releases its stored factory captures. An
      already-running operation retains its own captures until it returns.
    • SwiftPM DAG validation emits a comment-only generated Swift input so the
      consumer compiler waits for the gate instead of racing and cancelling its
      structured diagnostics on warm builds. Clang targets retain report-only
      outputs; Xcode's multi-destination always-run gate remains unchanged.
    • Doctor verification and Graphviz use owned process groups and bounded
      in-memory output tails (16 KiB per stream; merged for Doctor). Doctor keeps
      its 300-second timeout; Graphviz now has a 30-second timeout. Group cleanup
      has a 200 ms TERM grace then KILL, and signalled exit codes use 128+signal.
      Descendants that deliberately leave the owned group are not forcibly
      discovered or terminated. This is not a sandbox for untrusted commands.
      Closed caller standard streams are normalized before spawn so child
      output remains correctly separated or merged.
      These changes do not migrate standalone products, approve a new performance
      baseline, or constitute release approval. Upgrading existing 5.x consumers
      is not a prerequisite for publishing the 6.0 library.
  • SampleApp resolves its local dependency and DAG plugin using the checkout
    directory's normalized SwiftPM identity, matching the other examples.
    Renamed-checkout CI now tests and runs SampleApp as well as building the
    SwiftUI examples; no canonical InnoDI directory name is required.

  • Accepted RFC 0006
    following explicit owner approval on 2026-09-24, after the promotion PR's
    seven-day cooldown. This freezes the 6.0 assisted-factory, @Input, explicit
    container-role and multibinding syntax, including the documented replacements
    for 5.x declarations. It records design acceptance, not a GitHub PR review,
    merge, tag or release approval. Publication is established by the exact-SHA
    Release Gate and immutable GitHub Release, not by RFC acceptance.

  • Re-audited all 46 excellence requirements and 25 follow-up findings against
    code candidate 6332864ea83743fd5fec99c95b98a91b1b06ae8b. A clean Swift 6.4
    strict coverage run passed 355 tests in 37 suites with package line coverage
    90.28% and InnoDIMacros 90.75% (floor 90.70%). Public API, graph schema v6,
    DocC, localized README, link, validation-escape-hatch, fatal-trap, alias and
    runtime trace performance contracts also passed. The synchronized exact
    branch HEAD is rechecked by the release-validation matrix and consumers.
    These are historical candidate measurements, not the final release proof.

  • Hardened the 6.x release-candidate validator so publication fails closed
    unless RFC 0006 has exactly one Accepted status in both its authoritative
    document and the RFC index. Pending, missing, duplicate, and inconsistent
    records are covered by executable release-contract tests.

  • 6.0 breaking ownership correction (R02): Lazy<T> and Provider<T>
    no longer exempt dependency cycles. Local cycles are compile errors even
    with validateDAG: false; global DAG checks also include deferred edges.
    Migrate mutual references by extracting shared state or restructuring the
    graph. Acyclic forward references, transient re-entry, and escaped handle
    lifetime remain supported. No explicit scope-close API is introduced.
    The earlier candidate measurements immediately above predate this correction;
    see final hardening.

  • Migration publication and rollback now use a preserving atomic exchange
    (R01/R09), never an unconditional overwriting rename. Every displaced entry
    remains at a reported recovery path, including after success, so late writes
    through open editor descriptors are retained. A conflict exits nonzero and
    requires review of source and recovery paths; no unsafe restore is attempted.
    POSIX source modes are restored independently of umask. Doctor schema v3 adds
    recoveryPaths; migration's read-only report remains schema v1.

  • DIContainerHostOwner.close() releases stored factory/close captures before
    suspension, without clearing a reentrant new generation's callbacks (R03).

  • Subgraph retry now reserves library-owned scopes before checking states and
    commits all affected generations before release (R04/R05). Selected custom
    DIAsyncPreparing providers fail with nonTransactionalProvider before any
    mutation; prepare/close support remains. DIAsyncScope status/retry/reset/close
    are explicitly asynchronous, including calls made from actor-isolated code.
    Concrete, existential, and generic reset calls now share the same semantics.

  • Added graph explainability commands: --why traces a shortest root path,
    --dependents reports reverse impact, --unused finds containers outside
    every rooted graph, and --diff compares two schema-v6 JSON artifacts.
    --diff ... --check-contract turns that comparison into a CI gate: unchanged
    contracts exit 0 and any scope, node, or edge drift, including assisted input,
    assisted-factory ownership, or ordered contribution changes, exits 5 while
    preserving the human-readable diff. Schema v6 treats canonical factory
    parameter wiring and fixed/assisted child binding pairs as contract. It
    additionally records explicit collection kind, keys, order, contributor IDs,
    and contributor lifetimes. It rejects earlier schemas, missing binding
    metadata, and malformed collection contracts rather than treating them as
    unchanged. Regenerate older baselines before
    comparing them with this candidate. Query selectors now check container and
    provider namespaces together. Cross-namespace collisions list both candidate
    sets and require container: or provider:; exact graph IDs remain stable,
    and provider dependents follow canonical binding IDs rather than parameter
    labels. Fixed-child and assisted-factory queries also follow canonical parent
    input bindings per mount. JSON validation rejects dangling/foreign references,
    invalid ownership, and incomplete ordinary child input coverage before diffing,
    including identical invalid inputs.

  • Connected generated providers to opt-in runtime tracing. Container,
    component, override, on-demand, transient, and async paths now carry the
    canonical schema-v6 provider identity, container owner, and generation;
    start/terminal, override, cache-hit, and wait relationships are emitted
    automatically. The disabled default still avoids UUID/event/buffer
    allocation, events remain metadata-only, and opaque work started inside a
    service is deliberately outside the trace boundary.

  • Completed generated-mock stub preflight across properties, ordinary returns,
    untyped and typed throwing functions, and generic handlers. Setup state is
    independent from optional storage, so an explicitly stubbed nil is not
    reported as missing. Unnamed parameters now receive legal body identifiers;
    unsupported generic typed throws and static properties fail at the source
    attribute without emitting a partial conformance.

  • Added generation-aware reset to actual generated mocks. .calls atomically
    closes and returns the current call-history snapshot while preserving stubs;
    .all also returns every stub to its missing state. Sendable mocks use one
    shared critical region, and @MainActor mocks use actor serialization, so a
    racing call belongs to exactly one generation.

  • Added InnoDI-Migrate --report for deterministic schema-v1 JSON inventories
    before migration writes. Reports expose paths, stable codes, counts, status,
    and diagnostics without including original or migrated source bodies.

  • Removed the superseded underscored assisted-factory SPI after the public
    @Input(.assisted), @AssistedFactory, and @SubContainerFactory surface
    replaced its same-target, cross-module, runtime-isolation, and override
    evidence. The SPI was never covered by SemVer and no recorded pilot remains
    pinned to it.

  • The public assisted-factory bridge now preserves @MainActor on its
    initializer, call, and override-application closure. A same-target Swift 6
    strict-concurrency fixture guards the exact Xcode consumer shape that would
    otherwise reject override forwarding as a non-Sendable actor crossing.

  • Added public @Multibinding for one injectable deterministic ordered
    collection from explicit local synchronous providers with the same written
    type. Macro, serialized validation, graph-v6, and strict external-consumer
    tests cover invalid contributors, injection, shared/transient lifetime
    behavior, contributor order, and overrides. The superseded underscored SPI
    has been removed after public consumer migration.

  • Verified the public RFC 0006 runtime and SwiftUI host pilot in InnoSample
    commit ec88716 against validated InnoDI code candidate
    f1a3eaccf19bfc43164de3621c9197c731d92342. The People route passes the
    consumer's full Xcode 27 gate, proves per-child shared-state isolation plus
    overrides, and replaces its manual state wrapper with DIContainerHost.

  • Added two more committed consumer pilots against that code candidate. BlPia
    c12560d passes Doctor over 160 Swift files, an unchanged second migration
    pass, DAG validation, 10 test schemes, and a generic iOS/watch build; the
    strict hierarchy gate also corrected seven manually provided containers from
    component to local ownership. Lynceus 3edb77b passes Doctor over 81
    Swift files, an unchanged second pass, a real
    two-container full-root DAG, 41 tests, and its macOS build. Mulbyul was tested
    without source changes and is deliberately not counted as a committed pilot.

  • Refreshed the consumer boundary for the T42 candidate in isolated clones.
    InnoSample passes exact resolution, DAG, Remote tests, leaf/root features and
    generic iOS/watch builds. BlPia passes layer/feature/app tests and iOS build
    after explicitly linking trace runtime support into static test bundles.
    Lynceus passes format, Tuist sync, macOS build and all tests; Doctor correctly
    marks its helper-based Tuist target mapping analysis-incomplete instead of
    healthy. Mulbyul committed HEAD 092ff951 remains test-only: its isolated
    Layers build reaches the expected legacy @Provide(.input) source break,
    while read-only Doctor reports 481 files, one proposal and 11 errors without
    applying a change. The original Mulbyul and mixed BlPia checkouts are
    preserved.

  • Hardened migration and workspace analysis from real-consumer evidence:
    ambiguous unqualified 6.0 vocabulary now fails closed (dc34d14), Doctor
    recognizes direct Tuist package workspaces (ac1124b), and skipped hidden
    files no longer suppress following source siblings during full-root graph
    discovery (28a95a5).

  • Added isolated Thread Sanitizer and Address Sanitizer suites to both the main
    validation workflow and the SHA-bound release gate. They run every applicable
    in-process strict-concurrency test from separate scratch paths so sanitizer
    state cannot be reused across lanes; separately spawned fresh-consumer builds
    remain covered by the exhaustive and compatibility jobs.

  • Hardened Xcode 27 / Swift 6.4 release preparation: external-consumer
    diagnostics now preserve exact toolchain-specific compiler output, while the
    public API guard tracks only source-authored product declarations instead of
    SDK symbols re-exported by toolchain-specific SwiftUI symbol graphs. The
    schema-v4 API baseline also preserves a per-parameter default-presence vector:
    removing a default now fails even when the symbol identity does not change.
    Declaration formatting and default-expression values are not API identity;
    executable compiler/consumer fixtures verify the omitted-argument contract.
    Macro defaults are recovered even when older compiler symbol graphs omit
    functionSignature; missing metadata is not silently treated as no defaults.
    The
    coverage collector now accepts both the combined package test bundle used by
    earlier toolchains and Swift 6.4's per-target test bundles, including public
    executable entry points without lowering any checked-in floor.

  • The 6.0 vocabulary migrator and examples now emit a required role: label
    with a named, string-backed ContainerRole token and the established
    mainActor: true option. This avoids a Swift 6.2.3 compiler signal 11 while
    matching a public enum argument in the multi-role attached
    @DIContainerRole expansion, without dropping Xcode 26.2 compatibility from
    the release gate. Arbitrary strings fail with a stable InnoDI diagnostic.

  • Added owned on-demand and async preparation scopes, a SwiftUI container host,
    concurrency-safe public testing support, explicit cross-module ordered/keyed
    provider collections, schema-v6 provider contract queries, metadata-only
    bounded runtime tracing, and a read-only-first InnoDI-Doctor workflow for
    the 6.0 candidate.

  • Added @Provide(collection:) closed metadata for factory-built ordered,
    keyed, value, and provider collections. Key identity, order, canonical
    contributor, and declared contributor lifetime are contractual across graph
    artifacts; explicit empty is valid, duplicates fail, and no factory-body or
    module discovery is performed.

  • Async preparation now rejects already-cancelled waiters before factory start,
    reports request and owned-operation cancellation separately from failure,
    and retries a failed selected child plus its downstream in fresh generations
    while preserving ready explicit parent dependencies.

  • Generated override fallbacks now parenthesize precedence-sensitive raw factory ASTs, full-source
    validation rejects out-of-order child bindings: at the first mismatching
    key path, and async overrides no longer resolve dependencies used only by a
    bypassed live factory.

  • Feature-root helpers now include an identity-taking DIContainerHost
    overload, hosted content receives an explicit lifecycle handle through the
    SwiftUI environment, and #PreviewWithContainer constructs lazily through
    the same generation owner. Existing direct and manual host APIs remain.

  • Added explicit @Provide(effect: .sideEffect) metadata and generated
    Overrides completeness reporting. Test and preview targets can use
    InnoDITesting strict preflight to reject missing effect overrides before a
    live factory runs; recording mode returns the same deterministic report.
    Unmarked opaque factories remain unclassified, and production construction
    does not enable this opt-in policy globally.

Breaking and Behavior Changes

  • New 6.0 vocabulary: replace @Provide(.input) with @Input. Replace
    @DIComponent, @DIHierarchyRoot, and the former @DIContainer(root:mainActor:)
    options with @DIContainerRole(role: ContainerRole.component) for mountable
    features, ContainerRole.root for roots, or ContainerRole.local for local
    isolation. Add mainActor: true to the role macro when needed. Each
    declaration uses one container macro; ordinary containers continue to use
    @DIContainer.
  • Deferred ownership: Lazy and Provider no longer make dependency cycles
    valid. Local cycles are rejected even with validateDAG: false, and the
    global DAG includes deferred edges. Ordinary on-demand storage is not
    Sendable; nonisolated async dependency handles require a Sendable payload
    and an @Sendable factory. Keep non-Sendable state in its isolation domain.
  • Collection metadata: explicitly assembled key-path arrays must preserve
    AnyKeyPath & Sendable. The old assisted-factory and multibinding SPI is
    removed; use @Input(.assisted), @AssistedFactory, @SubContainerFactory,
    and @Multibinding.
  • Graph and tooling contracts: graph JSON is schema v6 and older baselines
    are rejected. Doctor schema v3 adds migration recovery paths; its read-only
    migration inventory remains schema v1. Ambiguous graph selectors require
    container: or provider:. A contract diff exits 5 on semantic drift.
  • Owned async lifecycle: DIAsyncScope status, retry, reset, and close are
    explicitly async. Transactional subgraph retry rejects selected custom
    DIAsyncPreparing implementations before mutation; prepare and close remain
    supported. Applications own shutdown and should await close hooks.
  • Migration safety: applying or rolling back a migration preserves each
    displaced entry at a reported recovery path, even after success. Conflicts
    exit nonzero instead of overwriting late editor changes. Review recovery
    paths before removing them.
  • Tracing and mocks: generated initializers and override operations add a
    defaulted _innoDITrace: parameter. Trace decoders must accept owner,
    generation, origin, related identities, and wait events. Same-cell synchronous
    trace callback reentry is diagnosed. @GenerateMock remains experimental;
    6.0 does not make its generated helper layout a stable API.

Upgrade Actions

  1. Read the 5.x to 6.0 migration guide
    and the accepted RFC 0006
    before changing the package requirement to from: "6.0.0".

  2. From an InnoDI 6.0 checkout, run these read-only checks first, replacing
    /path/to/consumer with the consumer's package or source-tree root:

    swift run InnoDI-Doctor --root /path/to/consumer
    swift run InnoDI-Migrate --root /path/to/consumer --check
    swift run InnoDI-Migrate --root /path/to/consumer --report

    --check exits 1 when migration is required; inspect the report rather than
    treating that result as a tool crash. Review the proposed vocabulary changes,
    commit or back up consumer work, then replace --check with --write only
    when ready to apply them. Resolve dynamic/conflicting sites manually and
    inspect any reported recovery paths.

  3. Replace cyclic deferred wiring, removed SPI, and erased collection key paths.
    Rebuild actual consumers under complete strict concurrency with warnings as
    errors; validate factory captures as well as their result types.

  4. Regenerate both graph baselines with the same 6.0 tools before enabling
    --diff ... --check-contract. Update JSON readers and trace event decoders
    for the schema and metadata changes above.

  5. Exercise async cancellation/retry/close, on-demand overrides, and SwiftUI
    host replacement in each adopting application. Existing products may remain
    pinned to 5.x; publishing the library does not migrate them automatically.