Add a form
By the end of this lesson, you can add one of your own forms: read its text, write its markers, rules and patterns, add a document type with its checks, make sure that no two forms match one document, and measure the forms together.
Lesson 2 left the profile pfx_supplier_forms with the document type invoice (with its checks), the form HARBOUR_INVOICE, 15 test cases and the measurements of that lesson.
This lesson starts from that state. It adds two forms and one document type: the freight invoice of Nordwind Logistics, and the delivery note of Harbour Office Supplies.
At the end, the test set has 23 test cases, and the profile has the measurements nordwind, all-pdf, all-naive and weak-marker.
Steps to add a form
Section titled “Steps to add a form”Do the same steps for each of your own forms:
- Collect sample documents of the form and write down their correct values.
- Read the text that ADM extracts from them.
- Choose markers that only this form matches.
- Decide whether the form uses an existing document type or needs a new one.
- Write the rules and the field patterns. Decide whether a line pattern or the model reads the line table.
- Test the markers of all forms against all documents.
- Measure the form, and correct it until it is good enough (lesson 2).
Collect sample documents
Section titled “Collect sample documents”Collect 5 to 10 documents of the form. Choose documents that differ, not ten similar ones. Look for these cases:
- A document with a value that is missing, for example no order number.
- A credit note or a cancellation, with negative amounts.
- A long document with several pages.
- A document with a discount, a surcharge or a special VAT rule.
- A document with numbers of other documents in its notes or in the payment text.
- A long name or address that the layout wraps onto two lines.
Write down the correct values of each document. For the course, samples/pdf/expected.json holds them, and 02_seed_test_set.sql writes them into the test set.
For your own forms, extract the documents, correct the results and approve them (lesson 5): every approved document goes into the test set.
Read the text of the new form
Section titled “Read the text of the new form”The markers and the rules work on the text that ADM extracts from the PDF, so read it first.
- Open the profile and the tab Document types & forms, and choose Create form.
- Enter the Form code
NORDWIND_INVOICE, choose the Document typeinvoice, and enter the Descriptiona freight invoice of Nordwind Logistics B.V., Rotterdam. - Go to the section Test the form on a document. The button Choose a document works after you have chosen a document type.
Choose it, search for
nordwind-invoice-01-standard.pdf, and choose Choose in its row. - The section Text shows the text. Text the markers see is the text that the markers match against, and Raw text is the text as the extraction returned it.

