# Selected-root Runtime read capacity evidence

This is the test-only P1c-M1 measurement harness for NexusCRM issue #3555. It
collects reproducible facts for Section 9 of
`docs/design/runtime-selected-record-read-contract.md`; it does not approve a
limit, define a wire format, or add a production Runtime capability.

The M1 harness ran the reviewed issue-tracker semantic consumer through the
real in-process path at its recorded revision:

```text
fixture Consumer
  -> records.ContractService.Retrieve
  -> records.PersistenceService.Retrieve
  -> metadata and object-Read gates
  -> persistence.RecordRepository.FindOne (TiDB)
  -> RLS
  -> FLS
  -> neutral record conversion
  -> deterministic selected-root projection
```

That measured revision used `RecordRepository.FindOne`/`SELECT *`; M2b later
added a separate selected-root projection-pushdown path. M1 artifacts remain
historical observations and must not be relabeled as post-M2b measurements.

The temporary TiDB database contains synthetic data only. No test2 tenant
metadata, identifiers, records, or traffic payloads are read. The M1 result
records that its measured repository used `SELECT *` and projected selection
only after the adapter; it must not be interpreted as post-M2b
selection-pushdown evidence.

The production app-packs source is read from the pinned commit solely to derive
the public CRM pack-declared field-count distribution. Before switching to the
scratch database, a test2 run may add only anonymized aggregate facts:
field-count
percentiles, identifier-length maxima, and the number of sampled public CRM
tables. The collector never emits object/field names, identifiers, records, or
traffic payloads. All lifecycle, aggregate, and measurement database operations
reuse `database.OpenDBFromEnv`, including its hostname-verified remote TLS
behavior. The fixture still reads only its isolated synthetic database.

For a local loopback TiDB development probe, use the explicit non-TLS opt-out:

```bash
export P1C_M1_APP_PACKS_ROOT=/path/to/nexuscrm-app-packs
export TIDB_HOST=127.0.0.1 TIDB_PORT=4000 TIDB_USER=root TIDB_PASSWORD=
export TIDB_DATABASE=nexuscrm # source connection used only to create scratch
export TIDB_TLS_DISABLE=1 # local loopback non-TLS TiDB only
export P1C_M1_ENVIRONMENT=local-development-probe P1C_M1_REPRESENTATIVE=false
export P1C_M1_SAMPLES=1200 P1C_M1_WARMUP=100
export P1C_M1_CONCURRENCY=1,4,16,64
scripts/performance/run-selected-root-capacity-evidence.sh
```

For remote TiDB, use an account that may create and drop the temporary scratch
database and preserve `database.OpenDBFromEnv`'s verified-TLS default. Configure
the normal TiDB CA inputs for the environment and do **not** set
`TIDB_TLS_DISABLE`:

```bash
export P1C_M1_APP_PACKS_ROOT=/path/to/nexuscrm-app-packs
export TIDB_HOST=tidb.example.internal TIDB_PORT=4000 TIDB_USER=benchmark
export TIDB_DATABASE=nexuscrm # source connection used only to create scratch
export P1C_M1_ENVIRONMENT=test2 P1C_M1_REPRESENTATIVE=true
export P1C_M1_REPRESENTATIVENESS_SCOPE='test2 host, TiDB service, and pool settings; not production traffic'
export P1C_M1_SAMPLES=5000 P1C_M1_WARMUP=200
export P1C_M1_CONCURRENCY=1,4,16,64
scripts/performance/run-selected-root-capacity-evidence.sh
```

Each run emits compact `result.json` and `interpretation.md`. The JSON records
the exact NexusCRM, production app-packs, and fixture revisions; environment;
dataset; sample/warmup counts; concurrency; tail latency; query count;
allocations; semantic request/response sizes; pool pressure; cancellation; and
identifier probes.

The capacity runner prints a `P1C_M1_PROGRESS` line before and after every
matrix cell and atomically replaces `partial-result.json` after each completed
cell. The M2d-A runner additionally checkpoints after sequential startup
readiness and, in `full` mode, wide c16 readiness before any timed cell. Schema
v5 also supports the reviewed `m2d-c-sql-tail` diagnostic mode: it keeps
startup readiness but runs only the identical 39-field/c16 cell after
concurrency-aligned pool warmup. Its `complete: true` means that focused slice
completed, not that the full matrix, P1c, a production SLO, or retained cutover
gates passed. The focused JSON carries the prior 512-field/c16 deadline tail as
an explicit open `retained_cutover_gates` entry and marks
`readiness_warmup_status` as skipped, so an unexecuted wide phase cannot be
mistaken for a zero-valued successful result. Each partial checkpoint has
`complete: false`; only a mode-valid result has `complete: true`. M2d-A v1
artifacts contain only the earlier wide readiness object; v2 adds both
readiness phases; v3 adds bounded trailing-window convergence; v4 adds
connection lifecycle evidence; v5 adds the explicit evidence mode, completion
scope, and inherited cutover gate.
Each
read has a configurable 30-second default harness-liveness timeout; this is a
benchmark safety guard, not an observed or proposed production Runtime
deadline. The downstream test2 workflow owns the scratch name/token before it
starts the runner and invokes marker-verified idempotent cleanup from a separate
`if: always()` step, so cancellation does not rely solely on the killed shell's
EXIT trap.

M1 semantic sizes use deterministic compact JSON over the existing fixture types.
They are a transport-independent logical-size proxy, not predicted protobuf or
gRPC bytes. Because P2 generation remains blocked, transport headroom remains
explicitly unavailable. The future reviewed codec must replay the same vectors
and compare encoded sizes with configured send/receive limits before a decision
PR may approve headroom.

## M2d-A post-pushdown evidence

M2d-A deliberately does not overwrite or relabel the M1 harness. It reuses the
same revision pins, reviewed fixture snapshot, scratch-database ownership,
artifact format, and lifecycle controls through a separate entry point:

```bash
P1C_M2D_A_APP_PACKS_ROOT=/path/to/nexuscrm-app-packs \
P1C_M1_ENVIRONMENT=test2 \
P1C_M1_REPRESENTATIVE=true \
P1C_M1_REPRESENTATIVENESS_SCOPE='test2 host, TiDB service, and pool settings; not production traffic or deployment topology' \
scripts/performance/run-selected-root-m2d-a-evidence.sh
```

The downstream test2 workflow must still prove that the exact NexusCRM
revision is merged to `main` before it runs. Do not use a local TiUP result as
the decision artifact.

The measured path is the post-M2b current in-process implementation:

```text
records.ContractService.ReadSelectedRecord
  -> records.PersistenceService.ReadSelectedRecord
  -> analytics.QueryService.ReadSelectedRootProjection
  -> permissions.PermissionService.BuildRLSResult
  -> persistence.QueryRepository.Find
  -> metadata-aware scalar hydration
  -> deterministic authorized selected-root result
```

The report retains the pinned CRM pack distribution and the reviewed/current
anonymous test2 p50/p95/p99/p999/maximum metadata distribution. The executable
A1 load matrix is deliberately the reviewable workload set `1,15,39,256,512,
513`: the smallest diagnostic, two ordinary CRM shapes, the historical
candidate, the current wide candidate, and one over it. It performs 5,000
39-field/concurrency-1 startup-readiness reads and then 5,000
512-field/concurrency-16 wide-readiness reads before measurement, recording both
tail distributions. The startup phase has exactly 5,000 attempts and records
all cold-start errors. Before its final window, only `deadline-exceeded` is an
admissible cold-latency outcome; every other error class fails the gate. Timed
cells begin only when the final 1,200 attempts have zero errors and p99 below
the 250 ms diagnostic readiness target. This is a benchmark convergence
criterion, not a production SLO. The separate
phases exist because test2 run `29171276326` proved that the concurrent phase
alone did not stabilize the following c1 baseline, while run `29173225117`
proved that requiring the entire cold-start phase to be error-free conflates
environment startup with steady-state measurement. The harness then uses 1,200
samples per cell and deterministically
shuffles field shapes within ascending concurrency tiers `1,4,16,64`. Any error
stops later load tiers. The two-second per-read context is a test of the
unapproved attempt candidate, not production enforcement.

The success-capacity dataset uses physically present, readable root fields so
the 512-field cell measures a complete 512-field authorized projection.
`DeclaredAbsent` and `FLSHidden` remain in the semantic goldens and M2d-B fault/
omission matrix; including either in the success load would respectively turn
the path into a schema/storage fault or silently reduce the authorized response
width.
Every successful capacity read also asserts that the authorized response
contains exactly the selected-field count.

M2d-A reports current in-process Runtime-equivalent latency, SQL query count,
semantic JSON size, allocations, pool pressure, and a derived retry-
amplification model. It does **not** measure Gateway/AppService route work,
split-process transport, a generated codec, automatic retries, admission, or
load shedding. In particular, the 750 ms route-work reserve remains a design
allocation until a representative current route measurement closes it or the
P4/P5 cutover gate measures the real owner.

This is a modeling/profiling gate, not a final performance acceptance test.
Opt-in process-local observations split metadata/object security, selection
normalization, FLS, projection planning, RLS, repository preparation, SQL
execution, raw row scan, storage hydration, typed projection, and semantic JSON
serialization. The artifact also reports GC, heap, goroutine, and pool pressure.
The diagnostic 15/39-field c16 p99 `<250ms`, 512-field c16 p999 `<1s`, and
all-c16 `<2s` targets are hypotheses only. Missing a latency target selects a
profile/optimization loop; one-call/query fan-out, unbounded resource growth,
leaks, or a required semantic contract change are the signals that reopen the
service boundary.

## M2c candidate-envelope evidence

`nexuscrm-records/selected_root_envelope_candidate_test.go` is a separate,
ordinary-CI test. Its reviewed JSON golden records exact/one-over vectors for
the lead candidates without changing production admission:

- 256/257 selected fields;
- 65,536/65,537 semantic request bytes;
- 1,048,576/1,048,577 complete response bytes;
- 255/256 UTF-8 identifier bytes;
- five seconds/five seconds plus one nanosecond; and
- the codec/framing budgets reserved by 128 KiB receive and 2 MiB send caps.

The compact JSON structs in that test are measurement projections, not wire
DTOs. The golden explicitly records that current code accepts 257 fields, a
missing deadline, and a deadline over five seconds; the candidates are not
existing enforcement. It also records that 255-byte object/field identifiers
conflict with M1's TiDB physical-name result (64 accepted, 65 rejected), while
the synthetic 255-byte record-ID probe conflicts with the current generic
object owner (`Id VARCHAR(36)`, 18-byte generated IDs) and does not establish a
public maximum.

Run the evidence with:

```bash
(cd nexuscrm-records && GOWORK=off go test . -run '^TestP1cM2cCandidate' -count=1)
```

The transport numbers reserve space equal to the semantic cap, but this is not
measured codec headroom. After P1c approval, P2 must replay the same vectors
through the reviewed generated codec and fail before deployment if the encoded
messages do not fit. No protobuf or gRPC dependency is permitted in M2c.

## M2c-E structurally valid envelope

`nexuscrm-records/selected_root_valid_envelope_candidate_test.go` is a separate
ordinary-CI oracle. It preserves the original M2c golden and derives a valid
cross-limit candidate from current owners and the two reviewed test2 artifacts:

- 512 selected fields, covering the anonymized test2 metadata maximum of 352;
- 64-byte ASCII object and field identifiers under direct TiDB physical naming;
- a 255-byte opaque record read-input bound, distinct from 36-byte generic UUID,
  18-byte metadata Flow, and other narrower stored-ID owners;
- 34,720 bytes for all structurally valid maxima together; and
- valid 512-field complete responses at 1 MiB and one byte over; and
- 64 KiB retained only as a defensive semantic request cap.

The record candidate does not promise that every object stores 255-byte IDs and
does not add physical-column introspection. Over-limit input is a future request
resource failure; an in-bound value that names no row remains the same masked
missing outcome. The oracle derives the managed system-catalog ID-owner counts
through the kernel catalog, derives test2/CRM observations from the reviewed,
tenant-neutral numeric-only snapshot in `testdata/m2c_e_anonymous_evidence.json`,
verifies its app-packs/fixture tuple against `revisions.env`, and records exact one-over vectors in
`nexuscrm-records/testdata/selected_root_valid_envelope_candidate_golden.json`.
The authoritative snapshot contains run/artifact IDs and result hashes, but no
L2 repository or workflow URL. It changes no production behavior or approved
limit. P1c-D also uses `revisions.env` as the single reviewed pin for the final
M2d-C execution-evidence revision; the decision oracle must not duplicate that
SHA as a source-code literal.
