feat(reference): publish what an artifact CONTAINS, not just that it has a shape - #663
Open
beyondnetPeru wants to merge 4 commits into
Open
feat(reference): publish what an artifact CONTAINS, not just that it has a shape#663beyondnetPeru wants to merge 4 commits into
beyondnetPeru wants to merge 4 commits into
Conversation
…has a shape The registry names an artifact and points at its schema's $id. A consumer therefore learns that a PRD is required in discovery and still cannot find out what a PRD is supposed to contain: an $id is an identity, deliberately not a location, and nothing dereferences it. That gap is not academic. The satellite waiting on it evaluates gate criteria against a flat field map, and with no fields a tenant can configure a rule over a document that nothing will ever read — the gate ends up checking that a file exists and never what it says. Measured on a live tenant before this: 34 catalogued artifacts, zero field schemas with any field, zero criteria. So each registry entry now carries its FIELDS, derived from the schema the Core already ships. The schemas are not rewritten flat: they stay the source and this is a projection, so a schema change propagates on the next read instead of needing a second file kept in sync. Across the corpus that is 529 fields from 50 schemas — the PRD alone goes from nothing to 18, with types and requiredness. The type vocabulary is small on purpose: exactly what the existing criterion operators can judge. A type outside it yields a field no criterion can evaluate, which is worse than a missing one because it can be selected and never satisfied. Collections are omitted for the same reason — gte, in-set and regex all assume a single value — and REPORTED rather than dropped quietly, so someone counting 13 sections against 18 fields can see the difference is arrays and not a truncated schema. An unreadable schema leaves that one artifact without fields instead of failing the registry: one malformed file must not take down the catalogue every other artifact needs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: aarroyo <beyondnet.peru@gmail.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📊 Bilingual Coverage ImpactPR Changes
Repository Coverage
✅ Good: All EN changes have ES counterparts. Generated by GitHub Actions |
The labels these produce become the labels of a FORM — the satellite renders one input per field — so the case matters. Title Case makes a form read like a menu of commands rather than a set of questions, and it clashes with the sentence case the rendering surfaces use everywhere else; two cases on one screen look like two systems sharing it. The acronym list exists because there is no rule to replace it. Lowercasing every word turns `technicalFeasibilityId` into a label ending in "id", which reads as a mistake, and leaving the camel case alone gives "Id", which reads as a typo. Nothing in the spelling separates `id` from `is`, so the terms that get shouted are named one by one. The list is short deliberately: a term missing from it comes out as an ordinary word, which is merely plain, while a term wrongly in it comes out shouting. None of this runs for a schema that publishes a `title`. That is words chosen by whoever owns the shape, and no amount of string-splitting here improves on them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: aarroyo <beyondnet.peru@gmail.com>
The labels this publishes become the labels of a FORM in whatever consumes them, and until now every one of them was English. A Spanish reader got a Spanish screen wrapped around English field names, which is not a partial translation — it is the seam showing through at the exact place a person is being asked to write something. One language is computed and the other is written down, and the asymmetry is real rather than arbitrary: these keys ARE English, so a label derived from `cpuCoreLimit` is right by construction, while no amount of string-splitting turns an English identifier into Spanish. Word order alone defeats it — `technicalFeasibilityId` is «ID de viabilidad técnica», not three words in the order they were written. So the Spanish has to come from somewhere, and this is where. It is keyed by LEAF NAME, not by field path. 559 published fields across the corpus are only 348 distinct names, and keying by name is what makes `status` read «Estado» in all nineteen schemas that declare it instead of nineteen chances to say it differently. A schema whose context makes a shared word wrong can override it with `x-title-es` on the property — the glossary is an addition to what the schemas say, never a replacement. Both languages travel TOGETHER on every field. A consumer syncs this catalogue on a timer, tenant-agnostic and cached, and then renders it for whoever happens to be looking; publishing one language per request would mean either a fetch per reader or documents in the wrong language. Nothing here can take the catalogue down. A missing or unreadable glossary costs the Spanish labels and nothing else, and a field with no entry reaches a reader with its English name — plain, not broken. The catalogue is what every gate depends on, and no translation is worth failing it for. The guard closes both directions, because a glossary rots two ways. A field added with no entry half-translates a form, which nobody notices until a customer does. An entry left behind by a rename looks exactly like coverage and translates nothing. Neither is visible to any other check in this repository, which is the whole reason this one exists — and its tests were written against a version that only looked for the first kind. Descriptions are still English. They are 252 sentences rather than 348 names, they are prose rather than labels, and they belong in their own pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: aarroyo <beyondnet.peru@gmail.com>
The field names came out in Spanish and the headings above them did not, which is the same half-translation one line higher up: «Límite de núcleos de CPU» under «Technical constraints». The section was being recovered downstream by splitting the path, and that is the whole problem — splitting `technicalConstraints.cpuCoreLimit` yields «Technical constraints» and can never yield «Restricciones técnicas». The words belong to whoever owns the shape, headings included, so the enclosing object's name now travels down with the fields it holds. An object still is not a field: publishing the container as a field would offer a path whose value is a document, which no operator can compare. It is a name a person reads, which is a different thing, and it is carried as one. The glossary needed the 96 container names, and the guard needed to start demanding them. That second part is the point: without it the corpus could grow a section nobody translated and the only symptom would be one English heading in a Spanish form — which is exactly the kind of thing that ships. The guard's own tests were updated to say so, including the one that used to assert a container was NOT asked for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: aarroyo <beyondnet.peru@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the half of the artifact registry a satellite could not use.
The gap
The registry names an artifact and points at its schema's
$id. A consumer therefore learns that a PRD is required in discovery and still cannot find out what a PRD contains — an$idis an identity, deliberately not a location, and nothing dereferences it.That is not academic.
evolith_trackerevaluates gate criteria against a flat field map: a criterion resolves afieldPathand compares it. With no fields there is nothing to resolve, so a tenant can configure a rule over a document and nothing will ever read it — the gate checks that a file exists and never what it says.Measured on a live tenant before this change:
What this does
Each registry entry now carries its fields, derived from the JSON Schema this repo already ships.
The schemas are not rewritten to a flat shape. They stay the source and this is a projection, so a schema change propagates on the next read instead of needing a second file kept in sync.
Across the corpus: 529 fields from 50 schemas. The PRD alone goes from nothing to 18, with types and requiredness:
Three decisions worth reviewing
The type vocabulary is small on purpose —
text,rich-text,number,date,boolean,enum,url. It is exactly what the consumer's criterion operators can judge. A type outside it produces a field no criterion can evaluate, which is worse than a missing one: it can be selected in a rule and never satisfied.Collections are omitted, and reported.
gte,in-setandregexall assume a single value, so a list has no operator that can judge it. They are not dropped in silence:omittedFieldssays which and why, so someone counting 13 sections against 18 fields can see the difference is arrays and not a truncated schema. Corpus-wide that is 248 paths, all declared.An unreadable schema costs one artifact, not the catalogue. A malformed file leaves that entry without fields rather than failing the whole registry, which every other artifact depends on.
Verification
GET /phases/discovery/artifactsreturns the PRD with its 18 fields, and the Tracker'sartifact-field-schemas/prd— which used to answerbaseFields: []— now resolves themOrdering
The satellite side is a separate PR in
evolith_tracker. This one should land first: with the Tracker's change deployed against an older Core, its artifacts simply have no fields again until this follows.🤖 Generated with Claude Code