Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
159773 stories
·
33 followers

Former Microsoft product manager launches bid to end clock change in Washington state, Congress or not

1 Share
Scott Thurlow is founder of Last Fall Back Washington. (Photo courtesy of Scott Thurlow)

Scott Thurlow isn’t a morning person. So much so, he wants to change state law.

In 2019, Washington lawmakers voted to put the state on permanent daylight saving time if Congress ever allows it. Thurlow has a different idea: Stop changing the clocks now, even if that means staying on Pacific Standard Time for a while.

Thurlow spent 32 years at Microsoft in product management for franchises including the original Outlook, Teams and, most recently, Copilot. A constant stressor was working across time zones. 

“We always dreaded the time zone changes on either end because it was meeting chaos,” he said. “Talking with India, which is like 12 hours off, went from really bad to worse.”

In July, Thurlow took part in Microsoft’s voluntary retirement program, and was featured in a GeekWire story along with several others. Last week, he launched Last Fall Back Washington, a nonprofit campaign built around what he’s calling the Last Fall Back Act. The idea is straightforward: Washington should move to permanent Pacific Standard Time immediately. 

Thurlow’s campaign is timely: British Columbia is dropping its seasonal clock changes and moving to permanent daylight time, meaning Washington will fall an hour behind its northern neighbor from November until March. Thurlow argues the difference could complicate everything from cross-border travel to transportation schedules and business meetings.

His own proposal would make that gap year-round at first, since Washington would sit on the winter clock while B.C. stays on the summer one. He accepts the tradeoff: stop the switching now, and get back in sync later if Congress makes daylight time permanent nationwide.

He also points to research linking the spring clock change with short-term increases in heart attacks, workplace injuries and fatal crashes — in 2020, one study published in Current Biology reported that fatal crashes increase by about 6% in the week after the spring time change.

Under the federal Uniform Time Act, states can opt out of daylight saving time changes, but only by staying on standard time. Permanent daylight time requires an act of Congress. Permanent standard time does not, which is how Arizona and Hawaii do it. That’s the path Thurlow’s proposal would take.

“If and when Congress ever really does act,” Thurlow said, “we would snap into daylight time.”

Done waiting for Congress

In July, the House passed the federal Sunshine Protection Act by a 308-117 vote, sending the bill to the Senate. The legislation would make daylight saving time permanent nationwide, but the Senate has not taken it up. Thurlow isn’t counting on that changing — although President Trump is pushing for it.

“It’s going to end up withering on the vine and stalling,” Thurlow said.

Washington’s Legislature has also considered permanent-time legislation, but bills introduced since 2022 have stalled without reaching a floor vote.

Washington has two types of citizen initiatives: an initiative to the people, which goes directly to the ballot, and an initiative to the Legislature, which gives lawmakers the opportunity to pass the measure themselves or send it to voters.

Thurlow plans to spend the coming months building support for the latter approach and pushing legislators to introduce and pass the Last Fall Back Act when the 2027 session begins.

“The single most effective thing we can do is have lots of people contacting their legislators,” he said.

If lawmakers again decline to act, he expects to file an initiative to the Legislature around March 2027. The campaign would then need to collect about 386,000 signatures, providing a cushion above the 309,000 valid signatures required. If lawmakers still don’t pass the measure, it could go before voters in November 2028. 

Experts are divided 

Experts seem to agree Washington should stop changing its clocks — but disagree on how to go about it. 

University of Washington law professor Steve Calandrillo has long advocated permanent daylight time, and has testified against Washington legislation that would put the state on standard time. He told GeekWire he appreciates Thurlow’s efforts to pressure Congress, but doesn’t want Washington to spend years on standard time while waiting for federal action.

“I don’t want to see us go in the wrong direction,” he wrote in an email.

Under Washington’s current system, daylight saving time effectively functions as the state’s default for about two-thirds of the year. Permanent standard time would move sunset an hour earlier throughout that period, Calandrillo argues, creating safety risks and other costs.

Evening darkness is more dangerous than morning darkness, he argues, because more people are traveling and spending time outside in the evening — and there’s a greater chance of crime.

Other UW researchers have split on the question. Biology professor and circadian researcher Horacio de la Iglesia has testified in favor of permanent standard time. 

Environmental and forest sciences professor Laura Prugh testified against the 2024 bill alongside Calandrillo, citing research she co-authored that modeled about an 8% increase in deer-vehicle collisions in Washington under year-round standard time. She also worked on a study across 23 states that showed collisions with deer jump by 16% in the week following the autumn clock change. 

National groups are similarly divided. Save Standard Time has supported Washington legislation favoring permanent standard time, while Lock the Clock has pushed Congress to give states more flexibility rather than taking a position on which permanent time is best.

Temporary costs for long-term gains

Thurlow’s campaign acknowledges the tradeoffs: permanent standard time would put Washington out of sync with Oregon and California for much of the year, shorten summer evenings and potentially increase deer collisions.

But those costs would be temporary, he argues. The twice-yearly clock changes, by contrast, would continue indefinitely unless someone breaks the stalemate.

