Chapter 12: General Database Functionality (Business Record Browses)

CH. 12 OF 19 DRAFTED
Listen to this chapter
Can't play? Download the MP3 directly.
Reference build: chandra-enterprise-editor.html, badge v31c425 (2026-08-09). This chapter documents the Business Records browse — the FileMaker-style window you get from opening a Hub's records — and the ten core capabilities below. Everything described here was verified directly against the shipped UI and JS in that file, not assumed from the naming scheme.

General Database Functionality (Business Record Browses)

Reference build: chandra-enterprise-editor.html, badge v31c425 (2026-08-09). This chapter documents the Business Records browse — the FileMaker-style window you get from opening a Hub's records — and the ten core capabilities below. Everything described here was verified directly against the shipped UI and JS in that file, not assumed from the naming scheme.

Every business-record browse in CEE shares one toolbar. Left to right: Add / View / Edit / Duplicate / Soft-delete as always-visible icon buttons, then five menu launchers — Find, Found Set, Sort/View, Hub, Form, Trigger, Test, Import/Export — followed by Refresh and a live search box. All ten capabilities in this chapter live inside that one toolbar; nothing in this chapter requires leaving the browse window.

A running status line under the toolbar always reads: <found count> · <sort summary> · Query plan: local scan · <n> selected. Treat that line as a state readout — it is the fastest way to tell whether you are looking at the full table or a found set, and in what order.


1. Sort

Where: Sort/View menu → Sort Records, or click any sortable column header directly.

Sort in CEE is a draft-based operation with true Apply/Cancel isolation — nothing changes on screen until you explicitly click Sort in the dialog. Opening the dialog shows one row per active sort key; + Add Sort Field appends another. Multiple keys are evaluated top to bottom (a genuine multi-key sort, not a single field with tiebreakers bolted on), and each row can be reordered with the ↑/↓ controls or removed with ×.

Per sort key you control:

Control Effect
Field Any sortable field on the current form design (text, number, date, boolean, select types)
Direction Ascending / Descending
Empty placement Empty values sort first or last, independent of direction
Natural Natural (numeric-aware) string comparison vs. strict lexical
Case sensitive On/off — off by default
Select ordering For Select fields only: sort by current label text, or by the field's defined option order

Quick column-header sorting is layered on top of the same mechanism: clicking a sortable header sets it as the sole sort key; shift-clicking (additive) extends the existing sort with that column as an additional key; clicking an already-sorted header toggles its direction. There's no separate "quick sort" data path — it's the same sortSpec the dialog edits, so the two are always consistent with each other.

Sorting operates on the current found set, not the whole table — if you've constrained down to 12 records, Sort only reorders those 12. The active sort is shown in the Sort/View button's own label (Sort: <field> ↑) and in the status line, and it persists across Refresh and lifecycle-view changes until you change it or clear it.

If a sort key references a field that no longer resolves (retired, renamed, or type-changed since the sort was set), CEE flags it as Missing field in the dialog rather than silently dropping or misapplying it — you have to resolve or remove it before sorting again. Any other resolution problems (an unparseable date or non-numeric value in a numeric-typed field, for instance) surface as inline diagnostics rather than corrupting the row order.


2. Found-Set Operations

Where: the Find menu (search/constrain/extend) and the Found Set menu (omit/omitted-only/return/show all) — two menus working over one shared found-set state.

CEE's found-set model is the direct FileMaker analogue: a business browse always has a base set (everything, or the result of your last Find) and an omitted set layered on top of it. The two menus split responsibility cleanly:

Find menu: - Find Records — opens the Find dialog fresh, or reopens your last active criteria if a found set already exists. - Saved Searches — CU-backed saved search definitions you can name, re-run, and manage independently of the current browse state. - Constrain Found Set — runs a new Find inside the current found set (intersection). Disabled until a found set is active. - Extend Found Set — runs a new Find and unions the result into the current found set, with automatic de-duplication. Also requires an active found set first. - Show All Records — the hard reset: clears findActive, the base ID set, and all omissions in one step.

