postulo-identifiers: one registry with a subject matrix, because ISNI is both #109
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Depends on
#99 Europass becomes an internal plugin
Postulo/postulo
Reference
Postulo/postulo#109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observation
The separation asked for already exists — and that is the least interesting part
Two registries, both built on the same
core.identifiers.Scheme:CompanyIdentifier.schemetakesjobs.identifiers.CHOICESand a person's takesaccounts.identifiers.CHOICES, so a company scheme cannot appear on a person today. Themodule says why:
So this issue is not for the separation. It is for the sentence above being wrong in an
interesting way, and for what the separation costs.
The sets are not disjoint, and pretending they are loses real identifiers
Three of these identify people and organisations, and the split has quietly picked a side
for each:
So a researcher cannot record their Wikidata item, and a university cannot record its ISNI
— which most of them have, and which is exactly the identifier an EU application form asks
an institution for. Neither is a bug anybody filed; both follow from the sets being kept in
two files that never had to agree.
The matrix fixes that by construction: a scheme says which subjects it can identify, and
three of them say both.
What the plugin would be, and why this one fits where contact details did not
Schemes are data and behaviour, not tables.
CompanyIdentifierandPersonIdentifierstay exactly where they are, in core, owned and migrated by core. What a plugin contributes
is the registry: a key, a label, a pattern, a checksum, a link template, an example, and
the subjects it applies to.
That is the difference from #100's second half. Contact details would have needed a plugin
to own a table, and plugins cannot. A scheme owns no rows.
And there is a real itch behind it.
registeris one generic scheme for every nationalcompany register — SIRET, NIF, Companies House, KvK, Handelsregister — each with its own
format and its own checksum, none of which Postulo validates. A plugin per country could,
and that is precisely the case
registry.pydescribes: "the person who cares about aparticular job board... should not have to wait for this project to accept a patch".
The matrix, and what it must enforce
absent from a dropdown. That is what makes the requested guarantee a guarantee: today it
rests on which module the choices were imported from, which is a convention, and a
convention holds until somebody wires a form up differently.
otherstays available to both, which it already effectively is — it is the one key inboth registries today, and that overlap is the hint the matrix is the right model.
Care needed
No validation may get weaker. ORCID has a checksum and the module is pointed about why:
"the checksum catches the typos that a lookup would — which is the entire reason ORCID has
one." Merging registries must carry every pattern and every check across, and the existing
tests should pass unchanged rather than be adjusted to fit.
Existing rows carry scheme keys. Any key that changes is a data migration, and there is
no reason for one to change — the keys are already distinct across the two registries except
other, which staysother.Nothing may start touching the network. Both modules say so, twice, and a plugin
contributing a scheme must not be the loophole: a scheme validates what was typed and knows
where it links, and looking an identifier up somewhere else is "a deliberate act for
another day".
Scope
identifierplugin kind, the way #99 addedimporter— internal only, no third-partygroup advertised until there is a contract for one.
postulo-identifiersas the internal plugin, holding both registries and the subjectmatrix, with the identity fields from #97.
subjectsonScheme, and a model-level check that refuses a mismatch.given an LEI through any route including the API; a company can be given an ISNI.
Classification
Enhancement. Depends on #97 for the identity fields and on #99's kind machinery as the
worked example.
Done in
fea7b090.The matrix
Schemegainssubjects, and three of them say both:otherSo a university can record its ISNI and a researcher their Wikidata item, neither of which was possible before. Everything else keeps the side it had.
One scheme identifying two subjects turned out to need two addresses, which is a thing two registries could never have said: a LinkedIn company page is
/company/<slug>/and a personal profile is/in/<slug>/.Scheme.person_linkexists for exactly that, and/in/joins the paths a pasted URL is lifted from.The guarantee, made a guarantee
Your ask was "no valid company identifier is shown on the user data", and you were right that the existing separation was a convention rather than a rule. It is now three things at once:
schemes_for(subject)— the picker offers only what applies, as before;Identifies("person")) that travels with the column, so a form and an import get the same answer;save()on both models, because refused at the model has to meanobjects.createtoo. That is the route a form never takes and an importer or a plugin might, and it is the one that decides whether this is a guarantee or a habit.accounts.identifiersandjobs.identifierskeep their whole public surface but every function in each is scoped to its subject, so an LEI reaching the person's side is unknown scheme rather than badly formatted — which is the honest answer: there is no such scheme for a person.What kind of plugin this is
The
identifierkind is new and does two things differently, both deliberate.It governs nothing. Every other kind answers is this on for this person; this one answers what does this key mean. Switching it off would leave every stored identifier without a label, a link or a check, which is not what off means anywhere else in Postulo — so it joins
transportinUNGOVERNED_KINDS, for a different reason from the transport's.It advertises no entry-point group, and that is how "internal only" is enforced rather than intended:
GROUPS["identifier"] == ""and_load_third_partyreturns nothing for an empty group. When there is a contract worth promising, the group is one string.You were right that this fits where contact details did not: a scheme owns no rows.
PersonIdentifierandCompanyIdentifierstay in core, owned and migrated by core.Nothing got weaker
Every pattern, both checksums, every URL-lifting rule and every normalisation came across. The per-scheme behaviour that used to be
if scheme_key == ORCID:in two modules is now carried by the scheme itself (tidy,checksum,checksum_message,segments,lower), which is what made one table possible without one long branch.tests/test_identifiers.pyandtests/test_person_identifiers.pypass unchanged apart from one line that readidentifiers.SCHEMESand now readsidentifiers.schemes(). That was the check that mattered most — a merge is exactly where a validation quietly goes missing.No key changed.
choicescame off both columns, for the same reason it came offCV.themein #132: choices are frozen into every migration, so a scheme from a plugin could never be one. Every existing row keeps its value, and both migrations areAlterFieldwith no data step.The itch, acknowledged
registeris still one generic scheme for SIRET, NIF, Companies House, KvK and Handelsregister alike, validated no further than a two-letter country prefix. That is now a plugin's job to improve rather than a patch to this repository — which is the caseregistry.pydescribes, and the reason the kind exists at all. The module says so where somebody looking atregisterwould read it.Also
postulo-identifiersships its ownlocale/, 68 catalogues, with every existing translation carried across rather than re-typed. Three strings are new; all 39 European catalogues carry them.tests/test_identifier_registry.py, 27 tests. Suite 4330 passed, 29 skipped; browser suite 54 passed.docs/PLUGINS.mdgains Identifier registries, and its list of shipped plugins is now eleven across eight kinds rather than the seven it still claimed.