# /polyArch v2 - Self-Configuring Polymorphic Architecture
## Core Rules Summary (TL;DR for LLMs)
- **Module Locality is Key:** Everything for a module goes in the module.
- **Inject Shared Resources:** DB connections, etc., must be passed in.
- **Use Frozen `process.global` for Universals:** Only for `xLog`, `getConfig`, etc.
- **Use the Registry Pattern:** No `switch` statements in factories.
- **Formal Interfaces are Required:** Use TypeScript `interface` or JSDoc `@interface`.
---
## Overview
The Self-Configuring Polymorphic Architecture pattern (v2) creates robust, enterprise-grade applications by composing self-configuring components that present formal, uniform interfaces. This version refines the original pattern with clearer guidelines for dependency management, scalability, and safety.
## Fundamental Principle: Complete Module Locality
**To the maximum extent possible, all information, code, config, and resources needed to understand, debug, and extend a module should be present in that module.**
This remains the cornerstone of the architecture. Its goal is to enable a developer to open a single file and gain a complete understanding of that module's behavior and dependencies.
## Naming Principle: Descriptive and Searchable
**Never use common words (value, data, library, etc.) for names except for minimal local variables used within a few lines.**
This principle is critical for maintaining clarity in a system composed of many small modules. Names must be **descriptive**, **uniquely searchable**, and **specific**.
## Core Principles
### 1. Self-Configuration via a Global Context (The Exception)
While global state is generally an anti-pattern, a pragmatic exception can be made for a small, immutable set of truly universal utilities. Functions for **logging** and **configuration access** are candidates for this approach.
By placing these on `process.global`, they become available throughout the codebase without the need for repetitive dependency injection.
**Crucial Safety Guideline:** If using this pattern, the global object must be frozen at application startup to prevent accidental modification.
```javascript
// main.js - At startup
const { xLog, getConfig, commandLineParameters } = require('./lib/setup-env');
// Define the global context
process.global = { xLog, getConfig, commandLineParameters };
// Freeze it to prevent any modification
Object.freeze(process.global);
// Now any module can safely use it
const { xLog, getConfig } = process.global;
```
### 2. Self-Containment and Injected Shared Resources
Modules should instantiate their own stateless dependencies locally. However, any dependency that is stateful, expensive, or manages a shared resource pool **must be injected** by the orchestrator. This is the key distinction between a *shared resource* (like a DB connection) and a *global utility* (like a logger).
### 3. Formal, Polymorphic Interfaces
Components with varying implementations must adhere to a **formally defined interface**. This provides a strong contract for developers and allows the orchestrator to use components interchangeably.
In TypeScript, this should be enforced with `interface`:
```typescript
// /interfaces/DataExtractor.ts
export interface DataExtractor {
extract(source: string): Array;
getSourceType(): string;
describe(): string;
}
```
In JavaScript, use JSDoc for static analysis. This provides type-checking hints to editors and documents the expected contract.
```javascript
/**
* @interface DataExtractor
* @property {function(string): Array