Found Set menu: - Omit Selected — removes the currently selected row(s) from view without touching the underlying records. If no found set is active yet, Omit Selected implicitly promotes "everything" into the base set first, so omission always has something concrete to subtract from. - Show Omitted Only — flips the browse to show just the omitted records, for review. - Return to Found Set — flips back to the included view. - Show All Records — same hard reset as in the Find menu, exposed here too for convenience.

Buttons are gated to valid states automatically: Omit Selected is disabled with nothing selected or while already viewing the omitted set; Constrain/Extend are disabled with no active find; Show Omitted Only is disabled with nothing omitted. You don't have to remember the legal sequence — the toolbar enforces it.

A word on reliability here: the found-set fields (foundBaseIds, omittedIds, foundView, findOperation) are the single source of truth that every later Refresh recomputes against. A past bug (fixed) briefly let a post-import view get into a state where the toolbar looked like a found set but the underlying fields weren't set consistently, so Refresh kept re-deriving an empty result from stale state. That specific failure mode is closed now, but the underlying lesson is durable and worth knowing: if a browse ever looks "stuck" showing nothing when you know records exist, Find menu → Show All Records is the unconditional reset, and it does not require a reload.


3. Record Navigation

Where: navigation controls on the business browse, operating over whatever is currently on screen.

First / Previous / Next / Last step through the current visible found set, in the current sort order — not the whole table. Each navigation action selects exactly one canonical record (never a range) and the browse shows your position as Record n of m. Buttons disable themselves at the boundaries (Previous/First disabled on record 1, Next/Last disabled on the last record), and the newly-selected row is scrolled into view automatically so you never lose visual track of where you are, especially in a long found set.

Because navigation reads the same found-set/sort state as §1 and §2, the three chapters compose the way you'd expect from FileMaker: sort first, constrain the found set second, and First/Next/Last will walk exactly that filtered, ordered sequence — no separate configuration needed.


4. Duplicate Record

Where: the Duplicate icon button in the always-visible toolbar row.

Duplicate is enabled only when exactly one active record is selected and the Hub has a published form design (the same form-design gate that governs Add and Edit). Clicking it opens the standard record editor pre-loaded with a deep-copied snapshot of the source record's field values — not a reference to the source, a genuine value copy, so editing the draft can never mutate the original.

What is deliberately not copied: - Canonical record identity (the duplicate gets a fresh ID on creation, through the normal record-genesis path — same as a brand-new record) - CU history / chain — the duplicate starts its own provenance chain from its own genesis - Parent linkage is preserved (the duplicate stays attached to the same parent record), but it is not a reference back to the source record

The draft retains source-record and tail provenance internally for audit purposes, but that's metadata about how the draft was created, not a live link. Cancel is fully inert — if you cancel out of the duplicate editor, nothing is written anywhere and the source record is untouched.

On save, the new record goes through the ordinary create path, the browse reapplies the current found set and sort, and the new record is selected automatically if it falls within the current found set. If it doesn't — say you're duplicating from within a constrained view and the copy's field values would put it outside that constraint — CEE tells you explicitly ("Duplicate created, but it is outside the current found set") rather than leaving you to wonder where it went.


5. Import / Export

Where: the Import/Export menu → Export / Report (CSV · PDF)… / Import CSV….

Export opens the Export / Report dialog, which as of this build handles both CSV and PDF from one place — see §9 for the PDF half (layout modes, generation, and attestation). For CSV specifically: it exports whichever scope you choose (found set / tagged / current record — §9 has the full scope picker breakdown) in the current sort order, with display-formatted values (select fields export their current label text, not raw option IDs), a SHA-256 digest of the output, and a CU-attested export job so it's part of the governed audit trail rather than a side-channel file dump.

