# Slipstream and AetherCore: interface and integration review

Prepared 2026-10-10, America/Edmonton. Source inspection only; no service was started, connected, deployed or changed. The private Sites interface uses fictional records and browser-local state. Production elystrumcore.ai is outside this change.

## Recommended responsibility split

AetherCore construction remains authoritative for projects, memberships, drawing revisions, welds, material heats and construction workflows. Slipstream owns extraction evidence. Review converts that evidence into a proposed domain change. An authorized construction service validates and acknowledges that change. Cyclone knowledge promotion is a separate outcome; it does not certify a weld, a drawing revision or a human approval.

Start with a weld-register vertical slice: uploaded document → immutable revision → durable extraction run → table and source cells → human review → dry-run import → authorized apply → acknowledgement. Do not write extracted values straight into weld_records. In particular, the preview does not assert NDE acceptance, material traceability or engineering approval.

## Source baseline

- aethercore-monorepo: `0fa09295f7c0cd9c796a62b3ce9c523e7abd5621`
- Slipstream standalone: `55812f6f6472b15af013a026f6d3b0d80b720664`
- Fleet catalogue generated 2026-10-10T10:07:42Z; used to locate the repositories. CodeGraph used before targeted source reads.

Paths below are relative to aethercore-monorepo unless stated otherwise. These are observed source contracts, not assertions about a live deployment or migration state.

## Existing construction tables to reuse

| Table | Key / scope | Relevant content |
|---|---|---|
| projects | id String(100); tenant_id nullable String(100) | Project master; resolve tenant on server, never trust a browser tenant field |
| project_members | UUID id; project_id String(100) | Member and project role; reuse the canonical access service |
| drawing_register | UUID id; project_id String(100) | Drawing number, title, discipline, revision, spatial anchor and RFI/change-order links |
| drawing_revisions | UUID id; project_id; drawing_id UUID | Issued revision, file URL, transmittal, current/superseded history |
| drawing_ingest_log | UUID id; project_id | Drawing number, revision, SHA-256, ingestion type and source |
| weld_records | UUID id; project_id | Weld number, spool, drawing, NPS, WPS, welder, NDE and status |
| weld_heats | UUID id; weld_id / heat_record_id UUID | Traceability links; a string heat number alone does not establish this relation |

Evidence: `apps/construction/api/app/db/models.py:65-95,1086-1108`; `db/models_field_ops.py:80-153`; `db/models_drawing_ingest.py:29-45`; `db/models_mtr.py:201-266` (the latter three paths share `apps/construction/api/app/`).

## Existing connections and material gaps

1. **Upload already forwards to Slipstream.** `routes/upload.py:250-257,320-323` derives project_id from the upload namespace when it is not the default `aethercore`. `routes/upload.py:796-804` forwards the file, project ID (or `unassigned`), job ID as source ID, and optional scope. The earlier comment at line 33 saying project_id is never captured is stale relative to this implementation. A new UI should send an explicit authorized project; a free-form namespace is not a sufficient identity contract.
2. **Transport success is currently over-labelled.** `services/slipstream_promotion_client.py:108-129` returns any parsed successful response, or None on failure. `routes/upload.py:803-804` marks a truthy dictionary promoted. `packages/intelligence/slipstream/api/extraction_api.py:116-131` can return HTTP 200 with an error and zero promotions, or a valid zero-promotion result. Read `error`, promoted count and individual skipped decisions. Preserve upload, extraction, review and promotion statuses independently.
3. **The extraction endpoint is a promotion contract.** `extraction_api.py:58-76` accepts file, doc_type, project_id, source_id and optional spatial fields. It returns promotion decisions, not the complete reviewed-table contract designed here. Add a versioned structured extraction result rather than treating that response as a table store.
4. **Service identity needs an explicit contract.** The inspected forwarding client supplies no service credential; the extraction route declares no authentication dependency, and is mounted directly in `api/main.py:384`. The reviewed middleware provides logging, headers and rate limiting. Do not infer tenant isolation from the form's project_id. Before connection, implement/verify authenticated service-to-service access, server-side project authorization and fail-closed behavior for missing tenant/project context. The construction helpers in `app/auth/dependencies.py:69-124` also allow missing user/tenant/project context for open/demo behavior; these helpers do not by themselves establish project membership or a review/apply permission. Add explicit fail-closed authorization for the new workflow. This is source evidence, not a claim about external gateway configuration or live exposure.
5. **Construction already has applicable routes, but no reviewed-table handoff was identified in this path.** `/api/projects/{project_id}/drawing-ingests` records the ingest ledger. Weld routes provide create/list and PCF import with `apply=false` preview (`routes/welds.py:65-103`). PCF import is not a generic reviewed-table import. Reuse domain services through a new validated adapter, not direct writes from Sites.
6. **Idempotency needs deliberate handling.** `services/weld_trace.py:48-62` creates a row and generates a count-based number when none is provided. The reviewed `weld_records` project/number index is not declared unique. A retried table import needs an import key, payload digest, concurrency handling and acknowledged target IDs; do not assume existing creates are safe to repeat.

The standalone Slipstream `src/slipstream/di/document_processor.py:108-162` has TableCell(row, col, content, spans, header) and ExtractedTable(cells, rows, cols, bbox, caption). This provides a useful extraction shape. It does not by itself provide durable construction review state. Do not assume the standalone and monorepo packages have identical deployment contracts.

## First table structure

The accompanying SQL is a non-applied PostgreSQL proposal in a separate `slipstream_review` schema. It references existing `public.projects(id)` using varchar(100) and application-supplied UUIDs for new records.

| New table | Why it exists |
|---|---|
| document_sources | One logical source scoped to a construction project |
| document_revisions | Immutable file hash, object key and revision label |
| extraction_runs | One attempt with extractor version and separate promotion result |
| extracted_tables | Page, table number, bbox and column schema |
| extracted_rows | Immutable raw cells with cell-level evidence |
| review_decisions | Append-only approval/rejection, proposed values, mapping snapshot and reviewer |
| construction_handoffs | Idempotent proposed payload and separate construction acknowledgement |

Composite foreign keys retain the same project through source → revision → run → table → row → review. Source and row IDs are not inferred from content hashes. One content hash is not an access-control boundary. SHA-256 is retained on revisions; retries share a logical request key but use a distinct attempt number.

**Deliberately unfinished:** the draft enables and forces row security with no allow policies. It is unusable by an application role until tested project-membership policies and grants are designed. API authorization is also required. Review append-only enforcement, immutable source enforcement, cross-record review validation and concurrency locking still need a migration/service implementation. Handoff review_ids is a draft UUID array; replace it with a join table (or enforce referential checks transactionally) before applying. No production migration should be generated from this file without those decisions. The SQL ends in ROLLBACK.

## First handoff contract

- Project identity: String(100), resolved and authorized server-side. Reject missing, legacy-unscoped or `unassigned` project for this new write path.
- Source identity: source/revision/run/table/row IDs, full file hash, page, bounding boxes when available. Do not invent coordinates or confidence when the extractor omits them.
- Values: typed domain fields, raw values, units, mapping version and selected review decision IDs. NPS is numeric inches in the preview; unit conversion must be explicit in the real adapter.
- Approval: authenticated reviewer and immutable decision timestamp; snapshot both mapping and proposed values. A changed mapping/value invalidates approval for that version.
- Idempotency: tenant/project + request key + payload digest. Same key/same digest returns existing acknowledgement; same key/different digest is a conflict.
- Result: `prepared`, `pending`, `accepted` or `rejected`; successful acceptance returns construction entity IDs. Network failure remains pending/failed, not accepted. Keep Cyclone promotion result separately.

Suggested new adapter: `POST /api/projects/{project_id}/document-handoffs/preview` and `/apply`. These are proposed routes, not existing endpoints. Preview resolves source references, duplicate/conflicting welds, required fields, revision supersession and units without mutation. Apply repeats validation and binds reviewed snapshots in one transaction with an outbox/acknowledgement. Use current auth/RBAC services and route guards, verifying fail-closed behavior for the new path rather than inheriting permissive demo behavior.

## Next implementation slice

1. Agree on deploying the monorepo extraction service versus the standalone service; pin its result version and service authentication.
2. Implement the seven evidence tables plus a normalized handoff-review join, migration, immutable history enforcement and project authorization tests.
3. Expose project-scoped read endpoints for this workbench and an asynchronous extraction run endpoint; persist job/result state and distinguish failed/partial outcomes.
4. Add dry-run weld mapping/validation and duplicate/revision conflict checks.
5. Add approved apply and acknowledgement, then connect the UI. Validate retries, concurrent apply, cross-project references, stale review and partial extraction failure before any real construction writes.

## Preview verification scope

The site exercises document selection, row source evidence, mapping changes, correction, row review, review gating, CSV and JSON exports, responsive navigation and reset. It does not run OCR, open real drawings, assert engineering correctness, contact a service or persist changes. Browser and data tests prove that demonstration only.
