Three independently ugly bugs that all fed the same log flood:
* Electron's `WebFrameMain.send` writes every "Render frame was disposed"
to stderr via `console.error`. When the worker fans a second
agent-event past a reloading renderer, we produced thousands of
identical lines and stalled the main loop on stderr I/O. Added a
`mainFrame.detached` guard so the send is short-circuited before
Electron's own catch block fires, and installed a targeted filter in
`suppress-warnings.ts` (now actually imported from the entry point)
so the specific `console.error("Error sending from webFrameMain:"…)`
noise never reaches the terminal. Any other payload still surfaces.
* `dispatchAgentMessage` accepted the human-reader sentinel as a wake
target when an agent replied to `__board__` — `wakeAgentIfPossible`
then called `db.getAgent("__board__")`, threw, and the dispatcher
kept repeating on every send. Strip `HUMAN_SENDER_ID` at
`resolveMessageWakeTargets`, and keep a defense-in-depth guard in the
heartbeat so a stray caller (future automation fan-out) cannot
reintroduce the crash.
* Pi's skills loader rejects any SKILL.md whose frontmatter `name`
diverges from its parent directory. The four bundled `my-writing-style`
copies declared `name: writing-style-skill`, so every install emitted
a warning and dropped the skill. They also lived as orphan gitlinks
(mode 160000 without .gitmodules), and the global `*.md` gitignore
hid every other SKILL.md from version control. Fixed the frontmatter
to match the dir, converted the dangling submodules to plain trees,
and allowlisted `builtin-skills/**/*.md` so a fresh clone carries the
catalogue instead of silently losing it.
70 lines
2.1 KiB
Markdown
70 lines
2.1 KiB
Markdown
---
|
||
title: Avoid Framework Imports in Inner Layers
|
||
impact: CRITICAL
|
||
impactDescription: prevents framework lock-in, enables 10× faster unit tests
|
||
tags: dep, frameworks, imports, isolation
|
||
---
|
||
|
||
## Avoid Framework Imports in Inner Layers
|
||
|
||
Entities and use cases must never import framework-specific types. Framework dependencies in inner layers create tight coupling that makes testing slow and migration impossible.
|
||
|
||
**Incorrect (use case imports framework types):**
|
||
|
||
```csharp
|
||
// Application/UseCases/ProcessPaymentUseCase.cs
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Newtonsoft.Json;
|
||
|
||
public class ProcessPaymentUseCase
|
||
{
|
||
private readonly DbContext _context; // EF Core dependency
|
||
private readonly IHttpContextAccessor _http; // ASP.NET dependency
|
||
|
||
public async Task Execute(PaymentRequest request)
|
||
{
|
||
var userId = _http.HttpContext.User.Identity.Name;
|
||
var payment = JsonConvert.DeserializeObject<Payment>(request.Data);
|
||
_context.Payments.Add(payment);
|
||
await _context.SaveChangesAsync();
|
||
}
|
||
}
|
||
```
|
||
|
||
**Correct (use case depends only on abstractions):**
|
||
|
||
```csharp
|
||
// Application/UseCases/ProcessPaymentUseCase.cs
|
||
// No framework imports
|
||
|
||
public class ProcessPaymentUseCase
|
||
{
|
||
private readonly IPaymentRepository _payments;
|
||
private readonly ICurrentUserProvider _currentUser;
|
||
|
||
public async Task Execute(PaymentCommand command)
|
||
{
|
||
var userId = _currentUser.GetUserId();
|
||
var payment = new Payment(command.Amount, command.Currency, userId);
|
||
await _payments.Save(payment);
|
||
}
|
||
}
|
||
|
||
// Infrastructure/Persistence/EfPaymentRepository.cs
|
||
using Microsoft.EntityFrameworkCore;
|
||
|
||
public class EfPaymentRepository : IPaymentRepository
|
||
{
|
||
private readonly DbContext _context;
|
||
// Framework usage isolated to infrastructure
|
||
}
|
||
```
|
||
|
||
**Benefits:**
|
||
- Use case tests run without framework bootstrapping
|
||
- Framework can be upgraded or replaced independently
|
||
- Business logic remains readable without framework noise
|
||
|
||
Reference: [Clean Architecture - Frameworks are Details](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
|