The form has no marker yet, so the test shows no marker result.
03_show_text.sql prints the text of one sample document. Run it for the first Nordwind invoice:
@03_show_text.sql nordwind-invoice-01-standard.pdfFreight invoice NWL/26/10482NORDWIND LOGISTICSNordwind Logistics B.V. | Waalhaven Oostzijde 120 | 3087 BM Rotterdam | The NetherlandsVAT NL854122736B01 | KvK 72410593 | accounts@nordwind-logistics.exampleFREIGHT INVOICEInvoice to:Van Dijk Bouwmaterialen B.V.t.a.v. CrediteurenadministratieIndustrieweg 413044 AS RotterdamThe NetherlandsInvoice No:NWL/26/10482Invoice Date:14 Mar 2026Due Date:13 Apr 2026Account:400-2213Your PO:4500127733Shipment:SHP-88412CodeServiceQtyUnitRate EURAmount EURFRT-PALPallet transport Rotterdam - Antwerp6pallet85.00510.00FUELFuel surcharge1flat61.2061.20TOLLRoad toll1flat18.4018.40Net amount589.60VAT 21%123.82Total EUR713.42Payment within 30 days to IBAN NL20 INGB 0001 2345 67, BIC INGBNL2A, reference NWL/26/10482.All transports are carried out under the general conditions of the Dutch Transport Operators (AVC 2002).Questions about this invoice? Please quote your account 400-2213 and shipment SHP-88412.Both ways show the same text. A label and its value are often on separate lines: Invoice No: is on one line and NWL/26/10482 on the next.
Compare the text with the fields of the document type invoice, and note each place where the model can go wrong:
- The customer number is labeled
Account:, and the order reference is labeledYour PO:. Shipment:holds a number that looks like a reference, but it is a number of the carrier.- Numbers use the English format
1,234.56, and dates look like14 Mar 2026. - The line table has the column
Codeinstead ofItem no.
Each of these points becomes a rule.
Choose markers that only this form matches
Section titled “Choose markers that only this form matches”A marker is a regular expression. A form matches a document when all its markers match the text. A marker must match every document of the form and no document of another form. Good markers are values that only the issuer prints, and only on this kind of document:
- The identity of the issuer, for example its VAT ID or registration number. A company name is weaker: other documents mention it too.
The Harbour delivery notes name the carrier
Nordwind Logistics B.V., but they do not contain its VAT ID. - The title of the document, as a whole line. Harbour prints invoices and delivery notes with the same letterhead.
Only the title line
INVOICEorDELIVERY NOTEtells them apart. The pattern^DELIVERY NOTE$matches only a line with exactly this text:^and$match at the start and at the end of each line.
The two new forms use these markers:
NORDWIND_INVOICE "markers": ["VAT NL854122736B01", "^FREIGHT INVOICE$"]HARBOUR_DELIVERY_NOTE "markers": ["VAT ID DE 812 334 905", "^DELIVERY NOTE$"]Decide between a new form and a new document type
Section titled “Decide between a new form and a new document type”A new issuer or a new layout always gets a new form, because the form holds the markers and the layout rules. The document type depends on the data that your application needs from the document:
- If the document returns the same fields as an existing document type, the form uses that document type.
It gets the JSON schema and the check expressions of that document type, and you write only the configuration of the form.
The Nordwind invoice is such a form: it uses the document type
invoiceof lesson 1. - If the document returns other fields, create a new document type first, with its own JSON schema and checks. Then create the form for it. The Harbour delivery note is such a form: a delivery note has delivered quantities, not amounts and VAT.
A document type with one form is normal. A second form of the same document type costs less work, because the schema and the checks already exist.
Add a second layout of a document type
Section titled “Add a second layout of a document type”The Nordwind invoice is a second layout of the document type invoice. It returns the same fields as the Harbour invoice, so it needs no new schema.
The rules of the profile and of the document type apply to it, and so do the check expressions of lesson 2.
The figure shows the same fields on both invoices. The Nordwind invoice prints them at other places, with other labels and with the English number and date format:

The configuration of the form describes what is different on its page:
{ "markers": ["VAT NL854122736B01", "^FREIGHT INVOICE$"], "field_patterns": { "invoice_number": "^NWL/[0-9]{2}/[0-9]{5}$", "customer_number": "^400-[0-9]{4}$", "invoice_date": "^20[0-9]{2}-[01][0-9]-[0-3][0-9]$", "discount_amount": "^[0-9.]+$", "line_items.item_number": "^[A-Z]{3,4}(-[A-Z]{3})?$" }, "rules": [ "The customer is the company under \"Invoice to:\".", "The customer number is the value of \"Account:\". The order reference is the value of \"Your PO:\"; \"n/a\" means there is none: return null.", "\"Shipment:\" is a shipment number of the carrier, not an order reference.", "Numbers use English format: \",\" groups thousands and \".\" is the decimal separator. \"1,234.56\" is 1234.56.", "Dates are printed like \"14 Mar 2026\".", "There is no discount: return 0.", "\"VAT 0% (reverse charge ...)\" means a VAT rate of 0." ]}Write a field pattern for each identifier, for each date and for the sign of each amount. The patterns catch a wrong value that the check expressions cannot catch.
The form has no line_pattern, so the model reads its line table. A table of a few lines is short work for the model, and the check expressions check every line.
Write a line pattern for a form whose tables can be long, as on the Harbour invoice: a pattern reads them faster and copies every value exactly.
- In the form that you started in the previous section, open the tab Advanced (JSON). Replace the text of the field Configuration with the JSON above, and choose Apply to form.
- Return to the tab Form. The sections Markers, Field patterns and Rules now hold the values of the JSON.
- Applying the JSON clears the document of the test. Choose
nordwind-invoice-01-standard.pdfagain. Both markers match. The line Forms that match now lists saved forms only, so it saysNoneuntil you save this form.

