Skip to content

Compatibility

An installed CLI is not updated when the portal is. Changing what the portal answers breaks machines nobody touched — and the breakage shows up nowhere until someone runs a pipeline that already worked.

There are two layers, they break in different ways, and they are easy to confuse.

The fields the portal invents: namespace, nome, versao, efeitos, privilegioMaximo, dependenciasAdicionais, depreciada.

Rule inside /api/v1: additions only.

Change Allowed Why
new field yes the CLI ignores what it does not know
rename a field no the CLI reads by name
remove a field no same
change the type no "1" and 1 are not the same thing on the other side
always-present field becoming sometimes-absent no that is conditional removal

Nulls travel explicitly: motivoDepreciacao arrives as null when there is no deprecation, rather than disappearing. The shape of the response does not change with the data.

Breaking any of these rules requires /api/v2 served in parallel — v1 does not go away while there is an old CLI installed, and there is no way to know there is not.

What guarantees it. CatalogoApiTest freezes the shape of every response, including the field count. Renaming a record field turns the test red. It has been verified that it actually fails when that happens — a contract test that does not catch the break is worse than none, because it gives false confidence.

When the portal refuses, the body is a ProblemDetail (RFC 9457) with three things, each serving a different reader:

Field For whom Stability
HTTP status the CLI contract
codigo the CLI contract
detail the person none — it is prose, and it changes language
problemas the person a list, only on 422

codigo exists because status alone is not enough: two 403s can call for opposite actions. “You are not a member of the organisation” says to ask for the role; “this task has maintainers and you are not one of them” says to ask for maintenance — and sending the first to someone who is already a publisher makes them go looking for access they have.

The CLI decided that by looking for the word mantenedores inside detail. It worked, and it would have silently stopped working on the portal’s first translation: wrong hint, no failure, same exit code. That is the worst kind of break — the one that does not show.

The rules match layer 1: a new code is an addition, renaming or removing is not. The status is fixed per code: the same code answering 400 here and 403 there would force the CLI to look at both. And a CLI never fails on a code it does not know — it falls back to the status generic, which is what lets the portal gain new reasons before the CLIs are updated.

Language. detail comes out in the language of the request’s Accept-Language — English by default, Portuguese if asked, English for anything else. The response declares what it did in Content-Language. codigo does not change with the language: that is the whole point of it existing.

What guarantees it. CodigoDeErroTest freezes the list by hand — deriving it from the enum would make the test agree with the change it is supposed to prevent. It also requires an English message for every code, otherwise the raw key would leak to the screen. IdiomaDaRespostaTest goes end to end: what broke once was the link between the resolver and the header, not each piece in isolation.

The documento is the task.yaml as it was published. The portal does not invent it: it belongs to the spec, and is versioned by the apiVersion it carries inside (oren.sh/v1).

Here the break is subtler, because it does not go through the portal. The spec schemas are strict (additionalProperties: false in 4 places in the task one, 7 in the implementation one). So:

If the spec gains a field, and someone publishes a document that uses it, every CLI older than that field rejects the document — with “does not satisfy the schema”, which explains nothing to whoever consumes it.

It is not a portal bug and the portal cannot avoid it alone. It follows from two choices that remain correct: a strict schema (which is what would have caught the incremenMajorVersion that survived 16 releases) and serving the document intact.

Rule: within oren.sh/v1, the spec only admits optional additions. A new field requires oren.sh/v2, and then it is the CLI that decides whether it knows how to read it.

What the portal guarantees today. ValidadorDeDocumentos refuses at publish time any document that does not satisfy the schema the portal knows. That prevents the common case — publishing junk — but not the layer 2 case, which is publishing something too valid for an old CLI.

Three places, one rule: English by default, Portuguese when asked, English for any other language.

Where Where the choice comes from Catalogue
CLI OREN_LANG > LC_ALL > LC_MESSAGES > LANG cli/src/i18n/
Portal (API) the request’s Accept-Language portal/src/main/resources/messages*.properties
Portal (web) the picker’s choice > navigator.languages portal/web/src/app/i18n/
Docs the URL (/ or /pt/) docs/src/content/docs/

English is canonical in all of them: in the TypeScript catalogues it defines the TYPE the other languages must satisfy, and in messages.properties it is the file WITHOUT a suffix, which is the fallback for any locale.

Both ends send Accept-Language with the language THEY chose, not the system’s. Without that the screen comes out in one language and the error message inside it in another — which is what happened to whoever chose Portuguese on a browser configured in English.

What is NOT translated: command names (oren run is the same word everywhere), help metavariables (<source>, [pipeline]), roles (publicador, admin — they are database values and appear in the API), the problemas list of a 422, which comes from the schema validator in English, and the human text of the published contracts, which is immutable.

  • The order of implementations. It is presentation, computed by privilege. Changing the criterion breaks nobody: the CLI does not choose by the ranking, the oren.yaml does.
  • The columns derived in the database. efeitos, privilegio_max and company are recomputable from the document. The database schema can change; the response cannot.