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

AI's 'Creepy' Crawlers Criticized by Linux Foundation's IT Infrastructure Director

1 Share
The Linux Foundation's director of IT infrastructure says they now spend more CPU cycles "rendering commits for scrapers than we spend on all other kinds of legitimate access." At any one time, across 5 geo-distributed nodes, there are 14 CPU cores doing nothing but rendering git commits as html.... [W]hen a source is guaranteed to be LLM-free, like the entire history of kernel commits, it's worth its weight in gold as a source of training data... At the time of writing, linux.git is about 1.48 million commits. Oh, and we have about 922 forks of it on git.kernel.org — but don't worry, it's actually extremely efficient on the backend, since it's mostly the same objects in every fork. Unless, of course, you're a scraper, in which case you have, oh, several BILLION valid URLs you can scrape, only to get 922 duplicates of the same 1.48 million commits — which is exactly what the scrapers are doing. But wait, it's not just commits itself. You can also ask for patches, plain renders, diffs between arbitrary commits — cgit is happy to let you, which was perfect for the times when the Internet was for humans or crawlers who obeyed robots.txt, and is AWFUL right about now, because we can generate 1.2 METRIC BAJILLION valid URLs just for a single fork of linux.git. Initially, this was the solution — look through the logs, find out which IPs are obvious scraper bots, and fail2ban them. At first, this was easy, because the bots helpfully told you who they were via their user-agent. Then, they wised up and started pretending that they were random vanilla browsers. So, we started banning them by IP — after all, it's easy to figure out that an IP that is trying to grab every possible commit in a 8-year-old abandoned fork of linux is not really some lone Chrome on Windows user who is just furiously clicking every link that comes across their screen. The bots then started fanning out to entire subnets, but this was still meh, because obviously an IP coming from Google Compute is just pretending to be a Firefox user... And... that's when things turned really, really ugly. Suddenly, the crawlers were coming from millions of random residential or mobile IPs, all pretending to be random modern browsers. An IP like that would make 4-5 requests and then never show up in the logs again... They descended like swarms of locust, hit hard and fast until the system fell over and then moved on to the next target until you recovered. Then, they returned. Rinse. Repeat. They still do that — welcome to the wonderful world of "proxy SDK monetization." It's big business, and your TV is probably doing it... Today, git.kernel.org receives about 6M daily requests demanding to see random commits. Of these, 66% are still immediately batted away with the Anubis challenge, but 33% are now solving the math and getting through to the main site — because apparently what we have to offer is worth spending a ton of cycles to calculate the Anubis challenge... With a bunch of generous assumptions, legitimate requests are only about 2% of git.kernel.org traffic — everything else are scrapers... [W]e're turning off features to reduce the number of crawlable URLs and to gate off actions that are expensive for us to run. Expect to lose some functionality, at least when accessing our resources anonymously. Trust me, we hate it just as much as you, but at this point it's a necessity... [W]e promise to still offer all of our data for download to anyone who asks. You just may have to jump through more hoops to get it. Sorry.

Read more of this story at Slashdot.

Read the whole story
alvinashcraft
42 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Production Flutter Networking Without the Boilerplate: Reactive Repositories with BlocSignal

1 Share

The Networking Architecture Dilemma in Production Flutter

If you survey ten seasoned Flutter developers about how they structure networking in production, you will almost certainly see the same multi-tiered pipeline:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Traditional Flutter Networking Pipeline                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ [Dio / HTTP Client] ─▢ [API Service] ─▢ [Repository Layer] ─▢          β”‚
β”‚                      [Cubit / BLoC] ─▢ [UI Builders & Banners]         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The underlying architectural principles are sound: separation of concerns, testability, and isolating network transport details from UI widgets.

However, in practice, this classical layered stack demands an enormous amount of repetitive boilerplate:

  1. Async State Union Ceremony: Defining four separate state classes (Initial, Loading, Success(data), Failure(error)) or union types for every single API endpoint.
  2. Race Conditions & In-Flight Cancellation: When users type queries or switch tabs rapidly, requests finish out of order. Preventing stale responses requires complex Dio CancelToken plumbing or heavy rxdart switchMap streams.
  3. Offline Caching & "Stale-While-Revalidate": Showing cached data on Frame 1 while fetching fresh updates in the background usually requires database synchronization and stream merging logic.
  4. The Repository vs. Controller Divide: Repositories hold data and caching logic, while BLoCs or Cubits hold reactive state. Because Dart only allows single inheritance, developers end up maintaining two separate class hierarchies connected by verbose dependency injection glue.

With bloc_signals, we can preserve complete separation of concerns while eliminating 70% of the friction.

Let us examine how to architect a modern, clean, production-ready networking layer using CubitSignalMixin, HydratedMixin, and .toAsyncBlocSignal().

⚑ 1. Symmetrical Async Projection with .toAsyncBlocSignal()

In many cases, a feature only needs to fetch data from an endpoint and present it in the UI with loading and error states.

Instead of writing a custom Cubit and four distinct state classes, any Dart Future<T> converts directly into a BlocSignalBase<AsyncState<T>> with a single method call:

class UserProfileService {
  UserProfileService(this._dio);
  final Dio _dio;

  Future<UserProfile> fetchUserProfile(String userId) async {
    final response = await _dio.get('/users/\$userId');
    return UserProfile.fromJson(response.data as Map<String, dynamic>);
  }
}

In your presentation layer or view model:

// Converts Future<UserProfile> into a synchronous BlocSignalBase<AsyncState<UserProfile>>
final userProfileBloc = profileService
    .fetchUserProfile('user_123')
    .toAsyncBlocSignal();

Declarative Exhaustive UI Binding

Because AsyncState<T> is a sealed class hierarchy (AsyncLoading, AsyncData, AsyncError), you get compile-time exhaustive pattern matching in your Flutter widgets:

BlocSignalBuilder<BlocSignalBase<AsyncState<UserProfile>>, AsyncState<UserProfile>>(
  bloc: userProfileBloc,
  builder: (context, state) => switch (state) {
    AsyncLoading() => const Center(
        child: CircularProgressIndicator(),
      ),
    AsyncData(:final value) => ProfileDetailsView(user: value),
    AsyncError(:final error) => ErrorCard(
        message: error.toString(),
      ),
  },
)

No custom state classes, no manual try/catch event plumbing, and no FutureBuilder rebuild bugs.

🧬 2. Reactive, Offline-Cached Repositories with CubitSignalMixin & HydratedMixin

In enterprise apps, repositories often need to extend an existing API client base class (such as BaseApiClient or AuthenticatedHttpService) while maintaining persistent local caches.

Because Dart only permits single inheritance, traditional repositories could not be state containers.

With CubitSignalMixin and HydratedMixin, your repository IS the reactive, persistent state container:

import 'package:bloc_signals/bloc_signals.dart';
import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';
import 'package:dio/dio.dart';

/// A production domain repository extending BaseApiClient with 0ms reactivity & disk caching!
class ProductRepository extends BaseApiClient
    with
        CubitSignalMixin<AsyncState<List<Product>>>,
        HydratedMixin<AsyncState<List<Product>>> {
  ProductRepository(super.dio) {
    // 1. Initialize reactive signal container
    initCubitSignal(initialState: const AsyncLoading());

    // 2. Initialize Frame-1 persistent storage cache
    initHydrated(storageKey: 'cached_products_v1');
  }

  /// Refreshes data from the network using toFutureSignal to eliminate try-catch
  Future<void> refresh() async {
    emit(const AsyncLoading());

    // ⚑ toFutureSignal automatically projects success into AsyncData and exceptions into AsyncError!
    final fetchSignal = _fetchProducts().toFutureSignal();
    await fetchSignal.future;
    emit(fetchSignal.value);
  }

  Future<List<Product>> _fetchProducts() async {
    final response = await dio.get('/products');
    final rawList = response.data as List<dynamic>;
    return [
      for (final item in rawList) Product.fromJson(item as Map<String, dynamic>),
    ];
  }

  // πŸ’Ύ Pattern matching for instant offline hydration:
  @override
  Object? toJson(AsyncState<List<Product>> state) => switch (state) {
        AsyncData(:final value) => [
            for (final product in value) product.toJson(),
          ],
        _ => null,
      };

  @override
  AsyncState<List<Product>>? fromJson(dynamic json) => switch (json) {
        {'products': List<dynamic> list} => AsyncData([
            for (final item in list) Product.fromJson(item as Map<String, dynamic>),
          ]),
        List<dynamic> list => AsyncData([
            for (final item in list) Product.fromJson(item as Map<String, dynamic>),
          ]),
        _ => null,
      };
}

What This Architecture Delivers:

  1. Instant Frame-1 Rendering: When the app opens, HydratedMixin restores the cached List<Product> synchronously before the first pixel renders. Zero loading flickers.
  2. Background Refresh: Calling repository.refresh() executes network I/O and updates the UI synchronously on emit(AsyncData(freshProducts)).
  3. Single Class Hierarchy: Extends BaseApiClient without needing an intermediate wrapper or proxy Cubit.

πŸ›‘ 3. Eliminating Network Race Conditions with restartable()

One of the most insidious bugs in mobile networking is the out-of-order response.

If a user searches for "Fl", then "Flu", and finally "Flutter", the network request for "Fl" might take 800ms while "Flutter" takes 200ms. Without cancellation, the "Fl" response resolves last and overwrites the screen with stale data!

With BlocSignalMixin, solving this requires zero cancel tokens or Rx streamsβ€”just apply the built-in restartable() transformer:

sealed class SearchEvent {
  const SearchEvent();
}

final class SearchQueryChanged extends SearchEvent {
  const SearchQueryChanged(this.query);
  final String query;
}

