DEV Community

Cover image for Binding members to a persona without magic
Ernesto Herrera Salinas
Ernesto Herrera Salinas

Posted on

Binding members to a persona without magic

Automatic coherence sounds like magic, and magic in a library is a liability.
The entire job in this part of the design was making it trustworthy: it has to fire when it should, stay silent when it should not, and be explainable when you ask. Several decisions, one theme.

Binding: automatic, with an explicit escape

First, how does a member get attached to its object's persona? I shipped two paths on purpose.

The primary path is automatic. Semantic inference, which already recognizes FirstName and Email, binds those members to the object's persona, so Lie<Customer>.Generate() comes out coherent with zero configuration. That is the seed/demo win, and it has to be the default because it is the only thing that reaches the headline one-liner.

The escape path is explicit: a d.Person accessor you can read inside a With or Derive rule when you want precision. It is a complement, not a replacement, and an explicit rule always overrides the automatic binding.

Where it lives: a stage, not a patch

Coherence is not bolted onto the semantic matcher. It is its own resolver stage on the ordered pipeline I pre-paid for earlier in the series, driven by an entity descriptor that maps roles to facets. That choice is what allows the same machinery to later serve Address and Company by adding a descriptor instead of rewriting the matcher. It also gives Explain() a real, first-class thing to report.

Detection: borrow the truth you already have

Now the part that decides whether the whole feature is trustworthy. How does the engine know FirstName is a person facet and Name on a Product is not?

The tempting move is to give the persona its own table of names it owns. I did not do that, because then two tables can drift. Instead, the persona piggybacks the existing semantic candidate table: a member binds to a facet when the semantic candidate it already wins is one the persona claims. One source of truth, no drift. And the existing model-hint disambiguation comes along for free:
Product.Name already resolves to a product-name candidate, never a person one, so coherence inherits that false-positive avoidance without writing a line of new
guarding.

Activation: gate on evidence

The last question is: when does an object get a persona at all? Always-on would be reckless. So activation reuses the inference mode the library already exposes (Conservative, Balanced, Aggressive) as an evidence dial, and counts corroborating role members:

Conservative: needs a name anchor (FirstName/LastName/FullName)
Balanced:     a name anchor, or two correlated members
Aggressive:   one matched member is enough
Disabled:     never
Enter fullscreen mode Exit fullscreen mode

It is a build-time pre-pass, not a per-member check, and it self-limits the two-people collapse from the last post: prefixed, ambiguous members score low, so the mistaken merge only happens under Aggressive, where you asked for reach.

(Two smaller decisions ride along here: the explicit d.Person is a fixed snapshot of properties, not a generator, so reads inside a rule line up with the
auto-bound members; and reading it on an object with no activated persona materializes one lazily. That lazy draw is the one order-dependent corner in an otherwise eager design, and it is documented as such.)

Takeaway

Automatic behavior earns trust by reusing the system's existing truth and gating on evidence, not by inventing a parallel guesser that can drift or misfire. Magic
you can explain is just a feature. Magic you cannot is a support ticket.

What's next

I have been hand-waving one contractual detail: when exactly does a persona draw its random values from the stream? In a deterministic library, that is not a detail at all. Next post: the PRNG draw-tape, eager versus lazy.

Top comments (0)