Skip to main content

Upload who owns what

This page is for an administrator who keeps — usually in a spreadsheet — a list of who is responsible for which area of the business, and which products sit under it. You upload that list, Prism connects each owner to a person in your directory, and questions can then travel it: who is responsible for Payments, and what did the people under those owners do last month.

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. Owners are connected to people, and Prism has no people until a directory is designated as this installation's organisational context stream — a warehouse view, or an uploaded staff list for the weeks before there is one. Without one, the import stops at the first step and says so.

Where it happens. On Admin → Definitions, the Who owns what card opens Upload a CSV. Everything on this page happens there, in five steps, and nothing is stored until you press Import as a draft. Activating the draft afterwards is the definition's own button in the list, like every other definition. Making the calls is the same thing without the page, for scripting.

What the file has to look like​

A CSV with a header row and three kinds of column. You tell Prism which of your headings is which; it does not guess from their names.

Your columnWhat it isRequired
the ownerthe person responsible, spelled as your business spells themyes
the areawhat they are responsible foryes
the productswhat sits under that area, if you track itno

A minimal file is two columns:

Leader,Responsible for
Ada Lovelace,Ledger
Grace Hopper,Settlement

and one with products is three:

Leader,Responsible for,Products
Ada Lovelace,Ledger,Beacon;Lantern
Grace Hopper,Settlement,Compass

The one thing Prism will not guess​

What separates two products in one cell. In the example above it is a semicolon, and you type it in Products are separated by (the mapping's product_delimiter, if you are scripting). Prism splits on exactly that and on nothing else.

That is deliberate, and it is the one place this import asks you for something a spreadsheet does not carry. A comma is a separator in some organisations and part of a product's name in others. If one of your products is called Beacon, Lantern Edition, a comma is part of its name and not a separator — and only you know that. Guessing would split it in half silently, and the population that name selects would then be wrong rather than empty.

If you name a products column and no separator, the upload is refused and says so. If you have no products column, no separator is needed.

What happens when you upload​

Choose the file. Prism reads it straight away and stores nothing: it says how many rows and columns it found, which directory owners will be connected to, and lists your file's own columns, each with a few of its values. A file it cannot read — not UTF-8, a repeated heading, a ragged row — is refused here, naming the row.

Say which column is which. For each column choose the owner, the area, the products or not used, and type the product separator if you have a products column. Then press Read the table.

Reading the table stores nothing. Prism reports:

  • how many claims the table makes — one per owner/area/product row;
  • how many distinct owners it names;
  • how many of those it could place in your directory, and how;
  • any rows it could not read, by row number and why;
  • any exact duplicates — the same owner, area and product twice;
  • the groups this table would create, one for each area and each product, with how many owners each has — and whether a word is already in use.

Those are different numbers on purpose and Prism does not mix them. Four rows can be five claims, three owners and three people, and a table naming one person under two spellings has more owners than it has people. A single number would hide whichever of those you needed.

A name that matches more than one person is yours to settle. The page lists every such owner with the people it matched — each with the name fields your directory discloses for them and the key it identifies them by, which is what tells two people with one name apart — and a third answer, Neither — leave this owner unplaced. Choose, then press Read the table again: the owner moves from unplaced to chosen, and the counts are read again. It never picks for you: a figure reported about the wrong person is worse than a question that could not be answered.

A name that matches nobody is counted, not dropped. The rows stay in the table and the owner is reported as unmatched, so you can correct the spelling or accept that this person is not in your directory.

The groups this would create are listed last, and a word that is already one of your definitions is marked there, before you activate anything.

Import as a draft writes it, with the sizes stored beside it, once the table has a name and a one-line summary. It imports exactly what the page last read: change anything after reading — including while a read is still running — and the button goes back to not yet until you read the table again. A name that is already a definition of another kind is refused rather than replaced.

Importing asks your directory again, so if the directory changed in between, the stored counts can differ from the ones you read. The page shows the counts that were stored and says when they differ; check them before you activate. Nothing a reader asks is affected until you activate it in the list on Admin → Definitions, the same button every other definition uses.

The stored draft records the sizes and the grains that describe the table itself. It does not record the rows that were skipped or the duplicates, and it does not record what changed since your last upload — those describe the upload rather than the table, and you read them in the report above while you decide.

What activating it creates​

Activating the table creates one group for each area and each product in it, named exactly as your table names them, and those are what a reader asks about. A table naming Ada as the owner of Ledger makes a group called Ledger, so "how much did the Ledger team ship last month" works with no further setup.

Each group is everyone under that area's owners — not the owners themselves. If Ledger has two owners and Prism reports 41 people, those two are not among the 41. That is what "everyone under" means, and it is the same whether the owners sit in one chain or in different parts of the organisation: a director who owns a product jointly with their own manager is left out exactly as the manager is.

An owner Prism could not place adds nobody, and the answer says so. If Ledger names Ada and somebody the directory holds nobody of (or several people, with none chosen), the Ledger group is everyone under Ada. An answer about Ledger then says the table also names one owner Prism could not place, and that they add nobody to the group. It counts owners, not rows, so a name that appears on two rows is one owner. An owner the directory matched to several people, one of whom is already one of the group's owners, is not counted: they may be that person. Nor is one it matched to more people than it lists, since any of the unlisted may be. Asking who is responsible names them. A group compiled before 0.16.0 does not carry this count. Re-upload the table and activate it to get the sentence for it.

A word that is already in use is not taken. If you have defined Ledger yourself on Admin → Definitions, an area called Ledger will not overwrite it — the rest of the table still activates, and the report tells you which words are held before you activate, so you can rename the area in your file or withdraw the definition holding the word.

That includes a definition you have started and not activated. A draft holds its word exactly as a live definition does, because the two share one namespace and losing somebody's unfinished work to an upload is not a trade worth making.

A word you have withdrawn is free, and the group that takes it says so: its description reads this word was previously a withdrawn context document, so a name whose history shows two kinds has a visible reason.

Withdrawing the table withdraws the groups it created. Re-uploading it replaces them, and any area you have dropped from the file stops answering questions.

Replacing the table with something else of the same name does the same. If you write a context document under the name your ownership table had, the groups that table created go out of service with it — they would otherwise stay live under a table that no longer exists in any form you approved.

Asking who is responsible​

Once the table is active, a reader can ask "who is responsible for Payments?" and get the people, not a number. This is a lookup in your own file, not a walk of the org chart, and there are three answers.

The people, as your file spells them. Prism gives the owner's name exactly as your spreadsheet writes it, alongside the name your directory holds for the same person, and it names the table, the revision and the date that revision was activated. Both spellings are there on purpose: the first is what you can search your own file for, the second is what every other Prism answer will call them.

A name Prism could not place. If your table names somebody the directory does not hold, the answer says so in those words — the table names Marla Vint for Reconciliation, and this installation could not identify that person. It does not say the area has no owner. Your file made a claim, Prism could not connect it to a person, and both of those facts reach the reader. The fix is the one on Re-uploading a corrected table below: correct the spelling, or bind the owner by hand.

Note that the group for such an area does not exist — a group with no members would answer questions with zero — but the owner is still returned. Those are two different questions and Prism does not let the first silence the second.

A word nobody has claimed. If no table names the word, the answer says the word is not in your ownership table and lists what is. That is not "nobody owns it": nobody has told Prism who does. It also says nothing about whether there is data about the subject.

Who is responsible is not the same question as what the team did. The owners are not in the group named after their area — see the section above — so "who is responsible for Payments" and "what did the Payments team do" return different people by design. Ask both if you want both.

What is returned, and what is held back​

Returned: the owner's name — both spellings — and, where your directory allows it, their directory key.

Held back: email addresses, wherever they appear. If your directory is keyed on email the key is withheld. And if your own table spells its owners by address — a perfectly ordinary export — that address is replaced in the answer with [email address withheld], in the owner's name and in the sentence alike, and the answer says how many were removed. Internal addresses with no public domain (grace@localhost) count, and so does anything else shaped like name@host. Your people's addresses do not enter a chat answer because somebody asked who owns a product.

That does mean an answer can come back with a placeholder where you expected a name. It is telling you your table identifies that owner by an address; the fix, if you want the name shown, is to put a name in the owner column.

The per-person figure floor does not apply here, and that is deliberate: the floor exists so a figure cannot be traced back to an individual, and this is your own document saying who someone is.

Making the calls​

The page calls two routes you can call yourself, with a super-administrator session, the same as the page.

Both calls take the same JSON body: the file base64-encoded in data, and a mapping naming which of your headings is the owner, the area and, if you have one, the products, with the separator between products. The first stores nothing — and with no mapping at all it returns the file's headings, a few values of each and its row count, and looks nobody up:

# `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/ownership/inspect" \
-H "Content-Type: application/json" \
-d "{\"data\": \"$(base64 < owners.csv | tr -d '\n')\", \"filename\": \"owners.csv\",
\"mapping\": {\"owner\": \"Leader\", \"area\": \"Responsible for\",
\"products\": \"Products\", \"product_delimiter\": \";\"}}"

An owner that matched more than one person is reported with its candidates under owners[].evidence.candidates, each with person_key, called and the name fields your directory discloses (its own non-hidden name fields). Add choices once you have settled them: it maps the owner as your table spells it to the person_key you picked. POST /api/admin/definitions/ownership takes the same body plus name, summary, and base_revision: 0 for a new definition, or the revision you are replacing. It writes the draft.

When you re-upload, send the same name, so the report compares against the table that is active now, and send the revision that name is at now as base_revision. GET /api/admin/definitions lists it as latest_revision. Sending an older one is refused with a 409 that names the current revision.

Re-uploading a corrected table​

Upload the new file the same way, with base_revision set to the revision the name is at now (Making the calls says where to find it). Before you activate, Prism tells you if an owner you had previously connected to one person now matches somebody else, naming the owner and both people.

That is the change worth catching. Everything that owner's areas select would quietly become a different team's work, and no figure would look wrong.

Limits​

file size2 MB
rows5,000
distinct owners in one file250
distinct owners of any one area, or any one product50
distinct areas and products in one file250

These are fixed rather than settings, because a table of who owns what is a short document by nature — the ones we have been sent are a handful of rows.

The first three are about the file and the request. Each distinct owner is one lookup against your directory, which is why there is a limit on how many one file may name.

The last two are different, and they are about the question rather than the file. Each area and each product in your table becomes a group Prism can be asked about by name.

Fifty owners of one area or product. That group is everyone under its owners, so answering it walks your directory once per owner, all in one query — and the cost of that query grows with the size of your directory as well as with the number of owners. Fifty is where a large directory still leaves most of the time budget for the rest of the question. A group nobody can be asked about is not worth importing.

Two hundred and fifty areas and products in one file. Each one is a group with a name of its own, so a file describing hundreds of them is a list of work rather than a statement of who is responsible for what.

Both checks run when the file is read, before any lookups, and name the column and the rows rather than the value. In practice both are generous rather than tight: an ownership table names a handful of people per area and a manageable number of areas. If you meet either, the likeliest cause is the same one — the column you mapped as the area or the product is not the one you meant.

One word cannot be both an area and a product. They would become one group with one name, and a reader asking about that word would get one of them with no way to tell which — so a file using a word both ways is refused, naming the rows rather than the word.

If you meet any of them, the file is probably an export of something larger than an ownership table — a directory or a project list — and the refusal says which limit it met.

What this does not do​

It does not map a product to repositories or Jira projects. Prism does not know which code implements Compass. What it can do is select the people under the owners of Compass, and report their activity — labelled as exactly that, their activity, and never as "all work on Compass". If some of that work was on something else, that is true and the answer says so.

It does not keep history. The table you upload is what is true now, and a question about last quarter is answered using it — Prism does not invent who owned something in April.

The answer says so. A figure for last quarter over the Ledger group is the people under Ledger's owners today, measured over last quarter's work. The answer says that the membership is not from the period asked about, and it states no observed zero for that window: somebody who joined afterwards would otherwise read as having done nothing in a quarter they were not here for. See the four participation counts.