# CRM Dialect Source Extraction Contract

Status: app-packs source mode.

The v63 route drain and composition inversion are complete. The CRM dialect Go
source is no longer owned by the NexusCRM platform checkout; it is supplied from
the official CRM app-packs repository:

- `pingcap-inc/nexuscrm-app-packs/dialects/dialect-sf-crm`
- `pingcap-inc/nexuscrm-app-packs/dialects/dialect-sf-crm-soql`

The ownership target is:

```text
platform / L0  ->  shared neutral contract  <-  app / L1
```

`shared` is the neutral seam. Salesforce/v63 route grammar, SOQL syntax,
response envelopes, and CRM distribution facts belong to the L1 CRM
distribution/app-pack side.

## Current Guard Shape

The repository has two app-packs source proofs, with separate owners:

- `backend/distributions/appsource/app_packs_source_guard_test.go` proves the
  repository's app-packs module topology: the platform checkout no longer
  contains staged dialect module directories, `go.work` does not list them,
  parent `backend/go.mod` has no app dialect require/replace entries, and
  `backend/distributions/go.mod` owns the app dialect replaces to
  `../../nexuscrm-app-packs/dialects/...`.
- `.github/workflows/go-ci.yml` proves source supply where that workflow runs:
  on pushes to `main`. It checks out `pingcap-inc/nexuscrm-app-packs` at the
  CRM distribution lock revision, builds/tests/seals both dialect modules under
  `GOWORK=off`, checks the CRM distribution dependency closure, runs the full
  backend test suite in default and `crm` tag configs, and builds
  `infra/backend.Dockerfile` as a real image smoke.

`go-ci` is a main-branch source-supply proof, not a pull request readiness
owner. Pull requests must not depend on skipped `go-ci` runs, informational
`go-ci` runs, label-triggered `go-ci` runs, or reviewed-head `go-ci`
pre-merge proofs. The always-on executable source-supply proof is the push to
`main`, with immediate repair expected if that main run fails.

The checked-in pull request readiness owner is
`.github/workflows/codex-review.yml`, not `go-ci`. Codex Review is a
`pull_request_target` review workflow: it checks out the trusted base, prepares
PR diff and changed-file snapshots, evaluates standard and adversarial reviews
against those inert inputs, fails closed on stale heads, removes
`ready-to-merge` on blocking verdicts, and applies `ready-to-merge` on aggregate
approval. It does not checkout private app-packs or run Docker smoke.

In this document, a merge criterion means an enforced condition that can block
merge or control the `ready-to-merge` label. `go-ci` is not modeled as a pull
request merge criterion: Codex Review, branch protection, and repository
rulesets must not consume `go-ci` as a required pull request proof. If private
app-packs checkout, Docker smoke, or L0 neutrality execution becomes a
pre-merge requirement, introduce that as a separate merge-policy change with an
explicit owner and read path.

The Go test intentionally does **not** parse the GitHub Actions workflow or the
Dockerfile. A test that statically audits the workflow that runs it is
self-referential and can always be bypassed by another workflow feature. The
source-supply proof is the executable workflow itself where it runs, not a text
audit inside the product runtime test package.

`go-ci` is not an all-PR review gate in this cost model. Ordinary PR review is
owned by Codex Review and branch/ruleset configuration outside this document.

The app-packs source mode cannot be proven by grep-only predicates. Source
supply is proven by a real private app-packs checkout/source acquisition and
Docker coverage in the same main-branch CI job.

## Local Staging Mode

This retired transitional mode was valid only while all of these were true in
the same commit:

- `go.work` lists `./dialect-sf-crm` and `./dialect-sf-crm-soql`.
- `backend/go.mod` replaces both dialect modules to the local sibling paths.
- `dialect-sf-crm/go.mod` replaces `dialect-sf-crm-soql` to the local sibling
  path.
- `infra/backend.Dockerfile` builds successfully from the repository root.
- `.github/workflows/go-ci.yml` builds/tests/seals both local dialect modules
  under their own module closures and runs a Docker image smoke.

This mode must not be reintroduced. Bringing back local staged dialect source
would recreate a second source of truth for L1 CRM wire grammar inside the
platform checkout.

## App-Packs Source Mode

This is the current mode. A change that touches dialect source supply must
preserve all of these invariants in the resulting main-branch state:

- The dialect Go modules are owned by `pingcap-inc/nexuscrm-app-packs` (or a
  repository explicitly owned by the CRM app-pack distribution).
- `backend/distributions/go.mod` resolves both dialect modules to
  `../../nexuscrm-app-packs/dialects/...`; parent `backend/go.mod` and
  `go.work` do not list CRM dialect modules from the platform checkout.
- The main-branch executable source-supply workflow obtains the app-pack source
  through a real checkout of `pingcap-inc/nexuscrm-app-packs` at path
  `nexuscrm-app-packs`, pinned to the CRM distribution lock revision, then runs
  the same build/test/seal checks from:
  - `nexuscrm-app-packs/dialects/dialect-sf-crm`
  - `nexuscrm-app-packs/dialects/dialect-sf-crm-soql`
- The L0 serving processes are `backend/cmd/runtime-api`,
  `backend/cmd/runtime-workers`, and `backend/cmd/runtime-integration`; they do
  not compose CRM dialect modules.
- CRM HTTP serving belongs to `nexuscrm-app-packs/appservices/sfcrm` and its
  independently built AppService image. The retired monolithic CRM server and
  `infra/backend.Dockerfile` are not source-supply consumers.
- Retained CRM setup and publication tools under `backend/distributions/cmd/`
  consume the pinned dialect source. They do not serve application requests.

The source mode requires executable proof: the source-supply workflow must
acquire the pinned app-pack repository and run its module checks, and
`backend/distributions/appsource/app_packs_source_guard_test.go` must preserve
the topology guard. Runtime image proof lives in the serviceified L0 build;
AppService image proof belongs to L1. See
[`infra/runtime/README.md`](../../infra/runtime/README.md) for the serving
process contract.

## Shared Contract Rule

Physical source extraction must not add product wire to `shared/pkg/contract`.
If a new seam is needed, it must pass `docs/design/l0-l1-standard.md` and update
`docs/design/shared-contract-plane-ledger.md` in the same PR.
