← All guided builds

Guided build · 04

Debug and harden a model

Separate failed business checks from error values and compiler diagnostics, then add explicit recovery and guarded write contracts.

You will finish with: A defensive text-processing model plus an expense model whose invalid inputs fail visibly without replacing valid state.

25 minBeginnerSource checked for Grid 0.61.0Reviewed 2026-08-25
Related canonical example03-text-and-quality.grid
Get Grid
Practice modeldefensive-text-practice.gridA safe baseline with commented fault injections for each debugging exercise.

Watch it in Grid

See the workflow before you build it.

Follow the finished interaction, then use the written steps below to build and inspect it yourself.

Companion film

Strict by dimension

Try to combine incompatible currencies, see Grid stop the mismatch, then make the conversion explicit.

19 secGrid 0.61.0
Open film page
On this page

What you will build

You will diagnose four different outcomes: a business rule that returns false, a formula error value, a strictness failure, and a rejected input write. Each needs a different repair.

1. Establish a clean baseline

Open the practice model above or the canonical Text And Quality example. Its parsing layer is:

A4 = REGEXMATCH(A1, A3)
A5 = REGEXEXTRACT(A1, /INV-(\d+)/)
A6 = REGEXREPLACE(A2, /owner:\w+/, "owner:shared")
A7 = WILDCARDMATCH(A1, glob"INV-*-001")

Checkpoint: A4 = TRUE, A5 = "2026", A6 = "priority:urgent owner:shared", and A7 = TRUE.

The downstream cells settle at B1 = :accepted, B2 = "current", B3 = 0, and B4 = "unassigned".

2. Treat rejection as data, not failure

Temporarily change only the wildcard in A7:

A7 = WILDCARDMATCH(A1, glob"PO-*-001")

Checkpoint: A7 = FALSE and B1 = :rejected; A4 remains TRUE, A5 remains "2026", and B2 remains "current".

Nothing crashed. The model computed a valid negative business result. Restore the original wildcard before continuing.

3. Observe and recover from an error value

Replace the guarded formula temporarily:

B3 = 10 / 0

Checkpoint: B3 = #DIV/0!.

An error is a value and propagates unless a formula handles it. Restore the intended boundary:

B3 = TRY 10 / 0 ELSE 0

Checkpoint: B3 = 0.

The fallback is policy. It should be visible in source rather than inferred from a blank display.

4. Expose a hidden coercion

Add this temporary binding:

C1 = "5" + 3

In the default loose mode, C1 = 8. Add coercion strict after the model header directives.

Checkpoint: C1 = #TYPE! because the arithmetic requires text-to-number coercion.

Repair the assumption explicitly:

C1 = VALUE("5") + 3

Checkpoint: C1 = 8 under coercion strict.

Remove the temporary binding and directive before moving to the canonical validation model.

5. Reject bad writes without losing good state

Open Cell Metadata & Validation. Its guarded inputs include:

input UnitPrice = 40
  VALIDATE BETWEEN 0 AND 500 MESSAGE "Unit price must be between $0 and $500."

input Category = "travel"
  VALIDATE IN ["travel", "software", "meals", "hardware"] MESSAGE "Pick an approved expense category."

input InvoiceRef = "INV-1042"
  VALIDATE STARTS WITH "INV-" MESSAGE "Invoice references begin with INV-."

Baseline checkpoint: Subtotal = 120, BudgetShare = 0.005, NetAmount = 114, and ApprovalStatus = "auto-approved".

Try writing 600 to UnitPrice, "office" to Category, and "1042" to InvoiceRef.

Checkpoint: each write returns its authored message and leaves UnitPrice = 40, Category = "travel", and InvoiceRef = "INV-1042".

A validation rejection is neither a formula error nor a compiler failure. The stored state remains valid.

6. Catch a bad default before use

Temporarily change the declaration to:

input Units = 60 VALIDATE 1..48

Checkpoint: diagnostics include GRID_VALIDATE_UNSATISFIABLE because the authored default violates its own contract.

Restore Units = 3.

Try it yourself

In Text And Quality, set A1 = "INV-2025-099" without changing either pattern.

Checkpoint: A4 = TRUE, A5 = "2025", A7 = FALSE, B1 = :rejected, and B2 = "legacy". Explain why the regex and wildcard answer different questions.

In Cell Metadata & Validation, make valid writes Units = 48 and UnitPrice = 120.

Checkpoint: Subtotal = 5,760, BudgetShare = 0.24, NetAmount = 5,472, and ApprovalStatus = "needs-approval".

You are done when

  • You can tell a valid rejection from an error value and a diagnostic.
  • Division-by-zero recovery is explicit in source.
  • Strict mode no longer depends on silent numeric-text conversion.
  • Invalid writes preserve the last valid input state.
Build statusReached the expected checkpoint?