Skip to content

About

Schema-driven KYC / beneficial-ownership intake prototype — rules engine, dynamic form, evidence-bearing payload, print layout. One offline HTML file.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Dynamic Intake

A schema-driven KYC / beneficial-ownership intake prototype. It replaces a static printed form with a data capture whose output is a document: a declarative rules engine, a form generated from the schema, a live requirements panel that explains every requirement by rule id, an evidence-bearing Salesforce-ready payload, and a print layout that mirrors the approved paper form.

The whole thing is one offline HTML file — vanilla HTML/CSS/JS, no framework, no npm dependencies, no CDN, no network calls at runtime. It opens by double-click and can be emailed.

Try it

Download dist/intake.html, open it in a browser, and use Demo → Load scenario to load a synthetic case (start with S1-standard, then switch Risk tier to enhanced).

Architecture

  • src/schema.json, src/config.json, src/rules.json, src/sf_map.json — the data layer: fields, thresholds, rules and Salesforce targets. Schema, rules and config are version 0.3.0; rules.json contains {version, rules}. Editing these never requires an engine change.
  • src/engine.js — pure, DOM-free functions: evaluateRules(state, config, rules), validate(state, schema), buildPayload(state, schema, sfMap), computeEffectiveOwnership(parties, holdings), deriveLane(state, evaluation, config). Deterministic: same state → same output, no clock access.
  • src/view.js — pure view model (deriveView, Review/print projection); src/actions.js — pure state transitions (record certification/refusal, mock stamp, case serialize/parse). The browser supplies timestamps to those actions.
  • src/ui.js, src/styles.css, src/print.css — rendering only. No rule logic in the UI.
  • build.py — inlines src/* plus the scenarios and test files into dist/intake.html, with SHA-256 rulebook metadata. Python standard library only.
  • tests/scenarios.json — synthetic scenarios S1–S6; tests/run.js runs them in Node against the engine, and the same file runs in the browser from the footer Scenario self-test link.
  • tests/check_view.js, tests/check_bundle.js, tests/check_handover.js — view/Review, built-bundle and handover-pack checks. tests/browser_smoke.js is an optional Playwright check that also regenerates the sample PDFs.
  • docs/ — milestone plans and reports, the generated handover pack, sample print output, and the session prompts that produced the code.

Conventions

  • Every rule carries { id, basis, why, params, cite, cite_status }. basis is [REG] (a regulatory requirement), [POLICY] (a bank-policy assumption to be confirmed), or [REG]/[POLICY]. cite is a supplied reference or null; its status is confirmed or verify. R7 retains a second reference in additional_cites. The requirements panel shows the rule id and why, with citations/statuses on the tag tooltip. R6 FAQ numbering, R7's additional FAQ reference and R8's paragraph citation remain marked verify.
  • Every schema field carries a basis ([REG], [POLICY], [FOLKLORE] or TBD) and string/null cite. The legal-floor handover groups the whole inventory. [FOLKLORE] is the future deletion-candidate list after the paper form is inventoried; no field is assigned that classification by inference.
  • Anything the bank has not supplied is a TBD_-prefixed placeholder: paper-form fields, certification wording, enhanced-tier fields, and every Salesforce object/field API name. Placeholders stay placeholders — the prototype never invents a field name, a policy or a regulatory requirement.
  • The public repository holds generic conventions and synthetic scenarios only. Real field lists, risk-tier definitions, certification wording, Salesforce API names and bank policy decisions belong in a private overlay of the JSON files.
  • Risk tiers are standard and enhanced. The higher-risk tier lowers the beneficial-ownership threshold (25% → 10% here) and reveals an extra information section; both come from config.json, not from code.
  • R7 reuse is recorded in attestation.bo_certification: confirmation, confirming name/role, verbal/written channel, browser recording time and confirmed BO-file version. Record certification captures the time and file version; Record refusal records confirmed: false and refused_at. The old no-change boolean is removed. The record is separate from the mock stamp and implements no electronic signature.
  • R7 separates [POLICY] bo_rebuild_triggers from bo_certify_events. Rebuilds require full ownership/control collection; certify events permit reuse with a recorded confirmation, with explicit refusal returning to full collection. With a prior file and no event, always_certify_on_reuse controls whether the record is required. Reuse retains signer/trustee CIP, trust documents and foreign-party obligations. Payload evidence records which class fired.
  • Lane L/H is a [POLICY] operating-model signal. Entity owners, trust involvement, foreign parties, enhanced risk or a rebuild trigger select H; the ownership-coverage warning also selects H when its policy option is enabled. Reasons appear on the top-bar tag, in Review and in payload evidence. Lane selection changes no collection requirement or readiness decision.
  • The build pins the canonical {rules, config, schema} JSON: recursively sorted object keys, retained array order, compact UTF-8 encoding, then SHA-256. intake-meta carries the hash and three versions; payload.evidence.rulebook_pin copies them and Review shows the short hash. Reconstructing the rulebook requires the exact associated source JSON.
  • Save/Load exchanges {schema_version, saved_at, state} with exactly six live keys: customer, parties, holdings, documents, attestation and as_of_date. Load accepts only 0.3.0, rejects 0.2.0 without migration, refreshes the as-of date and preserves a saved mock stamp. Case files are the only persistence.
  • Data is synthetic everywhere: Synthetic … names, 123-45-0000 / 00-0000000 tax IDs, FAKE-ID-… identity documents, 0 Example … addresses.

Handover pack

docs/handover/ contains eight generated Markdown documents (00–07): field inventory with basis/cites, rule explanations and citation statuses, a customer-type × risk-tier collection matrix, the full Salesforce map and relationship/evidence shapes, consolidated policy confirmations, implementation notes, and the legal-floor inventory. It is a prototype specification with TBD_ placeholders, not an approved bank document. Regenerate it with python3 handover.py; tests/check_handover.js regenerates and verifies it independently of build.py.

Build and test

python3 build.py             # writes dist/intake.html
node tests/run.js            # engine scenarios S1–S6
node tests/check_view.js     # view model and Review projection
node tests/check_bundle.js   # the built single file
node tests/check_handover.js # regenerates and verifies docs/handover/

The optional browser check needs a separately installed Playwright:

NODE_PATH=<path to a separately installed Playwright> INTAKE_BROWSER_CHANNEL=chrome node tests/browser_smoke.js

It reports SKIP when Playwright is absent. Node and Python are development tools only; the sole runtime deliverable is dist/intake.html.

Disclaimer

This is a prototype built with synthetic data. It is not legal, regulatory or compliance advice, it is not an approved form, and it is not affiliated with or endorsed by any bank or financial institution. Regulatory references (the FinCEN CDD rule, FinCEN Order FIN-2026-R001) are cited for context only — confirm every requirement with your own counsel and compliance function. Every [POLICY] tag marks an assumption that has not been confirmed by anyone.

License

MIT — see LICENSE.

About

Schema-driven KYC / beneficial-ownership intake prototype — rules engine, dynamic form, evidence-bearing payload, print layout. One offline HTML file.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages