Upload a classification of your people
This page is for an administrator who keeps — usually in a spreadsheet — the list of combinations that decide who counts as something: which job family, job profile and business title together mean developer, or which business unit and worker type together mean field engineer. You upload that list, Prism counts what it would select in your directory, and questions can then be scoped to it: how many pull requests did developers merge last month, with developer meaning exactly what your list says.
It takes about ten minutes. Nothing leaves your network: the file goes from your machine into your own appliance, and Tetrate never sees it.
You need a connected directory first — and its rows have to be in Prism's memory. A classification names values in your directory's own columns, so there is nothing to count until a directory is designated as this installation's organizational context stream, and until its rows have been ingested. An uploaded staff list or a
snapshotinstance of your warehouse view both qualify. Aquery-throughdirectory does not: its rows are never copied into Prism's memory, and the import says so rather than counting nobody.
What a classification is
A classification is one of Prism's definition kinds. It is a named list of accepted combinations over one or more fields of your directory, and it selects every person whose row matches any one of them.
The one thing to understand before you upload is what a row means:
-
A row is an AND.
Accounting, Analyst II, Software Engineerselects a person whose job family is Accounting and whose job profile is Analyst II and whose business title is Software Engineer. -
The list is an OR. Two rows select everyone who matches either.
-
It is never three column lists. Given
Job Family,Job Profile,Business TitleAccounting,Analyst II,Software EngineerAdministrative,Coordinator,Developerthe classification selects those two combinations and nobody else. It does not select everyone whose family is Accounting or Administrative, whose profile is Analyst II or Coordinator, and whose title is Software Engineer or Developer — that reading would admit
Accounting, Coordinator, Developer, a combination you did not list, and on a real file an administrative coordinator was counted as an engineer that way. Prism's statement for a classification cannot express the wrong reading; the file is matched row by row. -
It is a membership list, not a verdict on everyone else. A person no row names is unclassifiable. They are not a confirmed non-developer; they are somebody your list did not mention. Prism reports that number beside the number it selected, and never lets a reader subtract one from the other and call the remainder a population.
One field is a valid classification. Business Unit alone, with one row
Northwind, is how you say "Northwind is a business unit".
What the file has to look like
A CSV with a header row and one column for each directory field you want
to bind. Other columns are ignored. Values are matched as text against your
directory's own values, ignoring case and surrounding space — sw development
matches SW Development; Sw Dev does not.
Employee,Job Family,Business Title
E1,Accounting,Software Engineer
E3,Administrative,Developer
E5,SW Development,Sr Developer
You tell Prism which of your columns holds which directory field. It does
not guess from the heading text — Job Profile, job_profile and Profile
are one column to a person and three to a matcher, and a guess that landed on
the wrong field would build a population nobody asked for. It does not ask you
to type either side, though: it reads your file's first row and lists your
columns, each with a few of its values, and for each one you choose, from the
fields your organizational context stream declares, what that column is — or
leave it as not used. The mapping that makes is:
{"job_family": "Job Family", "job_title": "Business Title"}
The fields offered are the ones on your organizational context stream's
manifest — the same names Admin → Context streams shows. A field the
manifest marks hidden is offered and marked hidden on the stream, and
choosing it is refused with its own sentence, because it is there and you can
unhide it. The Employee column in the example is left as not used, so it
never enters the definition.
What happens when you upload
On Admin → Definitions, under Import a classification from a file, choose the file. Prism reads it straight away and stores nothing: the line under the file picker says how many rows and columns it found, and Columns lists your file's own columns, each with a few of its values so you can tell which is which without opening the spreadsheet. A file Prism cannot read — not UTF-8, a repeated heading, a ragged row — is refused here, before you have mapped anything, naming the row or the column.
Then, for each column you need, choose the directory field it holds, and leave the rest as not used. Name the definition, write the one-line summary, and press Check the file.
The summary is required, and Check the file does not ask for it. Checking reads the file and stores nothing, so it passes with the box empty; Import as draft writes a definition, and a definition with no summary is refused — "a definition needs a one-line summary: it is what the agent reads to decide whether this definition is what the reader meant". Write it before you check, and the refusal never arrives.
Step one reads the file and stores nothing. Prism reports two things side by side, and it is worth reading both.
What the file said:
| rows | how many data rows the reader found — the header not counted, and a completely blank line not counted either |
| combinations | how many it kept — the rows, less exact duplicates |
| duplicates | identical rows, removed. Untidy, not ambiguous, and not refused |
| case variants | rows that differ only by case or surrounding space. Kept, and counted so you can see them |
What the directory said, measured by the same statement every answer will use:
| people | distinct people in your directory this classification selects |
| directory people | distinct people in the directory at all — the denominator, because 1,874 means nothing without it |
| unclassifiable | distinct people no combination names — unclassifiable is the key's name in the report and in the stored counts |
| combinations naming nobody | rows that match no person at all |
Person counts come from your directory's own key, never from the row count of the file. A 4,290-row list is not 4,290 people, and a directory that keeps three monthly snapshots reports each person once.
Combinations naming nobody is where a dirty value surfaces. #NAME? — what
Excel leaves in a cell whose formula failed — is kept as a value, matched like
any other, matches nobody, and lands here as a number you can act on. Prism
does not silently correct it, because it does not know what you meant. A
large number here with the people count near zero usually means a column was
mapped to the wrong field.
Check the row count against your spreadsheet
This is the number to read before anything else. A file that was cut off — an export that stopped, a copy that lost its tail — is not always refusable, because a shorter list of combinations is still a valid list:
- a cut that lands in the middle of a row leaves a row with too few cells, and the upload is refused naming that row;
- a cut inside a quoted value leaves the file invalid as CSV, and the upload is refused naming the line;
- a cut on a line boundary leaves a perfectly good file of fewer rows, and nothing can tell. The rows figure is what tells you.
If your spreadsheet has 4,290 data rows and the report says 2,000, do not import it. The definition would activate, report a plausible number of people, and be wrong about everyone in the missing half.
Step two writes a draft, with the four directory numbers stored beside it, measured by the same counter the Re-preview button in the definition's history runs. A classification you type as JSON on the same page is counted the same way, against the same designated directory. Nothing a reader asks is affected until you activate it on the same page, the button every other definition uses. The stored draft records what the directory said; it does not record the row count, the duplicates or the case variants — those describe the upload rather than the definition, and you read them in the report while you decide.
What is refused, and what is not
Refused, naming the row or the column, with nothing stored. A row is named by its data row number — the first row after the header is 1, and a completely blank line is not counted:
- a blank cell in a mapped column. In the file, a trailing separator and a deliberate "these people have no job profile" are the same bytes, and the two want opposite treatment. A directory value that is genuinely empty cannot be named by a classification in this version; leave those people out and they are counted as unclassifiable;
- a ragged row — more or fewer cells than the header;
- a heading repeated in the first row, or a mapped heading the file does not carry;
- a file that is not UTF-8 CSV — a UTF-16 "Unicode Text" export, a
workbook saved as
.csvin name only; - a mapping key the directory does not declare, or one it hides;
- a file with no data rows — a filter that matched nothing exports as a header alone, and a classification of no combinations would answer a confident zero.
Not refused, and reported instead: exact duplicates, case variants, and a value that names nobody.
Re-uploading a corrected file
Upload the new file under the same name. Prism writes it as the next revision — you will be asked for the revision you are replacing, which the page fills in — counts it again, and you activate it the same way. The previous revision stays readable, so an answer given last month that named it can still be read back.
Limits
| file size | 8 MB |
| rows | 50,000 |
| fields in one classification | 8 |
| length of one value | 500 characters |
These are fixed rather than settings. A classification is the combinations that decide membership, and the file this feature was built for is 4,290 rows of three short values — a third of a megabyte. A file that meets one of these is almost always the directory itself rather than the list that classifies it, and the refusal says which limit it met.
What this does not do
It does not change how any figure is calculated. A classification tells Prism what a word means — who developers are — and nothing else. It cannot alter a metric, a required filter or a disclosure floor, because none of those reads it.
It does not resolve names. A classification names directory values, not people, so there is nobody to look up and no ambiguity to settle. Who is in it is whoever the directory's rows say, at the moment a question is asked.
It does not infer. A misspelt value stays misspelt and names nobody; the report shows it as a combination naming nobody, and the fix is in your spreadsheet.
For scripting
The page calls routes you can call yourself, with the file base64 encoded in a
JSON body. inspect with no mapping reads the file and returns its
headings, up to five values of each column (each cut at 60 characters) and its
row count, measuring nothing; with a mapping it reads, counts and stores
nothing. GET /api/admin/definitions/fields returns the fields your
organizational context stream declares, each with hidden set as the manifest
says. POST /api/admin/definitions/tuples writes the draft.
Every one of them needs a super-administrator session, the same as the page.
# `tr -d '\n'` because GNU and busybox `base64` wrap their output at 76
# columns and macOS's does not; the JSON needs one unbroken string either way.
curl -sS -X POST "https://<host>/api/admin/definitions/tuples/inspect" \
-H "Content-Type: application/json" \
-d "{\"data\": \"$(base64 < developers.csv | tr -d '\n')\", \"filename\": \"developers.csv\",
\"mapping\": {\"job_family\": \"Job Family\", \"job_title\": \"Business Title\"}}"
POST /api/admin/definitions/tuples takes the same body plus name,
summary, optional aliases, and base_revision — 0 for a new definition,
or the revision you are replacing.