# Coded entities — system-allocated business codes

The platform ships a **complete code-generation engine**: a business code (invoice number, mandate
code, matricule, opportunity reference) is allocated **atomically and gaplessly at insert** by the
shared `CodedEntitySaveHandler`, on `core.seq_Sequences` under `UPDLOCK/SERIALIZABLE` **inside the
entity's own insert transaction**. The counter is contiguous, survives restarts, and never collides
under concurrency.

Every registered key surfaces automatically in **Administration → Configuration → Code patterns**,
where an admin can override the format, scope, reset and start value. **A `CodePattern` DB row is only
ever an OVERRIDE of the descriptor's built-in default** — so there is *no seed and no migration* to
write, ever.

## The rule that closes the incident

> **Never model a counter.** No `{Entity}Sequence` entity, no `nextValue:int` column, no
> `{tenantId, year}` allocator table, no client-side "numbering service". The BA declares a
> `- **Code pattern**` line on the entity that CARRIES the code — that is the whole job.

This is the `code-generation` entry of `lib/capability-catalog.ts` (C-6 / DM-019 / CODE-006), and
audit **DM-017** errors on a re-modelled allocator. The historical failure: the BA levels used to
*instruct* modelling the counter for any gapless pattern — and gapless is the socle **default**, so
every module shipped a duplicate of an engine it already had.

## The two halves (both deterministic, both scaffolded)

| Half | CLI | Emits |
|---|---|---|
| **Entity** | `cli/scaffold-entity` (`codedEntity: { codeKey }`) | the `Code` column (engine-assigned — NEVER a Create/Update input), the `ICodedEntity` implementation, the EF unique index chosen from `tenantMode` |
| **Descriptor** | `cli/scaffold-coded-entity` | `{Entity}CodeKeyDescriptor.cs` (`ICodeKeyDescriptor`) + the `services.AddSmartStackCodeKey<…>()` line between the `<<< CODED-ENTITY-KEYS-DI >>>` markers |

Audit **DEV-API-022** verifies all four legs at the Phase 2 gate: `ICodedEntity`, the
`AddSmartStackCodeKey` DI line, the `ExtensionsDbContext` ctor forwarding `IServiceProvider`
(**without it allocation is silently skipped and Codes ship empty**), and the unique `Code` index.

The key MUST be namespaced (`orders.invoice`, `crm.opportunity`) — un-namespaced keys belong to the
platform's own `CodeKeys` constants.

## The format grammar is CLOSED

`CodePatternValidator` runs on **every allocation** and throws `InvalidCodePatternException` on
anything it does not recognise — an invented token ships a feature that 500s on first create.

| Family | Tokens |
|---|---|
| Engine | `{YYYY}` `{YY}` `{MM}` `{DD}` `{TENANT}` `{SEQ:n}` |
| Derived (pre-substituted from field inputs) | `{FIELD:Champ}` `{UPPER:Champ}` `{LOWER:Champ}` `{SLUG:Champ}` `{INITIALS:Champ}` `{ABBR:Champ:n}` |

Hard rules the engine enforces:

- `{SEQ}` / `{SEQ:n}` is **required**, unless the format derives from ≥1 field token (a pure function
  of the inputs — pair it with `CollisionStrategy.Suffix` **and register a uniqueness probe**, see
  below: since v3.67 `Suffix` consults the key's `ICodeUniquenessProbe` to append `-2`, `-3`… and a
  key without one refuses the allocation instead of suffixing blindly).
- A derived token must name its field: `{SLUG:Name}`, never a bare `{SLUG}`.
- `Reset=Yearly` requires `{YY}`/`{YYYY}`; `Monthly` requires + `{MM}`; `Daily` requires + `{DD}`.
- `{NNNN}`, `{YEAR}`, `{SEQUENCE}` are **not tokens**. A sequence counter is `{SEQ:n}`.

`cli/scaffold-coded-entity/code-pattern-grammar.ts` mirrors this grammar and fails the scaffold
closed, so a bad format is caught at generation time instead of at runtime.

## Scope and reset

`CodeScopeKind` is exactly `Tenant` (default) or `Global` — **there is no per-parent scope**. A
"counter inside a parent" is expressed in the format instead:
`{ABBR:ClientName:3}-{SEQ:4}`. `CodeResetPeriod` is `None` / `Yearly` / `Monthly` / `Daily`; the
period key segments the counter, so it restarts on its own with no reset job.

`Gapless = true` (the socle default, and what legal/accounting numbering requires) allocates under the
DB lock; `false` switches to the HiLo cache — faster, but codes may gap on rollback.

## Uniqueness probe (hand-written — required for `Suffix`, recommended everywhere)

Since v3.67 the socle exposes `ICodeUniquenessProbe` ("is this code taken?") and the two-generic seam
`services.AddSmartStackCodeKey<TDescriptor, TProbe>()`. The probe mirrors the entity's unique `Code`
index; it is what (a) makes `CollisionStrategy.Suffix` work, (b) turns a taken code under `Fail` into
a clean domain error instead of an SQL unique-index violation, and (c) lets the platform's
deterministic code SUGGESTIONS (`GET /api/codes/{codeKey}/field`, `POST /api/codes/suggest` — the
`SmartCodeField` component in creation forms) only ever propose FREE codes. **No scaffolder emits it**
— which perimeter the probe answers for (tenant-partitioned? shadowing globals?) is a business
decision; write it by hand next to the descriptor:

```csharp
public sealed class OpportunityCodeUniquenessProbe(AtlasExtensionsDbContext context) : ICodeUniquenessProbe
{
    public string CodeKey => "crm.opportunity";
    // Contract: AsNoTracking (runs inside SaveChangesAsync), never SaveChanges, mirror the unique index.
    public Task<bool> IsTakenAsync(string code, CancellationToken ct = default)
        => context.Opportunities.AsNoTracking().AnyAsync(o => o.Code == code, ct);
}
```

then upgrade the DI line between the `<<< CODED-ENTITY-KEYS-DI >>>` markers to the two-generic form.

## Spec shape

```json
{
  "appCode": "Atlas",
  "projectPath": "D:/apps/atlas",
  "entities": [
    {
      "entityName": "Opportunity",
      "applicationCode": "crm",
      "module": "pipeline",
      "codeKey": "crm.opportunity",
      "label": "Opportunity codes",
      "description": "Codes for the CRM pipeline opportunities.",
      "defaultFormat": "OPP-{YY}-{SEQ:4}",
      "scopeKind": "Tenant",
      "reset": "Yearly",
      "gapless": true,
      "collisionStrategy": "Fail",
      "probeType": "OpportunityCodeUniquenessProbe"
    }
  ]
}
```

`probeType` (optional) names the hand-written `ICodeUniquenessProbe` (simple
name = qualified into the descriptor's namespace; dotted = verbatim) — the DI
line is then emitted two-generic `AddSmartStackCodeKey<Descriptor, Probe>()`.
It is REQUIRED with `collisionStrategy: "Suffix"` (validate fails closed —
the v3.67 engine refuses a probe-less Suffix allocation at runtime).

The ENTITY half (`scaffold-entity`) takes the SAME mask as
`codedEntity.format`: it feeds `GetCodeInputs()` with the fields the derived
tokens reference (`{ABBR:ClientName:3}` → `["ClientName"] = ClientName`).
Omitting it on a derived-token pattern ships an empty dictionary and the
allocation fails at insert — pass the entité.md mask to BOTH halves.

```bash
npx --prefer-offline tsx skills/development/backend/data-layer/cli/scaffold-coded-entity/index.ts \
  --spec-file /tmp/coded-entity-spec.json --outdir /path/to/target-app
```

## Forbidden

Every shape below is caught deterministically by **DEV-API-034** (err) on the
generated C# — the BA-side nets (DM-017 checks 5/6, CODE-006) only read
entité.md.

- A counter / sequence / allocator entity, or a `nextValue`-like column, anywhere in the MCD.
- A client numbering service, a `MAX(Code)+1` query, a `Guid`-derived or timestamp-derived code.
- Trusting a `Code` from a Create/Update DTO **directly**, or exposing it as a required editable form
  field. Since socle 3.66.0 the ONE sanctioned exception is an OPTIONAL `code` on the create command,
  validated through `ISuppliedCodeGuard.EnsureAvailableAsync(codeKey, code)` then applied via
  `ApplyCode` before the save (`HasCode` short-circuits the allocation — the idempotency contract:
  imports/reprises arrive WITH their number and keep it). This exception is no longer hand-authored:
  the BA DECLARES it (`surchargeable à la création` on the `**Code pattern**` line), derive-code-specs
  stamps `codedEntity.supplied` on the pagespec, and scaffold-business/scaffold-controller/
  scaffold-component EMIT the whole seam — `string? Code = null` terminal on Create Dto/Command, the
  guard call `entity.ApplyCode(await _codeGuard.EnsureAvailableAsync(((ICodedEntity)entity).CodeKey,
  command.Code, ct))` before `Add`, and the create-only `SmartCodeField` on the form (DEV-API-022's
  supplied legs audit it). Updates never touch `Code`; a naked `entity.Code = dto.Code` remains
  forbidden (DEV-UI-034 / SCR-015).
- Seeding a `CodePattern` row to "install" a pattern: the descriptor IS the default; a row is an
  admin override.

## Limits (by design — do not "fix" these)

- **`ISuppliedCodeGuard` checks shape + freedom, never mask conformance** — « the mask says how codes
  are GENERATED, not which codes are legal ». Do not add a mask-conformance validator client-side:
  duplicating the guard's charset (`^[A-Za-z0-9._/ -]+$`, ≤ 100) is a drift point, and legality is
  the guard's job (its `DomainException` renders a clean 400).
- **The sequential allocator never consults the uniqueness probe** — a supplied code inside a
  `{SEQ}` sequence's FUTURE corridor is only caught by the unique index, LATER, when the sequence
  reaches it (the gapless transaction then reclaims the number on rollback). This is the socle's own
  trade-off; the BA-side warn (DM-017 check 7, PRD-132) steers supplied codes out of the mask's shape.
- **The floor is socle 3.66.0** (`MIN_SOCLE_SUPPLIED_CODE_VERSION`) — `ISuppliedCodeGuard` + the
  `/api/codes/{codeKey}/field` and `/api/codes/suggest` endpoints ship there. scaffold-business
  fail-closes below it; DEV-API-022 skips the supplied legs with a warn.