class SearchRepository extends BaseApiClient
    with
        CubitSignalMixin<AsyncState<List<SearchResult>>>,
        BlocSignalMixin<SearchEvent, AsyncState<List<SearchResult>>> {
  SearchRepository(super.dio) {
    initCubitSignal(initialState: const AsyncData([]));

    // ⚑ Built-in concurrency control: automatically aborts prior in-flight queries!
    on<SearchQueryChanged>((event, emit) async {
      final query = event.query.trim();
      if (query.isEmpty) {
        emit(const AsyncData([]));
        return;
      }

      emit(const AsyncLoading());
      final searchSignal = _executeSearch(query).toFutureSignal();
      await searchSignal.future;
      emit(searchSignal.value);
    }, transformer: restartable());
  }

  Future<List<SearchResult>> _executeSearch(String query) async {
    final response = await dio.get('/search', queryParameters: {'q': query});
    final results = response.data as List<dynamic>;
    return [
      for (final item in results) SearchResult.fromJson(item as Map<String, dynamic>),
    ];
  }
}

πŸ›οΈ Summary Architecture Comparison

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Architectural Concern        β”‚ Traditional Flutter    β”‚ BlocSignal Ecosystem   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Async State Representation   β”‚ 4 custom classes/enums β”‚ AsyncState<T> sealed   β”‚
β”‚ In-Flight Race Conditions    β”‚ Dio CancelToken / Rx   β”‚ restartable() builtin  β”‚
β”‚ Duplicate Tap Protection     β”‚ Custom boolean flags   β”‚ droppable() builtin    β”‚
β”‚ Frame-1 Offline Persistence  β”‚ SQLite / SharedPreferencesβ”‚ HydratedMixin frame-1β”‚
β”‚ Existing Base Class Interop  β”‚ Proxy/Wrapper classes  β”‚ CubitSignalMixin       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

By pairing pure Dart reactive signal primitives with composable mixins and higher-order concurrency transformers, your networking layer remains clean, testable, and robustβ€”with a fraction of the traditional ceremony.

πŸ’¬ Join the Discussion!

How do you currently handle cancellation, offline caching, and async state in your Flutter networking layer?

Share your architecture setups and thoughts in the comments below!

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Designing Android's missing WorkManager test rule

1 Share

TL;DR - create a work manager rule to make your tests easier to write. It’s not hard to do, and it pays off.

I have been working quite a bit with WorkManager stuff these days, and while attempting to write tests for them, I realised there were things I was doing repeatedly.

Work Manager provides a helpful testing library - androidx.work:work-testing and they have a very nice guide on how to write tests for work manager - both integration tests, and testing worker implementation details1, and despite this, I found myself writing a couple of things over and over again.

This post is somewhere between bringing awareness to testing APIs available for WorkManager, and showcasing a test rule that I think can help lower the barrier to testing.


Before

Say I have a SyncDispatcher class that does sync, and sometimes, I want to keep existing work, and other times, I want to replace the existing work.

class SyncDispatcher(val workManager: WorkManager) {
  
  fun sync(params: SyncParams) {
    val existingWorkPolicy = if (params.syncAll) {
			ExistingWorkPolicy.REPLACE
    } else {
      ExistingWorkPolicy.APPEND_OR_REPLACE
    }
    
    val workRequest = OneTimeWorkRequestBuilder<SyncWorker>()
      .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
      .build()
    workManager.beginUniqueWork("sync-work", existingWorkPolicy, workRequest)
    	.enqueue()
  }
}

If I wanted to test this behaviour in an β€œintegration-testing” style, I could use the TestDriver API2 of work manager to instrument the constraints that my work depends on, be it initial delay, network condition, period delay (for perioidic work), stopping the work with a reason, and so on.

// SyncDispatcherTest.kt
@Before {
  val config = Configuration.Builder().setExecutor(SynchronousExecutor()).build()
  WorkManagerTestInitHelper.initializeTestWorkManager(testContext, config)
}

@Test
fun `sync all drops all prior sync requests`() = runTest() {
  // given that we have previous sync work enqueued
  dispatch.sync(syncPartialParams)
  
  // when we receive a refresh all
  dispatch.sync(syncAllParams)
  
  // then when all constraints are met
  val requests = WorkManager.getInstance(context)
  	.getWorkInfosForUniqueWork("sync-work")
  	.get()
  val driver = WorkManagerTestInitHelper.getTestDriver(context)
  requests.forEach { driver?.setAllConstraintsMet(it.id)  }
  
  // then we verify that the syncer recorded only the "sync all" params
  assertEquals(
    listOf(syncAllParams), 
    fakeSyncer.recordedSyncParams,
  )
}

By the time I want test various combinations of work state, like failed sync, retries, etc, I will be doing a lot of these checks queries, and driver calls. Then, when I want to do it for another worker, I have to do the same scaffolding - initialising the work manager test init helper, and execute various APIs to enqueue work and query the work state.

Over time, I have found that these operations were finite, in some sense. I typically would do things like: make a certain work run (whether by tag, or unique name, or by id), confirm that a certain work is cancelled, and so on.

So, naturally, I started thinking about how to stop writing all these things over, without creating a BaseWorkManagerTest, because test rules are better for composition, than a base test class3.

I thought about simple top-level functions with the convenience APIs I wanted. That would work, but I would still have to copy-pasta a lot of the work manager test initialisation and test cleanup, and the retrieval API. Furthermore, I did not like that the top-level functions would not be scoped to anything.

I understand that it may be hard to find an API that covers everyone’s use-cases, so your mileage may vary, but I think an API like this should exist.

WorkManagerTestRule4

The rule itself is not a lot, the problems I wanted to solve were:

  1. Easy initialisation with the ability to override the configuration during setup.
  2. Unified API access to work manager test utilities. I noticed some of my test operations involved using the TestDriver to modify the work state, and some involved querying the work manager directly to verify the state. I would love a unified API to mess with work manager in my test environment.

Work Manager Initialisation in tests

class WorkManagerTestRule(
  private val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
) : ExternalResource() {

  private val executor = SynchronousExecutor()

  /**
   * [Configuration.Builder] for the [WorkManager] used in the test.
   *
   * The default value sets the executor to be the [SynchronousExecutor]. To add more config or
   * change the builder, do so before your test setup returns.
   */
  var configBuilder: Configuration.Builder =
    Configuration.Builder().setExecutor(executor).setTaskExecutor(executor)

  val driver: TestDriver? by lazy {
    WorkManagerTestInitHelper.getTestDriver(context)
  }

  val workManager by lazy {
    WorkManager.getInstance(context)
  }

  override fun before() {
    super.before()
    WorkManagerTestInitHelper.initializeTestWorkManager(context, configBuilder.build())
  }

  override fun after() {
    super.after()
    WorkManagerTestInitHelper.closeWorkDatabase()
  }
}

If you’re using JUnit 5 already in your project (I’m jealous), then you can convert that into an extension and applying the corresponding test lifecycle callbacks.

Work Manager Convenience APIs for tests

To solve the problem of convenience APIs, I created a bunch of helper methods that mirror what I tend to do often.


/**
 * Enqueues a [WorkRequest]. The work request only runs if there are no constraints or all the
 * constraints are met.
 *
 * Shortcut for [WorkManager.enqueue]
 */
fun WorkManagerTestRule.enqueue(request: WorkRequest): Operation {
  return workManager.enqueue(request)
}

/**
 * Enqueues a list of [WorkRequest]s. The work requests only run if there are no constraints or all
 * the constraints are met.
 *
 * Shortcut for [WorkManager.enqueue]
 */
fun WorkManagerTestRule.enqueue(requests: List<WorkRequest>): Operation {
  return workManager.enqueue(requests)
}

/**
 * Enqueues a [WorkRequest], and then meets its constraints to execute it.
 *
 * Shortcut for [WorkManager.enqueue] and [TestDriver.setAllConstraintsMet]
 */
fun WorkManagerTestRule.execute(request: WorkRequest) {
  with(request) {
    workManager.enqueue(this)
    driver?.setAllConstraintsMet(id)
  }
}

/**
 * Enqueues a list of [WorkRequest]s, and then meets all their constraints to execute them.
 *
 * Shortcut for [WorkManager.enqueue] and [TestDriver.setAllConstraintsMet]
 */
fun WorkManagerTestRule.execute(requests: List<WorkRequest>) {
  requests.forEach { request ->
    execute(request)
  }
}

/** Executes all work that match the given [query] by meeting all their constraints to. */
fun WorkManagerTestRule.execute(query: WorkQuery) {
  val infos = workManager.getWorkInfos(query).get()
  infos.forEach { setAllConstraintsMet(it.id) }
}

/**
 * Sets all constraints on the WorkManager work with the given [workSpecId]. Shortcut for
 * [TestDriver.setAllConstraintsMet]
 */
fun WorkManagerTestRule.setAllConstraintsMet(workSpecId: UUID) {
  driver?.setAllConstraintsMet(workSpecId)
}

I couldn’t possibly figure out whatever everyone would like to do, so I decided to expose the driver, and the work manager as well, and if there’s some operation that the rule does not support, you could write your own extension and implement it.

The test rule helps me to hide the complexities involved in the work manager lifecycle - which in itself is complex, and tends to bring the complexity into the test code, and I suspect this is why I haven’t seen a lot of these integration tests in the project I’m working on.

After

With the test rule, the original SyncDispatcher scenario then looks like this:

// SyncDispatcherTest.kt
-@Before {
-  val config = Configuration.Builder().setExecutor(SynchronousExecutor()).build()
-  WorkManagerTestInitHelper.initializeTestWorkManager(testContext, config)
-}
+@get:Rule
+val workManagerTestRule = WorkManagerTestRule(context)

@Test
fun `sync all drops all prior sync requests`() = runTest() {
  // given that we have previous sync work enqueued
  dispatch.sync(syncPartialParams)
  
  // when we receive a refresh all
  dispatch.sync(syncAllParams)
  
  // then when all constraints are met
-  val requests = WorkManager.getInstance(context)
-  	.getWorkInfosForUniqueWork("sync-work")
-  	.get()
-  val driver = WorkManagerTestInitHelper.getTestDriver(context)
-  requests.forEach { driver?.setAllConstraintsMet(it.id)  }
+  val syncWorkQuery = WorkQuery.Builder.fromUniqueWorkNames(listOf("sync-work")).build()
+  workManagerTestRule.execute(syncWorkQuery)

  // then we verify that the syncer recorded only the "sync all" params
  assertEquals(
    listOf(syncAllParams), 
    fakeSyncer.recordedSyncParams,
  )
}

