# Object → performer is the product; performer → objects is refused

> worklists.dev — 2026-08-20
> Written for ED-1 — the supply-chain ISV / traceability-vendor engineering org — the vendor engineer who has been asked by a customer for a per-person report and needs the argument for why this door will not build it.

One thesis: **object → performer is the product; performer → objects is refused.** The two are the
same join read in opposite directions, and a work door that answers one must refuse the other at
the point where a query is built, not at the point where a report is styled. That refusal is not a
missing feature. It is what makes the first question answerable at all.

## The two directions

Start from a bag of lettuce. A lot is under recall, and the question is: *who touched this pallet,
at which dock, inside which window?* That is object → performer. It is the question an auditor,
a customer and a chargeback panel ask, and a ledger of attested events with a task above each one
answers it exactly — a real *who*, at a real place, inside the window.

Now start from a person. *What has this receiver done this week?* That is performer → objects. It
is the same tables, the same join key, one `WHERE` clause moved from the object to the person. And
it is refused.

```
   object    → performer     "who touched this pallet?"      PERMITTED — it is the product
   performer → objects       "what has this person done?"    REFUSED
```

## Why the second one cannot be allowed

Because the attested *who* is what makes the first question answerable, and the attested *who* is
only present when performers have a reason to let it be. Identity on this door is regime-scoped.
Where a regulation requires the performer be identified — 21 CFR Part 11, OSHA 1910.178(l), FAA
14 CFR 43.9, HACCP monitoring — who-completeness is a compliance metric and it is legitimate. Where
nobody requires it, it is not sold. **A scope with no cited authority does not get the metric.**

The moment a door will answer *what has this person done*, every performer on it has a reason to
make sure the answer is flattering, and the cheapest way to do that is to stop scanning honestly.
The per-person report poisons the ledger it is drawn from. Refusing it is how the ledger stays
worth reading.

## Where the refusal lives

A rule that lives in the rendering layer is a rule somebody regresses by adding a column. So this
one is enforced where queries are **constructed**, at the four places a person-key can hide — the
same four the console's metric gate reads:

1. **The grain.** A query whose row grain is a performer is refused.
2. **The group-by.** A query that groups by a performer, role, team, department, crew, approver or
   warrantor is refused.
3. **The parameters** — names *and* values. The leak arrives as a reasonable-looking filter:
   `?performer=...` is obvious; a person hiding in a param value is not, and the package's test
   suite carries a poison fixture for exactly that.
4. **The rendered keys.** A face that would print a person as a column is refused before it
   renders.

`src/refusal/person-dimension.json` in the package copies the console's token artifact
byte-for-byte and adds this door's own terms, each with its reason. A test fails if the copied half
ever drifts.

## What is permitted, and checked to be permitted

Rendering an assignee or a role on a task is permitted and is **not** checked. A task's own record
shows who holds it; `trace` on a task shows its assignments. That is object → performer, and it is
the product. Half of the package's rule-6 tests assert the permissive side, because a gate that
quietly refused the legitimate direction would be a regression dressed as hardening.

Two further consequences for the integrator:

- A worklist query has no assignee member. "Me" comes from the auth rail; you cannot construct a
  query for someone else's list.
- A failed `claim` says *held*. It does not say who holds it, because that is performer → objects
  one task at a time.

## Never a per-unit-time figure

A per-person report is one shape of the refused direction. A per-unit-time figure is the other, and
it is refused even when it is not keyed by person, because it becomes one the moment anyone groups
it. The door computes no duration, no per-unit-time count, nothing that can be summed across
people and compared — not to the worker, not to any customer, not in any export. A count is
allowed. A timestamp is allowed. A step indicator within one task is allowed.

## For the vendor

Your customer will ask for the per-person report, and will describe it reasonably. The answer this
door gives is that the report and the evidence cannot both exist, and the evidence is what they are
paying for. *Who touched this pallet* is answered fully, with attestation, on a bag of lettuce or a
lot of ten thousand. *What did this person do* is a query the package refuses with a typed problem,
at construction, with a fixture proving it.

Get started by writing a query grouped by object and then by performer, and reading the two
responses. One is the product.

---
Get started: https://worklists.dev/get-access/ · All posts: https://worklists.dev/blog/ · Machine face: https://worklists.dev/llms.txt
