@campfire-interactive/required-assets-matcher
v0.1.0
Published
The Required Assets rules: requirements, documents, quote lines and satisfying links in, filled / partial / missing and unambiguous auto-matches out. Pure functions, zero dependencies.
Readme
@campfire-interactive/required-assets-matcher
The Required Assets rules, as pure functions. Requirements, the quote's documents, its finished goods and the links that already satisfy rows go in; filled / partial / missing, plus the auto-matches that are unambiguous enough to place, come out.
Zero dependencies, and a test enforces that. These rules decide whether a gate opens, so every consumer must be running the same function over the same inputs. A module that could reach for a database or a client would quietly make the answer depend on what that client could see.
import { matchRequiredAssets } from '@campfire-interactive/required-assets-matcher';
const result = matchRequiredAssets({
rows, // requirement definitions — master-data
documents, // the quote's documents — dms
lines, // the quote's finished goods — master-data
links, // which document already answers which row
linesAvailable, // see "failing closed" below
});The two rules that carry the design
Read these before wiring inputs. They are the reason the shape is what it is.
1. Satisfaction comes from the LINK, not the type. A row is filled because a document is joined to it, and for no other reason. The document type only decides whether an unclaimed document can become a candidate for a row. Two consequences worth stating: typing a row can never take away a satisfaction a tenant already had, and an untyped row still works exactly as it always did — somebody uploads through it.
2. A type that names two rows never auto-matches. If "Initial BOM" and "Final BOM" both point at the BOM type, a BOM arriving from somewhere else could belong to either, including as a new revision of the one already filled. A person decides; the rules do not guess. Only a type naming exactly one row on the quote can auto-match, and only into a slot that is empty.
Failing closed
The rules are used by gates, and a gate that opens because data was missing is worse than one that stays shut. Two inputs encode that:
linesAvailable: falsemeans the quote's finished goods could not be loaded — distinct from "the quote genuinely has none". Finished-good-grain rows then fail CLOSED: their expected count is unknown, so they are never reported satisfied. A consumer that omits the flag gets the safe answer.- An empty document list falls back to the links. A dms read that returned nothing does not retract a row that a link says is answered.
Who may write
Reading is anyone's. The auto-match write is not. A link recorded as placed "automatically" has to be trusted to have been placed by these rules, so only a service principal writes those. A browser-side evaluation should report candidates and let the person place them, which writes a link under their own name — the honest record for a human decision. DMS's uniqueness on the link is what stops two service writers placing the same document twice.
Vocabulary
The package speaks the platform's spelling, not any one app's. Grain is
'quote' | 'finished_good', matching master-data's column. Consumers holding a
different internal spelling map at their own boundary.
SatisfyingLink is a DMS link: a document joined to a requirement, carrying the
quote line it answers for, whether the rules placed it, and who placed it if a
person did. placedBy is optional and the rules never read it — it is there so
a consumer rendering provenance does not need a second lookup.
Versioning
These are rules, so the usual semver reading is sharpened:
- A change to what an existing input means — how
linesAvailableis interpreted, when a candidate becomes an auto-match — is a major, and consumers move in lockstep. Two apps on different majors can give different answers for the same quote, which is the one outcome this package exists to prevent. - A new optional input or output field is a minor.
0.xwhile the input types still have one move left in them: the satisfying link lands in DMS in phase 04c of the master plan.1.0once it has.
See also
nextgen/docs/plans/2026-09-10-documents-on-the-quote.md— the master plannextgen/docs/decisions/2026-09-12-quote-document-requirements-are-platform-data.md— why consumers compute rather than call omsf