By the time you apply this to all the work manager states and behaviour you may be testing, all the other workers, etc, this simple rule starts to pay off in terms of test code size and complexity.

Footnotes

  1. WorkManager integration test guideΒ 

  2. WorkManager TestDriver API for instrumenting the work manager workersΒ 

  3. β€œDon’t be lazy, use @Rules” 

  4. WorkManagerTestRule - my take on the missing WorkManager test ruleΒ 

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

How fast is .NET 11 Runtime Async?

1 Share

How fast is .NET 11 Runtime Async?
11 minutesΒ by Kai Sawano

Runtime Async is a new asynchronous execution model arriving in .NET 11. Instead of having the C# compiler eagerly turn every async method into a state machine, it preserves the original asynchronous control flow until runtime, where the JIT can process and optimize it directly.

Cut AI Coding Token Costs by up to 36% with Sonar Vortex
sponsored by Sonar

Sonar Vortex operates inside your AI coding agent’s inner reasoning loop, supplying deep architectural context before code is written, then verifying the output in real time. In testing, software defects dropped by 92% and token consumption decreased. Build safer code while spending less on LLM calls.

Garbage collection fundamentals in .NET
11 minutes by Abdul Rahman

.NET developers never manually free memory. The runtime's Garbage Collector handles it automatically by tracking which objects are still in use and reclaiming the rest. It does this through three steps: marking live objects, sweeping dead ones, and compacting survivors to close memory gaps. Knowing how the stack, heap, and GC work together helps you write code that uses less memory and puts less pressure on the runtime.

Eventual consistency explained
7 minutes by Irina Scurtu

Distributed systems often show stale data briefly after an update. This is not a bug but a deliberate trade-off called eventual consistency, where systems prioritize staying available over guaranteeing every node agrees instantly. DNS, CDNs, and read replicas all work this way already. The real risk is not choosing this trade-off, but failing to design for it and discovering the gap when users notice their data has vanished.

What's new with CoreCLR GC handles
14 minutes by Austin Wise

.NET 9 and 10 brought major updates to GC handles in CoreCLR. Four new generic handle types were added as public APIs, offering better type safety, cleaner code, and a modest performance boost over the old GCHandle struct. Two new internal handle types were also introduced. Weak interior pointer handles track object locations across GC moves, while cross-reference handles solve a tricky problem of coordinating object lifetimes between the .NET and Java garbage collectors when running MAUI apps on Android.

Finding the total number of processors on a machine with .NET
11 minutes by Andrew Lock

Modern .NET has no built-in way to get the total CPU count of a host machine. Environment.ProcessorCount returns processor count available to the process, not the host total. The only solution is to call native system APIs on Windows and macOS, and read a system file on Linux. Each platform needs its own code, then a shared helper ties them together based on the current OS.

And the most popular article from the last issue was:

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

OpenAI leaving Cursor: β€œDevelopers have to be prepared to adapt when it happens.”

1 Share
Abstract digital glitch art with neon pink, green, blue, purple, and white wavy distorted lines on a black background.

OpenAI stated on Friday that it has notified SpaceX that it intends to wind down its contract providing OpenAI models to Cursor, the Musk empire’s AI-powered code editor.

“We are making this choice because we cannot be confident that SpaceX will use our technology within our terms of service, based on our experience with Elon Musk‘s companies violating contracts,” states OpenAI.

The proposed shutoff date is November 12, 2026. Developers who have invested time and effort to skill up with OpenAI via Cursor are now potentially left out in the cold due to corporate machinations beyond their control.

“We know that the people most affected by this decision are the developers who rely on OpenAI models in Cursor. We care about their experience in this transition, and we’re ready to go above and beyond to support them,” states the blog post in a conciliatory tone.

“We cannot be confident that SpaceX will use our technology within our terms of service, based on our experience with Elon Musk’s companies violating contracts.”

OpenAI says it “cares deeply” about developers.

OpenAI’s moves appear to be directed at the broader SpaceX corporate mission and its behavioral traits, rather than at the no-doubt worthy software developers within the organization who work on Cursor. As such, OpenAI is maximizing the time developers can retain access to its models through Cursor by providing the “maximum notice provided” required by its contract. 

“This decision was incredibly tough, as we care deeply about our models being broadly available for developers,” said OpenAI.

SpaceX agreed to acquire Cursor maker Anysphere in June and completed the acquisition on August 14. OpenAI said it has worked with the Cursor team “for nearly four years,” which amounts to almost all of its existence. 

The organization has explained how it uses custom contracts to ensure compliance with its terms of service when working with large corporations such as SpaceX. This custom alignment is designed to ensure that, when integrations with its platform occur, it has adequately provided for safety at scale. 

