# Codify Pipeline: Level B (New Extension TypeScript Files)

Level B is the codify pipeline for changes that require creating a new TypeScript file under
`core/config/extensions/`. This pipeline is used when the user wants to add or extend a System,
add an Action, add a custom entity type, or make any structural addition that cannot be expressed as a simple
field override in `core/config/organization-model.ts`.

Level B is **only offered when the user explicitly asks** for something that requires a new file.
Never silently escalate from Level A to Level B. If Level A is sufficient, use it.

---

## When Level B applies

- Adding or extending a System that does not exist in the platform defaults, including routing,
  manifest wiring, and route references
- Adding an Action that is invokable by a workflow, agent, command, or UI trigger
- Adding a custom entity extension (new Zod schema extending a base entity type)
- Any structural addition the caller's domain operation has determined cannot be expressed as a
  field value in the existing adapter

The calling operation (or the legacy compatibility notes in `features.md`) is responsible for deciding when Level B is needed
and for confirming the intent with the user before invoking this pipeline.

---

## Pipeline

### Step 1: Snapshot all files that will be touched

Before any write, read and snapshot:

1. `core/config/organization-model.ts` (always touched for wiring)
2. The target extension file path (if it already exists -- confirm overwrite with user)

```
Read("core/config/organization-model.ts")   -- store as ROLLBACK_ADAPTER
Read("core/config/extensions/{target}.ts")  -- store as ROLLBACK_EXTENSION (if exists)
```

The target extension file path follows the naming convention:
`core/config/extensions/{kebab-case-system-or-action-id}.ts`

### Step 2: Scaffold the extension file

Create `core/config/extensions/{id}.ts` using the Write tool.

The file shape depends on the extension type:

**Custom system/action extension (common Level B case):**

```typescript
/**
 * {System or action label} extension.
 * Registered in core/config/organization-model.ts.
 */
import type { OrganizationModelSystem } from '@elevasis/core/organization-model'

export const {SYSTEM_CONST}: OrganizationModelSystem = {
  id: '{system-or-action-id}',
  label: '{System or Action Label}',
  description: '{optional description}',
  enabled: true,
  entityIds: [],
  surfaceIds: [],
  resourceIds: [],
  actionIds: [],
}
```

Replace `{SYSTEM_CONST}` with the SCREAMING_SNAKE_CASE version of the system or action ID
(e.g. `CLIENT_PORTAL_SYSTEM`).

The caller provides the exact field values based on what the user confirmed.

### Step 3: Wire the extension into the adapter

Edit `core/config/organization-model.ts` to:

1. Import the new constant from the extension file.
2. Add it to the appropriate `systems` or `actions` collection in the `defineOrganizationModel({...})` call.

Example import addition:

```typescript
import { CLIENT_PORTAL_SYSTEM } from './extensions/client-portal'
```

Example system collection addition:

```typescript
systems: [
  ...existingSystems,
  CLIENT_PORTAL_SYSTEM,
],
```

### Step 4: TypeScript type-check

```bash
pnpm -C operations check-types
```

Capture stdout and stderr. If the command exits non-zero, proceed to Step 6 (rollback).

### Step 5: Runtime schema validation

```bash
pnpm -C operations check
```

If either check fails, proceed to Step 6 (rollback).

### Step 6: Rollback (on failure only)

If Step 4 or Step 5 failed:

1. Restore `core/config/organization-model.ts` from ROLLBACK_ADAPTER.
2. If the extension file did not previously exist, delete it. If it previously existed, restore
   from ROLLBACK_EXTENSION.
3. Re-run `pnpm -C operations check-types` to confirm the restore is clean. If the restore
   itself fails type-check, report both the original error and the restore state to the user --
   do not silently leave the project in a broken state.
4. Return the error message to the caller.

### Step 7: Success signal

If Steps 4 and 5 both passed, return a success signal to the caller with:

- Extension file path created
- Adapter wiring changes (import + systems/actions collection entry)
- `Type-check: PASS`
- `Schema validation: PASS`

The caller formats and presents the final report to the user.

---

## Caller Contract

Callers must provide before invoking this pipeline:

- **Extension file path:** `core/config/extensions/{id}.ts`
- **Extension file content:** the full TypeScript content for the new file
- **Adapter changes:** the exact import line and systems/actions collection addition to write into the adapter
- **Confirmed:** the user has already said yes to the proposed change and explicitly requested
  a new extension file

This pipeline does not ask the user any questions. All confirmation and escalation decisions
happen in the domain operation before this pipeline is invoked.

---

## Constraint: Extension files are Tier 3 (never synced)

Files under `core/config/extensions/` are Tier 3 -- project-specific, never overwritten
by `/external sync`. This means custom systems, actions, and entity extensions survive template upgrades
automatically. Do not put platform-default overrides in extension files; those belong directly in
`core/config/organization-model.ts` (Tier 2, merge-aware).
