Skip to content
Back to skills

Finance Elt Staging

ASecurity

Normalize a raw accounting-system trial-balance export (QuickBooks Online / NetSuite / Xero / Sage Intacct) into the ONE canonical staging schema — account,description,debit,credit,entity,period,currency — that the close autopilot consumes, via a data-driven per-source column-map. Stamps entity/currency dimensions + a close-period watermark, blocks on an unbalanced export, writes atomically. Runs scripts/tb_stage.py. Used by `controller`.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 23, 2026
ai-agentspythonrustgoshellapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned September 23, 2026

npx -y skills add mcorbett51090/RavenClaude --skill finance-elt-staging --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Finance Elt Staging?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Finance Elt Staging
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mcorbett51090-finance-elt-staging/badge)](https://www.skillsdirectory.com/skills/mcorbett51090-finance-elt-staging)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: finance-elt-staging
description: "Normalize a raw accounting-system trial-balance export (QuickBooks Online / NetSuite / Xero / Sage Intacct) into the ONE canonical staging schema — account,description,debit,credit,entity,period,currency — that the close autopilot consumes, via a data-driven per-source column-map. Stamps entity/currency dimensions + a close-period watermark, blocks on an unbalanced export, writes atomically. Runs scripts/tb_stage.py. Used by `controller`."
---

# Skill: finance-elt-staging

**Purpose:** Turn a messy vendor export into the **canonical trial-balance staging table** the rest of the controller-autopilot reads — without hand-editing headers, and without a per-vendor code branch. This is the ELT *staging* seam: the deterministic transform between "a connector produced a raw CSV" and "`statement_engine.py` / `reconcile_summary.py` can consume it."

Engine: [`../../scripts/tb_stage.py`](../../scripts/tb_stage.py) (stdlib only, Python 3.8+).

## The load-bearing contract

The canonical staging columns are, **exactly and in this order**:

```
account,description,debit,credit,entity,period,currency
```

This header is **byte-identical to a dbt staging model** (`stg_trial_balance`). A locally-staged CSV and the warehouse staging table are therefore the **same contract** — "local CSV == staging columns" is the whole point. Do **not** reorder or rename it; every downstream engine keys off these names. `validate` rejects any file whose header isn't byte-identical.

## When to use

- You have a raw TB export from an accounting system and need the canonical staging CSV that feeds [`produce-gaap-statements`](../produce-gaap-statements/SKILL.md) and [`reconciliation-summary`](../reconciliation-summary/SKILL.md).
- You are wiring a new source (a new entity's GL) — you author its **column-map**, not new code.

## How it works — one adapter, data-driven per source

There is **no per-vendor code path**. Each source is described by a small **column-map JSON** ([`examples/column-map-netsuite.json`](examples/column-map-netsuite.json), [`examples/column-map-qbo.json`](examples/column-map-qbo.json)):

| Key | Meaning |
|---|---|
| `map` | `{canonical_col: source_col}` — at minimum `account`, `description` |
| `amount_column` | *(optional)* one **signed** net-amount column to split into debit/credit (NetSuite-style) |
| `amount_sign` | `debit_positive` (default) or `credit_positive` — which sign is a debit |
| `constants` | static injections for columns the export lacks (`entity`, `currency`) |
| `close_period` | the **close-period watermark** stamped into every row's `period` |

The two example maps target the **same** entity/period from **different source shapes** — NetSuite's single signed amount and QBO's separate `Debit`/`Credit` columns — and both normalize to the identical canonical output. That is the reuse claim, proven by the acceptance suite.

## The three disciplines that make it honest

1. **Dimensions + a close-period watermark are stamped, not assumed.** `entity` and `currency` become explicit columns (so a multi-entity / multi-currency staging table can be filtered downstream), and every row carries the `period` being closed — the watermark that makes staging partitionable / incrementally loadable by close period.
2. **Blocks on a bad export.** `stage` validates its own output *before* publishing — canonical header, numeric debit/credit, non-blank dimensions + watermark, and the fundamental invariant **debits == credits** — and refuses (non-zero exit) to emit a broken trial balance rather than silently landing it.
3. **Atomic write.** Output is written to a temp file and `os.replace`d into place, so a reader never sees a half-written staging file.

## Invocation

```shell
# Normalize a raw NetSuite-style export -> canonical staging CSV
python3 scripts/tb_stage.py stage \
  --raw        examples/raw-export-netsuite.csv \
  --column-map examples/column-map-netsuite.json \
  --out        staging/trial-balance-MRI-2026-06.csv

# CLI can override/supply the dimensions + watermark (reuse one map across periods)
python3 scripts/tb_stage.py stage \
  --raw examples/raw-export-netsuite.csv --column-map examples/column-map-netsuite.json \
  --out staging/tb.csv --period 2026-07 --entity MRI-UK --currency GBP

# Validate any canonical staging file (columns/types + debits==credits)
python3 scripts/tb_stage.py validate --staging staging/trial-balance-MRI-2026-06.csv
```

The staged CSV then flows straight into `statement_engine.py --tb` and `reconcile_summary.py --tb`.

## Extraction is a separate, credentialed tier — not this skill

This skill operates on a raw export **file**. Pulling that file from a vendor API (OAuth2, rotating refresh tokens, rate limits, pagination) is a **separate tier** with real credential-handling failure modes. Read them before wiring a live connector:

- **Blocking connector facts + the rotating-refresh-token failure mode:** [`../../knowledge/finance-elt-connector-facts.md`](../../knowledge/finance-elt-connector-facts.md)
- **Per-entity wiring (ENV-VAR NAMES only — never values):** [`../../templates/connector-config.template.json`](../../templates/connector-config.template.json)

## Correctness discipline

- The golden [`examples/expected-staging-2026-06.csv`](examples/expected-staging-2026-06.csv) is **hand-derived** from the raw export by independent arithmetic (each signed amount split by sign), **not** frozen from a `tb_stage.py` run — so a staging bug cannot ship inside its own golden. Acceptance suite: [`../../scripts/test_elt_stage.py`](../../scripts/test_elt_stage.py).
- All fixtures are **synthetic and obviously fake** (the Meridian Robotics worked entity); no company data, PII, or secrets.

## What this is not

Not an accounting/audit/tax opinion, and not a live connector — outputs are decision-support (see [`../../CLAUDE.md`](../../CLAUDE.md) §3). Staging normalizes structure and enforces the TB invariant; it does **not** validate that the source GL is itself correct, reconciled, or complete. A balanced staging file is a necessary, not sufficient, condition for a trustworthy close — reconciliation (`reconciliation-summary`) and the governed review→approve→lock spine (`close-approval-workflow`) still apply.

Files in this skill

  • SKILL.md6.2 KB
  • examples/column-map-netsuite.json456 B
  • examples/column-map-qbo.json521 B
  • examples/expected-staging-2026-06.csv992 B
  • examples/raw-export-bad.csv592 B
  • examples/raw-export-netsuite.csv622 B
  • examples/raw-export-qbo.csv753 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…