Elon Musk “broke and violated” terms of contract and service

Citing a report in the New York Times, OpenAI states that, “After Musk acquired Twitter, now part of SpaceX, the company broke the terms of our contract (alongside many others). Under oath earlier this year, Musk admitted⁠ that xAI, now also part of SpaceX, had violated OpenAI’s terms of service (terms which are similar to xAI’s own).”

Detailing its displeasure openly, OpenAI further mentioned that Musk admitted that as a working organization inside of SpaceX, “xAI had violated OpenAI’s terms of service”

Legal & policy analyst and publisher of The Mitchell Report, Andrellos Mitchell tells The New Stack that so long as OpenAI is acting within the terms of its contract, he doesn’t see why it should be expected to continue a business relationship it no longer trusts.

“I think OpenAI and Musk’s companies and products need a clean and permanent break from each other – their relationship has become too adversarial. At some point, continuing to do business together stops making sense,” Mitchell says.

Lamenting the impact these moves have on programmers, Mitchell agrees that developers will “certainly be inconvenienced” and that some may have to change how they work. But he says, “Developers are talented people,” i.e., they will find new tools, new projects, and new jobs to work on. 

“The bigger lesson here is that no developer should assume any particular corporate relationship is permanent. Companies change ownership. Contracts end. Business relationships fall apart. That is part of the marketplace. Developers have to be prepared to adapt when it happens,” underlines Mitchell.

“The bigger lesson here is that no developer should assume any particular corporate relationship is permanent. Companies change ownership. Contracts end. Business relationships fall apart. That is part of the marketplace. Developers have to be prepared to adapt when it happens,” underlines Mitchell.

Underhand use of model distillation techniques

One alleged violation concerns xAI’s partial use of OpenAI technology to train its models, which OpenAI characterizes as prohibited distillation. Musk admitted that xAI had “partly” used OpenAI in this regard.

To add insult to injury, OpenAI reminds the public in its statement that its terms of service are not dissimilar to xAI’s own stipulations regarding operational mandates.

“As AI capabilities advance, we also have a new level of accountability to ensure our upcoming model, Astra, is being used in accordance with our terms. Given all of this, we’ve decided to hold the contract cancellation to the latest date we can while not providing future models to Cursor,” said OpenAI.

See also: OpenAI’s Astra can do a researcher’s week of work. That’s the problem.

Wider reactions, contractions and ramifications

Co-founder and CEO of Cursor (and now a SpaceX employee), Michael Truell, writes on X that he’s sorry to see OpenAI’s intended block now coming to light.

“OpenAI models serve about 5% of Cursor user traffic, and we’re speaking with the OpenAI team to resolve this. Cursor was one of the very first users of OpenAI; we’ve worked closely with their team for years, and we’ve trusted their platform to be neutral infrastructure for our business,” writes Truell.

Anthropic co-founder and chief compute officer Tom Brown capitalized on the opportunity and his firm’s ongoing bond with Cursor. He used X to state that, “Cursor has been a trusted partner of Anthropic since Sonnet 3.5. We’ll continue to increase compute to support Claude models in Cursor and are excited for what comes next with them at SpaceX.”

AI startup advisor at Open Machine and ex-IBM Watson and machine learning leader at AWS, Allie K. Miller, writes on X to say that, “It’s hard for me to see a world where OpenAI continues to provide model access to a Musk-led company. Maybe if the structure of SpaceX shifts to allow for it, but that’s a big shift.”

What alternatives can developers turn to next?

To continue using OpenAI models within the Cursor application, OpenAI invites developers to choose one of three options that best fit their workflow.

  • Option #1 is to bring your own OpenAI API key. This means developers could continue using OpenAI models in Cursor’s local Chat and Agent features, but appropriately billed at OpenAI API prices
  • Option #2 is to use the Codex IDE extension; this means developers would useOpenAI’ss AI coding agent, Codex, directly in Cursor with a ChatGPT subscription or an OpenAI API key. 
  • Option #3 is to use an AI gateway provider, meaning developers would connect Cursor to OpenAI models through an account they have with a compatible provider such as Amazon Bedrock, Azure, or another OpenAI-compatible gateway.

This is not the first time OpenAI has been concerned about potential or alleged misuse of its models in relation to distillation. In February of this year, Reuters reported that OpenAI had warned U.S. lawmakers that “Chinese AI startup DeepSeek is targeting the ChatGPT maker” and the nation’s leading AI companies to replicate models and use them for its own training.

The post OpenAI leaving Cursor: β€œDevelopers have to be prepared to adapt when it happens.” appeared first on The New Stack.

Read the whole story
alvinashcraft
2 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Overcoming Dart's Single Inheritance Wall: Composable CubitSignalMixin & BlocSignalMixin in Flutter

1 Share

Breaking Free from Dart's Single Inheritance Constraint in State Management

Every Dart and Flutter developer eventually runs headfirst into a fundamental language constraint: single inheritance.

In Dart, a class can extend only one superclass.

In greenfield tutorials, this is rarely an issue because classes start from a clean slate. But in real-world Flutter engineering, domain repositories, controllers, and services frequently already belong to an established inheritance hierarchy:

  • A search field controller that must extend Flutter's TextEditingController (which itself extends ValueNotifier<TextEditingValue>).
  • A view controller that extends ChangeNotifier or AnimationController.
  • A domain repository that extends an enterprise BaseRepository<T>, EntityStore, or microservices client.

Historically, if you wanted that class to also be a Cubit or BLoC, you were out of luck. You could not write:

// ❌ Impossible in Dart (Multiple Inheritance is forbidden):
class SearchController extends TextEditingController, CubitSignal<SearchState> { ... }

This forced developers into a frustrating dilemma:

  1. The Wrapper / Proxy Anti-Pattern: Creating a wrapper class that held an internal _cubit reference, requiring tedious method forwarding and manual synchronization.
  2. Duplicate Controller Lifecycles: Managing two separate objects in the widget treeβ€”a TextEditingController for the input widget and a separate SearchCubit for the stateβ€”forcing you to wire listeners between them in initState/dispose.
  3. Inheritance Refactoring: Trying to refactor existing base classes, often breaking third-party library contracts or enterprise architectures.

With bloc_signals 1.2.0, that single inheritance wall has been completely demolished.

We have introduced CubitSignalMixin and BlocSignalMixin, enabling any class in an existing inheritance hierarchy to become a first-class, 0ms reactive BlocSignalBase container with zero wrapper boilerplate.

🧬 How the Composable Mixins Work

Because BlocSignal has a lean, highly disciplined API surface, mixing it into arbitrary classes introduces zero namespace pollution.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        BlocSignal Mixin Architecture                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Mixin                          β”‚ Capabilities Added                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ CubitSignalMixin<StateType>    β”‚ state, stateValue, emit(newState),    β”‚
β”‚                                β”‚ equals(), createEffect(), close()     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ BlocSignalMixin<Event, State>  β”‚ on<E>(), concurrency transformers     β”‚
β”‚                                β”‚ (restartable, droppable), add(event)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

1. CubitSignalMixin<StateType>

CubitSignalMixin implements BlocSignalBase<StateType>. All you do is mix it in and invoke initCubitSignal(initialState: ...) in your constructor:

class UserProfileRepository extends BaseRepository
    with CubitSignalMixin<UserProfileState> {
  UserProfileRepository(super.apiClient) {
    initCubitSignal(initialState: const UserProfileInitial());
  }

  Future<void> fetchProfile(String userId) async {
    emit(const UserProfileLoading());
    try {
      final profile = await apiClient.getProfile(userId);
      emit(UserProfileLoaded(profile));
    } catch (error, stackTrace) {
      emit(UserProfileError(error.toString()));
    }
  }
}

2. BlocSignalMixin<Event, StateType>

When you need full event-driven state machines with concurrency transformers (restartable(), droppable(), sequential()), mix in both CubitSignalMixin and BlocSignalMixin:

class OrderService extends BaseService
    with CubitSignalMixin<OrderState>, BlocSignalMixin<OrderEvent, OrderState> {
  OrderService(super.networkClient) {
    initCubitSignal(initialState: const OrderInitial());

    on<SubmitOrder>((event, emit) async {
      emit(const OrderSubmitting());
      final result = await networkClient.postOrder(event.order);
      emit(OrderSuccess(result.orderId));
    }, transformer: droppable()); // Discards duplicate taps while in flight!
  }
}

🎯 Real-World Killer Use Case: The Self-Debouncing TextEditingController

Let us look at a practical scenario where this pattern shines: a live product search input.

In traditional Flutter architectures, building a debounced search input requires:

  1. Creating a TextEditingController in widget state.
  2. Creating a SearchBloc or SearchCubit.
  3. Adding a listener in initState that forwards controller.text into bloc.add(SearchQueryChanged(text)).
  4. Remembering to dispose both in dispose().

With BlocSignalMixin, your TextEditingController IS the debounced BLoC:

sealed class SearchEvent {
  const SearchEvent();
}

final class QueryChanged extends SearchEvent {
  const QueryChanged(this.query);
  final String query;
}

sealed class SearchState {
  const SearchState();
}

final class SearchInitial extends SearchState {
  const SearchInitial();
}

final class SearchLoading extends SearchState {
  const SearchLoading();
}

final class SearchSuccess extends SearchState {
  const SearchSuccess(this.results);
  final List<Product> results;
}

final class SearchError extends SearchState {
  const SearchError(this.message);
  final String message;
}

