# Sibyla — Backlog v6.0

**Plan of record:** `docs/V6.md`
**Date:** 2026-08-25 · rev. 60
**Supersedes:** `docs/project-todo.md` (v5.0), `docs/project-todo-v4.md` (v4.0)

> **2026-08-26 correction to the 2026-08-25 closeout.** `S2-11` was recorded complete while the
> rule it governs could not be imported and its detector had no reachable state: `!153` issued
> the rule as `EF0000065`, a code the FDR source had already given to a different rule, and
> `CK_DOCFLG_DeterministicEvidence` demanded an enforcement date `GovernDOCEFLRule` forbids for
> an `Annotation`. `!155` and `!157` are what make the claim true. The original closeout text
> follows, unedited, because it is the record of what was believed at the time.
>
> **2026-08-25 closeout.** `S2-9`, `S2-10` and **`S2-11` are complete**. `S2-11` closed through
> MR `!153`: source `bc5d94a7882db5be9bd3f0b5a807ee65415a9a2d` merged as
> `4167f7e67da02f9527a3433908396d49580c9d29` at 2026-08-25T16:34:27.226Z; MR pipeline
> **2789667930** and post-merge `main` pipeline **2789745778** succeeded. The GitLab `main` API
> reported exactly that merge and its parents `cca363a96b041ef2bf5f5919bd400a583e18f707`
> and `bc5d94a7882db5be9bd3f0b5a807ee65415a9a2d`; this is not a claim that local `main` or any
> local upstream-tracking ref is synchronized. **`S2-12` is the next implementation item.** No
> deployment, live migration, ERP activation, EntryCode/LGCode issuance or live-tenant operation
> was performed or verified.
>
> **S0 is closed — 8/8.** The GD-1 channel-intake E2E rerun succeeded on **2026-08-18**, closing
> **S0-4**, and `docs/STATE.md` now carries the nine steps marked from it, closing **S0-5**. The
> 2026-08-10 run was preliminary and is superseded. Outcome: steps 1, 3, 6 and 9 **work** (9 for
> fiscal GD-1), steps 2 and 4 are **broken** on unresolved company / counterparty / direction,
> steps 5 and 7 are **missing**, and step 8 was **not reached** because outbound **business**
> integrations were deliberately disabled — Cegid, Microsoft Graph and the financial push paths —
> so no external business-integration job, commit, operation or call was attempted. **OIDC
> discovery and token acquisition did occur**, as authentication to the Sibyla API for the intake
> submission; no token, client id or value is recorded.
>
> **S1 seeding is complete, and the screens have started.** `S1-3a` closed 2026-08-16 (MR `!62`).
> Merged 2026-08-16/19: `S1-9a` module shell (`!63`), `S1-9b` reference grid pattern (`!64`), the
> three `S1-9c` code-list screens — ITMCLS (`!65`), MNGACC (`!66`), COCACC (`!69`), all read-only —
> the second half of **`S1-6a`** across `!70`–`!72`, which retired `DocumentTypeSetting` and
> `FinancialDocumentType`, the first **`S1-9d`** slice (`!74`): the Entity 360 shell with a
> **read-only** Identity tab over merged ENTMST (recorded by docs-only `!75`), the second
> `S1-9d` slice (`!79`): the governed Identity/ENTMST write-service pattern, and — on
> **2026-08-19** — the third `S1-9d` slice (`!82`): governed Entity 360 **Tax identifiers**, the
> fourth `S1-9d` slice (`!84`): governed Entity 360 **Roles**, and the fifth `S1-9d` slice
> (`!86`): a **read-only** Entity 360 **Aliases** tab. Two
> further docs-only
> merges followed `!74`, changing no runtime behaviour: `!76` *docs: refresh S1 state and flow v16*
> (`d449f87` → `0312db6`) and `!77` *docs: record verified S0 intake principals*
> (`fbef709` → `917f81e`), which recorded the verified channel-intake client and principals without
> itself performing the GD-1 E2E; `!77` was the `main` tip until `!79` (source `03180d1d` → merge
> `8d924db6`, green head pipeline **2770706234**) landed, and docs-only `!80` and `!81` followed it.
> `!82` (source `2e9732e` → merge `3fb806b`, merged 2026-08-19T04:40:56.137Z) was the latest
> runtime change until `!84`, and a docs-only merge recording it followed (merge `0b031c5`,
> no runtime behaviour).
> `!84` (source `b9b332b` → merge `2c7eab4`, merged 2026-08-19T10:17:17.49Z) was the latest
> runtime change until `!86`; docs-only `!85` (merge `ff8773e`) recorded the Roles delivery and
> changed no runtime behaviour. `!86` (source `d2064e8` → merge `c1cec04`, merged
> 2026-08-19T12:26:35Z) shipped the read-only Aliases tab, no write
> path, and an empty-`Up`/`Down` model-mapping migration
> (`20260819111951_S19dEntityAliasesReadModel`), no schema change; MR pipeline **2772364485** and
> post-merge `main` pipeline **2772402931** both succeeded. `!89` (source
> `a6b70fc2987bf274b7304d44032c2ff55a9b0c5c` → merge
> `35ca2e7016a629292c2a084fe22a4692d74438ba`, merged 2026-08-19T17:42:38.385Z) **was the
> immutable runtime baseline until `!91`** — the current one is `!145` (merge
> `9778f43288ffbe23ed1d356908e7e1b1b19983ba`, 2026-08-24), and `STATE.md` carries the chain:
> update-only existing aliases; Alias plus explicit scope
> writable; ALCode, EntityId, generated NormalizedAlias, CodeName and Flag read-only; server-side
> Administrator / Finance / Accounting authorization, active company, `xmin`, same-transaction audit,
> current/submitted conflict, one update seam and durable `HumanOwned`; seeder lock order preserves
> human Alias/scope while syncing source evidence. Additive migration `20260819144205` has a
> count-only preflight, `CK_ENTALS_Alias_NonBlank`, `HumanOwned` default false, and no repair,
> backfill or code issuance. MR pipeline **2773586157** and post-merge `main` pipeline
> **2773640192** succeeded; all three jobs succeeded. Local observations: Release 0 warnings / 0
> errors, default 1660/1660, `FdrDatabase` 305/305, final review ACCEPT. As ever the record above is
> an **immutable runtime merge**, and the baseline it set held only until the next runtime merge —
> it is not a claim about the current Git tip of `main`, which
> docs-only merges advance without
> changing runtime. Open
> S1 work ended with `S1-9` — **`S1-9c` closed 2026-08-20** with the read-only EXCRAT (`!100`,
> with the missing-rates panel), ITMALS (`!101`, first `GlobalOrActiveCompany` grid) and ENTALS
> (`!102`, surfacing `HumanOwned`) descriptor screens. **The new descriptor/reference-grid surfaces remain read-only first
> cuts**, while **Entity 360 Identity now has the governed write path from `!79`**: it introduced
> service-side `ClaimsPrincipal` authorization
> (`Administrator` required for `InternalCompany`), the exact governed writable field set with
> permanent codes and every other field staying preserved and read-only, PT/EN validation and error
> copy, a before/after `AuditEvent` in the same transaction as the write, and optimistic concurrency
> on PostgreSQL `xmin` — no speculative `Version` column, no migration; **Tax identifiers has
> the same governed path from `!82`**, which reused that pattern for 1:N `EntityTaxIdentifier`
> mutations plus the atomic `ENTMST.FiscalNo` primary projection; and **Roles has it from `!84`**,
> which reused it again for `EntityRoleAssignment` through a single mutation seam, leaving
> `ENTMST.Role` untouched and `InternalCompany` read-only; **Aliases shipped read-only with
> `!86`** and gained its **governed update-only write with `!89`** — scope shown
> explicitly, an unscoped alias rendering as "all companies" in PT/EN, never blank, human edits
> durably `HumanOwned` and preserved by the seeder; and **Banking has the same governed path from
> `!91`**, which edits the ENTBNKMethod/ENTBNKAccount child values one at a time and regenerates
> the parent ENTBNK projection strings from the children in the same transaction — never the
> reverse. The
> pre-existing supplier
> Update/Verify/Merge writes remain in place, unaffected and still supplier-scoped. **Items has the
> same governed path from `!93`**, which edits the
> per-row SNCACC/CostCentre account mapping (the S3-4 learning-path target) with the SNCDSC
> description regenerated from the mapped account, never edited directly; and the three read
> surfaces — **Documents** (`!96`, recent DOCLOG rendered honestly while writerless), **Balances**
> (`!97`, source-owned operational values labelled as not master data) and **Audit** (`!98`, a
> type-scoped view of the entity's governed-write events) — completed the nine tabs on
> **2026-08-20**, and the `S1-9c` remainder — **EXCRAT** (`!100`), **ITMALS** (`!101`),
> **ENTALS** (`!102`) — closed the same day.
> **S1 closed 2026-08-20**: the "CTT" exit was demonstrated on the demo database — the
> 2026-08-20 14:45 session plus the same-day revalidation of the materialized Tax Identifiers —
> and **validated by Miguel, with screenshots as the record**. The carried remainders moved out
> with it: `g3` stays blocked on **O-1** (Luís), the DOCEFL editor is S2 work (**O-4** Miguel's).
>
> **S1.5 is complete through `S1.5-8`.** Cumulative MR `!59` merged source `394fbbd` to `main` as
> `60ffb46` on 2026-08-15. Pipeline **2762302842** succeeded: Debug and Release builds each had
> 0 warnings and 0 errors; default 1183/1183, `PartyCollapseContract` 38/38, `P11aDatabase` 61/61
> and PostgreSQL 17 `FdrDatabase` 189/189 passed with zero failures or skips. Detail stays with the
> S1.5 items below.

## Legend

`[ ]` not started · `[~]` in progress · `[x]` done · `[!]` blocker or standing caution ·
`[D]` deliberately deferred to Phase 2, with its reinstatement trigger in `V6.md` §7

**Detail is capped at the current phase plus the next** (V6.md §8 rule 3). S0–S2 are itemised.
S3–S7 are sketched at the level needed to sequence and staff them, and get itemised when the
phase before them closes. This is deliberate — v5.0 itemised fourteen phases in detail and
delivered one, because detail written three phases ahead is written from assumptions the current
phase is about to invalidate.

**Counting.** 77 live items across S0–S7 plus 3 standing platform constraints — **80 live**, which
is what the item-count table at the foot of this file sums to. Rev. 28 added **S2-15** (the
Invoice Skill Build extraction reconciliation) — a deliberate scope addition moving S2 from 14 to
15 items, and **not** to be confused with the "80" and "81" carried by
rev. 13, which were arithmetic errors against unchanged per-phase rows and stay withdrawn. Gates, reviews and decisions are not backlog items and
never move the numerator; only demonstrated work does. A phase closes on its exit criterion being
demonstrated to a person, not on its boxes being ticked.

---

## Decisions (V6.md §2)

| # | Decision | Date | Reverses if |
|---|---|---|---|
| `[x]` V6-D1 | July stack is the spine; FDR tables are the schema | 2026-08-10 | S0-4 finds the July stack unrecoverable |
| `[x]` V6-D2 | Cegid izibizi is the first ERP target | 2026-08-10 | izibizi credentials prove unobtainable |
| `[x]` V6-D3 | No document data imported; documents arrive one at a time through channels | 2026-08-10 | an accounting or legal requirement to hold history inside Sibyla appears |
| `[x]` V6-D4 | Only Layer 2 and Layer 4 data imported | 2026-08-10 | with V6-D3 |
| `[x]` V6-D5 | Security hardening deferred while agents and skills are still changing | 2026-08-10 | pilot runs on real company data (O5 stays a production gate regardless) |
| `[x]` V6-O1 | **Verification replaces ceremony.** Pipeline green → merge; adversarial pass comments, never gates; fix forward; a review past ~20 min means the change is too large. Stop list = code that governs irreversible behaviour (destructive migrations · ERP write path · permanent code issuance · live-tenant config), **not** runtime events, which are features (`S2-12`, `S3`, `S4-2`). Full text in `V6.md` §2 | 2026-08-10 | a production defect traces to a skipped review — and then by tightening verification first |
| `[x]` M-D1…M-D7 | **Approved by Miguel 2026-08-11** — the master-data decisions. Collapse upward; one internal key style; internal companies as ENTMST rows; one generic grid; **business codes in `ExternalIdentity`**; EF migrations as the single schema authority; effective dating decided now and built later. Full text in `docs/master-data-and-ui-plan.md` §0; deferred remainder in `master-data-phase2-plan.md`. Adds phase `S1.5` | 2026-08-11 | M-D5 reverses only if an ERP cannot accept a code Sibyla did not mint |
| `[x]` M-D8 | **A source retirement is evidence, not a target mutation — and an identity pin binds to a natural key, not to a code.** Taken with the Stage 11 source alignment (`!135`/`!137`): a tombstoned source row keeps its code reserved, is validated like a live row, is never seeded and may not be referenced by any child file, while a row an earlier seed already placed under that code is left to the target and reported as `Skipped`; the two governed related-party kinds are pinned by their **(Class, Subclass)** pair rather than by the ITMCLS code carrying it. Full text in `docs/master-data-and-ui-plan.md` §0 | 2026-08-21 | a source retirement appears that *must* propagate as a target state change — then it needs its own governed command, not a seeder side effect |
| `[x]` M-D9…M-D12 | **The four Stage 11 follow-up decisions are recorded.** `!141` implements **M-D11**: RelatedParty/Kind resolves by the exact `(Class, Subclass)` pair through ITMCLS/`RelatedPartyKinds`, never by code or display prose, carries the source's `RelatedParty` truth, fails closed on an unbound or ambiguous pair, and preserves human-owned corrections. **M-D9** remains conditional and no destructive re-key was built: it exists only for a non-rebuildable database still on Aug-6 numbering. `S2-11` framework `!149` implements **M-D10** Relevancy persistence and **M-D12** by adding exactly `ITMMST` to the DOCFLG `RelatedRecordType` domain and pinning detector subjects by `EFCode`. Full decision text is in `docs/master-data-and-ui-plan.md` §0 | 2026-08-22 decisions · M-D11 implemented 2026-08-23 · M-D10/M-D12 implemented 2026-08-25 | **M-D9** if no non-rebuildable affected database exists (then no migration is built) · **M-D10** if the next pin adds a third literal (promote to catalogue/FK) or the source drops the member (retain nullable history) · **M-D11** if a third governed kind appears (governed catalogue/FK) · **M-D12** if a later pin emits a new primary `RelatedRecordType` |
| `[x]` M-D13 | **`DOCUMENT` joins the DOCFLG `RelatedRecordType` domain on `EF0000066`'s authored `AppliesToTable`, not on observed instances.** *(2026-08-26)* `M-D12`'s observed-instances-first test cannot be met here: Sibyla holds zero DOCFLG instances of any kind, and the prototype emits none for this rule either, because the subject is Sibyla's own intake record and the prototype has no such lifecycle — waiting for an instance is waiting for something that can only appear after the domain admits it. Bounded three ways: the subject is pinned to `EF0000066` **in both directions**; `CompanyRecordReference` is widened with it, without which the subject is un-insertable; `ITMCLS` and `FDCHDR` stay excluded on `M-D12`'s original reasoning | 2026-08-26 | an `AppliesToTable` names no Sibyla record type (the domain is tracking the source's vocabulary, not Sibyla's records) · a second rule needs `DOCUMENT` (the both-ways pin dissolves and `M-D12`'s test returns) |
| `[x]` M-D14 | **Which ITMCLS pairs may serve as a related-party kind is governed data, not a compiled list.** *(2026-08-26)* `CK_ENTMST_RelatedPartyKind_FundingOnly` was generated from a constant naming two codes, so admitting a third — `Shareholders / Transfers`, `CL000054`, which `EC000121` cites — was a deployment. ENTMST references a `RelatedPartyKindCatalogue`; the catalogue references ITMCLS by **one composite key** on `(CLCode, Class, Subclass)`, so a code and a pair cannot describe different rows, with `ON UPDATE CASCADE` so a renumbering propagates and `ON DELETE NO ACTION` so a cited pair cannot leave. **This supersedes `M-D11`'s reversal clause**, which called for a governed catalogue with an FK the moment a third kind appeared: this is that catalogue. P11a's `FK_ENTMST_RelatedPartyKind` is replaced rather than kept — carrying no `ON UPDATE` clause, it blocked the very renumbering the design exists to survive, and it is redundant once membership is transitive. `RelatedPartyKinds` survives as the bootstrap for an empty database. **Not done:** the page option lists are still fixed markup | 2026-08-26 | eligibility needs to differ per company (the catalogue gains a scope column) · the UI option lists are read from the catalogue, at which point the bootstrap list is the only compiled remnant left |
---

## S0 — Stop, ground, restart · ~3 days · 8 items

The goal is an honest picture, not a plan. Nothing here produces a feature.

- `[x]` **S0-1** V6-O1 decided 2026-08-10 — verification replaces ceremony. The v5 per-piece gate
  structure is withdrawn in full. Recorded in `V6.md` §2 and `AGENTS.md`
- `[x]` **S0-2** Close P1-1b. Piece D accepted and merged 2026-08-07. **Scopes 1–8 revoked
  2026-08-10** — both go-ahead documents carry a REVOKED banner and moved to `docs/archive/`.
  Nothing remains
- `[x]` **S0-3** The nine P1-1a / Piece A-B-C migration files are on `main`; the GitLab pipeline
  builds Debug + Release and runs the tests green against them (MR!36). Additive and paid for
- `[x]` **S0-4** Run the July stack end-to-end against the current schema and record what happens
  at each of the nine steps in V6.md §3. **Closed 2026-08-18** by the channel-intake E2E rerun; the
  2026-08-10 run was preliminary — three hosts under the `Development` InMemory fallback, no
  document admitted — and is superseded. The document is **GD-1**, fixed in
  `docs/golden-documents.md`. The final run submitted the **exact pinned GD-1 bytes** to
  `/api/channel-intake/v1` with the verified dedicated channel-intake client, against a
  **pre-existing enabled sender mapping**, an **isolated PostgreSQL** instance and an **isolated
  Local scratch** storage root, on installed artifact `a8d0a4bab7b2f93920ad29819d442e01c04dd374`
  — an artifact **ancestral to `main`**, so this is not a demonstration of the current `main`
  runtime and `main`'s governed staged migrations were not bypassed. Measured: 201 register, 200
  same-idempotency-key replay with `replayed=true`, 200 upload and status; Invoice recognised but
  internal company, counterparty and direction unresolved; Hermes job **Succeeded on attempt 1**
  with the response strictly validated and persisted as one revision and two lines; the
  deterministic gates **executed and returned false**, raising warning `LINE_SIGN_AMBIGUOUS` and
  routing to review; cataloging ran but found no account-mapping surface on the July
  `DocumentLine`; no DOCLOG/FDCHDR/FDCDTL writer exists; `AwaitingReview`/`NeedsReview` reached
  with a fingerprint-incomplete audit entry and **no human decision performed**; no
  correction-learning write-back exists; **outbound business integrations deliberately disabled —
  Cegid, Microsoft Graph and the financial push paths — so no external business-integration job,
  commit, operation or call was attempted**, while **OIDC discovery and token acquisition did
  occur** as authentication to the Sibyla API for the submission, with no token, client id or value
  recorded; and the exact original was stored immutably
  and rehashed to match, the non-fiscal archive branch not being applicable to GD-1. **No live
  write and no mapping edit.** After verification the disposable resources and sensitive snapshots
  were removed — listeners, container and temporary directory absent, the live Worker still Running
  under `.\GottSibylaDocumental`, the original GD-1 unchanged. No sender identity, identifier or
  field value is recorded here
- `[x]` **S0-5** The one-page state note. **Closed 2026-08-18.** `docs/STATE.md` replaces
  `PROJECT-STATE.md` as the live status document and carries the nine steps marked from the final
  S0-4 run — four **works** (step 9 for fiscal GD-1), two **broken**, two **missing** and one
  **not reached** — with the preliminary 2026-08-10 run kept distinct from it
- `[x]` **S0-6** Process corpus archived to `docs/archive/` — 62 files, 1.7 MB, `git mv` so history
  follows. `docs/*.md` went from 86 files to 26. Kept live out of the P1-0 set:
  `p1-0-schema-mapping.md` and `p1-0-vocabularies.md`. `docs/archive/README.md` states the folder
  carries no authority
- `[x]` **S0-7** izibizi prerequisites defined and owned — **B1 Miguel**, **B2 Luís**; four items
  reduced to two, both week-1 work. `docs/deployment/izibizi-activation.md`
- `[x]` **S0-8** Run restore, Debug/Release builds and tests on every GitLab branch push and merge
  request to `main`; require a green pipeline before merge

**Exit:** the one-page picture of the nine steps exists in `docs/STATE.md`. **Met 2026-08-18** —
the table is filled in from the GD-1 channel-intake rerun, with no step left `unknown`. (V6-O1 was
the other half of this criterion and closed 2026-08-10.) **S0 is closed; nothing in it reopens.**

---

## S1 — Reference layer live · ~1 week · 12 items

Every table below already exists — `P11aSchemaSql.cs` creates all of them, so this phase is
primarily a seeder and a screen. It is not a schema build-out, but it is not migration-free
either: representing the observed source semantics losslessly and fail-closed requires one narrow,
non-destructive forward correction, `20260811120000_S1Layer2CoreSourceSemantics` (S1-2 below).

### Seed — Layer 2, Entity Item Classification

- `[x]` **S1-1** Idempotent seeder, upsert by natural key, logs what changed, safe to re-run.
  One command, one transaction per table, no import-provenance machinery. **Merged in `!43` at
  `6b42d79`; pipeline 2750186302 passed on source `c67f33c`.**
- `[x]` **S1-2** ENTMST `entities.json` 119 · ENTALS `entals.json` 7 · ENTBNK `entbnk.json` 43 —
  counts **observed** on 2026-08-11 in the current source arrays, read without modification, and
  not acceptance criteria. The earlier ENTBNK 47 was not observed in any current source file and is
  withdrawn (`V6.md` §5); the gate is structural invariants and referential integrity.
  **Merged in `!43` at `6b42d79`; pipeline 2750186302 passed default
  697/697, `Category=FdrDatabase` 14/14 and `Category=P11aDatabase` 61/61; host-only
  `Category=FdrSource` 1/1 locally against the current read-only source.** Five modelling decisions carry and are
  recorded in `p1-0-schema-mapping.md` §3 "S1-2 source semantics — decisions of record", so that
  later code cannot reintroduce inference, truncation, fan-out or unscoped routing:
  - **Country.** `Country` becomes nullable beside two **structural booleans**, `CountryIsMissing`
    and `CountryIsNotApplicable`, both `NOT NULL DEFAULT false`, with **no country inferred**. CHECK
    `CK_ENTMST_Country_State` admits exactly three states — known (`Country` non-null, both false),
    missing (`Country` null, missing true, not-applicable false) and not applicable (`Country` null,
    missing false, not-applicable true) — and rejects both-true as well as null `Country` with both
    false, so a null country always states exactly one reason. There is **no status enum, column or
    literal**: the pair is derived structure, not vocabulary, so nothing is added to
    `p1-0-vocabularies.md`. The `false` defaults keep a legacy non-null-`Country` writer compatible;
    a null-country writer must state a reason itself. Missing means the required JSON `Country`
    property is present and holds the empty string; the parser rejects an absent, null or non-string
    `Country` and any nonblank value it cannot normalize. Not applicable is only the deliberate
    non-jurisdiction source sentinel. Observed in the current source: 117 normalized to ISO
    alpha-2, one non-jurisdiction sentinel, one empty string.
  - **Frequency.** `InvoiceFrequency` preserved losslessly as PostgreSQL `text`, never truncated,
    split or rewritten.
  - **Scope.** An **exactly empty** source `Company` maps to SQL `NULL` in ENTALS — the documented
    source wildcard, `NULLS NOT DISTINCT` uniqueness, **no company fan-out**, and no code issued
    because `ALCode` is read from the source — and in ENTBNK as unscoped payment-method evidence,
    with **no unscoped row assigned to a concrete company**. Whitespace-only `Company` is malformed
    and the parser rejects it; absent, null or non-string is rejected as before; a nonblank value is
    preserved exactly and never trimmed. Named CHECKs make it structural, closing the direct-write
    bypass: a non-null `Company` must contain at least one POSIX non-whitespace character,
    implemented as `Company ~ '[^[:space:]]'`, which blocks spaces, tabs and newlines.
    `CK_ENTALS_Company_NonBlank`, `CK_ENTBNK_Company_NonBlank` and
    `CK_ENTBNKMethod_Company_NonBlank` permit `NULL` or that; `ENTBNKAccount.Company` is `NOT NULL`
    and `CK_ENTBNKAccount_Company_NonBlank` requires that outright.
  - **Scope key.** Generated `ScopeKey` on ENTBNK, ENTBNKMethod and ENTBNKAccount is
    `CASE WHEN Company IS NULL THEN 'N:' ELSE 'V:' || Company END`, replacing the earlier
    `coalesce(Company,'')`. The discriminator makes it **injective**, so `NULL` cannot share a key
    with any non-null string — the collision a polluted `CompanyRegistry` could otherwise exploit.
    It is internal and generated, never entered and never a `CompanyRegistry` value.
  - **Routing.** On an unscoped ENTBNK row `PayAccount` may be `NULL` or whitespace-only — spaces,
    tabs, newlines — byte-preserved and materializing no `ENTBNKAccount` child; a `PayAccount`
    containing any non-whitespace character is rejected by the parser and by CHECK
    `CK_ENTBNK_Unscoped_NoPayAccount` (`Company IS NOT NULL OR PayAccount IS NULL OR
    PayAccount !~ '[^[:space:]]'`). `ENTBNKAccount.Company` stays `NOT NULL`, so no routed account
    exists without a company.

  Forward migration `20260811120000_S1Layer2CoreSourceSemantics` applies this to existing
  databases; its `Down` raises rather than discarding that state.
  **Measured locally on the host, 2026-08-11, after the final blocker fixes:** build 0 warnings /
  0 errors · default suite 697/697, within it the parser tests 47/47 and the migration model/SQL
  tests 4/4 · `Category=FdrDatabase` 14/14 and `Category=FdrSource` 1/1 against disposable
  PostgreSQL, the latter covering second-run idempotency and byte-equal `InvoiceFrequency` and
  ENTBNK parent `PayMethod`/`PayAccount` strings · `Category=P11aDatabase` 61/61 ·
  `git diff --check` clean. No write was made to the FDR prototype, which was read without
  modification, or to a live Sibyla database
- `[x]` **S1-3 + S1-4 combined delivery** — authorized by Miguel 2026-08-11 so account and
  cost-centre FK targets are seeded before dependent item rows. Read-only source observations **as at
  the Aug-6 pin, 2026-08-11** (superseded by Stage 11 — see `STATE.md`):
  ITMMST 391 · ITMALS 4 · ENTITM 327 source rows · ITMCLS 51 · MNGACC 34 · SNCACC 518 · COCACC 1;
  counts are not acceptance criteria. Exactly one ENTITM row is simultaneously unresolved against
  ITMMST and ITMCLS; it is explicitly disposed before persistence under the stable reason
  `AuthorizedDualUnresolvedItemAndTaxonomyReference`, anchored to the authorized row by a narrow
  canonical SHA-256 fingerprint. No identifier or source value is logged, no reference row is
  fabricated, and every other unresolved/ambiguous/malformed case aborts preflight. Exactly empty
  ITMALS Company maps to global SQL NULL without fan-out/defaulting; migration
  `20260811130000_S1ItemAliasScopeSemantics` adds nullable scope, `NULLS NOT DISTINCT` normalized
  alias uniqueness, named nonblank CHECK, conditional active-company enforcement, and a guarded
  Down. One combined parser/preflight and the existing advisory-locked seeder write MNGACC,
  topology-ordered SNCACC, COCACC and ITMCLS before ITMMST, then ITMALS and ENTITM. Measured:
  focused parser/migration 55/55; disposable `FdrDatabase` 21/21; current-source `FdrSource` 2/2;
  isolated default 748/748 excluding the unrelated concurrent Cegid changes; `P11aDatabase` 61/61;
  build 0 warnings/errors. The source tests cover field-by-field source-owned parity, target-owned
  COCACC notes, exact-disposition tampering on a temporary copy, source-owned updates and
  byte-equal idempotent replay; the CLI reports only aggregates and the stable disposition reason.
  **Merged to `origin/main` at `7a93a59` (`Merge branch 's1/layer2-items'`), through a merge
  request on a green pipeline.**
  > `[!]` **Consequence for S1.5:** this is the commit that made the FDR `ENTMST` populated. See
  > the note under S1.5

### Seed — Layer 4, Auxiliary Calculation

- `[x]` **S1-5** EXCRAT `exchangerates.json` — **merged at `43ad0e7`** (`s1/excrat-effective-
  dating`, MR `!50`, pipeline **2752362127** green). **47 rows were present, observed 2026-08-12** against the current read-only
  source; a second CLI run on the already-seeded disposable database reported EXCRAT unchanged=47.
  V6 records 75 from its earlier source observation; 47 is the current-source observation, and
  neither count is an acceptance criterion. Delivered more than a seed: migration
  `20260811142000_S1ExcratEffectiveDating` replaces
  the anonymous FEX check with four named CHECKs, adds `ValidFrom`/`ValidTo` as **generated STORED**
  columns derived from `Period`, and adds the GiST exclusion constraint
  `EX_EXCRAT_NoOverlappingRatePeriod` on `(From, To, daterange(ValidFrom, ValidTo, '[)'))`. The
  parser mirrors every invariant client-side and the seeder preflights DB-side overlaps by permanent
  code. **This closes `P2-4` for EXCRAT** — effective dating was to be built "when EXCRAT is first
  built", and it was; update the deferred list rather than leaving `P2-4` reading as pending.
  > `[x]` The zero-row asymmetry was fixed at `b0daccf` (`428203c` implementation): EXCRAT now
  > fails closed on an empty catalogue and the parser test covers it

### Seed — configuration, not data

- `[x]` **S1-6** DOCTYP `document_type_rules.json` — **merged at `5a8b050`** (`s1/doctyp-seed`, MR `!47`, pipeline **2751896890** green).
  Miguel decided 2026-08-10 that DOCTYP and DOCEFL are Layer 1 rule catalogues, not transactional
  document data excluded by V6-D3; seeded as configuration alongside Layer 2 and Layer 4. Migration
  `20260811143000_S1DocumentTypeCatalogue` adds the presentation columns, six named CHECKs and
  fail-closed defaults on the routing columns (`ProcessingRoute='Review'`, `FiscalEligible=false`),
  with a `Down` that locks the table and refuses if presentation data exists.
  > `[!]` **Correction to the row description above — resolved against the current source
  > 2026-08-12.** The parser implements **two independent one-time exclusions**, each gated by its
  > own SHA-256 fingerprint: one blank-`DTCode` row and one blank-`DocClass` row
  > (`FdrReferenceDataParser.DocumentTypes.cs`). Aggregated over the current
  > `document_type_rules.json`: **20 source rows, exactly one blank-`DTCode` row, zero blank-
  > `DocClass` rows.** The two fingerprinted paths therefore **do not** fall on the same source row,
  > and the blank-`DocClass` exclusion is **not exercised** by the current source — it stays in the
  > parser as a live fail-closed path, not dead code. **19 DOCTYP rows were present, observed
  > 2026-08-12**, an observation and never an acceptance criterion. The CLI run against the
  > already-seeded disposable database reported DOCTYP updated=1 unchanged=18; this records the
  > measured result without treating that run as byte-identical replay. No identifier or source
  > value is quoted here or logged
- `[x]` **S1-7** DOCEFL `flag_evaluation.json` — **merged at `5dfc919`** (`s1/docefl-seed`, MR `!49`, pipeline **2752318247** green).
  Included as configuration by the same 2026-08-10 decision. The code takes the current file and
  pins no count — `FdrFlagRuleSourceTests` asserts parsed count against whatever the source holds.
  V6 records 62 from its earlier source observation; **52 rows were present, observed 2026-08-12**
  against the current read-only source, and a second CLI run on the already-seeded disposable
  database reported DOCEFL unchanged=52. These are dated observations, never acceptance criteria.
  Adds `CK_DOCEFL_EFCode_Format`, expands
  `AppliesToTable` into `DOCEFLAppliesTo` child rows with contiguous ordinals, and introduces
  `GovernDOCEFLRule` (SECURITY DEFINER, granted only to `sibyla_piece_c_executor`) so setting
  `EnforcementStartsAt` and assigning ItemClass happen atomically
- `[x]` **S1-8** CodeLedger high-water marks from `permanent_code_ledger.json`, 7 buckets, so
  newly issued codes cannot collide with FDR codes if history is ever loaded. Merged at `5f8fb78`
  from reviewed SHA `596f963`; no history/binding import and no runtime issuance

- `[x]` **S1-3a** ITMMST gains `NormalizedItemDesc`, `IsActive`; retire
  `IntegrationProductPlKeyMapping`; repoint `IntegrationProductBinding` — **merged 2026-08-16 at
  `d959b8b` (`s1/item-master-consolidation`, MR `!62`; implementation `63e7083`).** Migration
  `20260815142000_S13aItemMasterConsolidation` with `S13aItemMasterConsolidationSql` and a
  provenance record; `IntegrationProductBinding` repointed to `ITMMST.ItemCode`; the Cegid and
  Moloni writers, sales sync and endpoints updated; `database-erd` and `p1-0-schema-mapping.md`
  updated in the same merge. Delivered with a 1072-line disposable migration database suite
  (`S13aItemMasterMigrationDatabaseTests`) plus model and binding-scope tests
- `[x]` **S1-6a** DOCTYP gains `LabelPt`, `LabelEn`, `SortOrder`, `IsActive` — in
  `20260811143000_S1DocumentTypeCatalogue`. **Closed 2026-08-18**; document types are now data.
  Three single-item merge requests, in order:
  - **`!70`** presentation data — merged at `b25d178` (`s1/doctyp-presentation-migration`,
    implementation `62d1bed`, pipeline **2767296596** green). Migration
    `20260817120000_S1DocumentTypePresentationData` copies `LabelPt`, `LabelEn`, `SortOrder` and
    `IsActive` from `DocumentTypeSetting` onto the matching DOCTYP rows. The columns remain
    target-owned — the seeder still does not write them, and the migration is their one legitimate
    writer besides the future `S1-9g` editing surface
  - **`!71`** routing through DOCTYP — merged at `e96cb06` (`s1/doctyp-routing-lookups-v2`,
    implementation `8392c0d`, pipeline **2767775709** green). `DocumentTypeRoutingService` serves
    `Treatment`, `DocClass` and `ProcessingRoute` from DOCTYP to `ChannelIntakeService`,
    `ExtractDocumentJobHandler` directly, `StoredDocumentRegistrationService`, the review services,
    the integration eligibility path used by `IntegrateDocumentJobHandler`, the Moloni writers and
    the Razor pages
  - **`!72`** the drop — merged at `1f47449` (`s1/doctyp-settings-drop`, implementation `0062a35`,
    pipeline **2768548294** green). `20260818120000_S1DocumentTypeSettingsDrop` removes
    `DocumentTypeSetting`, the `FinancialDocumentType` enum is retired, and
    `DocumentTypeSettings.razor` is rewritten onto a **read-only DOCTYP catalogue with a PT/EN
    verbal routing preview**. A destructive migration and therefore stop-list work: the record this
    repository holds is the merge itself — merged by GitLab user `gottsolutions.net` at
    2026-08-18T09:46:15.85Z. No approval text is quoted here because none exists in the repository.
    **Merged and closed; not to be reopened or repeated**
  > `[!]` **Provenance gap.** `S1-6a` is functionally closed and the destructive migration must not
  > be repeated, but the repository holds **no verbatim Miguel approval record** for it — only the
  > GitLab merge action above. This is a governance provenance gap to be noted, not a request to
  > rerun or revert the merge
  > `[!]` Both names now exist **only inside historical migration payloads**, which are never
  > edited. Any document still describing them as live application code is stale
- `[x]` **S1-7a** DOCEFL gains `LabelPt`, `LabelEn` — **done**, in `20260811144000_S1DoceflLabels`,
  with non-blank CHECKs on both. Target-owned, not written by the seeder

### Admin UI

- `[~]` **S1-9** Reference-layer browse, search, edit, create. Extend `Suppliers.razor` rather
  than building new. Broken out by the master-data plan §5; progress by piece:
  - `[x]` **a** module shell, menu tree and route redirects — **merged 2026-08-16 at `dbf1a50`
    (`s1/master-data-shell`, MR `!63`; implementation `8a1137c`).** Numbered pipeline groups in
    `NavMenu.razor`, the four §4 route moves as 301s in `LegacyPageRedirects` (`/documents/upload`
    → `/intake/upload`, `/documents/review` → `/review/queue`, `/entities/suppliers` →
    `/master/entities`, `/admin/settings/document-types` → `/admin/document-types`), covered by
    `S19aModuleShellTests` and `LegacyPageRedirectTests`
  - `[x]` **b** `<ReferenceGrid>` + descriptor + write-service pattern — **merged 2026-08-16 at
    `c5d783b` (`s1/reference-grid-pattern`, MR `!64`; implementation `f51b7f0`).** 406-line
    contract set (descriptor, policies, sorts/filters/paging, optimistic concurrency, deactivate —
    no delete), `ReferenceGridState` and the Razor component, ~2,400 lines of tests
  - `[x]` **c** descriptor screens — all six are done, all **read-only first cuts**
    under `sibyla.financial-operations`: **ITMCLS** merged 2026-08-17 at `def45d8` (MR `!65`) at
    `/master/item-classes`, **MNGACC** at `703e674` (MR `!66`; metadata alignment `d8c09dd`) at
    `/master/accounts/mng`, **COCACC** at `edf61fb` (MR `!69`, implementation `c0f7be2`,
    pipeline **2767014671** green) at `/master/accounts/cost-centres`, inert on its one placeholder
    row until **O-2** names an owner; then, merged 2026-08-20: **EXCRAT** at `5dc156c` (MR `!100`,
    source `80b3f0b`) at `/master/fx-rates` with the **missing-rates panel** — the needed set is
    every non-EUR currency carried by a canonical non-merged ENTMST row **or by an extracted
    document revision**, each needing a `(Period, From, To=EUR)` rate, and an invalid period fails
    closed with the service's PT/EN message under the `CK_EXCRAT_Period_IsCalendarMonth` grammar;
    **ITMALS** at `8a28cad` (MR `!101`, source `9f85337`) at `/master/item-aliases`, the **first
    `GlobalOrActiveCompany` grid** — an active company sees its own aliases plus the null-company
    all-companies rows, the page states that reading, and the nullable Company column is
    `required: false` (review fix, pinned by a descriptor test); and **ENTALS** at `f451bbf`
    (MR `!102`, source `8f0734d`) at `/master/entity-aliases`, reusing that scope and surfacing
    **`HumanOwned`** — read-only **by design** since aliases are edited on the entity's page
    through the `!89` governed path, with the grid service allowlisted as a pure reader in the
    ENTALS mutation-seam guard by an enforcing guard fact (review fix). **Still reserved from
    `c`:** the reference-grid write path — no descriptor screen exercises it yet; the `!105`
    DOCTYP presentation write shipped on the plain admin catalogue page instead, so the grid
    write path's first user is still open
  - `[x]` **d** **Entity 360** *(S1 exit criterion)* — **done; the exit was demonstrated
    2026-08-20 and validated by Miguel with screenshots** (record at the Exit paragraph below);
    the governed M-D4 write-service pattern is established. Sliced one merge request at a time to
    hold the ~20-minute review threshold:
    - `[x]` **slice 1 — read-only Identity shell** — **merged 2026-08-18 at `cdb26c5`
      (`s1/entity-360-identity-read`, MR `!74`; implementation `e7f46c9`, pipeline **2769319314**
      green).** The tabbed Entity 360 shell and a **read-only** Identity tab over merged ENTMST at
      `/{c}/master/entities`: canonical ENTMST list/detail, PostgreSQL-backed search and paging,
      `EntityCode` / `CodeName` resolved from `ExternalIdentity`, name, fiscal number, the country
      tri-state, currency, Role, Status, Origin, RelatedParty + Kind and external identities,
      honest placeholders for the tabs not yet built, service-side authorization and a test proving
      the read path writes no audit rows. **No migration, no snapshot and no new write path**; the
      pre-existing supplier Update / Verify / Merge panel stayed supplier-scoped. Merged by GitLab
      user `gottsolutions.net` at 2026-08-18T14:15:36.254Z. Local gates reported in the `!74` merge
      request description: Debug and Release builds 0 warnings / 0 errors, Release suite 1534/1534,
      `FdrDatabase` 244/244, `PartyCollapseContract` 38/38, `P11aDatabase` 61/61 and pending-model
      check clean
    - `[x]` **slice 2 — the governed Identity/ENTMST write service** — **merged 2026-08-18 at
      `8d924db6` (`s1/entity-360-identity-write`, MR `!79`; source `03180d1d`, green head pipeline
      **2770706234**).** Reuses the existing paths rather than duplicating them, keeps the
      permanent codes read-only, enforces authorization **service-side** — including an
      `Administrator` requirement for `InternalCompany` — validates with PT and EN messages,
      appends a before/after `AuditEvent` inside the same transaction as the write, and implements
      and tests **optimistic concurrency against PostgreSQL** on `xmin` (no speculative `Version`
      column, no migration). Transaction ownership and savepoints deny by default on unsafe
      caller-owned `ChangeTracker` state, and identity/role authorization races serialize at the
      PostgreSQL transaction level. The exact governed writable field set was shaped against the
      live code at the time; every field outside it stays preserved and read-only. The first MR
      pipeline failed in the `PartyCollapseContract` source/baseline contract and was fixed forward
      without weakening that contract. Local final evidence, observed 2026-08-18 and not an
      acceptance criterion: solution build 0 warnings / 0 errors, focused tests 102/102, the
      disposable-PostgreSQL Entity 360 tests 8/8, full suite 1567/1567, no pending model changes.
      Route unchanged: `/{c}/master/entities`
    - `[x]` **slice 3 — governed Tax identifiers** — **merged 2026-08-19 at `3fb806b`
      (`s1/entity-360-tax-identifiers`, MR `!82`; source `2e9732e`, merged
      2026-08-19T04:40:56.137Z).** It reused the M-D4 write-service pattern `!79` established
      rather than inventing a new one. Shipped across **21 files — 12 production/runtime paths
      under `src/` and 9 test paths under `tests/`**, route unchanged at
      `/{c}/master/entities`: an accessible PT/EN **Tax identifiers** tab; governed 1:N
      `EntityTaxIdentifier` mutations together with the **atomic `ENTMST.FiscalNo` primary
      projection**; service-side `ClaimsPrincipal` authorization; permanent fields not writable; a
      before/after audit write inside the same transaction as the mutation; `xmin` optimistic
      concurrency; caller transaction / savepoint handling and dirty-tracker **deny-by-default**;
      duplicate, primary and race handling; a **current/submitted reload-and-reapply conflict UI**;
      and supplier/Identity compatibility preserved. Migration
      `20260819030442_S19dEntityTaxIdentifierInvariants` is **additive** — four CHECKs and two
      unique indexes on `EntityTaxIdentifiers`, **no destructive repair and no backfill**,
      deterministic **count-only** preflights that fail closed without quoting a row value, and
      `Up`/`Down`/`Up` plus the pending-model gate proven — so it is **not stop-list work**.
      **Verified on GitLab, which is the gate:** MR head pipeline **2771182592** success on exactly
      source `2e9732eb6ec43d745e8d199446e67a4068a41a1c`, and post-merge `main` pipeline
      **2771203526** success on exactly merge `3fb806be571ea4a9c0a1c7e748a01d122b6d39bd`, jobs
      `build-test` **15973204170**, `p11a-database-tests` **15973204171** and `fdr-database-tests`
      **15973204172** all success. Local final evidence on that same source candidate, observed
      2026-08-19, an observation and **not** the green-pipeline gate: Release non-incremental build
      0 warnings / 0 errors, default suite 1592/1592, `FdrDatabase` 278/278,
      `PartyCollapseContract` 38/38, `P11aDatabase` 61/61, EF no pending model changes, and a fresh
      adversarial review returning ACCEPT
    - `[x]` **slice 4 — governed Roles** — **merged 2026-08-19 at `2c7eab4`
      (`s1/entity-360-roles`, MR `!84`; source `b9b332b`, merged
      2026-08-19T10:17:17.49Z).** It reused the M-D4 write-service pattern `!79` established
      rather than inventing a new one. Shipped across **24 files — 13 production/runtime paths
      under `src/` and 11 test paths under `tests/`**, route unchanged at
      `/{c}/master/entities`: an accessible PT/EN **Roles** tab; Supplier and Customer **add,
      deactivate and explicit reactivate**, preserving the permanent assignment and its
      verification evidence rather than re-creating either; **`InternalCompany` read-only**;
      **`ENTMST.Role` untouched**; verification **read-only**; **one `EntityRoleAssignment`
      mutation seam** used by Entity360, `BusinessEntityService` and Cegid alike, so no second
      write path exists; automation still **refusing inactive roles**; service-side Admin /
      Finance / Accounting authorization with **`Administrator` required for active
      `InternalCompany` entities**; parent `xmin` optimistic concurrency, advisory locking, a
      same-transaction audit write, savepoints and dirty-tracker **deny-by-default**; a
      **current/submitted conflict reload-and-reapply**; and **merge into an inactive destination
      role failing closed before repointing**. Migration
      `20260819082319_S19dEntityRoleAssignmentInvariants` is **additive** — **six count-only
      preflights** and **five CHECKs**, with **no repair, no backfill, no index alteration, no
      `ENTMST.Role` write and no seeder write**, and `Up`/`Down`/`Up` plus the pending-model gate
      proven — so it is **not stop-list work**.
      **Verified on GitLab, which is the gate:** MR head pipeline **2771963044** success on exactly
      source `b9b332b6674848c1a247ba0368610e3bbe30fbbe`, jobs `build-test` **15978432659**,
      `p11a-database-tests` **15978432660** and `fdr-database-tests` **15978432661** all success;
      and post-merge `main` pipeline **2772015854** success on exactly merge
      `2c7eab4d8a42ab5b5b5ad5c026096556852fb315`, jobs `build-test` **15978791686**,
      `p11a-database-tests` **15978791687** and `fdr-database-tests` **15978791688** all success.
      Local final evidence on that same exact source candidate, observed 2026-08-19, an observation
      and **not** the green-pipeline gate: Release non-incremental build 0 warnings / 0 errors,
      default suite 1607/1607, `FdrDatabase` 293/293, `PartyCollapseContract` 38/38,
      `P11aDatabase` 61/61, EF no pending model changes, and a final fresh Claude review returning
      ACCEPT
    - `[x]` **slice 5 — read-only Aliases** — **merged 2026-08-19 at `c1cec04`
      (`s1/entity-360-aliases`, MR `!86`; source `d2064e8`, merged 2026-08-19T12:26:35Z).**
      A **read-only** Aliases tab over ENTALS, following the Identity precedent of a read slice
      before a write slice: an accessible PT/EN tab at the unchanged `/{c}/master/entities` route;
      rows served only for canonical (non-merged) ENTMST entities; PostgreSQL-backed paging with a
      deterministic order (normalised alias, then scope, then `ALCode`); **scope shown
      explicitly** — an unscoped alias renders as "all companies" in PT/EN and is never a blank
      field; service-side read authorization (Administrator / Finance / Accounting). **No write
      path.** Its migration `20260819111951_S19dEntityAliasesReadModel` has an empty `Up`/`Down` —
      EF model-mapping alignment only, no schema change — so it is **not** stop-list work. MR
      pipeline **2772364485** and post-merge `main` pipeline **2772402931** both succeeded
    - `[x]` **slice 6 — governed Aliases/ENTALS write** (`!89`): update-only existing aliases;
      Alias plus explicit scope writable; permanent/generated fields read-only; server auth, active
      company, `xmin`, same-transaction audit, current/submitted conflict, one update seam, durable
      `HumanOwned`, and seeder preservation of human Alias/scope. Additive migration
      `20260819144205`; GitLab pipelines **2773586157** and **2773640192** success
    - `[x]` **slice 7 — governed Banking** (`s1/entity-360-banking`, MR `!91`; source `22392c3`
      → merge `4842500`, merged 2026-08-19T23:04:29.355Z): an accessible PT/EN Banking tab over
      ENTBNK per `(EntityId, ScopeKey)` with ENTBNKMethod/ENTBNKAccount children; explicit scope —
      unscoped renders as "all companies" and structurally carries no pay accounts; governed
      **update-only** child edits through the single `EntityBankingMutation` seam with the parent
      `PayMethod`/`PayAccount` projections **regenerated from the children in the same
      transaction, never edited directly**; server auth, active company, parent `xmin`,
      same-transaction audit, current/submitted conflict, durable `HumanOwned`, and seeder
      preservation with difference-gated projection regeneration. Additive migration
      `20260819211044`; GitLab pipelines **2774384047** and **2774401009** success
    - `[x]` **slice 8 — governed Items** (`s1/entity-360-items`, MR `!93`; source `7c094bd`
      → merge `01b6b90`, merged 2026-08-20T00:46:40.668Z): an accessible, paged PT/EN Items tab
      over ENTITM — `EICode`, item identity and class read-only — with a governed **update-only**
      write of the SNCACC/CostCentre account mapping (the S3-4 learning-path target), cleared only
      through explicit toggles, `SNCDSC` regenerated from the mapped account's description in the
      same transaction (and kept live for human-owned rows by a difference-gated seeder pass),
      unknown codes failing closed before any write, server auth, `xmin`, same-transaction audit
      keyed by `EICode`, current/submitted conflict, one `EntityItemMappingMutation` seam, durable
      `HumanOwned`, and seeder preservation of the human mapping while source-owned columns still
      sync. Additive migration `20260819235415` adds only `HumanOwned`. GitLab pipelines
      **2774534974** and **2774555750** success
    - `[x]` **slice 9 — read-only Documents** (`s1/entity-360-documents`, MR `!96`; source
      `5822188` → merge `ffc8d04`, merged 2026-08-20T02:04:51.064Z): a paged tab over recent
      DOCLOG matched through the entity's `fdr.code_name` identities, newest first; the empty
      state names the missing DOCLOG writer (S2) instead of pretending; empty-`Up`/`Down`
      model-alignment migration `20260820011243`. MR pipeline **2774628822** (one retried
      `build-test` job **15997571185** after a recorded pre-existing test flake) and post-merge
      **2774664385** success
    - `[x]` **slice 10 — read-only Balances** (`s1/entity-360-balances`, MR `!97`; source
      `4d1b81d` → merge `dfb7e96`, merged 2026-08-20T02:43:59.463Z): the source-owned operational
      balances (open payable/receivable, invoice frequency, expected value) labelled explicitly as
      **not master data** per the matrix's R-40 boundary, formatted faithfully to the stored
      `numeric(19,4)` scale in the page culture; no migration. MR pipeline **2774701711** and
      post-merge **2774717382** success
    - `[x]` **slice 11 — read-only Audit** (`s1/entity-360-audit`, MR `!98`; source `e6f4e19` →
      merge `ed9cf25`, merged 2026-08-20T03:22:11.391Z): a paged, type-scoped view of the
      entity's governed-write audit events — entity guid, `ALCode`s, `EICode`s and the `{guid}|`
      banking composite — with the merge-history and code-repointing attribution properties
      recorded in code; no migration. MR pipeline **2774744416** and post-merge **2774775333**
      success. **All nine Entity 360 tabs are built**; what remains of `S1-9d` is the
      demonstrated "CTT" exit below
  - `[x]` **e** — the **ITMMST item master** landed 2026-08-20 (`!109`, source `a814c7d` → merge
    `f8f64f0`): read-only grid at `/{c}/master/items` over the typed set, `AutoCreated` visible
    as the classification backlog; the **entity-item matrix with the classification queue**
    landed 2026-08-20 (`!110`, source `7ce8624` → merge `2f06ab0`): the ENTITM matrix at
    `/{c}/master/entity-items` plus the "unclassified lines seen in the last 30 days" view —
    current-revision lines with no ITMALS alias (company-scoped aliases cover only their own
    company's documents; duplicate-ignored and cancelled documents excluded) and SNCACC-less
    mappings; entity attribution of lines was waiting for `S2-6`, and `!141` now supplies the
    resolver. The
    **entity-banking catalogue** closed `e` 2026-08-20 (`!112`, source `dd28dff` → merge
    `2a65676`): one parent per (entity, scope) at `/{c}/master/entity-banking` with the child
    lists per row and the unscoped scope's missing accounts rendered as structure — this piece
    is now `[x]`
  - `[x]` **f** SNCACC tree — **done 2026-08-20** (`!113`, source `cf444ed` → merge `904b434`):
    the read-only tree at `/{c}/master/accounts/snc` over `ContaPai`, lazy expansion, search
    revealing the path to every match, and **direct** ITMMST/ENTITM posting counts per account
    (subtree postings live on the children; being a parent also makes a change unsafe). Adding
    a leaf issues a permanent SNCode and stays behind the stop list
  - `[~]` **g** DOCTYP — the **read-only** catalogue and its verbal routing preview landed with the
    `S1-6a` drop (`!72`), because the admin screen could not be left pointing at a dropped table;
    the **governed presentation write** landed 2026-08-20 (`!105`, source `a60113f` → merge
    `607c2ab`): administrators edit **LabelPt, LabelEn and SortOrder only** through one
    application service — Administrator-only authorization, `xmin` concurrency (model-alignment
    migration `20260820065333`, empty `Up`/`Down`), same-transaction before/after audit, PT/EN
    messages for the offered-type presentation rule, the 1–1000 sort-order range and the
    128-character labels, current/submitted conflict UI. **What remains under `g`**, per the
    corrected stop-list framing in `docs/s1-gated-editors-proposal.md` (2026-08-20: runtime
    editors are not automatically live-tenant configuration; slices are assessed individually):
    **g2, the `IsActive` offer toggle** — **done 2026-08-20** (`!117`, source `3d8f1ce` → merge
    `639dd65`): offer/withdraw on the `!105` write path, fail-closed presentation/active/
    group-divergence rules, server-enforced typed confirmation on withdrawal, before/after
    audit; the pre-push review folded all five should-fixes before the single pipeline —
    and **g3, the routing columns**, remains **blocked on O-1** (Luís), not on a Miguel gate
  - `[~]` **h** DOCEFL — the **read-only flag-rules catalogue** landed 2026-08-20 (`!104`, source
    `b93c4a6` → merge `75485e0`) at `/{c}/admin/flag-rules`, EF-mapped columns only, no write
    path, no migration, no O-4 dependency; the **editor is formally deferred to S2**
    (2026-08-20) — its pattern tester has no DOCLOG/FDCHDR/FDCDTL documents to test against
    until S2 builds them, it never ships without the pattern tester and impact count, and O-4
    stays Miguel's
  - `[x]` **i** repoint the entity half of `Companies.razor` — **done 2026-08-20** (`!107`,
    source `f511e08` → merge `01f9095`): the entity update goes through the governed
    `IEntity360IdentityWriteService` with the permanent code no longer submitted, the stored
    identifier type carried read-only, reload-and-reapply on conflict, and the fresh `xmin`
    adopted only post-commit; the gated creation path stays on the creation service, and the
    **connection half is untouched S4 code**
- `[x]` **S1-9c / P2-2 decision taken:** ITMCLS, MNGACC and COCACC stay separate. Do not create
  `ReferenceValue` and do not reopen this decision while building the three descriptors.

**Exit:** an operator searches "CTT" and sees the entity, its aliases, its bank accounts, its
usual items and the accounts those items post to. Re-running the seeder changes nothing.
**This happened on 2026-08-20.** Miguel ran the session at 14:45 against the demo database
rebuilt through the full S1.5 sequence from the real source: searched CTT, opened the real
`EC000007` row, and walked all nine tabs — Identity, Items (three rows, all mapped to SNC
accounts) and Balances carried data; Aliases and Banking showed honestly empty (the source
carries none for CTT); the seeder replay had already proven idempotent (`unchanged` across all
fourteen tables). The two findings were fixed the same day — the Roles-tab mojibake (`!121`)
and the empty Tax Identifiers tab (`!122` + the `!124` skip-and-report revision), after which
**Miguel revalidated that CTT shows its NIF on the Tax Identifiers tab and validated the exit
with screenshots as the record**. `S1-9d` is done and **S1 is closed**; date, person and
evidence are exactly these.

---

## S1.5 — Party collapse · ~1 week + 2 days · 9 items

**Authorised 2026-08-11.** Full reasoning in `docs/master-data-and-ui-plan.md`; the deferred
remainder in `docs/master-data-phase2-plan.md`.

**Complete via cumulative MR `!59`** (`394fbbd` → merge `60ffb46`). The approved upward collapse
renamed the live party table to `ENTMST`; the duplicate P11a table and its reproducible seeded rows
were removed. S1-9 can now be built once on the merged table.

- `[x]` **S1.5-0** ~~Rebase `s1/layer2-source-semantics` onto the merged-table shape~~ —
  **overtaken by events, closed with no work done.** That branch merged to `main` at `6b42d79` on
  2026-08-11, before this phase started; there is no branch left to rebase. The code it landed does
  target the ENTMST this phase replaces, so the repointing it was meant to avoid now falls to
  **`S1.5-8`** in full. Recorded rather than deleted, because the item's disappearance is otherwise
  indistinguishable from it having been done
- `[x]` **S1.5-1** **Phase 0** — pin the schema contract. **Merged at `79e20b6`**
  (`s1/party-collapse-contract`, MR `!46`, pipeline **2752078981** green). Delivered: `PartyCollapseSchemaContract.sql` with **30 numbered
  queries**, a fixture database (`.fixture.sql`), recorded baselines (`.phase0.txt` covering the
  FK-join roster, the `FDCHDR` composite anchor, tenancy guard triggers, both ERP binding reads and
  archive-path resolution; `.source-baseline.txt` for code readers/writers), the post-collapse
  shape (`.post-collapse.sql`) and behavioural tests. Query 03 is the `LegacyCode`-reader query, so
  **`P2-6` now has its measurable trigger**. Tests carry `Category=PartyCollapseContract` and are
  excluded from the default `dotnet test` filter — they need disposable PostgreSQL
- `[x]` **S1.5-2** **Phase A** — merged at `267d144` (`s1/party-collapse-data`, MR `!54`, pipeline **2754628230** green). The additive migration owns the nullable
  target columns and `ExternalIdentity`; the data migration owns `S15PartyReconciliationRecord`,
  `S15PartyReconciliation`, `S15PartyReconciliationSummary`, exact two-scheme identity binding and
  the ENTMST `CodeLedger` bootstrap. Matching is NIF then normalised name and fails closed on every
  unmatched source; there is no explanation model. The permanent-code stop-list work was authorised
  and merged
  > `[!]` **Traceability.** The additive migration reached `main` through the **DOCEFL** merge
  > request, not the party-collapse one: branch `s1/party-collapse-additive` (`f623c4a`) was folded
  > into `s1/docefl-seed`. Anyone reading merge requests to reconstruct what shipped will not find
  > it where they look. Not worth reverting; worth not repeating
- `[x]` **S1.5-3** Reconciliation report — **merged at `5a68c21`** (`s1/party-collapse-reconciliation`,
  MR `!56`, pipeline **2755656049** green; implementation `d5d3882`, docs evidence `7b903bd`).
  A read-only aggregate query fails closed unless the existing summary is complete and non-empty,
  source/reconciliation/target counts are exact, every target has the two required FDR
  identities, and every source has its exact ENTMST ledger binding. The CLI reads its connection
  string only from a named environment variable and emits aggregate-only stable output. Delivered
  `S15PartyReconciliationService`, its CLI, `scripts/run-s15-party-recovery-proof.ps1`, and a CI
  change: `fdr-database-tests` now provisions a `sibyla_test_guard.disposable_instance` marker
  before running `FdrDatabase`. Measured before merge, after integrating S1-8: focused report
  13/13; disposable synthetic mutation/recovery 2/2 with byte-equal canonical snapshots; host-only
  current-source validation/reseed parity 1/1, with source HEAD and working tree unchanged;
  `FdrDatabase` 117/117; default 1010/1010; build 0 warnings/errors. The current-source path is
  separate and makes no party-matching claim. **This is the demonstrated recovery that gates
  `S1.5-4` — the gate is satisfied**
- `[x]` **S1.5-4 Phase B** — the approved destructive migration dropped the P11a ENTMST and its
  seeded rows, renamed the live party table to `ENTMST`, moved child FKs to `ENTMST.Id`, and put the
  live schema under EF migrations
- `[x]` **S1.5-5 Phase B′** — replayed the unchanged phase-0 contract with an empty diff
- `[x]` **S1.5-6** — rewrote the `P11aDatabase` suite against migrations; pipeline 2762302842 ran
  61/61 successfully
- `[x]` **S1.5-7** — closed as the compatibility realization: the authoritative multi-role child
  remains `EntityRoleAssignments` with `InternalCompany`, ENTMST retains scalar `Role='Company'`,
  and party reads use merged ENTMST. No physical `ENTROL` table was introduced; the explicit
  counterparty-not-own-company enforcement was delivered by S2-7 in `!143`
- `[x]` **S1.5-8** — repointed the reference-data seeder to the post-collapse shape and covered
  governed, byte-equal replay. Pipeline 2762302842 ran PostgreSQL 17 `FdrDatabase` 189/189
  successfully

**Exit:** the phase-0 query set re-runs against the renamed table with an empty diff.

---

## S2 — Single-document intake on the FDR schema · ~3 weeks · 15 items

The phase that converts the FDR port from a programme into a feature. **This and S4 are the two
that matter.**

### Shape

- `[ ]` **S2-1** Adopt the two-record split: `Document` / `ExtractionRevision` / `FileAsset`
  remain the **intake** record (file, hash, storage, extraction attempts, raw agent output);
  `DOCLOG` / `FDCHDR` / `FDCDTL` become the **registry** record. One `Document` ↔ one `DOCLOG`,
  keyed by `LGCode` on `(Filename, EntryCode)`. `DocumentCatalogingService` is the bridge.
  Upload, storage, hashing, duplicate detection, agent invocation, contract validation and PDF
  text extraction are untouched — none of it is registry-specific and all of it works

### Persistence and classification

- `[~]` **S2-2** Re-point `DocumentCatalogingService` to write DOCLOG + FDCHDR +
  FDCDTL transactionally. **Slice 1 merged 2026-08-20 (`!127`)**: the governed enablement for
  runtime LG-code issuance — Miguel authorized issuance in the bridge the same day (stop-list
  act); `EnableS2DoclogRuntimeIssuance(role)` is operator-invoked per environment after the
  S1-8 high-water reservation, flips only the DOCLOG bucket, and the migration enables nothing
  by itself. **Slice 2 — the registry lifecycle contract + governed commit (`!129`, merged
  2026-08-21, branch `s2/registry-lifecycle-contract`; MR pipeline 2778141409, post-merge
  2778165438).** The pre-writer audit found the writer
  blocked by contract contradictions, not by authorization, and slice 2 fixes them rather than
  writing around them: **(a) birth rule** — DOCLOG is born only when the disposition is stable
  (`Posted` for PostFiscal/ArchiveOnly, `ReferenceOnly`); Review and unresolved documents stay
  intake-only and mint no permanent code, and intake-stage discards stay restorable and
  purgeable — so the bridge commits **after** validation and routing, never inside
  `ApplyExtractionAsync`; **(b) identity** — the natural key stays `(Filename, EntryCode)`,
  `Filename` being the governed registry filename (the validator already requires captured
  non-BNK filenames unique) and `SourceFilename` the upload name; for PostFiscal the EntryCode is
  issued first (Posted → `AllocateEntryCode` → `AllocatePermanentCode` → DOCLOG + FDCHDR +
  FDCDTL), so a permanent key is never rewritten; one Document ↔ one DOCLOG — replays and
  reprocessing return the existing code and keep the committing revision; **(c) state is one
  fact, mirrored** — migration `20260820235016` makes the state-carrying FKs (DOCLOG/FDCHDR →
  Documents; FDCHDR/DOCARC/OfficialBankStatementEvidence → DOCLOG/DOCARC) `ON UPDATE CASCADE`
  with guard triggers on the mirrored columns, so Discard/Purge work with a registry row present;
  `RestoreForReview` refuses once DOCLOG exists (the registry never returns to intake-only), and
  posted evidence (EntryCode binding, FDCHDR, official bank evidence) freezes a discard with a
  named reason; **(d) governed commit** — `CommitDocumentRegistry` (SECURITY DEFINER, its own
  authority, company/correlation GUCs, lower-cased SHA-256 into the CHECKed column, append-only
  command audit) + `EnableS2RegistryCommit(role)` (operator-invoked after the `!127`
  enablement; grants the commit/transition/EntryCode authorities and the read surface the
  deferred FDCHDR trigger needs; audited) + `RegistryCommitService` (fail-fast validation,
  transaction or savepoint, typed refusals). **Closed since:** the wiring from the
  post-routing decision to `RegistryCommitService` landed with `S2-3` slice 4 (`!131`), and the
  **canonical-filename policy** was **accepted 2026-08-21** — `{date}_{CompanyCode}_{DTCode}_{sha256[0..16)}.{ext}`,
  date = document date if extracted else capture date, unique at birth by content hash, built only
  from immutable capture facts; the human-friendly archive name lives in `ArchiveNameLedger` (S6).
  `RegistryFilenamePolicy` implements it with the **capture** date, the correctable document date
  being unfit for a permanent identity. **Remaining for S2-2:** entity resolution (`S2-6`), line
  classification (`S2-8`), deterministic FX cataloging resolution (`S2-9`) and VAT/date gates
  (`S2-10`) are delivered; PostFiscal remains deliberately unbridged because `S2-9` did not wire it
- `[~]` **S2-3** Classification against DOCTYP rules at cataloging time. `Treatment`
  (Include/Exclude) and `ProcessingRoute` (PostFiscal / ArchiveOnly / ReferenceOnly / Review)
  decide where the document goes. **The prerequisite is already met:** `S1-6a` retired the
  `FinancialDocumentType` enum path on 2026-08-18 and the July services read DOCTYP through
  `DocumentTypeRoutingService`, so this item is the registry-side application, not the removal.
  **Slice 4 — the non-fiscal wiring (`!131`, merged 2026-08-21):**
  `DocumentRegistryBridge` projects a routed ArchiveOnly/ReferenceOnly document onto the
  registry record from immutable capture facts — the accepted canonical filename
  (`RegistryFilenamePolicy`: `{capture-date}_{CompanyCode}_{DTCode}_{sha256[0..16)}.{ext}`, capture
  date rather than the correctable document date), the original asset's hash/size/name, the
  intake channel, the DOCTYP rule, the counterparty only with its `fdr.code_name` identity — and
  commits through `RegistryCommitService`. Two triggers, both *after* routing is stable: the
  extraction handler when the document is **auto-classified, every deterministic gate passed and
  the company resolved** (the same proof that queues a PostFiscal integration), and the review
  service on a **human confirmation**; anything less stays `AwaitingReview`. Success moves the
  document to `ArchivePending` (new transitions Extracting/AwaitingReview → ArchivePending — the
  S6 filing step follows); a governed refusal goes to `NeedsAttention` with the refusal's own
  code and message; `document.registry_committed` is audited. **PostFiscal remains deliberately
  unbridged:** `S2-6`, `S2-8`, deterministic FX cataloging resolution in `S2-9`, and the `S2-10`
  VAT/date gates are delivered, but none of that claims PostFiscal wiring;
  `NOT_A_DOCUMENT` and the
  byte-identical discard stay `S2-5`
- `[~]` **S2-4** EntryCode issuance from the CodeLedger sequences. **Slice 2 of S2-2 (2026-08-21) already
  issues the EntryCode inside the PostFiscal commit** through `AllocateEntryCode` (natural key
  `[CompanyCode, CounterpartyCodeName, NormalizedDocumentID, FlowType]`, `entry-v1`, bound to the
  Posted document before the LG code). **What remains here:** month-bucket provisioning —
  `BootstrapEntryCodeSequence` is bootstrap-only, so a month without a bucket refuses as
  `entry-code bucket is missing or disabled` and the commit rolls back intake-only; a governed
  runtime provisioning act (its own stop-list authorization) **was** the open piece, and slice 3
  closed it. **Slice 3 (`!130`, merged
  2026-08-21, branch `s2/entrycode-bucket-provisioning`):** migration `20260821005452` installs
  `ProvisionEntryCodeBucket(prefix, year, month)` — returns an existing bucket freely, otherwise
  requires the `ProvisionEntryCodeBucket` authority and company context, starts above every code
  already known for the month (ledger, FDCHDR, bindings, DOCLOG), registers the sequence enabled,
  audits append-only — and `EnableS2EntryCodeProvisioning(role)` (operator-invoked after the
  registry-commit enablement); `AllocateEntryCode` provisions a missing month itself when the session
  role holds the authority — inside the database contract, for every caller, after validation and
  the replay short-circuit. Remaining here: nothing structural — month buckets are now runtime-governed
- `[~]` **S2-5** `NOT_A_DOCUMENT` routing and byte-identical resubmission auto-discard.
  **Decisions taken 2026-08-21 (Miguel, via two review rounds):** **(1)** hash uniqueness is
  **per company, decided at the moment the company is known** — the F1 global unique index on
  `Documents.OriginalContentHashSha256` becomes unique on `(InternalCompanyEntityId,
  OriginalContentHashSha256)`; a capture registered without a company (every channel capture,
  web uploads without a company) is checked globally at intake and **re-decided when the company
  is assigned** by cataloging or review: if that company already holds a live capture of the same
  bytes, the document becomes a resubmission *then*; **(2)** an intake discard is a real governed
  disposition mirrored by a new **`DocumentStatus.Discarded`** (restorable through
  `RestoreForReview` — except a resubmission, which is evidence and is never restored); **(3)** a
  byte-identical resubmission is **registered, linked on its own field
  `ResubmissionOfDocumentId`** (never `DuplicateOfDocumentId`, which carries review and purge
  meaning), released from the per-company identity (its hash stays on the asset and in the
  capture evidence) **and auto-discarded** — the capture event is evidence, never a rejection
  without trace — and the registration service writes `RetainedContentHash`/`DocumentCaptureHash`
  at intake or at the moment the company becomes known (the evidence purge requires); **(4)** the
  signal is an **audit event now** (`document.resubmission_discarded`,
  `document.resubmission_detected`, `document.capture_discarded`) and a structural DOCEFL
  Annotation, delivered as **`EF0000066`** by `S2-11` — `!153` issued it as `EF0000065`, a code the source had already given to the customer-invoicing-cadence rule, and `!157` corrected it.
  **Slice 5 (`!133`, merged 2026-08-21):** migration
  `20260821085010` installs `RecordIntakeCapture`, `DiscardIntakeCapture`
  (`ByteIdenticalResubmission`/`NotADocument`, only before a disposition or registry record),
  `EnableS2IntakeCapture(role)`, the resubmission link and the per-company index;
  `TransitionDocumentDisposition` gains the "a resubmission is not restored" refusal; Down refuses
  once evidence, discards, resubmissions or per-company identical bytes exist. Application:
  `IntakeCaptureService` and `IntakeResubmissionResolver` through the shared `GovernedCommandScope`
  (adopted by `RegistryCommitService` too); the duplicate detector is per company when known;
  `StoredDocumentRegistrationService` is transactional (joins an ambient transaction), records
  evidence at intake and registers-links-discards a known resubmission
  (`RegisterResubmissionAsync`); the extraction handler and the review service resolve
  byte-identity when they set the company, record evidence before a NOT_A_DOCUMENT discard, and
  route a detected-but-undiscardable resubmission to attention; API/Web/channel keep their
  contract (`DuplicateDocumentException` now also names the discarded capture). **Enables nothing
  by itself:** without `EnableS2IntakeCapture` every path behaves exactly as before. Remaining
  here: the corresponding target-owned DOCFLG is governed as **`EF0000066`** by `S2-11`, after `!157` corrected the code `!153` had invented.

### Entity and line resolution

- `[x]` **S2-6** Entity resolution merged complete in `!141` on 2026-08-23 (source
  `4719d4181bfa6f034d41f333d768d2954dd60b97` → merge
  `847cb79057052c9e2f767193acc3484515788c28`; MR pipeline **2783312334**, `main` pipeline
  **2783365430**, both succeeded). Resolution is deterministic NIF → company-scoped/global alias →
  normalized name, with trusted append-only `MatchDecision` evidence. Unmatched evidence can create
  governed provisional ENTMST and CodeLedger state only through deny-by-default authorities. Source
  delta/revision lineage, replay, canonical merge chains, advisory locking, `ReadCommitted`
  transactions and human-owned correction precedence are covered, including `EC000050` and
  `EC000109`. `M-D11` is implemented by resolving RelatedParty/Kind through the exact
  `(Class, Subclass)` pair. Miguel explicitly authorized permanent ENTMST merge/emission before
  `!141` merged. **None of deployment, live migration, live issuance or FdrSource host proof is
  claimed or verified by this closeout; the explicit FdrSource mapping remains absent locally.**
  `M-D9` destructive re-keying was not built because it is conditional on a non-rebuildable affected
  database; `M-D10` Relevancy persistence and `M-D12` exact ITMMST constraints were later
  implemented by the `S2-11` framework in `!149`.
- `[x]` **S2-7** The `counterparty_not_internal_company` gate merged complete in `!143` on
  2026-08-24 (final source `0e18457e40953ed031a5d159549e7a483065b9c9` → merge
  `335a23ada4454241528c9d0071f8727fb7ad552d`). A counterparty cannot equal the selected company or
  carry an active `InternalCompany` role. Forbidden evidence is evaluated strictly in
  NIF → alias → name order through canonical merge chains. Unknown direction does not mutate state
  or issue identity; explicit human/upload identity, origin and confidence are preserved.
  Bidirectional PostgreSQL triggers share advisory serialization with application preflight, and
  migration `Down` is guarded. The first MR pipeline **2783866496** failed only because a database
  test fixture assumed a third baseline entity; it was fixed forward with a deterministic dedicated
  fixture. Final MR pipeline **2783891036** and post-merge `main` pipeline **2783915643** succeeded.
  Exact-candidate local evidence: build **0 warnings / 0 errors**; default **1904/1904**; changed
  PostgreSQL **146/146**; Party **38/38**; P11a **61/61**; migration database **5/5**; review
  **0 Critical / 0 High / 0 Medium**. This is merge and pipeline evidence only: **none of deployment,
  live migration or live issuance is claimed or verified by this closeout.**
- `[x]` **S2-8** Line classification merged complete in `!145` on 2026-08-24 (source
  `c56708c0d07e3ecf7cc77bb94bbe0635efc9f896` → merge
  `9778f43288ffbe23ed1d356908e7e1b1b19983ba`; MR pipeline **2786146252**, post-merge `main`
  pipeline **2786194796**, both succeeded). Resolution follows the exact
  ITMALS → ENTITM → ITMCLS → MNGACC → SNCACC chain, with optional COCACC, and has no fuzzy fallback
  or master-data mutation. `LineClassificationDecision` is append-only; the server derives its
  evidence and digest using ASCII byte-exact normalization, with aliases grouped before bounds are
  applied. Batch database round trips remain constant. Company and `MatchDecision` are the
  authorities, runtime access is restricted to functions only, and replay, concurrency and
  savepoints are covered. Handler revision visibility and rollback are covered; PostFiscal fails
  closed for a zero-line document. The slice performs no permanent issuance. Exact-source evidence:
  build **0 warnings / 0 errors**; default **1946/1946**; LineClassification PostgreSQL **28/28**;
  changed-path PostgreSQL **177/177**; P11a **61/61**; review
  **0 Critical / 0 High / 0 Medium**; EF/diff clean. This is merge and test evidence only:
  **none of deployment, live migration or live issuance is claimed or verified by this closeout.**
- `[x]` **S2-9** FX via EXCRAT is complete for deterministic cataloging resolution only; no
  PostFiscal wiring is claimed. MR `!147` merged source
  `42800a68e962d35feb37c4a415250d243bb7f281` as
  `d216f0adf4a2f59edafd355e6fcface8904a4dca`. MR pipeline **2787051255** and post-merge `main`
  pipeline **2787092890** succeeded
- `[x]` **S2-10** Complete for its authoritative backlog scope: VAT-splitting and date-validation
  gates. MR `!148` merged source `ccee284341097cbe26b8e643cb99ba8f8f0d12a3` as
  `7fe4c70e8899426932289088569c29c037138fca`. MR pipeline **2787103414** and post-merge `main`
  pipeline **2787139680** succeeded
> `[x]` **`S2-6` closed the `P2-3` decision point.** *(An annotation on the item above, not a
> second item — rev. 13 formatted it as a bullet under the same id, which made `S2-6` appear twice
> and inflated the then-correct count of fourteen. Rev. 28 later took the phase to fifteen for a
> real reason — the `S2-15` scope addition — so fifteen is now the correct count.)* `S2-6` writes the
> NIF → alias → name resolver and the trusted append-only `MatchDecision` row — strategy,
> confidence and `CandidateJson` of what else was considered. There is **no UI in Phase 1**. See
> `docs/master-data-phase2-plan.md` §1

### Flags

- `[x]` **S2-11** DOCEFL rule evaluation producing DOCFLG instances. Framework MR `!149` delivered
  the governed evaluator, `M-D10` verbatim `Consultive`/`Important` Relevancy, `M-D12`'s exact
  `ITMMST` subject domain and `EF0000057`. Item-detector MR `!151` (source
  `abc066ff1063b9710926303d613161eb5038f34b` → merge
  `aafbca4afec8ade1e43d847613fa8fa83209743f`; final pipeline **2787689712** succeeded) added
  `EF0000058` taxonomy mismatch, per-member FK-faithful `EF0000059` normalized-duplicate instances
  with group evidence, and `EF0000060` for both SNC sources blank; it also made same-document
  `EF0000057`–`EF0000060` resolution authoritative while preserving human-terminal and
  cross-document state.

  Closure MR `!153` merged source `bc5d94a7882db5be9bd3f0b5a807ee65415a9a2d` as
  `4167f7e67da02f9527a3433908396d49580c9d29` at 2026-08-25T16:34:27.226Z. The merge parents are
  `cca363a96b041ef2bf5f5919bd400a583e18f707` and
  `bc5d94a7882db5be9bd3f0b5a807ee65415a9a2d`; the GitLab `main` API reported exactly that merge.
  MR pipeline **2789667930** and post-merge `main` pipeline **2789745778** succeeded. It delivered
  target-owned permanent `EF0000065` as a terminal **Resolved · Non-Blocking · Consultive ·
  Annotation** on `DOCUMENT`, with exact provenance, permanent delete/rename guards and an
  irreversible `Down`; same-company capture-and-discard evidence is structural and locked in its
  original/current forms. Replay and caller-state atomicity hold in both the known-company and
  later-resolution paths. Ordinary `EvaluateCurrentDOCEFL` recognizes `EF0000065` separately as
  structural support and performs no item evaluation for it. **No other Status/Annotation mapping
  is required in Phase 1.**

  **Corrected by `!157`, 2026-08-26.** Everything above is accurate about what `!153` built and
  wrong about the code it built it under. `EF0000065` belongs to the source's customer-invoicing-
  cadence rule; the resubmission rule Miguel authored is **`EF0000066`**. Sibyla had issued a
  governed literal it does not own, against this item's own *"No EFCode or ItemClass was invented"*,
  and the live-source rule seed failed closed at `DOCEFL row 64` — which is `EF0000065` — because
  the migration's activation fields contradicted the source's. The rule is imported now, like every
  other; the migration keeps only the runtime that acts on it, and
  `S2PermanentNativeDoceflIdentity` is removed outright, its whole purpose having been to make
  permanent a code that should never have been issued. The `Down` no longer claims a *"permanently
  issued native code"* either; what remains irreversible is smaller and stated.
  **The correction exposed a contradiction the native `INSERT` had hidden:** `GovernDOCEFLRule`
  forbids an enforcement date for any class other than `Decision`, while
  `CK_DOCFLG_DeterministicEvidence` required the snapshot unconditionally, so **no DOCFLG instance
  for an `Annotation` rule could ever be written**. The constraint now mirrors that policy, and a
  test drives seeder shape → governed classification → detector end to end rather than asserting it.

  Final measured local gates: build **0 warnings / 0 errors**; default **2020/2020**; EF pending
  model clean; full disposable PostgreSQL `FdrDatabase` **463/463**; focused S2 **11/11**,
  S13a **22/22**, rule seeder + CLI **20/20**, exact predecessor **8/8**; final adversarial review
  **Findings: none**. This API, merge, pipeline and local-test evidence does not claim local
  `main`/upstream synchronization. **No deployment, live migration, ERP activation,
  EntryCode/LGCode issuance or live-tenant operation was performed or verified.**
- `[x]` **S2-12** `blocking_open_instances()` wired in from the start, not applied by discipline.
  **Merged 2026-08-27 (`!160`).** The gate is per action, because `BlockingLevel` names the action
  it stops; `Block Document` stops all of them. Enforcement is a trigger on `FDCDTL` rather than a
  call inside `CommitDocumentRegistry` — a check in the writer is one every future writer must
  remember, on the table it is one none of them can forget. An unrecognised action refuses rather
  than matching nothing. No grandfathering was built and none is needed: `D7` already settled that
  grandfathered instances stay open and reviewable and do not gate, and the evaluator records that
  verdict per instance at detection time. **Stated, not hidden:** the disposition-side gate cannot
  fire today — `DOCUMENT` rows are constrained non-blocking and the commit transitions before the
  `DOCLOG` row exists — so the fiscal-line trigger is what bites

### Quality

- `[x]` **S2-13** *(merged 2026-08-27, `!161`)* Build the golden set: ~20–30 real PDFs across purchase, sale, credit note,
  receipt, foreign-currency, multi-page and unreadable-scan cases. **Build it early in the phase,
  not at the end** — it is how skill regressions become visible in hours instead of weeks. The
  registry is `docs/golden-documents.md` and already holds GD-1; entries are path plus SHA-256
  against the read-only prototype, never copied files and never transcribed field values. The
  required scenario coverage is specified in `golden-documents.md` §Next, fed by **S2-15**
- `[~]` **S2-14** *(spine merged 2026-08-27, `!161`)* Golden-set harness re-runs on every skill or
  model change, emitting one pass rate. The harness exists and runs the set against the real agent;
  what it emits today is contract conformance plus reading-mode honesty, which is a floor and not
  the metric. **Blocked on `O13`, a decision and not code:** four runs on identical bytes differ on
  eleven of twenty-one documents, so a rate defined over line counts or warning presence is
  unstable at birth. **That number replaces the five data-quality baselines and the 55.9% figure as the
  project's quality metric**
- `[~]` **S2-15** *(added rev. 28, 2026-08-19; phase 1 done rev. 31, 2026-08-20)* **Reconcile the
  Invoice Skill Build's document-analysis knowledge with the production extraction agent.**
  **Phase 1 — the traceability matrix — is done**: `docs/invoice-skill-reconciliation-matrix.md`
  pins the reconciliation source at prototype commit `395f433` (origin/main tip, 2026-08-18, read
  via git plumbing without checkout; the rev-28 observation of tip `3dd4150` with uncommitted
  `SKILL.md` revisions is **superseded** — history is linear through `3dd4150` to `395f433` and
  the prototype tree is clean), enumerates **42 document-reading/interpretation rules** changed
  after `9359c67` from the 62 changed markdown files (every file reconciled in the matrix's
  completeness check), and records exactly one disposition per rule: **2** agent-instruction,
  **3** contract/validator, **26** cataloging/classification code, **1** golden-set scenario,
  **3** prototype-only (plus a reasoned out-of-scope list), and **7** already covered by
  `sibyla-documental/2.3`/v3.1. Nine scenario requirements were appended to
  `docs/golden-documents.md` §Next; seven open questions are recorded in the matrix for phase 2,
  not decided. **Remaining phases, one MR each:** ~~the instruction bump~~ — done 2026-08-28:
  `sibyla-documental/2.4` carries the closed warning vocabulary, the escape rule, and a
  stability requirement stated so a run can be checked against it · contract/validator only if
  genuinely required, which now includes the Worker-side version move that must pair with
  installation (`O16`) · the golden-set harness · target-host deployment, verified on a fresh
  `documental-agent` process before being called installed.
  Original scope: The extraction contract
  (`sibyla.extraction.v3.1`, instructions `sibyla-documental/2.3`) references the Invoice Skill
  Build at commit `9359c67` (2026-08-04); the prototype has since evolved — its local tip was
  observed at `3dd4150` (2026-08-06, five commits ahead: Stage 10 Rounds 7–8 controls,
  reconciliation and revenue-review updates, plus duplicate-ENTBNK merges), and its working tree
  carries later uncommitted `SKILL.md` revisions, so **the reconciliation pins the exact source
  state it reads** at pickup time. The work: build a **traceability matrix** for every
  document-reading or document-interpretation rule added or materially changed after `9359c67`,
  and give each rule exactly one disposition — **(1)** agent instruction (visual/textual evidence
  reading, safe for a stateless proposal-only agent), **(2)** extraction contract / deterministic
  validator (mechanically enforceable — never rely on prompt discipline where code can enforce),
  **(3)** cataloging or classification code (anything touching ENTMST/ENTALS/DOCTYP/ENTITM/
  ITMCLS/MNGACC/SNCACC/EXCRAT/DOCEFL, company scope or prior documents — the agent must not query
  or infer internal Sibyla identities), **(4)** golden-set scenario, or **(5)** prototype-only /
  out of scope (workbook, folder, code-issuance, bank-reconciliation mechanics), with reasons
  recorded. The monolithic skill is **not** copied into the agent instructions. Outputs: an
  updated `docs/hermes-documental-agent-instructions.md` with the instruction version incremented
  from `sibyla-documental/2.3`; contract changes only if new structured evidence or warning codes
  are genuinely required — any new warning code lands with contract, validator and tests in the
  same change; deterministic validation for every mechanically enforceable rule; scenario
  requirements appended to `docs/golden-documents.md` (no contents transcribed); deployment
  instructions so the new version installs persistently in the `documental-agent` profile,
  the `orquestrador` / `documental-agent` split preserved. The AI-proposes / code-decides
  boundary holds throughout; missing evidence stays null; printed amounts are never silently
  repaired. Split into small MRs per V6-O1 (matrix+backlog · instructions · contract/validator ·
  golden set · target-host deployment), and target-host installation is **not** claimed done
  unless the effective profile was inspected and tested. **This item feeds `S2-13`** — the
  scenario list in `golden-documents.md` §Next is its coverage specification — **and `S2-14`**,
  whose harness is what makes an instruction-version change measurable

**Exit:** drop one real invoice PDF into the web upload; a DOCLOG row, an FDCHDR row and FDCDTL
lines appear with the supplier resolved, lines mapped to accounts, and flags raised on whatever
was uncertain. Then run all 30 golden documents and record the pass rate.

---

## S3 — Review, correct, learn · ~2 weeks · 6 items

Sketch. Itemise when S2 closes.

- `[ ]` **S3-1** DOCRQE as the persisted review queue over real DOCFLG instances, severity-ordered
- `[ ]` **S3-2** Review UI — extend `DocumentReviewQueue.razor` and `DocumentReviewDetail.razor`
  to the per-field view
- `[ ]` **S3-3** The five decisions: Accept · Reject · Accept with Changes · Need More
  Information · Defer
- `[ ]` **S3-4** **The learning path — the point of this phase.** "Accept with Changes" on an
  entity or item writes back to Layer 2: a new ENTALS alias, a new ENTITM mapping, a corrected
  account. The next document from that supplier resolves without a human
- `[ ]` **S3-5** Comment log on the document — already built, keep and wire
- `[ ]` **S3-6** Discard and purge with tombstones

**Exit:** an operator corrects a mis-resolved supplier once; the next document from that supplier
resolves automatically, with the alias visible in the admin UI. Measure the golden-set pass rate
before and after ten corrections.

---

## S4 — Cegid izibizi push · ~2 weeks · 5 items + 2 blockers

Sketch. **The operational blockers are the highest-probability schedule risk in the plan and have
zero engineering dependency — start them in week 1, not week 8.**

- `[ ]` **S4-1** Re-point `IntegrateDocumentJobHandler` and the Cegid purchase writer from
  `Document` to FDCHDR / FDCDTL. API client, OAuth, product-code derivation,
  `external_reference` idempotency, PDF upload and `WriteUnknown` handling stay as built
- `[ ]` **S4-2** Approval gate — only a document with no open blocking flags and an explicit human
  approval is eligible to push
- `[ ]` **S4-3** Sales pull poller re-pointed to the registry tables
- `[ ]` **S4-4** Decide draft vs closed on `supplierInvoices/insert`. Deferred since July, now on
  the critical path
- `[ ]` **S4-5** Correct `docs/cegid-integration.md` — it still describes the pre-refactor
  Cegid-specific ledger and a "Moloni not implemented" placeholder, both superseded

**Blockers — defined 2026-08-10 in `docs/deployment/izibizi-activation.md`.** Pilot scope is
**one** company; the izibizi account is active with API access; the certificate is self-signed.
Both are week-1 work with no engineering dependency:

- `[~]` **S4-B1** Certificate + key ring **on the host** — **provisioning was done on 2026-07-21 and
  reconfirmed live on 2026-08-22.** The secret-protection code shipped in the July spine (`5f679a5`,
  2026-07-17); this was only ever provisioning, and it happened. **Owner: Miguel.** Measured on the
  machine, read-only: `Cegid:Enabled` **false**; `KeyRingPath` `D:\SibylaData\Keys\Cegid`; the
  configured certificate thumbprint matches a `LocalMachine\My` certificate
  `CN=GOTT Sibyla Cegid Data Protection` with `HasPrivateKey` **true**, expiring **2031-07-21**;
  the key ring exists and holds **1** `key-*.xml`; the key-ring ACL grants SYSTEM and Administrators
  FullControl and the **three live runtime identities** — worker `.\GottSibylaDocumental`,
  `IIS APPPOOL\Sibyla.Api`, `IIS APPPOOL\Sibyla.Web` — **Modify**; the private CNG key ACL grants
  those three **Read** and SYSTEM/Administrators FullControl; a `.pfx` backup exists under
  `D:\fileStorage\SibylaBackups\CegidSecretProtection` with an ACL of SYSTEM and Administrators only.
  **The one thing still outstanding, and the reason this is `[~]` rather than `[x]`: no `key-*.xml`
  backup exists under that backup root.** Back the **live key-ring XML** up before disaster recovery
  is declared complete — a named closeout, **not** a reason to reprovision anything. Record:
  `docs/deployment/izibizi-b1-verification.md`
- `[!]` **S4-B2** Endpoint, client id and client secret for the pilot company. **Owner: Luís.**
  **The credentials are set** — the earlier "nothing has been done" reading was wrong, and B1 never
  blocked it in the end. Live database aggregate, measured 2026-08-22 with **no secret, ciphertext,
  identifier or record value reproduced**: **1** `CegidCompanyConnection`, **disabled**; client id
  present; protected secret present; **all 3 endpoints HTTPS**; **1** fiscal-year mapping;
  configuration **not validated**; **no successful last test**; latest test
  **2026-08-11T12:34:52Z failed** with `cegid_fiscal_year_2026_rejected`. **B2 is therefore not
  operationally closed**: what remains is a successful save/reload/test with the connection enabled
  and the fiscal year accepted. **Nothing in this item authorizes enabling the connection or calling
  Cegid** — that is live-tenant configuration and sits on the stop list
- `[x]` ~~**S4-B3** Fiscal-year subentity per company~~ — **not a dependency.** `to_subentity_id` is
  discovered by *Discover and test fiscal years* via `GET /fiscal_years_list`. An operator task
  once B1 and B2 land, not something to chase
- `[D]` ~~**S4-B4** DPAPI token cache~~ — **not an izibizi prerequisite.** It serves the Microsoft
  Graph workbook projection; with `ExcelCommit__MicrosoftGraph__Enabled=false` a document reaches
  `Integrated` on the Cegid commit alone. Moves to Phase 2 with Excel

**Exit:** an invoice uploaded Monday morning is in Cegid izibizi Monday afternoon, PDF attached,
`external_reference` recorded, and re-pushing it creates nothing.

---

## S5 — Channels · ~2 weeks · 7 items

Sketch. The loop works; now let documents arrive the way they actually arrive.

- `[ ]` **S5-1** Configure Hermes `orquestrador` (Apolo) to call `sibyla.channel-intake.v1`
- `[ ]` **S5-2** Email intake, both forms
- `[ ]` **S5-3** Safe link downloader with a domain allowlist
- `[ ]` **S5-4** WhatsApp via Baileys, including LID and E.164 dual-alias authorisation
- `[ ]` **S5-5** Mattermost
- `[ ]` **S5-6** Admin UI for users, companies, departments, memberships, channels, allowlists
- `[ ]` **S5-7** `HERMES_HOME` backup including the Baileys session

**Exit:** forward an invoice from a phone by WhatsApp; it appears in the review queue within a
minute, attributed to the right company and the right sender.

---

## S6 — Archive and non-fiscal documents · ~2 weeks · 5 items

Sketch. Absorbs `general-document-archive-scope-plan.md` entirely.

- `[ ]` **S6-1** Nextcloud/WebDAV archive wired to the pipeline — client foundations exist
- `[ ]` **S6-2** DOCARC for non-fiscal documents: bank statements, leases, insurance policies,
  employment and supplier contracts, licences, financing. `ProcessingRoute = ArchiveOnly` —
  filed and findable, **never reaching FDCHDR**
- `[ ]` **S6-3** Legal path `{Company}/Legal/{Subtype}/{CounterpartyCodeName}/`
- `[ ]` **S6-4** Periodic PostgreSQL ↔ Nextcloud reconciliation
- `[ ]` **S6-5** Archive naming — **two names, two jobs** (restated 2026-08-22; the "defer until
  collisions occur" framing is withdrawn). The **canonical registry filename**
  (`{date}_{CompanyCode}_{DTCode}_{sha256[0..16)}.{ext}`, accepted 2026-08-21, implemented by
  `RegistryFilenamePolicy` in `S2-3`) is an **immutable capture identity** — unique at birth by
  content hash, built only from facts that cannot be corrected — and needs no collision sequence
  because it is never a display name. The **human-friendly archive name** is the correctable one and
  lives in **`ArchiveNameLedger`, which is S6 work rather than collision-gated**. Deep
  Legal/Procurement metadata stays deferred (`V6.md` §7)

**Exit:** a lease PDF arrives by email, is archived under Legal, is findable by counterparty, and
produced no fiscal entry.

---

## S7 — Pilot · 4 weeks running · 8 items

Sketch.

- `[!]` **S7-0** **O5 — restricted-token / service-identity validation on the target host.**
  Owner Miguel, carried since v3.2. A **production gate**, not a development gate: nothing in
  S0–S6 waits on it, and it must close before S7 runs on real company data. Preparation scripts
  exist and have been reviewed four times; they need one session on the target host
- `[ ]` **S7-1** One company, real documents, every day, through real channels, by the people who
  will use it
- `[ ]` **S7-2** Expired-lease recovery
- `[ ]` **S7-3** Dead-letter alerting and replay
- `[ ]` **S7-4** Off-host backup with one tested restore
- `[ ]` **S7-5** One worker-kill drill
- `[ ]` **S7-6** A small metrics set — documents in, auto-resolved, human-touched, pushed, failed
- `[ ]` **S7-7** Weekly spot-check of a sample against the ERP

Keep one list throughout: what broke, what a human had to fix, what the system should have known.

**Exit:** four weeks of daily use. **That list — not the v5 backlog — determines Phase 2.**

---

## Phase 2 — deferred, with reinstatement triggers

Not scheduled, not estimated, not designed. Each carries the condition that would bring it back,
so it can be revisited on evidence rather than re-argued. Full reasoning in `V6.md` §7.

- `[x]` **P2-2 — closed without consolidation.** ITMCLS, MNGACC and COCACC stay separate; do not
  create `ReferenceValue` or reopen the question at `S1-9c`
- `[x]` **P2-3 — matching records decisions, not just outcomes.** `S2-6`/`!141` delivered the
  trusted append-only `MatchDecision` log with `CandidateJson`; no Phase 1 UI
- `[D]` **P2-1 — `ExternalIdentity` absorbs `IntegrationPartyBinding` / `IntegrationProductBinding`.**
  Deferred on principle, not effort: both are written at step 8, and the S1.5 risk argument is that
  the Cegid and Moloni surfaces are not disturbed. Reinstate at a third provider
- `[x]` **P2-4 — effective dating for the rate-like tables** (M-D7). **Trigger fired and taken,
  2026-08-12.** The reinstatement condition was "when `EXCRAT` is first built", and `S1-5` built it
  with `ValidFrom`/`ValidTo` generated columns and the `EX_EXCRAT_NoOverlappingRatePeriod` exclusion
  constraint in the same migration. Free at creation, as predicted. **Still deferred for anything
  else rate-like** — the asymmetry M-D7 records is unchanged: `ENTMST` and the code lists get audit
  events, not bitemporality
- `[D]` **P2-5 — separate `Tenant` from `Company`.** Reinstate at the first customer with two legal
  entities on one subscription — a sales fact, not an engineering one
- `[D]` **P2-6 — drop `ENTMST.LegacyCode` and the transitional shims.** Reinstate when the
  `S1.5-1` contract query shows nothing reads it
- `[D]` Bank reconciliation, Layer 5 — BNKMOV / BNKCHK / BNKMAT / BNKREC / RECREV, 11 governed
  match types, statement parsers, Via Verde, Stripe tolerance. Statements are still archived from
  S6. Reinstate once S7 has produced a few months of real posted documents to reconcile against
- `[D]` Layer 6 ground truth — PAYCTR / PAYDTL / RCVCTR / RCVDTL, `ControlGoverningPeriod`,
  `UpsertControlSnapshot`, the SQLSTATE 23514 period-regression trigger. With Layer 5
- `[D]` The matcher governance triad — `MatcherProposal`, `RejectedMatcherConstraint`,
  `RejectPreviouslyRejectedProposal`. With Layer 5
- `[D]` `SourceKeyHash` generated column and the `pgcrypto` fail-closed preflight. With Layer 5
- `[D]` Historical document import and its grandfathering machinery — `EnforcementStartsAt`
  seeding, `IsGrandfathered`, the immutable reject trigger, TC5, `ImportBatch`,
  `ImportEvidenceRow`, the pinned-blob roster preflight
- `[D]` Multi-provider-per-company and Excel-as-provider — 0..N connections, `WorkbookDefinition`,
  per-flow toggles, `SalesOut` (no consumer), RF6 divergence detection
- `[D]` Moloni activation — adapter built and parked. A business blocker, not an engineering one:
  the client's API subscription and developer credentials
- `[!D]` Primavera / PHC — **do a two-day mechanism spike before promising anything to a
  customer.** Both are commonly integrated over SQL Server, ODBC or file exchange rather than
  REST, so the `Integration*` HTTP-adapter core may not fit at all. Largest unpriced risk in the
  roadmap
- `[D]` Excel export parity — byte-comparable output against the 31-sheet prototype workbook.
  Reinstate only if someone's actual work depends on that exact workbook
- `[D]` Deep Legal/Procurement metadata and alerting — `EffectiveDate`, `ExpiryDate`,
  `RenewalDate`, `NoticePeriodDays`, `AutoRenews`, expiry jobs, full-text search. Likely wanted
  after S7, and cheap once archiving works
- `[D]` `document-cataloging-remediation-plan.md` Phase 3 — `SupplierExtractionProfile`, hint
  transport, `OperatorHintJson`, reprocessing. Its root cause is fixed in S2-7; reinstate only if
  the golden set shows per-supplier hints are the remaining gap
- `[D]` Security hardening (V6-D5) — agent SOUL/SKILL SHA validation, full security battery
  re-execution per change, API-key secret store, egress policy, cost caps and usage alerting

**Not deferred, because they are architecture rather than hardening and are expensive to
retrofit:** the AI-proposes / code-decides boundary; per-job agent input and output directories;
append-only audit; company scoping on every document.

---

## Platform — three rules that cost nothing now and save a rewrite later

Sibyla is the first module of a platform that will also carry Medusa (CRM agents) and Calypso
(marketing agents). No work on either in Phase 1, and no abstraction built in anticipation of
them — but these three constraints apply to everything built in S0–S7.

- `[ ]` **P-1** The entity registry is platform-level, not Sibyla-level. ENTMST is the single
  record of who a counterparty is; Medusa's contacts point at it rather than copying it
- `[ ]` **P-2** The job engine takes a payload it does not understand. No document-shaped fields
  on `Job`
- `[ ]` **P-3** Channel intake produces a generic "something arrived from someone on some channel"
  record. Routing to a module is a separate decision — a WhatsApp message may be an invoice
  (Sibyla) or a client request (Medusa)

---

## Working rules (V6.md §8)

1. One status document, one page, updated in place. Over two pages means it is being used as a
   diary and needs cutting
2. A phase is done when its exit criterion is **demonstrated to a person**, not when its
   checklist is ticked
3. Plan detail is capped at the current phase plus a sketch of the next
4. Reviews are scoped, not universal (V6-O1). Fix forward
5. The golden set is the quality metric — one number, honest, trending
6. Decisions live in one table, one line each: decision, date, reason, what would reverse it

---

## Item count

| Phase | Items | Detail level |
|---|---|---|
| S0 Stop, ground, restart | 8 | itemised |
| S1 Reference layer | 12 | itemised |
| **S1.5 Party collapse** | **9** | itemised |
| S2 Single-document intake | 15 | itemised |
| S3 Review, correct, learn | 6 | sketch |
| S4 Cegid izibizi push | 5 + 2 blockers | sketch |
| S5 Channels | 7 | sketch |
| S6 Archive | 5 | sketch |
| S7 Pilot | 8 | sketch |
| Platform constraints | 3 | standing |
| **Total live** | **80** | 77 across S0–S7, plus 3 standing |
| Phase 2 deferred | 19 groups | not scheduled |

For comparison: v5.0 carried roughly 152 open items across fourteen phases, with no estimates on
any of them, and ERP integration in none of them.