Import is add-only in the current build — there is no update/upsert path yet. Every accepted row is created through the ordinary CU-backed record-create endpoint; nothing is ever an in-place overwrite of an existing record. The flow is:

  1. Import CSV → choose a file → Read CSV. Blocked until the Hub has a published form design.
  2. Map CSV Columns — CEE auto-matches header names to form fields by label or field key, and always treats identity-looking columns (record_id, canonical_record_id, source_record_id) as source provenance only — they're never imported as data and never used to overwrite an existing record. Every accepted row gets a fresh canonical record ID and its own genesis CU, unconditionally.
  3. Choose a commit policy: Commit valid rows only (skip and report failures, keep the good rows) or Stop on first write failure.
  4. Validate & Preview — every row is checked against the form design's real validation rules before anything is written: required fields, type coercion, and select-field resolution (a select cell that matches a current option label is resolved to that option's ID; text that already looks like a raw ID passes through unchanged; nothing is silently rejected just because it doesn't match a current label — see the label/ID handling below).
  5. Commit — writes the valid rows, then shows Import Completed: created count, rejected count, a per-row error table for anything rejected, the job ID, and the CU attestation (or an explicit attestation-failure notice if the job couldn't be attested). The browse automatically switches to show the affected-record found set afterward.

A few import behaviors worth knowing because they were hard-won: - Required fields: if the form design's name field is itself required (common for canonical_label-style base fields), the imported value for that field is preserved in the row's values — it is not silently stripped before the create call. - Select fields: CSV text is resolved against current option labels where a match exists (this also transparently "heals" an option that's since been renamed but is still present); otherwise the raw text is passed through as-is on the assumption that it's already a valid option ID. Nothing is force-cleared or rejected purely for not matching a current label. - Duplicate-file guard: if the same source file's digest appears to have already been imported into this Hub in this browser before, you get a confirmation prompt rather than a silent double-import.


6. Validation and Auto-Entry

This is the one chapter heading in James's list where it's worth being precise about where the capability actually lives, because it's split across two parts of the product rather than living in one obvious "auto-entry" panel.

Field-level validation, in the Form Designer (_form_design): every field carries Required and Indexed toggles you set when designing the field, plus a Case control (None / UPPERCASE / lowercase / Title Case) on text fields specifically. Case normalization applies live as you type in the record editor — the input field re-cases its own content on every keystroke via applyTextCase, so what you see while entering data is what gets saved, not a silent server-side rewrite you'd have to guess at. Required-field enforcement is checked both at interactive save time and, separately, at CSV import time — a required field with no value blocks the row in both paths, with an explicit "is required" message rather than a generic failure.

Auto-entry and cross-field validation logic, via governed Trigger Definitions: CEE does not currently expose a dedicated "auto-entry type" dropdown inside the Form Designer's field editor. Instead, auto-entry behavior (stamping a creation timestamp, the creating principal, a literal default, a UUID, or a monotonic sequence number) and validation logic beyond Required/Indexed (a conditionally-required field, an outright rejection rule) are configured as governed executor actions on a Trigger Definition, attached to an event like on-create or on-validate. See §10 below for the full editor — the two allowlisted validation executors (validation.require@v1, validation.reject@v1) and the field-stamping executors (field.set-timestamp@v1, field.set-principal@v1, field.set-uuid@v1, field.set-sequence@v1, field.set-literal@v1, plus the two text-normalization executors) are what implement this chapter's auto-entry half in practice.

Current gap, stated plainly: there is a real, tested acceptance-fixture harness (cee-validation-autoentry-fixture-runner) that exercises auto-entry semantics — normalization, defaulting, generation, matching the current principal, monotonic sequencing, and correct request rejection with no record created — but that harness drives the Trigger Definition executors described above, not a separate standalone "auto-entry" surface. If you're looking for a single dedicated auto-entry panel distinct from Trigger Definitions, it doesn't exist yet as of this build; the governed-executor Trigger Definition editor in §10 is the actual mechanism.


7. Related-Record Portals

Where: the Related Tables pane, permanently docked on the left side of every business browse, with a draggable splitter to resize it.

This is CEE's equivalent of a FileMaker portal, implemented at the table level rather than as an embedded row-list: select a parent record in the main grid, and Related Tables lists every child Hub attached under it, each showing status, last-updated, and a live child-record count. Clicking a related table opens a filtered browse scoped to that parent record — the same full-featured business browse described everywhere else in this chapter (its own sort, its own found set, its own toolbar), just pre-constrained to the selected parent.

Related Tables carries its own governance menu (+ Create Table, and a More ▾ menu with Hub Info, Open Form Designer, Duplicate Table Definition, Remove Relationship, Retire Hub, and Request Purge), so table-definition work and record-browsing work stay in the same pane without forcing a context switch to the Spine Editor for routine related-table administration.

The splitter width is remembered per browse window; double-clicking it resets to the default split.


8. Calculated Fields

Where: Form Designer (_form_design) → field editor → Calculated toggle, on any Number (integer) field.

Correction from an earlier draft of this chapter: this capability was verified against build v31c390 and found absent. It is present as of v31c425 — the current build adds it. The rest of this section documents the real, current UI.

A field becomes calculated by setting its Type to Number (integer) and its Calculated toggle to yes. Once calculated, the field's own Entry-mode/preset controls disappear (they don't apply — nothing is ever typed into it directly) and a Calculated badge appears on the field card as a visual flag that this value comes from a formula, not user entry.

Building the formula: the formula input itself is deliberately read-only — you never type into it freehand. Instead you build it token by token with two dropdowns next to it: - Insert field… — lists every compatible peer field (another Number/integer field on the same form, including other calculated fields, so a calculated field can depend on another calculated field) - Operator…+, , ×, ÷, (, )

Each selection appends its token to the formula and the dropdown resets, so the formula is always built by explicit, auditable clicks rather than free text. A Clear button resets it. The field itself is excluded from its own Insert-field list, so you can't wire a field to reference itself.

Dependency chains work as expected — CoD before WSJF, for example. If Field B's formula references Field A, and Field C's formula references Field B, the evaluator resolves A before B before C. This is stated directly in the UI's own helper text: "Field names are indexed names. Eval order: dependencies first (CoD before WSJF), then PEMDAS."

Locking: once a calculated field's formula has been published (i.e., it's a persisted field on a form design already in use), the formula locks — you cannot edit it in place. To change a published formula, retire the field and add a new one. This is the same "retire, don't silently rewrite" discipline CEE applies to every other locked/published field attribute.

