# Compliance and trust posture

Security and compliance in Vectros are not a feature toggle layered on after the fact —
they are design constraints that shaped the data model, the request path, the deployment
topology, and the operational posture from the first commit. Tenant isolation is enforced
structurally at the data layer; credentials are validated at the edge before any
application code runs; every public surface terminates TLS and every storage surface is
encrypted at rest; and the partner data-plane inference path runs inside the Vectros
perimeter so sensitive content on that path does not cross the boundary to a third-party
model host. The same posture applies on every plan tier — the architecture is identical
across tiers.

Vectros was extracted from a HIPAA-grade clinical product, battle-tested in production
against regulated content before it was offered as a platform. Compliance is the lead story
for regulated and healthcare workloads, and the strongest part of the trust moat.

This page is the posture-level trust narrative. The operational mechanics of webhooks,
usage, and teardown live in the sibling [explanation](explanation.md),
[how-to](how-to.md), and [reference](reference.md) pages.

> **A note on legal scope.** This page describes engineering mechanisms and the security
> posture. It is **not** a legal representation about specific regulatory coverage. Terms
> like HIPAA applicability, Business Associate Agreement coverage of any given subprocessor,
> data-residency obligations, and retention determinations are contractual and
> counsel-gated; nothing here should be read as a binding statement on those.

---

## The three sensitive-data mechanisms

Vectros handles sensitive fields through **three separate, complementary mechanisms**. They
are often confused with one another, so it is worth being precise: they operate at
different points in the data lifecycle and protect against different things. A field marked
sensitive on its schema is covered by all three.

### 1. Redact-at-write — sensitive fields are destroyed before they are persisted to history

When a record or document carrying a sensitive field is written, that field's value is
**redacted out of the retained version history and the structured change-diff at write
time** — before anything lands in durable history. This is **not reversible masking**: the
value is not stored-and-hidden, it is **destroyed before persist**. No scope, no
credential, and no later request can recover it from history, because it was never written
there. This is what keeps sensitive values out of the immutable audit trail entirely.

The same principle protects internal secrets: a webhook's signing secret, for example, is
stored on its live configuration row (delivery-time signing needs it) but is replaced with a
one-way hash in the retained history, so rotating the secret is still distinguishable from
leaving it unchanged without the raw value ever entering the audit record.

### 2. Read-time masking — sensitive fields are masked on read unless the token reveals them

When a record is read back, sensitive fields are **masked in the response unless the calling
token carries the explicit reveal scope** for sensitive data. A token without that scope
sees the record with its sensitive fields obscured; a token that has been deliberately
granted reveal authority sees the cleartext. This is the runtime access control on
sensitive data still present in live rows.

### 3. Search-exclusion — sensitive data never enters the search index

Sensitive fields are **excluded from the search index at index time**. They are never
embedded, never tokenized, never written into any search representation. The consequence is
strong: there is no query — semantic, keyword, or hybrid — that can surface a sensitive
value or use it as a matching signal, because it is simply not in the index to match
against.

**Why three and not one.** Redact-at-write protects *history*; read-time masking protects
*live reads*; search-exclusion protects *retrieval*. A single mechanism at any one of these
points would leave the other two exposed. Together they mean a sensitive value is destroyed
in history, masked on read, and absent from search — three independent guarantees, not one
guarantee restated.

---

## Audit and version history, retained compliantly

Versioning and deletion are first-class platform primitives, not features you wire up.

- **Every write to an audited model accrues an immutable version record** capturing what
  changed, who changed it, and the prior content (with sensitive fields already redacted per
  the mechanism above). Deletions leave a tombstone. Audited history is opt-in per record
  type via the schema's audit-history capability and is on by default.
- **History is tamper-evident.** Each retained record participates in a SHA-256
  state-continuity chain, so an out-of-band modification to the stored history is
  detectable. This is **tamper-evident**, not tamper-proof: the chain makes alteration
  *detectable*; it does not make the store physically immutable, and continuous automated
  verification is not part of the shipped surface.
- **Heavy history is externalized to a write-once, retention-locked object store** with a
  default retention horizon on the order of seven years. Compliance history is dispositioned
  only through a policy-aware path, never by silent auto-expiry.

This data-layer audit trail is distinct from the operational [activity log](reference.md#activity-log)
(the recent-API-calls view) — the former is retained compliance history, the latter is an
operational debugging surface.

---

## Tenant and context isolation as the security guarantee

Isolation in Vectros is **structural** — shaped by the data model and the data-access API,
not a runtime check a future change could quietly regress. Several invariants together form
the externally observable guarantee:

- **Tenant-scoped data access.** Every data lookup is shaped so it cannot be expressed
  without the tenant boundary; there is no path that returns another tenant's rows by
  accident.
- **A mandatory, fail-closed context partition.** Beyond the tenant boundary, each
  application context is an additional fail-closed partition on records, documents, folders,
  and schemas — derived from the credential, never defaulting to a wildcard. This is the
  per-customer / per-application isolation moat that the no-code path and multi-tenant apps
  build on.
- **Uniform "not found" responses.** A caller probing with another tenant's id gets exactly
  the same status and response shape as a caller using an invented id — verifiable from the
  outside with two requests. The same uniformity applies to out-of-scope rows: an in-tenant
  row your token may not see returns the same shape as a row that does not exist. Error
  messages are not a discovery channel.
- **Per-tenant search isolation.** Hybrid search inherits the same boundary — a query cannot
  return another tenant's content regardless of any query-time filter, and filter inputs are
  allow-list validated at the boundary so a crafted filter cannot break out of the tenant
  clause.

Per-customer and per-context **hard-delete is implemented** — decommissioning a customer's
context or an entire tenant runs a real owner-filtered cascade. See
[explanation.md](explanation.md#teardown-and-erasure-two-different-operations) for why this
is distinct from end-subject right-to-erasure.

---

## Edge security and rate limiting

Every request crosses multiple security layers before it reaches application code: a global
content-delivery edge with a web-application firewall, a regional firewall that locks the
API endpoint to edge-only traffic (so direct invocation bypassing the edge is denied), and a
dedicated authorizer that validates the bearer credential and emits an allow/deny decision.
Application-layer enforcement — scope checking, body-size limits, per-tenant rate limiting —
layers on top.

- **Two rate limits, two purposes.** A high per-IP ceiling at the firewall edge is DDoS
  protection — high enough that a legitimate server-to-server backend sails through, low
  enough to cut off a single-source flood before it reaches application code. A separate
  per-tenant business rate limit is enforced at the application layer and is selected from
  the account's plan tier at request time. The two are independent and tuned for different
  threats. **Reads pass the application limiter unthrottled** — only writes and searches
  count against the per-tenant budget.
- **Body-size and method caps.** Request bodies are capped per route at the firewall and
  re-checked a second time before any parsing, returning a `413` if exceeded — a
  belt-and-suspenders pattern that also catches `Content-Length` spoofing. File uploads do
  not flow through these body limits at all; they go directly to object storage via a
  presigned-URL handshake, so the request body the application sees is metadata, not bytes.

### Webhook SSRF prevention

The webhook system has a registration-time defense-in-depth check plus a delivery-time
enforcement gate. At registration, the hostname is resolved and the registration is rejected
if any resolved IP is private, loopback, link-local, any-local, multicast, carrier-grade NAT,
IPv6 unique-local, or the cloud metadata address. At delivery, **the same classification
runs again immediately before the POST**, so a DNS-rebinding attack that resolves to a public
IP at registration and a private IP at delivery is caught — and the offending registration is
auto-disabled. The delivery-time check is the real security gate; the registration check
exists to give immediate feedback and reject obvious garbage. See
[reference.md](reference.md#the-delivery-time-ssrf-gate) for the exact rejected ranges.

---

## Security audits

The partner-facing surfaces have been **hardened across two formal independent security
audits, with all Criticals remediated** before launch. That is the accurate claim — *not*
"zero findings." The audits exercised tenant isolation, scope enforcement, key construction,
the edge, the authorizer, and the webhook machinery; findings drove fixes that shipped, and
the do-not-regress constraints from those audits are enforced mechanically in the codebase so
the fixes cannot silently erode.

---

## What is NOT covered / reserved

An honest scope boundary. Evaluate these explicitly for a regulated workload.

- **End-subject right-to-erasure is reserved, not turnkey.** The per-individual erasure
  workflow has a frozen API contract but no live engine; the endpoint returns
  "not implemented" today. Per-customer and per-context hard-delete *is* implemented — do not
  conflate the two.
- **Read-access logging / accounting-of-disclosures is available, but off by default.** The
  mechanism to record and report who *read* a given subject's PHI is implemented: when enabled,
  per-subject reads are logged (metadata only — caller, time, subject, record, and whether any
  sensitive value was returned unmasked; no PHI payload), and the recorded accounting is
  queryable via the admin accounting endpoint. It is **opt-in per context and off by default** —
  enable it for any workload that needs a §164.528-style read accounting.
- **Per-tenant data residency for data *at rest* is reserved.** Where your records,
  documents, and search index physically live is bounded to the single deployment region per
  environment; an EU or other non-US residency option for stored data is not available today.
  (Inference *serving* region is a separate, enforced control — see the inference-region note
  below.)
- **Customer-managed encryption keys (BYOK / CMK) are reserved.** All keys are
  platform-managed; bring-your-own-key is not available on any tier today.
- **Retention is a platform constant, not controller-configurable.** You cannot today
  configure or shorten retention/purge windows per account; disposition follows the platform
  policy.
- **No SOC 2 report and no third-party penetration test today.** The platform has been
  through structured independent security review, but it does not hold a SOC 2 report and has
  not had a third-party external penetration test; both are roadmap items. Vectros does not
  represent that it holds either.
- **Inference region serving is an enforced control, within bounds.** Inference is served
  from a US region by default for every tenant, resolved fail-closed. A tenant entitled by a
  signed global-processing waiver may opt an individual request into a lower-cost global
  region via `allowGlobalRegion`; the flag is rejected for tenants without that entitlement.
  This governs only **where the model runs** for a given request — not where your data is
  stored or indexed (see the data-residency note above), and it is not a per-region data
  isolation guarantee.
- **The in-perimeter / no-egress claim is scoped to the partner data plane only.** The
  guarantee that sensitive content stays inside the Vectros perimeter applies to the partner
  data plane. The agent-facing tool surface exposes **Vectros data-plane tools only** — it
  has no web-search or third-party web-fetch tools — but the in-perimeter boundary should be
  understood as a property of the partner data plane, not a whole-platform legal
  representation.
- **Partner-side application security is the partner's responsibility.** Vectros covers the
  platform boundary — the API, the data layer, the inference path, the developer portal, and
  everything inside the Vectros perimeter. Your own application's auth system, frontend and
  backend code, deployment posture, logging, and incident response are out of scope. The
  platform gives you a HIPAA-grade *substrate*; it does not make your application HIPAA-grade
  on its own.
- **Multi-region disaster recovery is not in scope today.** Deployment is single-region per
  environment; point-in-time recovery and retained backups provide in-region recovery, but
  cross-region failover is not configured.

---

## Where to go next

- [explanation.md](explanation.md) — the operational mental model: webhooks, the two-axis
  usage model, and the teardown-versus-erasure distinction.
- [how-to.md](how-to.md) — runnable recipes, including verifying a signed webhook delivery.
- [reference.md](reference.md) — the exhaustive field, envelope, limit, and error catalog.
- The generated API reference (OpenAPI/Scalar) — the authoritative wire-level endpoint and
  schema listing.