- Choose Create form.
03_add_forms.sql calls create_form with the code, the document type, the description and this JSON:
l_form_id := adm_ai_form_config_api.create_form( p_profile_id => l_profile_id, p_form_code => 'NORDWIND_INVOICE', p_doc_type_id => adm_ai_form_config_api.get_doc_type_id(l_profile_id, 'invoice'), p_description => 'a freight invoice of Nordwind Logistics B.V., Rotterdam', p_config_json => q'~{ ... the JSON above ... }~');Run @03_add_forms.sql now. It creates all three objects of this lesson: this form, the document type delivery_note and the form HARBOUR_DELIVERY_NOTE.
The next section explains the two other parts. When you run the script a second time, it deletes the two forms and the document type and creates them again.
forms NORDWIND_INVOICE and HARBOUR_DELIVERY_NOTE, document type delivery_noteAdd a new document type
Section titled “Add a new document type”The delivery note is a new document type. It gets its own JSON schema, with the fields of a delivery note and a line table with the delivered quantities.
Its check expressions are different too: the delivered quantities must add up to the printed total.
The figure marks the fields of the document type delivery_note on a sample delivery note.
The line table has three quantities, and quantity in line_items is the value of the Delivered column:

This is the configuration of the document type:
{ "json_schema": { "type": "object", "properties": { "delivery_note_number": {"type": "string"}, "delivery_date": {"type": "string", "description": "Date of the delivery as YYYY-MM-DD"}, "customer_number": {"type": "string", "description": "The number of the customer at the issuer"}, "customer_name": {"type": "string", "description": "Company name of the customer who ordered the goods"}, "order_reference": {"type": ["string", "null"], "description": "Order number of the customer, null if there is none"}, "total_quantity": {"type": "number", "description": "The printed total of the delivered quantities"}, "line_items": { "type": "array", "items": { "type": "object", "properties": { "item_number": {"type": "string"}, "quantity": {"type": "number", "description": "The delivered quantity"} }, "required": ["item_number", "quantity"] } } }, "required": ["delivery_note_number", "delivery_date", "customer_number", "customer_name", "order_reference", "total_quantity", "line_items"] }, "annotation_fields": ["delivery_note_number", "order_reference"], "line_checks": [ {"name": "delivered quantity >= 0", "expr": "quantity >= 0"} ], "checks": [ {"name": "sum of delivered quantities = total", "expr": "abs(sum_quantity - total_quantity) <= 0.01"} ]}The form HARBOUR_DELIVERY_NOTE belongs to this document type. One of its six rules names the column that holds the quantity: The quantity of a line is the Delivered column.
{ "markers": ["VAT ID DE 812 334 905", "^DELIVERY NOTE$"], "field_patterns": { "delivery_note_number": "^DN-[0-9]{4}-[0-9]{4}$", "customer_number": "^C-[0-9]{5}$", "delivery_date": "^20[0-9]{2}-[01][0-9]-[0-3][0-9]$", "line_items.item_number": "^[A-Z]{3}-[A-Z0-9-]+$" }, "decimal_comma": true, "rules": [ "The customer is the company in the BILL TO block. The DELIVER TO block is only the shipping address.", "Dates are printed as DD.MM.YYYY.", "\"Your order\" holds the order reference.", "The line table has three quantities: Ordered, Delivered and Open. The quantity of a line is the Delivered column.", "The total quantity is the value of \"Total delivered\".", "The carrier is not the customer." ]}A new document type and a new form need no code: the checks are part of the configuration.
- On the tab Document types & forms, choose Create document type. Enter the name
delivery_note. - Open the tab Advanced (JSON), replace the text with the document type JSON above, and choose Apply to form. The tab Form shows the six fields, the two line columns, the check and the line check.

- Choose Create document type.
- Choose Create form. Enter the Form code
HARBOUR_DELIVERY_NOTE, choose the Document typedelivery_note, and enter the Descriptiona delivery note of Harbour Office Supplies GmbH, Hamburg. Paste the form JSON above on the tab Advanced (JSON) and choose Apply to form. - Test the markers on a document that is no delivery note: in the section Test the form on a document, choose
harbour-letter-prices.pdf. The letter has the letterhead of Harbour, but no title line of a form. The first marker matches, the second does not, and the test says that the document does not belong to the form.

- Choose Create form. The tab Document types & forms now lists two document types and three forms.