Thurlow also expects opposition over winter darkness, particularly concerns about children walking to school before sunrise. His response is that many Washington students already do so under the current system, and that changing school start times can address the problem. Seattle and other districts have already adjusted schedules for other reasons.

“There’s sort of a set of gut reactions and instant responses that people have, which may not be grounded in truth,” he said. 

Thurlow is betting that enough Washingtonians are tired of changing their clocks that the campaign can turn a decades-old annoyance into a political issue — and give the state a way out before Congress decides on the issue. His campaign is in early stages, with a handful of signups through his website.

Read the whole story
alvinashcraft
20 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

GitHub added 3 million CPU cores. It still couldn’t keep up with your commits.

1 Share

Per month, GitHub now sees 2.9 billion commits, 130 million merged pull requests, and 24 million new repos. Back in April, GitHub already had a hard time handling ‘only’ 1.4 billion commits.

To a large degree, that’s thanks to how popular coding agents have become and how quickly software development is changing. But it’s also no secret that GitHub, despite its efforts to move to a more modern architecture, simply hasn’t been able to scale fast enough to meet this demand.

“We have made progress, but these incidents make clear that we must accelerate this work.” — GitHub CTO Vlad Fedorov.

Why GitHub went down on August 17

The new data comes from a postmortem of its August 17 outage, which lasted almost eight hours. That was GitHub’s second major outage in August alone.

As GitHub CTO Vlad Fedorov notes in the postmortem, “We have made progress, but these incidents make clear that we must accelerate this work.”

Credit: GitHub.

He stresses that the outage was due to scaling issues, not any code changes. GitHub’s infrastructure ran out of capacity, and those issues cascaded into this outage.

“Our investigation found that the outage began when traffic reached a new peak, and a critical infrastructure component in our Central US data center failed to scale with it,” he explains. “The resulting capacity pressure spread through our systems, causing authentication failures and disrupting multiple GitHub services.”

Credit: GitHub.

3M new CPU cores and GitHub still can’t keep up

It’s worth noting that this is not because GitHub isn’t scaling its infrastructure. Fedorov used the post to disclose that 58% of GitHub’s platform load is now served by Azure. That’s up from 12% in May. Half of all Git operations are now served by Azure, too.

The team added 3 million CPU cores this year, as well as 120 petabytes of high-speed storage, Fedorov writes.

As for GitHub’s own data center, that’s maxed out now. “We installed as much hardware as available power allowed in our existing data centers while accelerating our migration to Azure,” Fedorov says.

He also acknowledges that GitHub is facing other challenges as well.

“As the pace and complexity of change increased, our existing operational practices did not keep up. We have redirected teams and resources toward availability and invested in stronger testing, safer rollouts, better observability, and more effective alerting. We have made progress, but this work is not complete,” he writes. “In addition, we are also isolating critical systems and removing shared dependencies between them. This work is designed to reduce the likelihood of an outage and limit its impact when one occurs.”

For now, to avoid the issues that triggered the recent outages, GitHub is making a few concrete changes: it’s applying consistent retry limits and budgets, and tweaking timeouts across service-to-service interactions “to prevent retry storms and cascading load,” as Fedorov writes.

A creaking GitHub is an opportunity for others

GitHub is central to the developer ecosystem — and especially the open source ecosystem. Its recent issues, however, have created an opening for others to launch competing products.

That includes Entire, the startup founded by GitHub’s former CEO Thomas Dohmke, which is betting on a distributed system to better handle agent-driven development workloads. With Origin, Cursor, too, is getting into this game.

The post GitHub added 3 million CPU cores. It still couldn’t keep up with your commits. appeared first on The New Stack.

Read the whole story
alvinashcraft
21 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

What I Get to Forget About Riverpod Now That I Have BlocSignal

1 Share

The Best Feature in Software Is What You Get to Forget

In software engineering, we usually measure framework upgrades by what they add: new syntax, new macros, new features, new abstractions.

But as any developer who has maintained large Flutter applications over several years knows, the most profound upgrade in developer experience isn't what new concepts you are forced to memorize—it’s the mental gymnastics, framework-specific edge cases, and defensive rituals you finally get to forget and unlearn.

Before we dive into technical specifics, let's establish something essential: Rémi Rousselet is a pioneer and a brilliant engineer. When Rémi created provider in Flutter's early days and later built Riverpod in 2020, he solved real, glaring flaws in Flutter's core InheritedWidget mechanics (such as conditional dependency leaks and lack of compile safety). The entire Flutter ecosystem owes Rémi immense gratitude for pushing the boundaries of Dart architecture.

For years, I was a vocal, passionate—at times almost zealous—advocate for Riverpod. In discussions, community forums, and client architectures, I routinely recommended Riverpod above classic BLoC, Provider, and almost every other state management alternative. I championed its compile-time safety and global declarative graph vision because it genuinely solved tough problems we faced in earlier Flutter eras.

However, over the course of Riverpod's evolution across v1, v2 (the code-gen era), and v3, solving every edge case within a global declarative provider graph led to a staggering accumulation of cognitive surface area. Building real-world Flutter apps with Riverpod today requires developers to maintain a complex internal rules engine just to avoid subtle runtime footguns.

And yet, recognizing how much mental gymnastics this has gradually demanded, I find myself genuinely thrilled and relieved to be pivoting. When you switch to BlocSignal (which combines the proven discipline of BLoC/Cubit with the synchronous speed and fine-grained reactivity of Signals), you realize just how much mental baggage you were carrying—and I am excited to share that journey with all of you.

A Quick Note on Lints and IDE Assists

It is worth acknowledging that the Riverpod ecosystem has invested heavily in custom analyzer lints (riverpod_lint), IDE plugins, and automated quick-fixes (such as "Wrap with ConsumerWidget" or "Convert to Notifier").

While these tooling aids are genuinely helpful, they only address surface-level syntax—they cannot eliminate the underlying cognitive load. An IDE shortcut that automatically rewrites your widget class hierarchy does not prevent a controller from disposing mid-flight during an await gap, nor can a linter rule save a navigation stack from wiping when a router provider re-evaluates.

Tooling assists can bandage syntactic friction, but true architectural simplicity removes the friction at the root.

Here is the running list of everything you get to forget—and why your architecture gets significantly cleaner the moment you do.

1. 🗑️ Forget build_runner and Code-Gen Rituals

The Riverpod Gymnastics:

In modern Riverpod (v2/v3), code generation is the officially recommended path. That means:

  • Annotating classes with @riverpod.
  • Extending obscure generated private base classes (extends _$AuthNotifier).
  • Running dart run build_runner watch --delete-conflicting-outputs in a separate terminal tab, spinning laptop fans while consuming gigabytes of RAM.
  • Waiting several seconds every time you rename a parameter or add a method just for IDE autocomplete to work again.
  • Dealing with noisy .g.dart generated files cluttering Git diffs and code reviews.

(Yes, Riverpod still technically supports manual NotifierProvider / Notifier syntax without code generation. But code-gen is the officially documented standard and recommended default throughout modern Riverpod tutorials and guides. Writing manual syntax is verbose and forfeits features like typed .family parameter records.)

// 🤯 Riverpod (Code Generation Required)
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'counter.g.dart';

@riverpod
class Counter extends _$Counter {
  @override
  int build() => 0;

  void increment() => state++;
}

What You Do in BlocSignal:

You write pure Dart. No build_runner. No part files. No code-gen watchers. Instant autocomplete in every IDE, 100% of the time.

// ⚡ BlocSignal (Zero Code-Gen, Pure Dart)
import 'package:bloc_signals/bloc_signals.dart';

class CounterCubit extends CubitSignal<int> {
  CounterCubit() : super(initialState: 0);

  void increment() => emit(stateValue + 1);
}

2. 🗑️ Forget Widget Class Hierarchy Gymnastics & WidgetRef Plumbing

The Riverpod Gymnastics:

In Riverpod, you cannot read or watch state from standard Flutter widgets without either:

  1. Converting your StatelessWidget into a ConsumerWidget and changing build(BuildContext context) to build(BuildContext context, WidgetRef ref).
  2. Converting your StatefulWidget into a ConsumerStatefulWidget and State<T> into ConsumerState<T>.
  3. If using Flutter Hooks, extending HookConsumerWidget (a Frankenstein base class).
  4. Passing WidgetRef ref down private helper functions, widget sub-methods, and domain callbacks because ref is not accessible from standard BuildContext.
// 🤯 Riverpod
class UserProfileView extends ConsumerWidget {
  const UserProfileView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProvider);
    return Text(user.name);
  }
}

What You Do in BlocSignal:

You use standard Flutter widgets. StatelessWidget, StatefulWidget, or HookWidget. You interact via idiomatic BuildContext extensions or dedicated declarative widgets (BlocSignalBuilder, BlocSignalListener, BlocSignalConsumer):

// ⚡ BlocSignal
class UserProfileView extends StatelessWidget {
  const UserProfileView({super.key});

  @override
  Widget build(BuildContext context) {
    final user = context.watch<UserCubit, UserState>();
    return Text(user.name);
  }
}

Zero custom base classes. Zero WidgetRef drilling. Native Flutter.

3. 🗑️ Forget the Provider "Alphabet Soup" & Deprecation Whiplash

The Riverpod Gymnastics:

Over the last few years, Riverpod developers have had to navigate an exhausting taxonomy of provider variants:

  • Provider
  • StateProvider (deprecated in v2/v3)
  • StateNotifierProvider (deprecated)
  • ChangeNotifierProvider
  • FutureProvider
  • StreamProvider
  • NotifierProvider
  • AsyncNotifierProvider
  • StreamNotifierProvider
  • AutoDisposeProvider / AutoDisposeFutureProvider
  • .family modifiers with tuple parameter records

Each variant had its own slightly different rules for error handling, disposal, and lifecycle callbacks.

