Require Dart 3.13 / Flutter 3.47 and ride the breaking window - #4
Merged
Conversation
Raises the SDK floor on both packages so the workspace can use Dart 3.13 language features — primary constructors above all, which line up 1:1 with the C# primary constructors used throughout upstream dotnet/extensions. extensions moves from ^3.6.0 and extensions_flutter from ^3.10.1. extensions_flutter also gains an explicit flutter >=3.47.0 constraint, the release that ships Dart 3.13. No source changes are required by the bump: the codebase has no final/var-on-parameter declarations, so nothing becomes a compile error at language version 3.13. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dart fix --apply, 67 fixes across 42 files: 63 prefer_initializing_formals,
3 unnecessary_underscores, 1 use_null_aware_elements. dart analyze is clean
again afterwards, and all 997 tests pass.
prefer_initializing_formals accounts for nearly all of it, rewriting
`Foo({required String bar}) : _bar = bar` as `Foo({required this._bar})`.
Dart 3.13 strips the leading underscore from a named initializing formal,
so `Foo(bar: …)` call sites are unaffected — that is the same language
change that lets primary constructors initialize private fields, so this
is the form the port moves toward anyway.
Kept separate from the reformat so it can be reverted on its own if the
constructor style is not wanted; the alternative is disabling
prefer_initializing_formals in analysis_options.yaml.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Formatting only — no behavioural change. dart analyze is clean and all 997 + 47 tests pass. The tall-style formatter is gated on language version 3.7, so raising the floor to 3.13 switched it on for the whole workspace. Landing it as one isolated commit keeps it out of unrelated diffs; leaving it undone would make committed formatting non-idempotent, so the next format-on-save or `dart format .` would drag it into whatever change happened to be in flight. There is no supported way to stay on short style at language version 3.7 or above — `formatter: page_width` sets width, not style. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
analysis_options.yaml wrote the rule as `- lines_longer_than_80_chars: true`. That YAML is a list entry holding a map rather than a rule name, so the analyzer silently ignored it and the repo's own 80-character rule had never been enforced. Correcting it surfaced 17 violations in extensions. extensions_flutter had no such rule at all despite being held to the same convention; adding it surfaced 5 more. All 22 are comments, doc text, or strings the formatter cannot break, so they are rewrapped by hand. Three needed a small restructure: - CollectionModelBuilder: the VectorDataStrings.configuredEmbeddingType* calls are too long to fit at their nesting depth, so the ternary moves into _unsupportedConfiguredEmbeddingTypeMessage. - ToolCallAccuracyEvaluatorContext: the params suffix moves into _paramsSuffix. - The intent-resolution and task-adherence evaluators hoist the tool list into a local instead of interpolating a full map/join chain. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
porting.md's primary-constructor section said the workspace could not use them and warned that final/var-on-parameters made the bump "a real migration". Both are now wrong: the constraints are raised, and that idiom never appeared in this codebase — zero occurrences, zero analyzer errors at language version 3.13. Replaces the warning with what the bump actually cost (formatting and lints), adds the underscore-stripping rule for named initializing formals, and adds a Formatting section covering tall style and the correct YAML for lines_longer_than_80_chars. Marks the drift ledger's analysis_options hygiene item closed; the other two items in that entry are untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI ran only `dart test`, so nothing guarded the analyzer or the formatting the 3.13 move just normalised — the tall-style output is stable only while the SDK floor holds, and a stray reformat would otherwise land unnoticed. Uses --fatal-infos deliberately. Every lint this repo relies on reports at info severity, and a bare `dart analyze` exits 0 on those: verified against a probe file with an 81-character line, where plain analyze exits 0 and --fatal-infos exits 1. Without the flag the step would pass on exactly the violations it exists to catch. Runs as its own job rather than as steps in `test`. The reporter steps are guarded with `if: success() || failure()`, so a lint failure early in the test job would leave them reading a test-results JSON that was never written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No new upstream drift: upstream counts unchanged since 2026-08-13 and every unmatched type across all 15 scope rows was already an N/A entry or a known open item. API surface sample (10 abstractions) found no member gaps. New in the ledger: the IConfiguration/IConfigurationSection I-prefix inversion in configuration/ (public API, so a next-major item — three prior audits missed it because they grepped only `abstract interface class I`), test-coverage denominator recounted to 489 after the reformat, and confirmation dates refreshed. Also fixes the stale primary-constructor note in .claude/commands/drift.md, which still described the workspace as pinned to ^3.6.0 after the 3.13 bump; it now defers to porting.md as authoritative. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the ledger's first open priority. Every previously-unmatched type in the two 2026-08-13 scope rows now has a recorded ruling, each verified against fetched upstream source rather than assumed: - N/A by library: Evaluation.Console (executable CLI), Reporting.Azure (Azure Storage SDK bindings), and the entire OpenAI adapter layer (no allowlisted OpenAI Dart SDK to adapt; the Dart open_ai/ is a deliberate hand-rolled client). - N/A by collapse (~20 types, with the Dart counterpart named in each row): the *Extensions helpers fold into instance methods or existing extension types, the STJ serialization layer into dart:convert, SimpleChatClient into ResponseCachingChatClient, ContentSafetyService + payloads into the ContentSafetyEvaluator base (with a fidelity caveat recorded). - Four genuine gap clusters stay open, now precisely characterized: the report-generation pipeline, IntentResolutionRating + the evaluator's JSON protocol, result-level bulk helpers, and disk-store hardening (path-traversal guard + natural iteration ordering). 62 of the audit's 112 open types dissolve into recorded decisions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes most of the ledger's ai priority. Ported from upstream
Microsoft.Extensions.AI(.Abstractions), each as a Dart extension with the
getService overloads collapsed per the porting rules, all with tests:
- EmbeddingGeneratorExtensions: generateEmbedding, generateVector,
generateAndZip (Dart records for the C# tuple array)
- ImageGeneratorExtensions: generateImages, editImage, editImages (the
bytes+filename overload stays unported pending a MediaTypeMap)
- SpeechToTextClientExtensions: DataContent conveniences
- SpeechToTextResponseUpdateExtensions / TextToSpeechResponseUpdateExtensions:
update-stream combining, with adjacent-text coalescing on the STT side
and audio-chunk concatenation on the TTS side (the Dart response carries
a single DataContent rather than upstream's content list)
- HostedFileClientExtensions: uploadDataContent, downloadFromContent,
downloadAsDataContent (metadata via getFile), getMetadata
- TextToSpeechResponseUpdateKind + a kind field on the update, defaulting
to audioUpdating per the upstream property initializer
- AnonymousDelegatingEmbeddingGenerator, wired via
EmbeddingGeneratorBuilder.useGenerate
Breaking fix riding the 0.8.0 window: SpeechToTextClient.getStreamingText
returned Stream<SpeechToTextResponse> while upstream streams updates — the
ported SpeechToTextResponseUpdate type was dead code. The interface, all
four decorators, the OpenAI client, and the test fakes now stream updates.
Also exports InvalidOperationException from system.dart: public APIs threw
it, but consumers could not catch it by type without importing from src/.
N/A rulings recorded: TextToSpeechClientExtensions (getService-only),
HostedFileDownloadStream (collapsed onto Stream<List<int>> + getFile
metadata), AIJsonSchemaCreate{Context,Options} (creation side). The
AIJsonSchema transform walker is re-scoped in the ledger as the one
remaining open ai port. New small gap recorded: hosted-file scope
plumbing.
1,029 tests pass (32 new); analyze and format clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The no-I-prefix rule inverted in two places, both public API, both fixed now because the 3.13 floor bump already makes the next release breaking: - configuration: `Configuration` is the abstract type; `IConfiguration` stays as a @deprecated typedef for one release. The old backwards compat alias pointed the wrong way (bare name aliasing the I-name). `IConfigurationSection` keeps its prefix as a documented exception — the bare name is taken by the concrete `ConfigurationSection`, the same collision rule as the globbing IPattern family. - diagnostics: `IMetricListenerConfigurationFactory` had exactly one implementation and no other references, so it collapses into the concrete `MetricListenerConfigurationFactory` per the porting matrix ("interface with one implementation -> single concrete class"). The ledger's earlier rename suggestion assumed no concrete existed. Also fixes the four stale `[ILoggerProviderConfiguration*]` dartdoc references in logging/ — those types were renamed long ago but their docs still pointed at the C# names (4 of the 19 standing dartdoc warnings). The two `i_*.dart` filenames in logging/ stay (types inside are already clean); recorded in the ledger as cosmetic. Both packages: analyze clean, format clean, 1,029 + 47 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dart doc could not resolve a bare [audio] from the extension's scope; the target is TextToSpeechResponse.audio. Back to 16 standing warnings, three fewer than before this branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Second same-day full-scope run. Upstream file sets verified identical to
the morning fetch; the open set reduces to exactly what the ledger
records. The OpenAI and safety-payload N/A rows previously used glob
shorthand (OpenAIRealtime*, Payload{Format,...}) that the audit's literal
matcher cannot expand, which made ruled types look open — names are now
spelled out.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The new CI formatting gate failed on its first run, correctly: logger_provider_configuration_factory.dart was edited by the IConfiguration rename sweep and never re-formatted. The local checks before pushing ran `dart format --output=none --set-exit-if-changed` at the end of an && chain and read its text output — where "1 changed" is the failure signal, not a fix — so the non-zero exit was dropped twice. Verified by exit code this time; both packages format clean, analyze clean, 1,029 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Raises the SDK floor to Dart 3.13 (
extensionsfrom^3.6.0,extensions_flutterfrom^3.10.1, plus an explicitflutter: ">=3.47.0"), and lands everything that should ride the resulting breaking release. Twelve commits, each scoped to be independently revertible.The bump itself
final/varon normal function parameters — the one idiom 3.13 makes a compile error. porting.md's warning to the contrary was wrong and has been corrected.dart fix --applyfor the newly gated lints (67 fixes, dominated byprefer_initializing_formals— 3.13 strips the underscore from named initializing formals, so call sites are unaffected).Correctness fixes found along the way
SpeechToTextClient.getStreamingTextnow streamsSpeechToTextResponseUpdate(wasStream<SpeechToTextResponse>, diverging from upstream; the ported update type was dead code). Interface, all four decorators, the OpenAI client, and test fakes updated;toSpeechToTextResponse()combines updates.lines_longer_than_80_charsis now actually enforced. It was written as- lines_longer_than_80_chars: true, which the analyzer silently ignores; the repo's own 80-char rule had never applied. 22 violations fixed across both packages.dart analyze --fatal-infosanddart format --set-exit-if-changed(separate job;--fatal-infosis load-bearing — every lint this repo relies on reports at info severity, verified against a probe file).Breaking API changes (riding 0.8.0)
IConfiguration→Configuration(deprecated typedef kept for one release).IConfigurationSectionkeeps its prefix as a documented collision exception (concreteConfigurationSectionowns the bare name).IMetricListenerConfigurationFactoryremoved — single implementation, collapsed into the concrete per the porting matrix.InvalidOperationExceptionexported fromsystem.dart(was thrown by public APIs but unimportable).Ported from upstream
Microsoft.Extensions.AISix
*Extensionsconveniences (embeddings, image, STT, TTS-update, STT-update, hosted files),TextToSpeechResponseUpdateKind(+kindon the update), andAnonymousDelegatingEmbeddingGeneratorwithEmbeddingGeneratorBuilder.useGenerate— 32 new tests.Drift bookkeeping
Two full-scope audits (before/after) recorded in the ledger: upstream unchanged; every evaluation/OpenAI scope question now has a ruled N/A or a characterized open gap; ai reduces to the
AIJsonSchemaTransformtrio; dartdoc warnings 19 → 16.Verification: both packages analyze clean, format-idempotent, 1,029 + 47 tests pass.
dart docregion references all resolve (38 regions / 40 refs).🤖 Generated with Claude Code