Live preview on the record form: while entering a record, calculated fields render read-only with a "(calculated · live)" label, and their displayed value recalculates on every keystroke in any field they depend on — a client-side PEMDAS evaluator (proper operator precedence and parenthesization, division-by-zero and malformed-formula caught as explicit errors rather than silently producing garbage) gives you an immediate preview. That said, the preview is not authoritative. The final value is computed and locked in server-side at save time; the client evaluator exists purely so you can see the number before committing, not as the system of record.

A few edges worth knowing: - Calculated fields are excluded from CSV/PDF test-data generation (generatedRecordValues explicitly skips them) and from CSV import — you can't set a calculated field's value by import; it's always computed. - Switching a field's Type away from Number (integer) clears its Calculated flag and formula automatically (a formula only ever makes sense in a numeric field). - Switching a field's Type to File attach likewise clears any calculated/formula state — the two are mutually exclusive on a given field.


9. Reports and PDF Generation

Where: Import/Export menu → Export Found Set (the same dialog now handles both CSV and PDF — it's titled Export / Report).

Same correction as §8: absent in v31c390, present in v31c425. FileMaker-parity PDF reporting has been added on top of the existing CSV export path rather than as a separate surface, so this section supersedes the "Export" half of §5's format options where relevant.

Opening Export / Report now starts with a Format choice: CSV (data interchange) or PDF Report. Everything below Format — scope, field selection, ordering — is shared between both formats; only the output differs.

Scope, same three options as CSV export always had: current found set, tagged records (if any are tagged), or just the current record. The dialog defaults intelligently — if you have records tagged, it defaults to Tagged; otherwise, Current found set.

Field selection: the field list defaults to your form design's browse-grid columns, in their browse order, pre-checked; every other field on the form is listed below a divider, unchecked. Each field row has ↑/↓ to reorder it in the output, and there are Select all / None buttons for bulk toggling. An Include canonical record ID checkbox adds the record's system ID as a column if you want it.

PDF-specific: layout mode. Once Format is set to PDF, a PDF layout selector appears with two options:

Layout What it produces
Tabular list One multi-record table, columns = your selected fields in your chosen order. Auto-switches to landscape orientation at 5+ columns, and shrinks font size progressively as column count grows (down to 6.5pt at 12+ columns) so wide schemas stay legible rather than clipping. Long cell values are ellipsized rather than overflowing. Repeats the header row and paginates automatically via jsPDF-AutoTable.
Detail One record per page, form-style: field label on the left, value on the right, one row per selected field. Each page is headed with that record's display name. Best for something you'd actually hand someone as a document, versus a table for scanning many records at once.

Both layouts get a consistent header block (title, scope subtitle, operator/timestamp/CEE-version metadata line) and a footer with the Hub ID, job ID, and page number.

Generation and governance: clicking Generate PDF Report / Generate Detail PDF builds the document client-side (via jsPDF + the AutoTable plugin, loaded on demand from CDN — nothing is rendered server-side), computes a SHA-256 digest of the finished PDF bytes, and CU-attests the export job exactly like a CSV export does — same import-export-job artifact shape, with format: "pdf" and a report_kind of either tabular-list or detail-one-per-page. The PDF Report Generated confirmation shows record count, layout, scope, column count, the SHA-256 digest, job ID, and CU ID, so a generated report is just as auditable as any other governed export — it isn't a side-channel document dump.

The browser then downloads the file directly (<hub>-<scope>-<timestamp>.pdf, or with a -detail suffix for Detail layout) — there's no server round-trip for the file itself, only for the attestation.

Relationship to §5 Import/Export: this is genuinely the same dialog and the same governed job pipeline as CSV export, just with PDF added as a second output format. If you've read §5, everything about scope semantics, field selection, and CU attestation there carries over unchanged; the only new concepts are Format and PDF layout.


10. Governed Script Triggers (Trigger Definitions)

Where: the Trigger menu → Browse Trigger Definitions.

This is CEE's automation layer, and it's built on a hard architectural constraint that's worth understanding before you use it: there is no free-form code surface, anywhere, ever. Every action a Trigger Definition can take is one of a fixed set of allowlisted "governed executors." The save path itself pattern-matches the outgoing JSON for anything that looks like "javascript", "script", "eval", "shell", "command", or "code" as a key and hard-rejects the save if it finds one. This isn't a UI nicety you could route around from the API — it's enforced at the point of persistence.

Trigger Definition browse. Because a Hub may eventually carry multiple Trigger Definitions, this is a browse surface, not a single edit form: a table of Name / Event / Status / Priority / Action count, with Executor Catalog (lists every currently-allowlisted executor and its description), View Chain, Enable/Disable, and Edit Selected / Create Trigger.

The Trigger Definition editor, opened from that browse, has:

The current executor catalog (field.* executors stamp or normalize a value; validation.* executors gate the operation):

Executor Effect
field.set-literal@v1 Sets a field to a fixed literal value
field.set-timestamp@v1 Stamps the current timestamp
field.set-principal@v1 Stamps the acting principal (creating-principal auto-entry)
field.set-uuid@v1 Generates and stamps a UUID
field.set-sequence@v1 Stamps a monotonically increasing sequence value
field.normalize-uppercase@v1 Normalizes a field's value to uppercase
field.normalize-lowercase@v1 Normalizes a field's value to lowercase
validation.require@v1 Rejects the operation if a chosen field is missing, with a configurable message
validation.reject@v1 Unconditionally rejects the operation, with a configurable message (for gating on conditions expressed elsewhere)

Saving requires at least one action — an empty Trigger Definition is refused with "Add at least one governed action before publishing." A successful save is CU-backed ("Trigger Definition published"), and View Chain opens the same universal chain viewer used throughout CEE, so a Trigger Definition's history is auditable the same way a record's or a form design's is.


End of Chapter 1. Chapters on Form Design internals, the CU/chain model, permissions and RBAC, and the Spine/Worker administrative surfaces are outside this chapter's scope and belong in later chapters of the manual.

← All chapters  ·  General Reasoning, Inc. · Birmingham, Alabama · Manual v1.0
Join the beta. Two ways in: we can help you set up a closed beta -- use the Industry Configurator to generate a custom personality for your organization, then email the resulting JSON to inquiries@genreason.com along with the subdomain you'd like for an unpublished test site (integration assistance available). Or explore the public-facing Chandra Marshaller directly -- a number of companies are already populated there, no setup required. See current beta deployments.