03_add_forms.sql has already created the document type and the form. It passes the JSON to create_doc_type and create_form:
l_doc_type_id := adm_ai_form_config_api.create_doc_type( p_profile_id => l_profile_id, p_doc_type => 'delivery_note', p_config_json => q'~{ ... the JSON of the document type ... }~');
l_form_id := adm_ai_form_config_api.create_form( p_profile_id => l_profile_id, p_form_code => 'HARBOUR_DELIVERY_NOTE', p_doc_type_id => l_doc_type_id, p_description => 'a delivery note of Harbour Office Supplies GmbH, Hamburg', p_config_json => q'~{ ... the JSON of the form ... }~');Write the test cases of the new forms
Section titled “Write the test cases of the new forms”A test case names its form, and 02_seed_test_set.sql skipped the 8 documents of the new forms in lesson 2. Run it again now, in SQL, after the forms exist.
It replaces the 15 test cases that exist and writes the 8 new ones:
@02_seed_test_set.sqltest set: 23 document(s) writtenThe 23 test cases are the 21 PDFs, the image of the scan and the photo of a Nordwind invoice. The two images belong to lesson 4.
Test the markers against all documents
Section titled “Test the markers against all documents”Each document must match exactly one form, or no form when it is no form. This test calls no model.
The manager tests one document at a time. Open a form, and choose a document in the section Test the form on a document. The line Forms that match now lists every saved form whose markers all match, and the section Markers shows each marker of the open form. Test a Harbour invoice, a delivery note, a Nordwind invoice and the letter. The measurement of the section Measure all forms together tests every document in one run: its table lists the form that ADM found for each document.
03_test_markers.sql calls adm_ai_form_extract_api.matching_forms for the text of every sample PDF and prints the forms that match:
@03_test_markers.sqlharbour-delivery-01-complete.pdf HARBOUR_DELIVERY_NOTEharbour-delivery-02-partial.pdf HARBOUR_DELIVERY_NOTEharbour-delivery-03-backorder.pdf HARBOUR_DELIVERY_NOTEharbour-invoice-01-standard.pdf HARBOUR_INVOICEharbour-invoice-02-single-line.pdf HARBOUR_INVOICEharbour-invoice-03-day-month-ambiguous.pdf HARBOUR_INVOICEharbour-invoice-04-no-order-ref.pdf HARBOUR_INVOICEharbour-invoice-05-different-delivery.pdf HARBOUR_INVOICEharbour-invoice-06-notes-other-number.pdf HARBOUR_INVOICEharbour-invoice-07-large-amounts.pdf HARBOUR_INVOICEharbour-invoice-08-discount.pdf HARBOUR_INVOICEharbour-invoice-09-credit-note.pdf HARBOUR_INVOICEharbour-invoice-10-long-name.pdf HARBOUR_INVOICEharbour-invoice-11-two-pages.pdf HARBOUR_INVOICEharbour-invoice-12-scanned.pdf -harbour-invoice-13-five-pages.pdf HARBOUR_INVOICEharbour-letter-prices.pdf -nordwind-invoice-01-standard.pdf NORDWIND_INVOICEnordwind-invoice-02-reverse-charge.pdf NORDWIND_INVOICEnordwind-invoice-03-no-po.pdf NORDWIND_INVOICEnordwind-invoice-04-large.pdf NORDWIND_INVOICEEvery document matches the right form. The letter has the letterhead of Harbour, but no title line of a form, so it matches no form. The scan has no text.
Run this test after you add or change a form, against all documents of all forms. With many forms, two forms can match one document.
A document that matches more than one form gets the status REVIEW: ADM never chooses between forms. The next sections show how a measurement reports this.
Measure the Nordwind invoices
Section titled “Measure the Nordwind invoices”The first measurement uses the form NORDWIND_INVOICE and the documents whose name ends in .pdf. As in lesson 2, the name filter is a like pattern, so it needs the %.
- Open the tab Measurements and choose Run measurement.
- Enter the Label
nordwind. Choose the FormNORDWIND_INVOICE. Enter%.pdfin the field Name contains.

- Choose Start. The measurement runs as a background job. A job that the manager starts can take up to about two minutes to begin.
Until then, the profile page shows
Measuring (scheduled). Choose the label of the run when it has finished.


@02_measure.sql nordwind NORDWIND_INVOICE %.pdf rules NDOCUMENT_NAME OUTCOME SECONDS DETAILS------------------------------------------ ----------- ------- ------------------------------------------------------------------------------------------------------------------------nordwind-invoice-01-standard.pdf RIGHT 3.4nordwind-invoice-02-reverse-charge.pdf RIGHT 2.3nordwind-invoice-03-no-po.pdf RIGHT 2.0nordwind-invoice-04-large.pdf RIGHT 2.5
DOCUMENTS RIGHT FALSE_ALARM CAUGHT MISSED FAILED MEDIAN_S COMPLETION_TOKENS--------- ------ ----------- ------ ------ ------ -------- ----------------- 4 4 0 0 0 0 2.4 821All four invoices are RIGHT. This includes the line table, where the column is called Code on the page and item_number in the schema: the model matched them without a rule for it,
and the field pattern line_items.item_number accepted every item number.
The model wrote about 205 completion tokens for each Nordwind invoice (821 for four). For comparison, the run patterns of lesson 2 wrote 1,378 tokens for 13 Harbour invoices, about 106 each: those lines come from the line pattern, not from the model.
A measurement that finds no error does not show that the rules are needed. The section Measure the forms without their rules tests that.
Measure all forms together
Section titled “Measure all forms together”Measure all PDFs of the test set. This run includes the delivery notes and the letter. Leave the Form at All forms, and use the name filter %.pdf.
Choose Run measurement, enter the Label all-pdf, enter %.pdf in Name contains, and choose Start.
The table of the run lists the expected form and the found form of each document.

The form argument % selects all forms:
@02_measure.sql all-pdf % %.pdf rules NDOCUMENT_NAME OUTCOME SECONDS DETAILS------------------------------------------ ----------- ------- ------------------------------------------------------------------------------------------------------------------------harbour-invoice-12-scanned.pdf CAUGHT 0.0 wrong: form none | issues: the document has no text (8 characters); a person must read it
--------- ------ ----------- ------ ------ ------ -------- ----------------- 21 20 0 1 0 0 1.8 2423Twenty of the 21 PDFs are RIGHT, and nothing is MISSED. The remaining CAUGHT is the scan without text, which lesson 4 explains.
The letter is RIGHT: its correct result is “no form”, and it went to a person. For a text document without a form, ADM asks the model which form the document is,
and writes the answer into the issues as a hint for the person. The answer never chooses the form of a text document. Here the model answered unknown.
Measure the forms without their rules
Section titled “Measure the forms without their rules”Lesson 2 measured the prompt Naive for one form. Do the same for all forms, to see whether the rules of the two new forms change any outcome.
Choose Run measurement. Enter the Label all-naive and the name filter %.pdf. Choose the Prompt Naive and choose Start.
@02_measure.sql all-naive % %.pdf naive NDOCUMENT_NAME OUTCOME SECONDS DETAILS------------------------------------------ ----------- ------- ------------------------------------------------------------------------------------------------------------------------harbour-invoice-12-scanned.pdf CAUGHT 0.0 wrong: form none | issues: the document has no text (8 characters); a person must read it
--------- ------ ----------- ------ ------ ------ -------- ----------------- 21 20 0 1 0 0 2.0 2883The outcomes are the same as with the rules: 20 RIGHT, the scan CAUGHT, nothing MISSED. The tokens differ. The run all-pdf used 21,184 prompt tokens and 2,423 completion tokens, and all-naive used 17,657 and 2,883.
The rules are part of the prompt, which explains the shorter prompt. The recordings do not show why the answers are longer without them.
On these 21 documents, gpt-5.6-luna reads the Nordwind invoices and the delivery notes right without any rule.
Lesson 2 gives the way to decide: do not add a rule for a field that the measurement shows as right, and add a rule where a measurement shows a wrong value.
A rule that states what a field means, as in the Nordwind form ("Shipment:" is not the order reference), costs one line and protects against a layout that this small test set does not contain.
Measure again when you change the model: a weaker model can need them.
Correct a form whose markers are too weak
Section titled “Correct a form whose markers are too weak”The measurements above found no wrong value. The markers can still fail, and a measurement shows it. To see how, remove the title marker ^DELIVERY NOTE$ from HARBOUR_DELIVERY_NOTE.
The form then matches every document that carries the VAT ID of Harbour: the invoices, the delivery notes and the letter.
- On the tab Document types & forms, choose
HARBOUR_DELIVERY_NOTE. - In the section Markers, choose the trash icon of the second marker, and choose Save.
- Open the form again. In the section Test the form on a document, choose
harbour-invoice-01-standard.pdf. The only marker matches, and Forms that match now lists two forms.

