Docs Index
A GRADE EVIDENCE CROSSWALK.md

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.

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:

  1. 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.
  2. 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.
  3. On every /update-docs run, scan this file for path drift via node scripts/check-inbound-links.mjs and patch any links that have moved.
  4. Never inline metric values here. If a row needs a measured count (tests passing, accuracy %, coverage floor), cite the proof card or metrics.json row that already carries the appropriate claim:* tag rather than restating the number in this document — restating creates a second source of truth and a second drift surface.