What You Do in BlocSignal:

There are only two intuitive, unified primitives:

  1. CubitSignal<State>: For method-based state management (call methods, compute derived state, emit new values).
  2. BlocSignal<Event, State>: For formal, event-driven unidirectional data flow with explicit event hierarchies and concurrency transformers (droppable, restartable, sequential).

Both use standard Dart constructors, synchronous emit(), and expose state as a reactive ReadonlySignal<State>.

(While Riverpod's generic AsyncValue is handy for basic fetch-and-display screens, real enterprise applications quickly outgrow generic 3-state wrappers and require rich domain models—such as partial validations, optimistic rollbacks, and multi-step forms. With BlocSignal, you leverage the full expressive power of Dart 3 sealed classes for domain state, while retaining access to AsyncSignal when you want declarative async futures.)

4. 🗑️ Forget the "Ref World vs. Non-Ref World" Boundary

The Riverpod Dilemma:

As I taught developers and engineering teams about Riverpod over the years, I gradually adopted a mental model of the "Ref World" vs. the "Non-Ref World" to help students understand a fundamental reality of Riverpod's design.

In Riverpod, reactive state is strictly confined inside a ProviderContainer—the "Ref World". As long as you are inside a ConsumerWidget or inside another provider, you hold a Ref or WidgetRef, and everything connects. But the moment you step into standard Dart code—such as HTTP client interceptors, WebSocket listeners, background database services, or routing configurations—you are stranded in the "Non-Ref World". To connect the two, you are forced to:

  • Drill a Ref ref parameter through every layer and pollute pure Dart domain classes with framework dependencies.
  • Or expose a global top-level ProviderContainer variable as an escape hatch.

What You Do in BlocSignal:

bloc_signals is a 100% pure Dart package with zero Flutter dependencies.

  • You can instantiate and observe a CubitSignal or BlocSignal anywhere: inside Flutter widgets, CLI tools, Jaspr web applications, or Serverpod backend services.
  • Pure Dart services can read cubit.stateValue or subscribe directly to cubit.state.subscribe((state) => ...) with zero container ceremony.

What about cross-container coordination? In classic stream-based BLoC, coordinating two Blocs was notoriously clunky (often forcing developers to nest multiple BlocListener widgets in the UI tree). In BlocSignal, because every state is exposed as a reactive ReadonlySignal<State>, cross-Cubit derived state is trivial in pure Dart business logic:

// ⚡ Pure Dart Cross-Cubit Derivation (Zero UI Listeners Needed)
late final isCheckoutReady = computed(() => 
  authCubit.state().isAuthenticated && cartCubit.state().items.isNotEmpty
);

Zero widget tree nesting. Zero stream subscriptions. 100% testable in pure Dart.

5. 🗑️ Forget the routerProvider Navigation Stack Nuke

The Riverpod Footgun:

Perhaps the most notorious casualty of the "Non-Ref World" boundary is routing. Because routers like GoRouter are standard Dart objects that live squarely in the Non-Ref World, developers frequently attempt to pull their router into the Ref World by wrapping it in a Riverpod Provider so it can access ref and observe live authentication state:

// 💣 The Innocent-Looking Riverpod Disaster
final routerProvider = Provider<GoRouter>((ref) {
  final auth = ref.watch(authProvider); // 💣 DISASTER
  return GoRouter(
    redirect: (context, state) => auth.isLoggedIn ? null : '/login',
    routes: [...],
  );
});

The Runtime Bug: Whenever authProvider emits (or background token refresh occurs), ref.watch destroys and recreates the entire GoRouter instance.

  • The user's entire navigation history stack is wiped clean.
  • Deeply nested tabs and modal sheets vanish instantly.
  • Scroll offsets reset to the top.

To fix this in Riverpod, you cannot just write intuitive code; you must possess a deep, esoteric understanding of both how GoRouter manages its internal delegate and how Riverpod rebuilds provider dependencies. The prescribed workaround is constructing a custom ChangeNotifier bridge with ref.listen to feed refreshListenable.

Worse still, when this bug strikes in production, there are no error logs or stack traces—just an unexplained navigation reset. Developers are often left struggling with a complete lack of information and traceability, unclear even where to place debugger probes or log statements to catch why the router is vanishing.

What You Do in BlocSignal:

Your GoRouter instance is created once and remains permanent. You connect it directly using toListenable():

// ⚡ BlocSignal: Stable Router, Live Redirects
final router = GoRouter(
  refreshListenable: authCubit.toListenable(),
  redirect: (context, state) => authCubit.stateValue.isLoggedIn ? null : '/login',
  routes: [...],
);

Zero router destruction. Unbroken navigation stacks. 100% deterministic.

6. 🗑️ Forget the "Self-Disposing Async Mutation" Crash

The Riverpod Footgun:

In Riverpod 3.0, auto-disposal is enabled by default. While the intended goal of automatic disposal is commendable (preventing memory leaks in long-lived trees), using implicit UI reference counting to govern asynchronous business logic creates severe race conditions:

// 💣 Riverpod 3.0 Trap
@riverpod
class NoteController extends _$NoteController {
  @override
  Future<List<Note>> build() => repository.fetchNotes();

  Future<void> deleteNote(String id) async {
    state = const AsyncLoading();
    await repository.deleteNote(id);

    // 💥 CRASH: "Cannot use Ref after it has been disposed"
    // If the user navigates away or no widget is watching this controller during the `await`,
    // Riverpod garbage-collects this instance mid-flight!
    ref.invalidateSelf(); 
  }
}

To work around this in Riverpod, developers are forced into defensive gymnastics:

  • Defensive Guards: Sprinkling if (ref.mounted) checks after every single asynchronous await.
  • Action Controller Sprawl: Creating an entirely separate NoteDeleteActionController class just to execute a single async method call without auto-disposing the main list provider.
  • Keep-Alive Token Juggling: Manually acquiring and releasing KeepAliveLink tokens:
  final link = ref.keepAlive(); // 🤯 Manual retain-count management in Dart!
  try {
    await repository.deleteNote(id);
  } finally {
    link.close(); // Remember to release the token, or leak memory forever!
  }

Think about how absurd that is: you find yourself having to write meta-state management just to manage the lifecycle of your state management system. High-level declarative Dart is suddenly reduced to manual reference-count lock juggling.

What You Do in BlocSignal:

In BlocSignal, state containers are standard Dart objects with explicit, predictable ownership. If an async method is running, it executes to completion. If a Bloc is closed, emit() is safely dropped with zero unhandled runtime crashes:

// ⚡ BlocSignal
class NoteCubit extends CubitSignal<NoteState> {
  NoteCubit({required this.repository}) : super(initialState: const NoteState.initial());

  final NoteRepository repository;

  Future<void> deleteNote(String id) async {
    emit(stateValue.copyWith(isLoading: true));
    await repository.deleteNote(id);
    final notes = await repository.fetchNotes();
    emit(stateValue.copyWith(isLoading: false, notes: notes));
  }
}

7. 🗑️ Forget .family Parameter Isolation & Cache Silos

The Riverpod Dilemma:

When you use Riverpod's .family modifier to parameterize queries:

final userPostsProvider = FutureProvider.family<List<Post>, String>((ref, userId) => ...);
final postDetailProvider = FutureProvider.family<Post, String>((ref, postId) => ...);

Each parameter generates an isolated provider instance. If the user likes a post in postDetailProvider('post-123'), userPostsProvider('user-456') still contains the old, unliked copy of that post in memory. You now have to build complex cache invalidation bridges across multiple isolated providers.

What You Do in BlocSignal:

You use normal Dart parameters in constructors (PostCubit(userId: id)) and share live reactive signal stores (like mapSignal or computed()) across containers. When a post is updated in the central signal store, every widget and cubit observing it updates synchronously in the exact same frame.

8. 🗑️ Forget the ref.watch in Callbacks Infinite Loop Trap

The Riverpod Gotcha:

One of the most common mistakes for Flutter developers learning Riverpod is calling ref.watch inside an onPressed or gesture callback instead of ref.read:

// 💣 Riverpod Bug
ElevatedButton(
  onPressed: () {
    // 💥 Calling watch inside an event handler registers an invalid dependency
    // or creates unexpected rebuild cascades!
    ref.watch(authProvider.notifier).login();
  },
  child: const Text('Login'),
)

What You Do in BlocSignal:

The distinction in BlocSignal is natural and enforced by Flutter's existing BuildContext idioms:

  • In callbacks/handlers: context.read<AuthCubit>().login() (O(1) lookup, zero subscription).
  • In UI builders: context.watch<AuthCubit, AuthState>() or BlocSignalBuilder<AuthCubit, AuthState> (explicit reactive rebuild boundary).

9. 🗑️ Forget In-Place Mutation Silent Drop Traps

The Riverpod Footgun:

In Riverpod 3, notifying listeners relies strictly on reference equality (identical(oldState, newState)). If you mutate a list in-place:

// 💣 Riverpod 3 Silent Failure
state.add(newItem);
state = state; // ❌ Does NOT trigger UI rebuilds because identical(state, state) is true!

What You Do in BlocSignal:

BlocSignal provides explicit, customizable equality checks via SignalOptions(equals: ...) or standard value equality (using Dart 3 records, Freezed, or fast_immutable_collections). When you call emit(newState), the transition is explicit, logged through BlocSignalObserver, and propagated synchronously.

10. 🗑️ Forget Subtree ProviderScope(overrides: [...]) Scoping & Modal Traps

The Riverpod Gymnastics:

In Riverpod, when you need to scope data down a specific widget subtree—such as passing item data down a list view or customizing a controller for a nested section—Riverpod prescribes nesting a ProviderScope with overrides::

// 🤯 Riverpod: Scoping data in a list
ListView.builder(
  itemCount: todos.length,
  itemBuilder: (context, index) {
    return ProviderScope(
      overrides: [
        currentTodoProvider.overrideWithValue(todos[index]),
      ],
      child: const TodoItemTile(),
    );
  },
);

This pattern introduces several subtle, high-friction pitfalls:

  1. Container Overhead in Lists: Wrapping 100 list tiles in ProviderScope instantiates 100 nested Element widgets and separate internal provider container nodes.
  2. The "Split-Brain" Dependency Trap: If Provider B depends on Provider A, and you override A in a nested ProviderScope without also explicitly overriding B, Provider B still resolves against the root un-overridden A, causing baffling data desynchronization bugs.
  3. The Modal & Dialog Disconnection Bug: When you call showDialog() or showModalBottomSheet(), Flutter pushes the new route to the root Navigator overlay. Because the dialog is mounted outside the local subtree's ProviderScope, all local overrides are instantly lost—causing the modal to either crash with missing providers or silently read outdated root state.

What You Do in BlocSignal:

You use standard Dart and Flutter idioms:

  • In lists: Pass data directly via constructor parameters (TodoItemTile(todo: todos[index])).
  • In subtrees: Use standard Flutter scoping with BlocSignalProvider.value(value: todoCubit, child: ...) or provide scoped instances cleanly.
  • In dialogs: Pass the Cubit directly to BlocSignalProvider.value in the dialog builder, or let it resolve naturally up the Flutter element tree.

11. 🗑️ Forget Complex ProviderContainer Mocking & Test Rigmarole

The Riverpod Testing Ceremony:

In Riverpod, unit tests and widget tests require assembling a ProviderContainer or wrapping test widgets in ProviderScope(overrides: [...]):

// 🤯 Riverpod Test Ceremony
final container = ProviderContainer(
  overrides: [
    authRepositoryProvider.overrideWithValue(mockAuthRepo),
    apiClientProvider.overrideWithValue(mockApiClient),
    // ⚠️ Miss just one transitive provider in this list, and your test
    // will accidentally make real network calls or throw late-init errors!
  ],
);
addTearDown(container.dispose);

What You Do in BlocSignal:

State containers are plain Dart classes with direct constructor injection. You instantiate your Cubit or Bloc with your mock repository directly:

// ⚡ BlocSignal: Declarative, Instant Unit Testing
blocSignalTest<CounterCubit, int>(
  'emits [1] when increment is called',
  build: () => CounterCubit(repository: mockRepository),
  act: (cubit) => cubit.increment(),
  expect: () => [1],
);

Because BlocSignal state transitions are synchronous, assertions execute immediately without flaky tester.pumpAndSettle() timeouts or async race conditions.

12. 🤖 Forget the AI & LLM Hallucination Nightmare

The Riverpod AI Friction:

If you pair-program with AI coding assistants—whether Claude, Cursor, GitHub Copilot, ChatGPT, or Gemini—you have likely experienced how difficult Riverpod is for modern LLMs:

  1. The Version Multi-Verse: LLM training data contains years of conflicting Riverpod eras (v0.14 ChangeNotifierProvider, v1.0 StateNotifierProvider, v2.0 @riverpod code-gen, and v3.0 Notifier). AI models constantly mix up these eras, hallucinating deprecated APIs, invalid provider types, or incompatible syntax.
  2. Code-Gen Blindness: LLMs cannot see generated code before build_runner executes. When an AI generates a @riverpod class, it frequently botches the synthesized _$ClassName inheritance, misnames the generated provider, or forgets the part 'file.g.dart'; declaration.
  3. Ref Scope Confusion: AI models frequently lose track of the "Ref World" boundary—attempting to access ref inside widget constructors, passing WidgetRef into deep business logic layers, or failing to convert widgets to ConsumerStatefulWidget.
  4. Implicit Auto-Disposal Bugs: LLMs routinely write async mutation methods inside auto-disposing notifiers without accounting for ref.mounted guards or keep-alive tokens, generating code that looks plausible but crashes in production.

What You Do in BlocSignal:

LLMs excel at pure, standard Dart with explicit contracts:

  • Standard Dart & Predictable Conventions: Pure classes, direct constructor injection, and idiomatic Flutter BuildContext lookups. There is no code-gen magic for the LLM to guess.
  • Zero build_runner Feedback Loops: AI agents can write features, scaffold tests, and immediately verify analyzer diagnostics without waiting for external code generation steps.
  • Vast Training Ground: BLoC and Cubit are among the most consistently documented and deeply represented architectural patterns in AI training datasets. LLMs generate accurate, idiomatic BlocSignal code on the first try.
  • Deterministic AI-Generated Tests: AI tools generate rock-solid, synchronous blocSignalTest suites without getting tripped up by ProviderContainer setup boilerplate or async frame timing issues.
  • First-Class AI Skills From Day One: Rather than leaving LLMs to guess architectural boundaries, BlocSignal ships from day one with installable agent skills covering migrations, interop adapters, and production best practices.

Summary: The Cognitive Weight You Leave Behind

What You Leave Behind in Riverpod What You Enjoy in BlocSignal
build_runner & .g.dart Code Generation Pure, standard Dart with instant IDE autocomplete
ConsumerWidget & WidgetRef Plumbing Standard Flutter widgets & clean BuildContext APIs
Alphabet Soup of 10+ Provider Types 2 Unified Primitives (CubitSignal & BlocSignal)
Ref vs Non-Ref Boundary Walls Zero-dependency pure Dart state usable anywhere
GoRouter Navigation Stack Wipes Stable router instance with .toListenable()
"Self-Disposing" Async Mutation Crashes Predictable, developer-owned object lifecycles
Isolated .family Cache Silos Direct constructor injection & normalized Signals graph
ref.watch in Callbacks Rebuild Cascades Clean separation of context.read() & context.watch()
In-Place Mutation Silent Drops Explicit transitions via emit() with custom equality
Subtree ProviderScope(overrides:) & Modal Disconnects Standard Dart props & native InheritedWidget scoping
Complex ProviderContainer Test Overrides Direct constructor mocking & declarative blocSignalTest
AI / LLM Version Hallucinations & Code-Gen Errors First-shot AI accuracy with standard Dart & BLoC patterns

🌉 Currently Mired in Riverpod? You Don’t Need a Big-Bang Rewrite

If you maintain a large production codebase built on Riverpod, you might be thinking: "This sounds wonderful, but our entire team is already knee-deep in Riverpod. We cannot afford to halt feature delivery for a massive rewrite."

You don't have to.

Through bloc_signals_riverpod, you get a seamless, bidirectional interop bridge that allows you to adopt BlocSignal incrementally, one feature or screen at a time.

Direction 1: Expose a BlocSignal to Existing Riverpod Widgets

If you build a new feature using a clean, pure Dart CubitSignal, you can expose it directly to existing Riverpod widgets as a standard NotifierProvider using .toProvider():

// 1. Build your new feature with a pure Dart Cubit
final cartCubit = CartCubit();

// 2. Adapt it into a Riverpod provider with a single call
final cartProvider = cartCubit.toProvider();

// 3. Existing Riverpod ConsumerWidgets watch it seamlessly:
class CartBadge extends ConsumerWidget {
  const CartBadge({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cartState = ref.watch(cartProvider);
    return Badge(label: Text('${cartState.itemCount}'));
  }
}

Direction 2: Consume Legacy Riverpod Providers in BlocSignal

Conversely, if your new BlocSignal architecture needs to read data from legacy Riverpod providers that you aren't ready to rewrite yet, you can adapt any ProviderListenable with .toBlocSignal(ref):

// Adapt any legacy Riverpod provider into a reactive BlocSignal
final userBloc = legacyUserProvider.toBlocSignal(ref);

// Read stateValue synchronously or subscribe to state changes
print(userBloc.stateValue.userName);

You can migrate your application piece by piece—shedding the cognitive load on new features immediately while existing code continues running uninterrupted.

Getting Started

If you want the architectural discipline of BLoC combined with the modern, zero-latency reactive power of Signals—without the code-gen or cognitive overhead—give BlocSignal a spin.

dependencies:
  bloc_signals: ^1.0.0
  bloc_signals_flutter: ^1.0.0

  # Optional for incremental migration:
  bloc_signals_riverpod: ^1.0.0

Learn more at blocsignal.dev or explore the source on GitHub.

Read the whole story
alvinashcraft
21 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Daily Reading List – August 20, 2026 (#850)

1 Share

I’m adding things to my “you should try this technology” list much faster than I’m getting through it. At some point I’m going to declare bankruptcy and start over. Tomorrow’s looking like a clean “no meeting day” so I stand a chance to get through two of my top ones. Stay tuned.

[blog] Expanding Google Antigravity for enterprise customers. Now Gemini Enterprise users get the Antigravity harness across their favorite IDEs, pooled usage among teams, and backend enterprise controls. More here.

[blog] Practical Loop Engineering. Educational post on the type of agent loops, and how Addy applies them in his own work.

[blog] Add telemetry and observability to your AI agents. Does it really make a big difference to give your agent a memory? Jason built a reference system to test it out and see how behaviors diverge over time.

[article] Your coding agent got the onboarding your developers never did. I chuckled at the headline, because it hit home for me. Are we giving better budget, sponsorship, and patience to agents than we did to humans? Probably.

[blog] How Google Cloud MCPs Give Claude Code Inside Access. Investments in skills and MCPs shouldn’t be tool specific. The whole point is to make sure anyone can use them. Here’s one example.

[article] Only daily AI users feel positively about job security. I guess that doesn’t feel surprising. Those embracing and using the latest thing are likely more future-proofed.

[blog] 20× the CI traffic without getting slower: How we rebuilt Git serving at Datadog. You probably don’t have a git setup as complicated as this. But there are good lessons on unnecessary cloning, recognizing that CPU is the bottleneck, and being smart on your fetching strategy.

[article] Is Your Organizational Culture Too Nice? You know what this looks like. Bland feedback. Everyone gets great performance reviews. Everyone gets a voice. Stop that. Care deeply about others, while aiming for candid, results-focused kindness instead.

[blog] How AlloyDB ScaNN scales vector search to 10 billion vectors. Tremendous performance for a relational database. Here’s how we did it.

[article] When Your Buyer Is an AI Agent. Time to challenge your existing assumptions on pricing and managing buyer relationships.

Want to get this update sent to you every day? Subscribe to my RSS feed or subscribe via email below:



Read the whole story
alvinashcraft
23 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

How to Find an Exact Gmail Thread with Codex or Claude

1 Share
Use Gmail’s Message-ID to point Codex or Claude at one exact email and retrieve the complete conversation rather than a plausible result.
Read the whole story
alvinashcraft
4 hours ago
reply
Pennsylvania, USA
Share this story
Delete

An Overview of Agent Memory for .NET

1 Share

The ability for Microsoft Agent Framework agents to retain and utilize knowledge across interactions is critical. One solution for this is Agent Memory for .NET, a cutting-edge, mind-blowing, graph-native memory engine that leverages the robust capabilities of Neo4j as its backend. This framework is designed to empower AI agents with persistent memory, enabling them to provide contextually relevant responses and maintain continuity.

In this post, we will explore the key features, real-world applications, and implementation details of Agent Memory for .NET, along with a practical code example to get you started.

Get it? An elephant never forgets. Get it? Get it??

Overview of Agent Memory for .NET

Agent Memory for .NET is a sophisticated solution that allows AI agents to store and recall information across sessions. By utilizing a graph database structure, that is, one that organizes data as nodes, edges and properties, it enables agents to create a rich knowledge graph that captures entities, relationships, and interactions over time.

Key Features and Innovations

Types of Memory:

    • Short-term Memory: This component captures the immediate context of conversations, allowing agents to respond appropriately to ongoing dialogues.
    • Long-term Memory: This aspect stores a comprehensive knowledge graph that includes entities and relationships, enabling agents to recall past interactions and provide personalized responses.
    • Reasoning Memory: By recording the agent’s actions and decisions, this memory type enhances the agent’s ability to make informed decisions in future interactions.

    Time-aware Memory: One of the standout features of Agent Memory for .NET is its support for bitemporal recall. Bitemporal recall is the ability of a data system to track and query information across two distinct timelines — in this case valid time (when the fact was true in the real world) and transaction time (when the fact was recorded in the Database). This allows agents to answer questions based on both past beliefs and current knowledge, providing a more nuanced understanding of user queries.

    Integration: The framework is designed to be compatible with the Microsoft Agent Framework and other .NET applications. This seamless integration makes it easy for developers to incorporate Agent Memory into existing systems without significant overhead.

    Graph-Native Structure: By leveraging Neo4j’s graph database capabilities, Agent Memory for .NET can store and query memory efficiently. This structure allows for complex relationships and interactions to be represented in a way that is both intuitive and powerful.

    Implementation: Getting Started with Agent Memory for .NET

    To illustrate how to set up Agent Memory for .NET, let’s walk through a simple code example. This demonstrates how to initialize the memory store, store a memory, and retrieve it.

    Prerequisites

    Before you begin, ensure you have the following:

    • .NET SDK installed on your machine.
    • A running instance of Neo4j. You can download and install Neo4j from the official website.

    Code Example

    Here’s a straightforward example of how to set up Agent Memory for .NET using Neo4j:

    using Neo4j.Driver;
    using AgentMemory;
    
    class Program
    {
        static async Task Main(string[] args)
        {
            // Initialize Neo4j Driver
            var driver = GraphDatabase.Driver("bolt://localhost:7687", AuthTokens.Basic("neo4j", "password"));
    
            // Create a new memory store
            var memoryStore = new MemoryStore(driver);
    
            // Store a memory
            await memoryStore.StoreMemory("user123", "What is the capital of France?", "Paris");
    
            // Retrieve a memory
            var response = await memoryStore.RetrieveMemory("user123", "What is the capital of France?");
            Console.WriteLine(response); // Outputs: Paris
        }
    }

    Explanation of the Code

    1. Initialize Neo4j Driver: The first step is to create a connection to your Neo4j database using the GraphDatabase.Driver method. Replace the connection string and authentication details with your own.
    2. Create a Memory Store: An instance of MemoryStore is created, which will handle the storage and retrieval of memories.
    3. Store a Memory: The StoreMemory method is called to save a memory associated with a specific user. In this case, we store the question “What is the capital of France?” along with the answer “Paris”.
    4. Retrieve a Memory: Finally, we retrieve the stored memory using the RetrieveMemory method and print the response to the console.

    By leveraging the power of Neo4j, Agent Memory for .NET provides a solution for enhancing applications with persistent memory.

    For more information and resources, see the Agent Memory for .NET GitHub Repository and the Neo4j Blog on Agent Memory.

    Read the whole story
    alvinashcraft
    4 hours ago
    reply
    Pennsylvania, USA
    Share this story
    Delete
    Next Page of Stories