You read a TRACE FILE -- the production records a site holds for one trace request -- and return a REVIEWER'S TRACE WORKSHEET: the genealogy of one suspect raw-material lot. You return JSON and nothing else.
You are preparing a worksheet for a qualified reviewer. You never decide a recall, never place a hold, never withdraw or release stock, never notify a customer and never open a regulatory file. Your job is to say what the records state, apply the rulebook given below, and NAME THE LINKS THE RECORDS DO NOT ESTABLISH.
RULES, in order of importance:
1. ONE OBJECT PER NODE THE RECORDS PUT DOWNSTREAM OF THE SUSPECT LOT, AND NO OTHERS. A node is a production batch, a finished lot or a consignment. Work outward from the suspect lot: the batches that consumed it, the finished lots those batches were packed into, and the consignments that carried those finished lots.
2. FOLLOW THE CHAIN ALL THE WAY, INCLUDING THROUGH REWORK. A rework record that re-enters recovered material from a batch already on the worksheet into a LATER batch puts that later batch on the worksheet too -- and its packaging run, its finished lot and its consignment after it. A trace that stops at the first hop is wrong and looks complete.
3. A MATERIAL NAME IS NOT A LOT NUMBER. A batch that consumed a DIFFERENT lot of the same material is NOT on the worksheet, and nor is anything downstream of it. A batch ticket that names the material and records NO lot against it IS on the worksheet, with `link_state` 'not_determined'. Those two lines look almost the same and they are opposite answers.
4. THE CHAIN STOPS AT A LINK THE RECORDS DO NOT ESTABLISH. Report a node whose `link_state` is 'not_determined'; do NOT report what lies beyond it. The records do not say the material got that far, and putting the lot beyond it on a recall worksheet places stock there that nothing in the file places there.
5. REPORT WHAT THE RECORDS STATE. `source_record`, `identity_link` and `outflow` are readings of the paperwork, not judgements about it. If nothing in the file says what became of a node, `outflow` is 'silent' -- that is a finding about the records, not a gap in your answer.
6. `link_state` IS DECIDED ONLY BY THE RULEBOOK BELOW, from `source_record` and `identity_link`. Work through the five steps IN ORDER and STOP at the first that fires. In particular a shipment note that names ONLY the packaging code stamped on the cases, where a packaging run records that code against the finished lot, is 'established_by_pack_code' and never plain 'established'.
7. `disposition` IS DECIDED ONLY FROM `outflow`: 'shipment_recorded' -> 'left_site', 'consumed_onward' -> 'moved_on', 'held_in_stock' -> 'on_site', 'silent' -> 'not_determined'. It is asked of every node independently of its link call.
8. 'not_determined' IS A REAL ANSWER AND YOU ARE EXPECTED TO USE IT. A trace that never reaches for it is guessing, and a link recorded as established is a link nobody goes looking for.
9. Copy every code verbatim from the file. `reached_from` is ONE HOP BACK -- the suspect lot only for a batch that consumed it directly. Use the exact allowed value for every field that lists them, and return every field for every node.
GENEALOGY RULEBOOK (the authority for `link_state` and `disposition`; this is an ILLUSTRATIVE rulebook written for this kit, and it reproduces no traceability standard, regulation or company trace procedure)
WHAT IS ON THE WORKSHEET
- A node is on the worksheet if a record in this file puts it downstream of the suspect lot - directly, or through another node already on the worksheet.
- A CHAIN STOPS AT A LINK THE RECORDS DO NOT ESTABLISH. A node whose link_state is `not_determined` is ON the worksheet, because naming it is the whole point; what lies beyond it is NOT, because the records do not say the material got that far. The worksheet reports the candidate and stops.
- A batch that consumed a DIFFERENT lot of the same material is NOT on the worksheet, and nor is anything downstream of it. The material name is not the lot.
- A batch that consumed an unrelated material is NOT on the worksheet.
- REWORK FORKS THE CHAIN AND DOES NOT END IT. A rework record that re-enters recovered material from a batch on the worksheet into a LATER batch puts that later batch on the worksheet too, with everything downstream of it. Stopping at the first hop is the commonest way a trace comes back short.
NODE KINDS
batch a production batch, recorded on a batch ticket, that consumed material
finished_lot a finished lot produced by a packaging run from one batch
shipment a consignment recorded on a shipment note that carried a finished lot off the site
THE THREE STATED FACTS, read off the records for every node
source_record:
code_recorded the record that puts this node in the chain names the material it received BY CODE - a lot code, a batch code, a finished lot code or a packaging code
material_only the record names the material, the description or the product and records NO code against it
not_recorded the record does not state what this node received at all - it names the node, and declines to record what went into it
identity_link:
same_code the code the record uses is the upstream node's OWN code, and resolves directly. This is also the value when the record records no code at all, because no packaging code is in play
via_pack_code the record names only a PACKAGING CODE, and a packaging run in this file records that packaging code against the upstream node - so the code resolves, through a substitution
pack_code_unmatched the record names a packaging code that NO packaging run in this file records against anything - so it resolves to nothing
outflow:
shipment_recorded a shipment note in this file records this node leaving the site
consumed_onward a later batch ticket, rework record or packaging run in this file records this node being consumed
held_in_stock a stock position line in this file records this node still on site
silent no record in this file says what became of it
THE LINK CALL -- work through IN ORDER, stop at the first that fires
1. NO INPUT RECORDED. If source_record is `not_recorded`, the worksheet records `not_determined`. A record names this node and declines to say what went into it, so the records do not tie it to the suspect lot however plainly they name the node itself.
2. A MATERIAL NAME IS NOT A LOT NUMBER. If source_record is `material_only`, the worksheet records `not_determined`. The record names the material and records no lot against it, so this node MAY have consumed the suspect lot and the paperwork does not say. This is the branch a confident reader skips, because the material name matches and matching feels like evidence.
3. A PACKAGING CODE NOTHING RECORDS. If identity_link is `pack_code_unmatched`, the worksheet records `not_determined`. A code that appears in one record and nowhere else ties nothing to anything.
4. TIED THROUGH A PACKAGING CODE. If identity_link is `via_pack_code`, the worksheet records `established_by_pack_code`. The link HOLDS - a packaging run records that code against this node - but it holds through a code substitution rather than through the node's own code, and a reviewer has to be able to see which links rest on that.
5. ANYTHING ELSE. The worksheet records `established`.
THE DISPOSITION CALL
1. If outflow is `shipment_recorded`, the worksheet records `left_site`.
2. If outflow is `consumed_onward`, the worksheet records `moved_on`.
3. If outflow is `held_in_stock`, the worksheet records `on_site`.
4. If outflow is `silent`, the worksheet records `not_determined`. The disposition question is asked of every node INDEPENDENTLY of its link: a node the records do not tie to the suspect lot still either has a stated outflow or it does not.
WHY `not_determined` IS A REAL ANSWER
A trace worksheet that never says `not_determined` is not a complete trace, it is a confident one. The whole value of this shape is that a reviewer can see, in one column, which links the records actually establish and which ones somebody has to go and find the paperwork for. Over-confidence here costs more than caution in both directions at once: a link recorded as established is a link nobody goes looking for, and a chain that stops silently is stock nobody knows is out there.
Return these:
- trace_id (string) -- the trace request reference from the Trace Request section, verbatim
- suspect_lot (string) -- the raw-material lot code the Trace Request names as suspect, verbatim
- lot_remainder (enum) one of: remainder_in_stock, fully_consumed, not_stated -- what the Stock Position section says about the SUSPECT LOT ITSELF. 'remainder_in_stock' when a line records a remaining quantity of that lot still on site; 'fully_consumed' when a line records the lot fully issued to production with none remaining; 'not_stated' when the Stock Position section says nothing about the suspect lot. This is about the raw-material lot, never about a finished lot
- nodes (array of objects) -- one object per node the records put downstream of the suspect lot, each carrying:
- node_code (string) -- the code of this node, verbatim (for example BA-4417, FL-50231, SH-8802). THIS IS THE KEY -- one object per node the records put downstream of the suspect lot, and no others
- node_kind (enum) one of: batch, finished_lot, shipment -- what kind of thing this node is: a production batch, a finished lot produced by a packaging run, or a consignment on a shipment note
- reached_from (string) -- the code of the IMMEDIATE upstream node this one was reached from, verbatim -- the suspect lot code for a batch that consumed it directly, the batch code for a finished lot, the finished lot code for a shipment, and the SOURCE batch code for a batch reached through a rework record. One hop back, never the suspect lot for anything but a first-hop batch
- record_ref (string) -- the code of the record that makes this step, verbatim -- the batch ticket, rework record, packaging run or shipment note that ties this node to `reached_from` (for example BT-2140, RW-3301, PK-5512, SN-8802)
- source_record (enum) one of: code_recorded, material_only, not_recorded -- what that record says about this node's INPUT. 'code_recorded' when it names the input by code -- a lot code, a batch code, a finished lot code or a packaging code. 'material_only' when it names the material, description or product and records NO code against it. 'not_recorded' when it names no input at all. Report what the record says -- this is NOT on its own what decides `link_state`
- identity_link (enum) one of: same_code, via_pack_code, pack_code_unmatched -- how the record ties this node's OWN identity. 'same_code' when the record names this node's own code. 'via_pack_code' when it names only a PACKAGING CODE and a packaging run in this file records that packaging code against this node. 'pack_code_unmatched' when it names a packaging code that no packaging run in this file records against anything
- outflow (enum) one of: shipment_recorded, consumed_onward, held_in_stock, silent -- what this file records about what became of this node. 'shipment_recorded' when a shipment note records it leaving the site; 'consumed_onward' when a later batch ticket, rework record or packaging run records it being consumed; 'held_in_stock' when a stock position line records it still on site; 'silent' when nothing says
- link_state (enum) one of: established, established_by_pack_code, not_determined -- the worksheet's link call for this step, decided STRICTLY by the shipped rulebook from `source_record` and `identity_link` and nothing else. Work through the five steps IN ORDER, stopping at the first that fires. (1) source_record 'not_recorded' -> 'not_determined'. (2) source_record 'material_only' -> 'not_determined': A MATERIAL NAME IS NOT A LOT NUMBER. (3) identity_link 'pack_code_unmatched' -> 'not_determined'. (4) identity_link 'via_pack_code' -> 'established_by_pack_code', never plain 'established'. (5) anything else -> 'established'
- disposition (enum) one of: left_site, moved_on, on_site, not_determined -- the worksheet's disposition call, decided STRICTLY from `outflow`: 'shipment_recorded' -> 'left_site', 'consumed_onward' -> 'moved_on', 'held_in_stock' -> 'on_site', 'silent' -> 'not_determined'. Asked of every node independently of its link call
Return a JSON object with exactly these top-level keys: trace_id, suspect_lot, lot_remainder, nodes
`nodes` is an array. Return it empty only if no record in the file puts anything downstream of the suspect lot at all.
TRACE FILE
----------
Synthetic Record
----------------
Every site, material, code, quantity and consignee in this file is invented for a worked
example. No real plant, company, supplier, customer, product, consignment or person is described
here, and no traceability standard, regulation or company trace procedure is reproduced or
named.
Trace Request
-------------
TR-13846
Suspect raw-material lot: RM-50699
Material: Pectin blend PX-40
Raised with the quality desk for a genealogy assembly. No hold has been placed and no customer
has been contacted.
Receiving Note RC-6375
----------------------
Lot RM-50699, material Pectin blend PX-40, received 2026-08-05.
Quantity booked in: 876 kg.
Receiving Note RC-9113
----------------------
Lot RM-45397, material Pectin blend PX-40, received 2026-08-06.
Quantity booked in: 244 kg.
Batch Ticket BT-9992
--------------------
Batch BA-5863, made 2026-08-09 on line 3.
Consumed: Pectin blend PX-40, lot RM-50699, 190 kg.
Consumed: Calcium carbonate CC-08, lot RM-55381, 21 kg.
Batch Ticket BT-1850
--------------------
Batch BA-3455, made 2026-08-10 on line 3.
Consumed: Pectin blend PX-40, lot RM-50699, 418 kg.
Consumed: Pectin blend PX-40, lot RM-45397, 58 kg.
Consumed: Calcium carbonate CC-08, lot RM-55381, 36 kg.
Batch Ticket BT-1579
--------------------
Batch BA-5566, made 2026-08-12 on line 3.
Consumed: rework tray contents, 70 kg.
Consumed: Calcium carbonate CC-08, lot RM-55381, 23 kg.
Rework Record RW-1076
---------------------
Batch BA-5863 sent 70 kg of recovered material to the rework tray on 2026-08-10. Tray contents
were re-entered into batch BA-5566 on 2026-08-12. The tray is not segregated by batch and this
record does not state which batch's material entered BA-5566.
Packaging Run PK-2980
---------------------
Batch BA-5566 packed 2026-08-14 as finished lot FL-95813.
Cases stamped: PC-2897.
Packaging Run PK-9878
---------------------
Batch BA-3455 packed 2026-08-12 as finished lot FL-96151.
Cases stamped: not recorded on this run.
Shipment Note SN-9972
---------------------
Consignment despatched 2026-08-15 to consignee CN-1691.
Cases stamped PC-2527, 218 cases.
Stock Position
--------------
Batch BA-5863: held in quarantine on site, not packed.
File Notes
----------
Circulated for genealogy assembly only. Nothing in this file has been actioned; the disposition
of every lot named here remains as recorded above.