> ## Documentation Index
> Fetch the complete documentation index at: https://docs-terra.withunify.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Known Gaps

> What's missing, risk levels, and remediation plans

# Known Gaps

> Listing known gaps is not a weakness — it's proof of awareness and planning.

***

## Summary

| Gap                                                                   | Risk       | Blocks launch?  | Effort |
| --------------------------------------------------------------------- | ---------- | --------------- | ------ |
| [Cross-tenant isolation](#cross-tenant-isolation)                     | Medium     | If multi-tenant | Medium |
| [E2E fixture coverage depth](#e2e-fixture-coverage-depth)             | Low-Medium | Recommended     | Medium |
| [Async queue operational alerting](#async-queue-operational-alerting) | Low-Medium | Recommended     | Low    |
| [Import XSS validation](#form-import-xss)                             | Low-Medium | No              | Low    |
| [Migration boundary](#migration-boundary)                             | Low-Medium | Before cleanup  | Low    |

***

## Cross-Tenant Isolation

<Warning>
  **Risk: Medium** — No automated tests verify tenant data isolation.
</Warning>

Custom domain routing resolves tenants in middleware (`src/middleware.ts` lines 182-362), but there are no tests simulating requests from different domains and verifying data stays scoped.

**What could go wrong:** A routing misconfiguration leaks Tenant A's forms to Tenant B. The logic is correct today, but a regression would be invisible.

**Remediation:** Integration tests that simulate different hostnames and verify form/submission isolation. Needed before enabling multi-tenant custom domains for external agencies.

***

## E2E Fixture Coverage Depth

<Warning>
  **Risk: Low-Medium** — Playwright skip directives are now blocked, but
  coverage still depends on seeded fixture quality.
</Warning>

Static skip directives (`test.skip`, `describe.skip`, `it.skip`) are blocked by `apps/terra/scripts/check-terra-skipped-tests.mjs` and CI now runs public status smoke checks. The remaining gap is fixture depth: some high-value flows still rely on environment-specific seeded forms/accounts.

**What could go wrong:** A critical flow can pass locally in a bypass mode but fail in a fresh environment where fixtures are missing or drifted.

**Remediation:** Move to deterministic seeded fixtures in CI for both authenticated dashboard and public submission paths, and eliminate local-only fixture bypass for release branches.

***

## Async Queue Operational Alerting

<Info>
  **Risk: Low-Medium** — Retry exhaustion and dead-letter visibility are
  implemented, but automated alerting is still manual.
</Info>

Queue processing now exposes dead-letter counts and IDs (`/api/queue/process`), and dead-letter behavior has tests. The remaining gap is external alert routing when dead-letter counts spike.

**Remediation:** Add production monitors/alerts for dead-letter thresholds and document escalation + replay runbook.

***

## Form Import XSS

<Info>
  **Risk: Low-Medium** — Limited testing for XSS in imported form content.
</Info>

Forms imported from HTML/PDF/Google Forms have basic extraction tests, but no tests for `<script>` tags in field labels or descriptions. React auto-escapes by default, so this is largely mitigated by the framework.

**Remediation:** Add tests importing forms with script tags. Verify React's escaping handles them. Check for any `dangerouslySetInnerHTML` usage.

***

## Migration Boundary

<Info>
  **Risk: Low-Medium** — Backwards-compat fallback allows all access when
  `program_members` table is missing.
</Info>

`canEditForm()` in `team.ts` (lines 110-122) returns `true` when the table doesn't exist (Postgres error 42P01). This is a migration safety net for the `program_members` → `user_form_access` transition.

**What could go wrong:** If the table is accidentally dropped, all form access checks silently pass.

**Remediation:** Once the migration is fully deployed, remove the fallback and replace with a hard failure. Update the test that currently expects `true` on table-missing to expect `false`.

***

<CardGroup cols={2}>
  <Card title="PR Review Guide" icon="code-pull-request" href="/review/pr-review-guide">
    How to stay involved going forward
  </Card>

  <Card title="Test Coverage" icon="vial" href="/review/test-coverage">
    Full test inventory
  </Card>
</CardGroup>