03_set_markers.sql replaces the markers of one form and keeps its other keys. The arguments are the form code and a JSON array:
@03_set_markers.sql HARBOUR_DELIVERY_NOTE '["VAT ID DE 812 334 905"]'@03_test_markers.sqlharbour-invoice-01-standard.pdf MORE THAN ONE: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICEharbour-invoice-02-single-line.pdf MORE THAN ONE: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICE...harbour-invoice-11-two-pages.pdf MORE THAN ONE: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICEharbour-invoice-12-scanned.pdf -harbour-invoice-13-five-pages.pdf MORE THAN ONE: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICEharbour-letter-prices.pdf HARBOUR_DELIVERY_NOTEThe test finds the problem before any model call. A measurement of the Harbour invoices shows what it means for the extraction. Use the label weak-marker, no form, and the name filter harbour-invoice-0%:
Choose Run measurement. Enter the Label weak-marker and the name filter harbour-invoice-0%. Leave the Form at All forms and choose Start.

@02_measure.sql weak-marker % harbour-invoice-0% rules NDOCUMENT_NAME OUTCOME SECONDS DETAILS------------------------------------------ ----------- ------- ------------------------------------------------------------------------------------------------------------------------harbour-invoice-01-standard.pdf CAUGHT 0.0 wrong: form none | issues: more than one form matches: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICEharbour-invoice-02-single-line.pdf CAUGHT 0.0 wrong: form none | issues: more than one form matches: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICEharbour-invoice-03-day-month-ambiguous.pdf CAUGHT 0.0 wrong: form none | issues: more than one form matches: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICE...harbour-invoice-09-credit-note.pdf CAUGHT 0.0 wrong: form none | issues: more than one form matches: HARBOUR_DELIVERY_NOTE, HARBOUR_INVOICE
DOCUMENTS RIGHT FALSE_ALARM CAUGHT MISSED FAILED MEDIAN_S COMPLETION_TOKENS--------- ------ ----------- ------ ------ ------ -------- ----------------- 9 0 0 9 0 0 0ADM calls no model for these documents: the tokens are 0. Each document is CAUGHT with the issue more than one form matches, and goes to a person. The values would have been right, but nothing reads them.
The fix is in the marker, not in a rule. Put the title marker back.
Open HARBOUR_DELIVERY_NOTE again, choose Add marker, enter ^DELIVERY NOTE$ in the new field, and choose Save.
@03_set_markers.sql HARBOUR_DELIVERY_NOTE '["VAT ID DE 812 334 905", "^DELIVERY NOTE$"]'@03_test_markers.sqlThe output of 03_test_markers.sql is again the output of the section Test the markers against all documents: every document matches one form, or none.
The run weak-marker stays in the list of measurements as a record. You can delete it with Delete run on its page.
Choose the next step from the outcome
Section titled “Choose the next step from the outcome”The runs of lessons 2 and 3 show these outcomes, and what each one means for the next change:
| What the measurement shows | Cause in the recordings | What to do |
|---|---|---|
CAUGHT with more than one form matches. |
A marker that other forms of the same issuer match too (weak-marker). |
Add a marker that only this form matches, and run 03_test_markers.sql. |
CAUGHT with the document has no text. |
The PDF is a scan (harbour-invoice-12-scanned.pdf). |
Read it with OCR, or as an image with a vision model (lesson 4). |
FALSE_ALARM. |
A check that does not fit a correct document (checks-v1, the credit note). |
Change the check, and measure again (lesson 2). |
CAUGHT or MISSED with named wrong fields. |
The model read a value wrong. This did not happen with the forms of this lesson. | Quote the printed label in a rule, or add a field pattern or a check (lesson 2). |
| The model writes many tokens for the line table. | The form has no line pattern: about 205 completion tokens for each Nordwind invoice, and about 106 for each Harbour invoice, whose lines a pattern reads. | Write a line pattern for a form with long tables. |
A form whose result stays wrong after a few rules is still useful: its documents go to a person, with the fields that the model read correctly as a start.