Open Fusion Code Quality
Required Context
Before judging design, read the relevant spec and ADR. For core architecture, read:
docs/PRD.md
docs/adrs/0001-use-nestjs-backend.md
docs/adrs/0003-use-vercel-ai-sdk.md
docs/adrs/0007-provider-adapter-layer.md
Use this skill with open-fusion-tdd-cycle for implementation changes.
Design Principles
Apply SOLID pragmatically:
- Single Responsibility: controllers handle HTTP, config services handle config, adapters handle provider details, orchestration services handle orchestration policy.
- Open/Closed: new providers should be added by registering adapters, not editing controllers.
- Liskov Substitution: adapters must satisfy the same contract for success, stream, timeout, and error behavior.
- Interface Segregation: keep small interfaces for generation, streaming, config access, and secret resolution.
- Dependency Inversion: depend on internal abstractions, not concrete provider SDKs outside adapter modules.
Apply DRY after intent is clear:
- remove duplicated policy logic immediately;
- tolerate small duplicated tests until patterns stabilize;
- extract helpers only when they improve names and diagnostics;
- avoid generic abstractions for one provider or one endpoint.
Open Fusion Boundaries
Keep these boundaries explicit:
- HTTP API: request validation, headers, status codes, SSE framing.
- Application orchestration: route resolution, delegate limits, final response lifecycle.
- Configuration: schema validation, env secret resolution, immutable runtime config.
- Provider adapters: Vercel AI SDK/provider specifics and error mapping.
- Observability/security: request ids, logging, redaction, auth, timeouts.
Crossing these boundaries should happen through typed interfaces.
TypeScript Standards
- Prefer explicit domain types over loose
any.
- Do not leave untyped locals that widen to
any for provider, orchestration, or config results.
- Model config and API DTOs separately.
- Validate external input at boundaries before using typed runtime objects.
- Treat provider outputs as external input even when they came through an SDK type.
- Use discriminated unions for provider result/error variants when useful.
- Keep async cancellation/timeout behavior visible in function signatures or options.
- Extract shared domain types when the same request/client/config shape appears across services and Express request augmentation.
NestJS Standards
- Keep controllers thin.
- Put business rules in injectable services.
- Use guards for auth, filters for error envelopes, interceptors/middleware for request id/logging where appropriate.
- Do not read env vars from controllers or orchestration services.
- Do not import provider SDK packages outside provider adapter modules.
Code Smells To Fix
- provider-specific conditionals in controllers;
- repeated OpenAI error envelope construction;
- repeated config reference validation;
- raw secrets in logs or thrown errors;
- orchestration loops without hard backend limits;
- tests that only verify mocks were called;
- duplicated
AuthenticatedClient-style shapes across services and request typings;
- provider payload casts without runtime validation;
- public or operational errors with misleading status/code semantics;
- abstractions named
Manager, Helper, or Util without a clear domain role.
Refactoring Rule
Refactor behind passing tests. If tests are missing, first add characterization tests for the behavior being preserved.
1---2name: open-fusion-code-quality3description: Keep Open Fusion code maintainable with SOLID, DRY, clean architecture, and pragmatic TypeScript/NestJS design. Use when Codex designs modules, writes production code, refactors, reviews code quality, extracts abstractions, names services/adapters, or reduces duplication in the Open Fusion LLM gateway.4---56# Open Fusion Code Quality78## Required Context910Before judging design, read the relevant spec and ADR. For core architecture, read:1112- `docs/PRD.md`13- `docs/adrs/0001-use-nestjs-backend.md`14- `docs/adrs/0003-use-vercel-ai-sdk.md`15- `docs/adrs/0007-provider-adapter-layer.md`1617Use this skill with `open-fusion-tdd-cycle` for implementation changes.1819## Design Principles2021Apply SOLID pragmatically:2223- Single Responsibility: controllers handle HTTP, config services handle config, adapters handle provider details, orchestration services handle orchestration policy.24- Open/Closed: new providers should be added by registering adapters, not editing controllers.25- Liskov Substitution: adapters must satisfy the same contract for success, stream, timeout, and error behavior.26- Interface Segregation: keep small interfaces for generation, streaming, config access, and secret resolution.27- Dependency Inversion: depend on internal abstractions, not concrete provider SDKs outside adapter modules.2829Apply DRY after intent is clear:3031- remove duplicated policy logic immediately;32- tolerate small duplicated tests until patterns stabilize;33- extract helpers only when they improve names and diagnostics;34- avoid generic abstractions for one provider or one endpoint.3536## Open Fusion Boundaries3738Keep these boundaries explicit:3940- HTTP API: request validation, headers, status codes, SSE framing.41- Application orchestration: route resolution, delegate limits, final response lifecycle.42- Configuration: schema validation, env secret resolution, immutable runtime config.43- Provider adapters: Vercel AI SDK/provider specifics and error mapping.44- Observability/security: request ids, logging, redaction, auth, timeouts.4546Crossing these boundaries should happen through typed interfaces.4748## TypeScript Standards4950- Prefer explicit domain types over loose `any`.51- Do not leave untyped locals that widen to `any` for provider, orchestration, or config results.52- Model config and API DTOs separately.53- Validate external input at boundaries before using typed runtime objects.54- Treat provider outputs as external input even when they came through an SDK type.55- Use discriminated unions for provider result/error variants when useful.56- Keep async cancellation/timeout behavior visible in function signatures or options.57- Extract shared domain types when the same request/client/config shape appears across services and Express request augmentation.5859## NestJS Standards6061- Keep controllers thin.62- Put business rules in injectable services.63- Use guards for auth, filters for error envelopes, interceptors/middleware for request id/logging where appropriate.64- Do not read env vars from controllers or orchestration services.65- Do not import provider SDK packages outside provider adapter modules.6667## Code Smells To Fix6869- provider-specific conditionals in controllers;70- repeated OpenAI error envelope construction;71- repeated config reference validation;72- raw secrets in logs or thrown errors;73- orchestration loops without hard backend limits;74- tests that only verify mocks were called;75- duplicated `AuthenticatedClient`-style shapes across services and request typings;76- provider payload casts without runtime validation;77- public or operational errors with misleading status/code semantics;78- abstractions named `Manager`, `Helper`, or `Util` without a clear domain role.7980## Refactoring Rule8182Refactor behind passing tests. If tests are missing, first add characterization tests for the behavior being preserved.