# Order layout: `OrderItem` operational reconcile

Status: reviewed transitional operation for
[nexuscrm-pingcap-pack#4672](https://github.com/pingcap-inc/nexuscrm-pingcap-pack/issues/4672),
coordinated by
[nexuscrm-pingcap-pack#4370](https://github.com/pingcap-inc/nexuscrm-pingcap-pack/issues/4370).

## Ownership

This is an opt-in L2 operational reconcile, not deploy Seed, pack metadata,
automatic deployment behavior, or a permanent layout writer. The affected
Order layout may already be admin-owned in a live database. Fresh installs now
carry official `Order/default` so Catalog App metadata V3 has a live default.
The operational reconcile still does not run from bootstrap or deploy, and
related-list rules do not gain authority to overwrite admin-owned content.

The operation is registered as the
`order_layout_orderitem_operational_reconcile` exclusion in
`deploy-seed-catalog.json`. It does not run from bootstrap, staging deploy, or
production deploy. An operator invokes it only after reviewing the audit
receipt.

This is also not the final architecture from
[the #3814 contract](https://github.com/pingcap-inc/NexusCRM/blob/main/docs/design/schema-release-layout-bundle-activation.md).
It creates no BundleKey, `LayoutBundleRevision`, validation, Catalog revision,
activation, or serving claim. The retained post-state receipt is detached
Phase-0 lineage for the future initial Order layout revision.

## Frozen operation

The checked-in
`deployments/offline/runtime/reconcile/order_layout_orderitem.v1.json`
manifest binds the operation to the `order-line-items` rule in the committed
final pack. The script derives the target fields from that rule; it does not
carry a second copy.

The live final-pack lineage comparison binds the canonical JSON content while
excluding only its top-level `generatedAt` build timestamp. Staging pack
assembly may regenerate that timestamp for the same reviewed inputs; every
other lineage field remains part of the fail-closed identity.

The only permitted content transition is:

```text
Order_Product__c / Order__c
    ->
OrderItem / OrderId
fields = OrderItemNumber, Product2Id, Quantity, Net_fees__c, EndDate
```

The reconcile:

- locks every active Order assignment and its single selected layout in a
  TiDB Serverless-compatible `BEGIN PESSIMISTIC` transaction;
- fails unless every active assignment names the same live layout;
- requires the selected row to have NexusCRM's trusted admin source
  (`admin_created`, `cloned`, or `custom`) and an empty `OwnerPack`;
- preserves row ownership, default state, assignments, and every unrelated
  layout value;
- preserves non-empty related-list labels;
- writes the exact pre-change Config to `_System_PageLayoutHistory`;
- retains every prior history row so the reconcile itself performs no
  destructive retention pruning;
- updates Config with an exact binary preimage CAS;
- verifies the post-state and assignment digest before commit;
- stages and fsyncs the required apply receipt before commit, then publishes it
  atomically without overwriting an existing artifact;
- rolls the history append and Config update back together on any failure;
- makes an exact replay a no-op.

Audit is the default. Live staging and production execution is available only
through the checked-in
`.github/workflows/order-layout-orderitem-reconcile.yml` workflow. The
reconciler derives the trusted active runtime and the unique active User named
by its `VERIFY_USERNAME`; live runs reject runtime-file, database, actor, and
insecure-transport overrides. The receipt contains hashes and public lineage
facts, not the database host, username, password, database name, or actor ID.

## Preconditions

1. Merge the reviewed operation to `main`. Dispatch only from `main`, with
   `expected_downstream_commit` equal to the exact current `origin/main`.
   The workflow fails before dependency installation or evidence access unless
   checkout HEAD, the dispatched workflow SHA, current `origin/main`, and the
   supplied commit are identical.
2. Deploy that exact downstream commit to the selected environment. The
   reconciler independently proves the active runtime, runtime lineage,
   final-pack payload, and active `_System_InstalledPack` row before opening the
   layout transaction.
3. Confirm the checkout's
   `packs/NOT-EDIT-final-merged-packs/.build-lineage.json` names the intended
   NexusCRM and app-pack commits.
4. Confirm the environment has a current backup/PITR recovery point.
5. Hold a short Order layout-authoring freeze from the final audit through the
   replay audit and assignment/API verification. TiDB pessimistic transactions
   lock existing assignment rows but do not gap-lock a brand-new assignment.
   Keep the same downstream commit at current `main` across the audit and apply
   dispatches; if `main` advances, audit the new exact head again.
6. Treat workflow artifacts as private operational evidence. Do not commit
   receipts to the repository.

## Staging audit

Dispatch **Order Layout OrderItem Reconcile** with:

- `target_environment = staging`;
- `phase = audit`;
- `expected_downstream_commit = <exact current main SHA>`;
- `layout_authoring_freeze_confirmed = true`.

Expected first-run outcome:

- `mode = "audit"`;
- `outcome = "change_required"`;
- one selected layout;
- `ownership.source` is one of the three trusted admin sources, with empty
  `ownership.ownerPack`;
- `transition.target` is the exact relationship and five fields above;
- assignment before/after digests are equal;
- `target.attestation.kind = "trusted-active-runtime-v1"`;
- `target.attestation.downstreamCommit` equals the reviewed commit;
- `bom.installedPack` matches the attested expected active pack;
- the three authority claims under `claims` are `false`.

Stop if the script reports ambiguity, an ownership mismatch, an unknown
related-list shape, manifest/rule drift, or any other error. Do not weaken the
guard for the observed environment.

Download
`order-layout-orderitem-staging-audit-<commit>-<run-id>`, compute the external
SHA-256 of `audit-receipt.json`, and review the complete receipt. Retain both the
audit run ID and that external digest. An audit whose outcome is
`already_applied` does not authorize an apply dispatch.

## Apply to staging

After the audit receipt is accepted, dispatch the same workflow with:

- `target_environment = staging`;
- `phase = apply`;
- the same `expected_downstream_commit`;
- `prior_audit_run_id = <accepted staging audit run>`;
- `reviewed_audit_receipt_sha256 = <external audit-receipt.json SHA-256>`;
- `layout_authoring_freeze_confirmed = true`.

The workflow accepts only a successful audit run from this exact workflow,
environment, and commit. It downloads only the exact named audit artifact and
compares its file SHA-256 with the reviewed value before invoking the
self-attesting reconciler. Audit invocations never receive an approved-audit
argument. Apply passes that exact downloaded file through
`--approved-audit-receipt`.

Inside the same pessimistic transaction that could append history and update
Config, the reconciler locks the active installed pack, actor, assignments, and
selected layout, then requires the approved receipt to match the current
target/BOM, installed-pack evidence, actor digest, layout identity and
ownership, assignment digest, transition, and pre-change Config digest. Any
drift fails before history or Config mutation and requires a fresh audit and
review; workflow-side artifact validation alone is not mutation authority.

Require `outcome = "applied"`, equal assignment digests, a non-empty history ID
and positive history version, different pre/post canonical Config hashes, and
non-empty pre/post storage hashes. Storage formatting may differ because TiDB
normalizes JSON columns.

The workflow immediately runs a second self-attested audit. Require:

- `outcome = "already_applied"`;
- equal pre/post canonical Config hashes;
- the same assignment digest;
- no new history entry.

After an `already_applied` audit state exists, the workflow runs an API readback
while the layout-authoring freeze remains active. Layout, assignment, and
Order/OrderItem business metadata and records remain read-only. For apply, this
runs only after the apply/replay receipt chain has been validated. An audit with
`change_required` correctly produces no API receipt.

The API verifier independently re-attests the active runtime, requires the
receipt's exact target and actor, brackets its reads with the public `/health`
route for the attested backend port, and records only reviewed public facts. It
requires:

1. `GET /services/data/v63.0/ui-api/layout-assignments/Order` has the receipt's
   assignment count, every assignment names the receipt layout, and at least one
   wildcard route covers unmatched role/profile/record-type combinations.
2. `GET /services/data/v63.0/ui-api/layout/Order` and every record type available
   to the attested principal resolve to the receipt layout. Each served layout
   contains exactly one `OrderItem / OrderId` related list with the five fields
   and no `Order_Product__c / Order__c` related list.
3. `GET /services/data/v63.0/ui-api/layout/OrderItem`, an `OrderItem` query, and
   the selected row's SObject read all succeed.
4. `GET /services/data/v63.0/sobjects/Order_Product__c/describe` matches the
   retired labels from the exact installed final pack.

The public assignment response omits internal `RouteSource` and `OwnerPack`, so
the API receipt does not pretend to reproduce the database assignment digest.
Its claim is limited to the complete public assignment inventory plus the
attested principal's default and available record-type serving routes. No user
impersonation, layout or assignment mutation, or Order/OrderItem business-record
mutation is performed. Authentication and API reads may update session and
recent-item system state; the workflow revokes and verifies rejection of its
issued bearer before publishing acceptance.

Retain `approved-audit-receipt.json`, `apply-receipt.json`,
`replay-audit-receipt.json`, and `api-readback-receipt.json` together. When an
audit finds the state already applied, retain its audit receipt and API readback.

## Apply to production

Do not proceed until the staging audit, apply, replay, and API evidence is
accepted. Promote the same downstream commit to production and, while it is
still exact current `main`, repeat the two-dispatch flow with
`target_environment = production`:

1. dispatch `phase = audit`, download and review its exact receipt, and record
   the run ID plus external receipt SHA-256;
2. dispatch `phase = apply` with that production audit run ID and digest.

The production job uses the `prod` GitHub environment, the
`prod-release-tidb-boundary` concurrency group, and the production self-hosted
runner. The reconciler derives
`multi_prod/current/env/runtime.env` and fails closed unless the active release,
runtime lineage, final-pack payload, installed pack, database target, and actor
all agree. No staging credential, database ID, or actor ID is reused.

After production, repeat every staging assertion and retain the receipts as the
reviewed initial-revision migration input under #4370. Resolve #4672 only when
both environments have this evidence.

## Rollback

The apply receipt records `selection.layoutId` and
`history.versionNumber`. The history row contains the exact pre-change Config.
Rollback through the existing permission-gated layout restore API:

```text
POST /services/data/v63.0/ui-api/layout/{layoutId}/restore/{versionNumber}
```

After restore, verify the served layout and assignment digest, preserve the
incident evidence, and do not re-run `--apply` until the failure is understood.
Database branch/PITR recovery remains the fallback if the normal restore path
is unavailable.