/// A standard Flutter TextEditingController with built-in BLoC reactivity!
class SearchTextEditingController extends TextEditingController
    with
        CubitSignalMixin<SearchState>,
        BlocSignalMixin<SearchEvent, SearchState> {
  SearchTextEditingController(this._api) {
    initCubitSignal(initialState: const SearchInitial());

    // ⚑ Built-in restartable concurrency transformer automatically cancels
    // previous in-flight queries when new text is entered!
    on<QueryChanged>((event, emit) async {
      final query = event.query.trim();
      if (query.isEmpty) {
        emit(const SearchInitial());
        return;
      }

      emit(const SearchLoading());
      try {
        final products = await _api.search(query);
        emit(SearchSuccess(products));
      } catch (error) {
        emit(SearchError(error.toString()));
      }
    }, transformer: restartable());

    // 🎯 Forward controller text mutations straight into the event pipeline
    addListener(() => add(QueryChanged(text)));
  }

  final SearchApiClient _api;

  @override
  void dispose() {
    close(); // Closes signal subscriptions and cancels pending async transformers
    super.dispose();
  }
}

Clean, Declarative Flutter UI Binding

Because SearchTextEditingController extends TextEditingController AND implements BlocSignalBase<SearchState>, you pass it directly to TextField and read it directly with BlocSignalBuilder:

class SearchScreen extends StatefulWidget {
  const SearchScreen({super.key, required this.api});
  final SearchApiClient api;

  @override
  State<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {
  late final SearchTextEditingController _searchController;

  @override
  void initState() {
    super.initState();
    _searchController = SearchTextEditingController(widget.api);
  }

  @override
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TextField(
          controller: _searchController,
          decoration: const InputDecoration(
            hintText: 'Search products...',
            border: InputBorder.none,
          ),
        ),
      ),
      body: BlocSignalBuilder<SearchTextEditingController, SearchState>(
        bloc: _searchController,
        builder: (context, state) => switch (state) {
          SearchInitial() => const Center(
              child: Text('Type a query to search products.'),
            ),
          SearchLoading() => const Center(
              child: CircularProgressIndicator(),
            ),
          SearchSuccess(:final results) when results.isEmpty => const Center(
              child: Text('No products found.'),
            ),
          SearchSuccess(:final results) => ListView.builder(
              itemCount: results.length,
              itemBuilder: (context, index) => ListTile(
                title: Text(results[index].name),
                subtitle: Text('\$${results[index].price}'),
              ),
            ),
          SearchError(:final message) => Center(
              child: Text('Error: $message', style: const TextStyle(color: Colors.red)),
            ),
        },
      ),
    );
  }
}

Look at that simplicity:

  • Zero glue code.
  • Single object lifecycle: one controller to instantiate, one controller to dispose.
  • Native Flutter widget compatibility: passed directly to TextField(controller: ...).
  • 0ms Reactive UI updates: rebuilt synchronously on every state transition.

πŸ›οΈ DRY Core Architecture & Universal Polymorphism

One of our guiding principles in BlocSignal is avoiding parallel, divergent abstractions.

In bloc_signals 1.2.0, CubitSignal and BlocSignal themselves compose CubitSignalMixin and BlocSignalMixin as their single source of truth:

abstract class CubitSignal<StateType> extends BlocSignalBase<StateType>
    with CubitSignalMixin<StateType> {
  CubitSignal({
    required StateType initialState,
    bool Function(StateType, StateType)? equals,
    SignalOptions<StateType>? options,
  }) {
    initCubitSignal(
      initialState: initialState,
      equals: equals,
      options: options,
    );
  }
}

abstract class BlocSignal<Event, StateType> extends BlocSignalBase<StateType>
    with CubitSignalMixin<StateType>, BlocSignalMixin<Event, StateType> {
  BlocSignal({
    required StateType initialState,
    bool Function(StateType, StateType)? equals,
    SignalOptions<StateType>? options,
  }) {
    initCubitSignal(
      initialState: initialState,
      equals: equals,
      options: options,
    );
  }
}

Because CubitSignalMixin implements BlocSignalBase<StateType>, any class mixing it in is 100% polymorphic with the entire ecosystem:

  • BlocSignalProvider: Provide your mixed-in class directly with $O(1)$ lookup.
  • context.select: Fine-grained rebuilds on state sub-properties (context.select<SearchTextEditingController, int>((c) => c.stateValue.results.length)).
  • blocSignalTest: Declarative unit testing with zero mocking.
  • bloc_signals_riverpod: Convert mixed-in classes to Riverpod providers via .toProvider().
  • bloc_signals_hydrate: Add synchronous Frame-1 persistence by adding with HydratedMixin.
  • bloc_signals_replay: Add undo/redo change history by adding with ReplayMixin.
  • DevTools Extension: Automatically monitored in the DevTools timeline and instance tree.

πŸ“¦ Getting Started

CubitSignalMixin and BlocSignalMixin are available now in bloc_signals 1.2.0:

dependencies:
  bloc_signals: ^1.2.0
  bloc_signals_flutter: ^1.2.1

Or install via terminal:

dart pub add bloc_signals
flutter pub add bloc_signals_flutter

Check out the interactive documentation, live demo visualizer, and architectural decision matrix at blocsignal.dev.

πŸ’¬ Let's Discuss!

Have you run into Dart's single inheritance constraint when building custom Flutter controllers or enterprise repositories? How do you currently bridge TextEditingController or ChangeNotifier into your state management layer?

Drop your thoughts, questions, and feedback in the comments below!

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