A-Grade Evidence Crosswalk
Date: 2026-05-23
Plan reference: Phase 5 of the May-2026 A-grade adoption plan. The plan files were drafted as local working notes and are not in the repository; this crosswalk is the canonical repo-tracked artifact for outside reviewers.
Audience: outside auditor (Andy-style engineering evaluation) who wants to verify each A-grade claim without reading the merged remediation plan or any session handoffs. The reviewer mirror snapshot at https://github.com/KStratMD/Preston-Test-reviewer-snapshot is the public-access mirror an outside reviewer should browse alongside this document.
Executive verdict
A-grade evidence on Tier-A architectural debt and on the wedge controls that shipped: HITL approval queue, governed flow templates, SyncErrorAssist, the strategic-claim cleanup gate, and now the source-of-truth manifest with flow-layer ownership enforcement (PR 13). PR 10b platform adapters, PR 11 Reconciliation Center, PR 12 record-level lineage, PR 15 vertical pilot provisioning, and PR 13 source-of-truth manifest all shipped this cycle and are recorded in the evidence matrix below. Demo-grade A for the Squire executive evaluation; full audit-grade A is a post-pilot follow-on (PR 13b closes direct-connector-write enforcement).
The remaining work is parked deliberately, not by oversight. The "Parked Tier-B gaps" section below names each one, why it matters, and which evidence row's residual-risk column it lives in.
Doc discipline rules
These apply to every row of the matrix below; they are also the contract by which this document stays honest as the codebase evolves.
- Cite current files and tests, not historical plan text. Every Source cell points to a file that exists on
mainand a verify command that runs locally as of the date above. - CI-enforced vs manual is explicit. A row is CI-enforced when the Verify command, or a CI-required superset of it, runs on every push, on a schedule, or as a required check that blocks merge. The CI unit-test profile (
npm run test:coverage:ciinci-minimal.yml, which extendsjest.base.config.cjswithroots: tests/unit + src) covers unit tests only — any row whose Verify command isnpm test -- <pattern>qualifies if the matching tests live undertests/unit/**orsrc/**, since the broader CI command runs all matching tests in those roots. Integration tests undertests/integration/**are NOT in that profile; CI runs only a smoke subset vianpm run test:integration:smoke(currently four files:health,MCPAutoRedact,production.gating,workflowCentral-render-real-resolver). A row that cites atests/integration/**file as CI-enforced must verify it's in that smoke list, or downgrade to manual evidence. Annpm runaudit or abash tests/scripts/...regression test wired intoci-minimal.ymlorreviewer-mirror.ymlis also CI-enforced. Agh workflow run(i.e.workflow_dispatch) is manual evidence unless the workflow is also scheduled or on-push. The NetSuite live row below has BOTH triggers, so it qualifies as CI-enforced via its weekly schedule — a pure dispatch-only workflow with no schedule and noon:push trigger would remain manual evidence. Anything else (UX walkthroughs, proof-card recipes, type-system invariants) is manual; the Residual risk cell says so. The Residual risk cell should describe what's missing — typically a dedicated drift/audit gate — not restate that the evidence is unit-test-shaped. - "none" is a valid residual-risk value but must be justified. A blank residual-risk cell is a drift signal — fail closed on review.
- Parked work is named explicitly. If a criterion is only partially covered by a shipped control, the Residual risk cell names the follow-up PR (e.g. PR 13b for direct-connector-write enforcement of source-of-truth ownership) that would close it.
Evidence matrix
| A-grade criterion | Shipped control | Source | Verify | Residual risk |
|---|---|---|---|---|
| Single governance boundary for AI routes | Central AI route manifest + middleware (PR 1A/1B) | src/middleware/setup/aiRouteManifest.ts, src/middleware/governanceMiddleware.ts, tests/unit/middleware/aiRouteGovernance.inventory.test.ts |
npm test -- aiRouteGovernance.inventory |
manifest exhaustiveness (per-posture + per-family counts) and proxy-router wiring (GovernanceService + createGovernanceMiddleware references in the proxy source) are both CI-foreclosed by the inventory test; the residual risk is that the broader invariant — every /api/ai* mount has central-governance wiring beyond the proxy router — is held by code review, not by a drift gate |
| Outbound DLP at AI provider boundary | OutboundGovernanceService evaluated before every provider call (PR 2A/2B) |
src/services/governance/OutboundGovernanceService.ts |
npm test -- OutboundGovernance (the broader pattern matches all three relevant files — tests/unit/services/governance/OutboundGovernanceService.test.ts, .posture.test.ts, and tests/unit/services/ai/providers/OutboundGovernance.test.ts — since the providers file has no Service suffix in its path) |
CI-enforced — the full jest run (npm run test:coverage:ci in ci-minimal.yml) executes all three test files; the residual risk is the absence of a dedicated drift/audit gate (e.g. egress-dlp-coverage) that would fail CI if a new AI provider call skipped OutboundGovernanceService — currently a code-review-only invariant |
| Outbound DLP at connector write boundary | BaseConnector.validateOutboundWrite() called by every production connector's create/update/delete (PR 2C) |
src/core/BaseConnector.ts (validateOutboundWrite), src/connectors/NetSuiteConnector.ts, src/connectors/BusinessCentralConnector.ts |
npm test -- ConnectorOutboundGovernance |
CI-enforced — the full jest run (npm run test:coverage:ci) covers the helper and its connector callers; the residual risk is the absence of an AST/audit drift gate ensuring every production connector's write methods call validateOutboundWrite — ShipStation custom write methods historically bypassed the helper and still need explicit wiring before they can be claimed under this row |
| Per-tenant DLP posture | GovernanceService.getPostureForTenant cached posture lookup with fail-closed individual getBooleanStrict reads and fail-open-to-safe-defaults overall resolution (DEFAULT_POSTURE = {allowPII:false, blockOnDetection:false, autoRedact:true, piiTypes:[]} on any DB/repo error, SYSTEM_IDENTITY, or missing tenantId) — C3 / C3.1a / C3.1c, PRs #832 #834 #835 |
src/services/ai/orchestrator/GovernanceService.ts (getPostureForTenant) |
npm run audit-governance-posture-reads |
none — AST audit fails CI on any governance.* read outside getPostureForTenant |
| Encryption at rest for secret-bearing tenant config | TenantConfigurationRepository.getSecretString + PlaintextSecretError (C2, PR #831) |
src/database/repositories/TenantConfigurationRepository.ts (getSecretString) |
npm run audit-secret-key-encryption |
none — AST gate flags any .getString(...) whose key ends in secret / password / api_key / signing_key / hmac_secret |
| Tenant attribution mandatory on audit rows | audit_logs.tenant_id NOT NULL + identity-context extraction (PR 4A1 + C5 #830) |
src/database/migrations/031-harden-audit-logs-for-persistence.ts (ALTER COLUMN tenant_id SET NOT NULL), src/services/governance/identityContext.ts |
npm run audit-tenant-isolation-invariant |
none — schema constraint enforces attribution at write; drift gate enforces disableHeaderExtraction: true invariant on the central gate |
| AuditService persistence | Persisted-AuditService with cleanup-timer + DLP-aware persistence mapper (PR 4A2) | src/services/ai/orchestrator/AuditService.ts, docs/review/proof-cards/audit-service.md |
npm run test:coverage:core (covers the persisted AuditService); proof card recipe in audit-service.md §Verification |
CI-enforced — unit tests via npm run test:coverage:ci and the core-coverage ratchet (scripts/check-core-coverage-budget.mjs) both run in ci-minimal.yml; the residual risk is the absence of a behavioral end-to-end audit that asserts every AI route emits a persisted audit row |
| Tenant middleware central mount | optionalAuthMiddleware + tenantIsolation() mounted on /api/* (PR 4B #821) |
src/middleware/setup/RouteSetup.ts, src/middleware/setup/routeManifest.ts |
npm run audit-tenant-coverage |
none — drift gate enforces tenant-middleware presence on every route declared in the route classification manifest (routeManifest.ts) |
| HITL approval queue | ApprovalQueueService + ApprovalQueueRepository + ApprovalResumeWorker + Governance Approvals UI (PR 3A/3B/3C #819 #820 #824) |
src/services/governance/ApprovalQueueService.ts, src/services/governance/ApprovalQueueRepository.ts, src/services/governance/ApprovalResumeWorker.ts, public/embedded/approvals.html |
service correctness CI-enforced via npm run test:coverage:ci (covers ApprovalQueue* unit tests); the operator UI is manual evidence — open /embedded/approvals.html against a running server |
UX walkthrough is manual — not asserted by a screenshot diff or end-to-end UI test |
| Governed flow templates | FlowExecutor walks every template through transform → validate → governance scan → dispatch; CI gate enforces template DSL invariants (PR 14 + PR #825/#827); ownership pre-flight against the source-of-truth manifest now runs before OutboundGovernanceService.validateConnectorWrite() (PR 13) |
src/flows/templates/FlowExecutor.ts, src/flows/templates/FlowTemplate.ts, docs/review/proof-cards/flow-templates.md |
npm run audit-flow-templates (CI-enforced); unit suite via npm test -- FlowExecutor (CI-enforced); integration suite tests/integration/FlowExecutor.test.ts via npm run test:integration -- FlowExecutor is manual — not in the CI smoke subset |
LineageRecorder instrumentation now shipped in FlowExecutor via PR 12 (#846); OwnershipResolver pre-flight now shipped via PR 13; bulk dispatch still deferred to PR 14b; only one sample template ships today; integration suite is not CI-enforced |
| Sync Error AI Assist | NetSuite-side SuiteScript webhook + AI suggestion pipeline + operator review UI (PR 17a / 17b / 17c) | src/services/syncErrorAssist/SyncErrorAssistService.ts, src/middleware/syncErrorAssistWebhook.ts, src/routes/syncErrorAssistRoutes.ts, docs/review/proof-cards/sync-error-assist.md |
unit suite CI-enforced via npm run test:coverage:ci (covers the syncErrorAssist service, webhook middleware, and ingest-route unit tests under tests/unit/); the webhook end-to-end integration suite tests/integration/syncErrorAssistWebhook.integration.test.ts is manual — runs locally via npm run test:integration -- syncErrorAssistWebhook but is not in the CI smoke subset |
beta — no production credential test on file (pilot deployment with real NetSuite + Claude + SuiteScript afterSubmit is the next milestone); fixture corpus is Claude-drafted, not yet Squire-empirical (accept-rate target is a pilot measurement, recorded in the proof card); webhook integration suite is not CI-enforced; IPv6 /64-prefix masking on the pre-auth IP limiter deferred to a follow-up PR |
| WorkflowCentral no-hosting-data | Tagged WorkflowPayload union + payload-resolver render-by-ref + ADR-019 (PR #811 + #815) |
src/services/workflowCentral/payload/WorkflowPayload.ts, docs/review/proof-cards/workflow-central-operator.md |
proof card workflow-central-operator.md §60-second verification |
gated exception — the ephemeral_hosted variant of the union allows inline data for workflows that cannot be reference-based (cross-system compose, AI-generated workflows pre-creation), but only with expiresAt set, tenant opt-in (workflow.allow_ephemeral_payload) or env flag (WORKFLOW_ALLOW_EPHEMERAL_PAYLOAD), and redactWorkflowPayloadForAudit dropping data before any audit emit (load-bearing invariant per ADR-019) |
| Connector registry + wiring drift gate | Single-source-of-truth registry + AST wiring audit (PR 6A, ADR-015) | src/connectors/connectorRegistry.ts |
npm run audit-status-claims (includes --check-wired-connectors) |
none — AST audit fails CI on any new <ClassName>( outside the registry for a factory-wired class |
| GovernanceService coverage | Service-level proof card + core-coverage ratchet floor (PR 5 #786) | docs/review/proof-cards/governance-service.md |
npm run test:coverage:core then node scripts/check-core-coverage-budget.mjs |
none — ratchet fails CI on regression below floor |
| Strategic-claim cleanup gate | claim:evidence / claim:benchmark / claim:pilot-result / claim:labeled-projection tag classifier (PR 16 #809) |
scripts/check-strategic-claims.mjs |
node scripts/check-strategic-claims.mjs |
none — every metric-shaped claim outside that taxonomy fails CI |
| Reviewer mirror reproducibility | Orphan-commit force-push pipeline + content allowlist + provenance sentinel (PR 9) | .github/workflows/reviewer-mirror.yml, scripts/build-reviewer-mirror.mjs |
bash tests/scripts/reviewer-mirror.test.sh; public mirror at https://github.com/KStratMD/Preston-Test-reviewer-snapshot |
none — SOURCE_COMMIT sentinel is smoke-checked on every publish |
| V3 — NetSuite credential proof | Live sandbox CRUD as Jest integration + dispatch+scheduled CI workflow (Phase 1 of this plan, PR #836) | tests/integration/netsuite.connector.live.crud.test.ts, .github/workflows/netsuite-live.yml |
gh workflow run netsuite-live.yml on demand (requires NETSUITE_LIVE_TESTS=1 + 5 NETSUITE_* secrets); also runs automatically each Monday at 14:00 UTC via schedule: cron '0 14 * * 1' |
CI-enforced weekly (not on every push) and sandbox-only (not production NetSuite); per the doc-discipline rule, the scheduled run qualifies as CI-enforced even though it's not merge-blocking |
| M1 Phase A — AI accuracy baseline | Labeled-fixture harness + JSON + markdown emit (Phase 2 of this plan, PR #837) | scripts/run-ai-accuracy-benchmark.mjs, docs/review/ai-accuracy-benchmark.json, docs/review/ai-accuracy-benchmark.md |
npm run benchmark:ai (single cell; -- --matrix for the full cross-product; requires OPENAI_API_KEY + ANTHROPIC_API_KEY for the Anthropic cells; respects MAX_BENCHMARK_COST_USD) |
manual evidence — Phase B (2026-06-10) widened to a provider×pair matrix: OpenAI (gpt-5.4-mini) + Anthropic (claude-haiku-4-5) × SFDC→NS / SFDC→BC customers; remaining follow-on is OpenRouter/LMStudio columns, nightly CI smoke, and confidence intervals |
| PR 21 — cost transparency | Per-tenant / per-flow / per-provider cost rollups with measured-vs-estimated labels (Phase 3 of this plan, PR #839) | src/services/cost/CostTransparencyService.ts, docs/review/proof-cards/cost-transparency.md |
npm test -- CostTransparencyService |
service correctness CI-enforced via npm run test:coverage:ci; the operator-facing UI surface and finance-owner sign-off are manual evidence recorded in the pilot readiness packet |
| PR 22 — portfolio evidence | Static surface + bidirectional drift gate + mini-pack inline-embed (Phase 4 of this plan, PR #840) | public/squire-portfolio-evidence.html, scripts/audit-portfolio-evidence.mjs, scripts/lib/portfolio-evidence.mjs |
npm run audit-portfolio-evidence; regression net bash tests/scripts/audit-portfolio-evidence.test.sh |
none — drift gate fails CI on per-card diff, top-level keys, shape validation, and duplicate slugs |
| Embedded ERP launch surface | NetSuite SuiteApp + Business Central Extension adapters with server-to-server host-bootstrap. Two-layer enforcement: (1) assertEmbeddedPlatformAdapter() (src/embedded/adapters/EmbeddedPlatformAdapter.ts) throws on hostBootstrap.method !== 'server_to_server' OR browserBearerExposed !== false, executed in CI by the per-adapter descriptor unit tests under tests/unit/embedded/ (run by npm run test:coverage:ci); (2) scripts/check-adapter-conformance.mjs is a structural CI gate that fails if any *.adapter.ts lacks a paired test('<basename>: ...') block in tests/playwright/embedded/adapter-conformance.spec.ts — the spec itself also contains the same predicate assertions, but is structurally referenced by the gate rather than executed in CI (the e2e workflow runs only playwright.e2e.config.cjs against tests/e2e/, not tests/playwright/). So a future adapter cannot ship without (a) a passing assertEmbeddedPlatformAdapter() invariant in its unit test AND (b) a named test in the structural spec (PR 10b, #843) |
src/embedded/adapters/, platform/netsuite-suiteapp/, platform/business-central-extension/, tests/playwright/embedded/adapter-conformance.spec.ts, docs/review/proof-cards/embedded-platform-adapters.md |
npm run check:adapter-conformance (structural CI gate); npm test -- tests/unit/embedded/ (descriptor unit tests run via npm run test:coverage:ci, asserting the runtime predicates) |
platform-side install evidence depends on a real ERP shell; the two-layer gate proves the contract, not a signed SuiteApp/AppSource bundle |
| Reconciliation Center operator surface | Persisted exception queue (migration 048) + tenant-scoped repository with ReconciliationExceptionNotFoundError mapping + recurring ReconciliationScheduleJob lifecycle (1h cadence by default) + Bearer-JWT operator API at /api/reconciliation-center/exceptions and /api/reconciliation-center/exceptions/:id/resolve (PR 11, #845) |
src/services/reconciliationCenter/, src/routes/reconciliationCenterRoutes.ts, src/database/migrations/048-create-reconciliation-center-tables.ts, docs/review/proof-cards/reconciliation-center.md |
npm test -- reconciliationCenter |
service correctness CI-enforced via npm run test:coverage:ci (covers reconciliation service, repository, schedule job, route, migration); embedded operator UI deferred to follow-up (R16 de-scope per Codex P1 — iframe could not bootstrap an authenticated session against the Bearer-JWT mount); schedule-job tick is a zero-tick stub in this PR ({schedulesRun: 0, exceptionsCreated: 0} until per-cadence ERP-specific reconcilers land) |
| Record-level lineage | lineage_events table (migration 049) + LineageRecorder + FlowExecutor instrumentation for all four event types (source_read, transform, governance_decision, target_write) under a single chain_id + LineageQueryService.chainForRecord(...) + two HTTP surfaces (Bearer-JWT operator API at /api/lineage/records/... and embedded-session API at /api/embedded/lineage/... via validateGuestContext) + embedded operator UI at /embedded/lineage.html (PR 12 #846 + PR 12-FU-1 #847 source_read emission + PR 12-FU-2 #848 embedded UI) |
src/services/lineage/, src/flows/templates/FlowExecutor.ts, src/routes/lineageRoutes.ts, src/routes/embedded/embeddedLineageRouter.ts, docs/review/proof-cards/record-lineage.md |
npm run audit-lineage-instrumentation (CI-enforced); regression net bash tests/scripts/check-lineage-instrumentation.test.sh |
This row records lineage, it does not assert ownership; the source-of-truth ownership row below carries the PR-13 enforcement claim. ctx.sourceRecord is OPTIONAL on FlowContext — callers that have not plumbed an upstream ingest adapter still execute but omit source_read emission; per-caller plumbing is a follow-up to-do, not a deferral |
| Source-of-truth ownership enforced on governed-flow writes | PR 13 (this PR) | src/governance/sourceOfTruth/, src/flows/templates/FlowExecutor.ts (ownership pre-flight), scripts/check-source-of-truth-coverage.mjs |
npm run audit-source-of-truth-coverage |
Flow-layer enforcement only; direct connector writes (route handlers, sync jobs, ConnectorManager) audited via AuditService but not policy-gated — closes in PR 13b. Two conflict policies (merge_field_level, queue_for_human) declared in enum but CI gate hard-fails on use. |
| Vertical pilot provisioning | Pilot playbook + provisioning runbook + provision-pilot-tenant.mjs dry-run / apply / verify CLI wrapping rotate-embedded-service-token, with atomic-rename file perms, redacted stdout, and hash-integrity preflight on the bearer mint (PR 15, #844) |
docs/pilot/SQUIRE_VERTICAL_PILOT_PLAYBOOK.md, docs/pilot/PILOT_PROVISIONING_RUNBOOK.md, scripts/provision-pilot-tenant.mjs |
bash tests/scripts/provision-pilot-tenant.test.sh (CI-enforced — wired into ci-minimal.yml audit-tooling step) |
CLI correctness + atomic-rename / redacted-stdout / hash-integrity invariants are CI-enforced via the regression net above; the residual risk is that real pilot success still depends on a Squire-owned environment and named owners — the CLI scaffolds tenant + embedded service token + governance posture but does not execute the pilot itself |
Parked Tier-B gaps (residual risk)
All Tier-B engineering items shipped — no parked items as of 2026-05-24. The remaining audit-grade-A follow-on is PR 13b (direct-connector-write enforcement of source-of-truth ownership), tracked as a residual risk in the "Source-of-truth ownership enforced on governed-flow writes" row of the evidence matrix above; it is a post-pilot scope decision rather than a parked Tier-B item.
How this document is maintained
This file is intended to evolve in lockstep with the shipped controls, not as a snapshot. The cadence:
- On any PR that adds a new audit-style CI gate or proof card, add a row to the matrix in the same PR. The new row's Source cell must point to the file the PR adds; the Verify cell must run locally.
- On any PR that lands one of the parked Tier-B items above, move it from "Parked Tier-B gaps" into the matrix and revise the Executive verdict's A-minus framing accordingly.
- On every
/update-docsrun, scan this file for path drift vianode scripts/check-inbound-links.mjsand patch any links that have moved. - Never inline metric values here. If a row needs a measured count (tests passing, accuracy %, coverage floor), cite the proof card or
metrics.jsonrow that already carries the appropriateclaim:*tag rather than restating the number in this document — restating creates a second source of truth and a second drift surface.