Skip to content

Build1 publisher3 min readPublished

Rerunning the generator in --check mode makes a stale snapshot fail the build

Anton Brilliantov keeps one .proto per interface in a shared contract repository and generates the HTTP specification from it. The same discipline already governs his environment variable catalog and his metrics snapshot.

The Engineer · Build desk

What happened

  • Anton Brilliantov, splitting a live PHP monolith into Go services, declares every service-to-service call in a .proto held in one shared contract repository, one file per interface.
  • The build compiles that file into typed clients and servers for both sides, and the door service's HTTP specification is produced from the same schema, with the method's HTTP role set by an annotation.
  • He says he learned the rule on environment variables and metrics, whose hand-written descriptions drifted from the code without anything failing, and stayed wrong until somebody checked them against the source.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Once drift fails the build, adding a field stops being a documentation chore that can wait for review. The change cannot merge until every derived artifact regenerates, and the person mid-change pays that time.
  • cost The gate costs a shared contract repository and a generator pinned to the platform version in the service's modules. CI now owns a tool dependency that has to be upgraded in step with the service.
  • capability The contract tool compares each change against the published schema, so a breaking change can be argued over on the schema diff before anyone has written an implementation to defend.
  • exposure The catalog is authoritative only for statically declared names. An operator or auditor who reads it as the full inventory of consumed configuration still has to chase the runtime-built resource variables by hand.

The generator that writes the catalog also runs in `--check` mode, and it runs whenever any `.go` file, the manifest, the modules file or the snapshot itself changes [14]. A `--check` run regenerates the artifact and compares it with the committed one, so a snapshot that no longer matches the code fails the build [22]. The generator is installed at the same platform version the service has in its modules [15]. Without that pin, the check generates with a different tool and reports differences that belong to the tool.

The arrangement being replaced is three files for one interface: the schema declares the call, a separate OpenAPI document describes the HTTP surface, and human-facing documentation is the third [7]. Anton's version keeps one file per interface and treats everything else as output [2]. Two of those three artifacts stop being maintained by hand [23]. "Nothing in the pipeline notices when the schema gains a field the HTTP document has never heard of," he wrote [8].

He started somewhere else. The environment variable descriptions and the metrics descriptions were written by hand in files next to the code, and both drifted. Nothing failed, and the description stayed wrong for as long as nobody read it against the source [9][10]. Wrong documentation pages nobody. The catalog now records `defined_in`, the file and the line of the declaration, for a variable declared by the service configuration, and the owning catalog for one declared by the platform [12]. The metrics snapshot has one row per metric plus a `<dynamic>` row for the factory that registers metrics at runtime [13]. "A description written by hand drifts. A description that is derived and checked does not," Anton wrote [17].

The catalog leaves out resource variables. The platform builds their names by concatenation at runtime, so there is nothing static to read [16]. Anyone treating the catalog as the complete list of what the service consumes will be short by exactly those names.

For the HTTP half to transfer, the surface you need has to be expressible in the annotation the method carries. The specification is produced from that declaration, and the schema holds the messages, the required fields, the bounds and the refusal codes [6][5]. The post is one engineer's account of one system, and it does not report a service count, a team size, or how often the check has fired [21]. The compatibility claim is the one I would test before adopting any of it. Anton says the contract build tool checks every change against the published schema, so a breaking change is visible before a line of implementation exists [19].

"This is how I do it right now, with the price attached - maybe you already do it better, maybe you see it differently," he wrote [20].

What to watch

  • Whether the platform ever exposes its runtime name concatenation as a static declaration, which would let resource variables into the catalog.
  • Whether later parts of the series publish numbers: services under the scheme, generator runtime, how often the --check gate fires.
  • Whether the HTTP annotation still covers the door service's surface as endpoints appear that do not map cleanly onto one method.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories