Skip to content

X-02b · Pull line items from a Financial Statements engagement (cross-product)

SOP: SOP_XBRL_Filing.md §6 / Step 2.0 cross-product variant (Phase 3) Actors: XBRL Preparer (xbrl-preparer@spade.local) — holds INGEST_XBRL_DOCUMENT plus VIEW_FS_ENGAGEMENT (read-only cross-product reference). Pre-state: Filing at DRAFT with fsEngagementId set. The linked FsEngagement is at NOTES_COMPLETE. Both entities belong to the same clientId. Post-state: Filing at MAPPING_IN_PROGRESS with XbrlLineItem rows produced from the FS engagement's latest FsGeneratedStatement.statementsJson. Mappings are auto-confirmed where mapping_library.json carries a HIGH-confidence SFRS key → ACRA element correspondence.

0. Prerequisites

  • Filing at DRAFT with fsEngagementId set at create time (see X-01).
  • FS engagement at NOTES_COMPLETE (see FS-06).
  • Both engagement and filing share the same clientId (handler asserts).

NOTE

This is a Phase 3 flow. The endpoint and the service-layer expansion logic land after the Phase 1 FS module and Phase 2 XBRL module are in production. Until then, use the standard upload flow at X-02.

1. Steps

1.1 Trigger the pull

http
POST /ops/xbrl/filings/<filingId>/from-fs-engagement
Authorization: Bearer <xbrl-preparer-jwt>

(Or click Pull from FS engagement on the Documents tab when an fsEngagementId was set on the filing.)

The handler:

  1. Asserts INGEST_XBRL_DOCUMENT.
  2. Reads XbrlFiling.fsEngagementId; asserts it is set and the FS engagement is at NOTES_COMPLETE and belongs to the same clientId.
  3. Reads the latest FsGeneratedStatement.statementsJson for the FS engagement.
  4. Expands the JSON into XbrlLineItem rows:
    • Balance Sheet items → statement = balance_sheet
    • P&L items → statement = income_statement
    • Cash Flow → statement = cash_flow
    • Equity changes → statement = equity_changes
  5. For each line item, attempts to auto-confirm a mapping:
    • Looks up the SFRS taxonomy key in mapping_library.json for a corresponding ACRA elementId entry tagged as HIGH confidence.
    • If found, inserts XbrlTagMapping with confirmedById = <pulling staff user>, confidence = HIGH, confirmedAt = now().
    • Otherwise, inserts the mapping with confirmedById = NULL for manual confirmation.
  6. Transitions filing DRAFT → DOCUMENTS_INGESTED → MAPPING_IN_PROGRESS.
  7. Emits AuditEvent xbrl.cross_product.pulled with {fsEngagementId, lineItemCount, autoConfirmedCount, unconfirmedCount}.

2. Verification

Database

sql
SELECT statement, count(*) FROM xbrl_line_items
  WHERE xbrl_filing_id = '<filingId>' GROUP BY statement;

SELECT count(*) AS total,
       count(*) FILTER (WHERE confirmed_by_id IS NOT NULL) AS auto_confirmed,
       count(*) FILTER (WHERE confirmed_by_id IS NULL)     AS unconfirmed
  FROM xbrl_tag_mappings WHERE xbrl_filing_id = '<filingId>';
sql
SELECT status FROM xbrl_filings WHERE id = '<filingId>';
-- expect 'MAPPING_IN_PROGRESS'

Audit log

Event typeNotes
xbrl.cross_product.pulledPayload includes line-item count and auto-confirmed / unconfirmed split
xbrl.mapping.confirmedOne per auto-confirmed row; actor is the pulling staff user

3. Negative & edge cases

  • FS engagement not at NOTES_COMPLETE409 Conflict with reason: "fs_engagement_not_ready". The XBRL filing cannot pull from an unfinished FS engagement.
  • Mismatched clientId400 Bad Request. Cross-product is same-client only.
  • fsEngagementId is null on the filing400 Bad Request with reason: "fs_engagement_not_linked". The link must be set at filing creation (or via a patch, where supported).
  • Synonym library has MEDIUM / LOW correspondences — those rows land unconfirmed. The reviewer confirms them manually in X-03.
  • Pulling multiple times — idempotent; the second call replaces the line items. Existing manual confirmations on the same line-item labels are preserved when the label matches exactly.

Next

Proceed to X-03 · Confirm tag mappings. Auto-confirmed rows from the cross-product path still surface in the mappings UI for review; the reviewer can revert any auto-confirmation by clicking unconfirm.

Internal use only — BreezyCorp