You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Six idiomatic SDKs is the product, and six hand-written generators follow from it. That is not the problem. The problem is that language-independent policy is transcribed once per language, so a rule with one meaning has six implementations that can and do diverge.
The declaration loaders. Once the verb set moved to spec/generated-verbs.json, six hand-written loaders disagreed about what the file means — five times, for five different reasons: Kotlin's jsonPrimitive.content coercing a number to text, Rust's filter_map dropping non-strings, Ruby's ASCII-oriented String#strip, Swift's String.allSatisfy being vacuously true for the empty string, and JavaScript's $ matching before a final line terminator. Three different predicates were tried; each relocated the disagreement rather than closing it. One validator, six readers: stop the generators disagreeing about the shared declaration #933 is in progress.
The pattern is the same each time: the parity checks prove the six copies agree, but nothing prevents them from encoding the rule six ways in the first place, and a checker that compares copies cannot see a rule that every copy gets wrong identically.
The question worth deciding
For each policy below, should it keep N hand-written expressions with parity checks, or have one definition that the generators consume without re-deriving?
Not a proposal to collapse the generators. The generators should stay hand-written and idiomatic — that is why the SDKs are worth using. The question is only whether a rule that is the same in every language should be written in every language.
Why this is filed rather than fixed in passing
Each instance is individually small, which is how all four got written, and fixing them opportunistically inside whatever PR happens to surface one produces half-migrations. Worth deciding as a set, then sequencing.
Six idiomatic SDKs is the product, and six hand-written generators follow from it. That is not the problem. The problem is that language-independent policy is transcribed once per language, so a rule with one meaning has six implementations that can and do diverge.
Four instances surfaced in a single day:
generate-url-routesplusscripts/gen-catalog. An operation on any other verb was dropped from every SDK in silence (Generators iterate a five-verb list, so an operation on any other HTTP method is silently dropped from every SDK #925). Fixed in Find operations by what they are not, so no HTTP verb can drop one in silence #931 by removing the enumeration rather than correcting the copies.spec/generated-verbs.json, six hand-written loaders disagreed about what the file means — five times, for five different reasons: Kotlin'sjsonPrimitive.contentcoercing a number to text, Rust'sfilter_mapdropping non-strings, Ruby's ASCII-orientedString#strip, Swift'sString.allSatisfybeing vacuously true for the empty string, and JavaScript's$matching before a final line terminator. Three different predicates were tried; each relocated the disagreement rather than closing it. One validator, six readers: stop the generators disagreeing about the shared declaration #933 is in progress.SERVICE_SPLITSandTAG_TO_SERVICEare hand-transcribed inkotlin/.../Config.kt,kotlin/.../OperationParser.kt,python/scripts/generate_services.py,ruby/scripts/generate-services.rb,rust/generator/names.tomlandrust/generator/src/naming.rs— then restated inSPEC.mdand enforced bycheck-operation-assignment-parity,check-service-inventory-parityandsync-doc-constants.rb. Every retag this week (Tag the recordings operations as their own domain, and require a tag on every operation #922, Let the Recordings tag reach the Rust generator #928, Tag a recording's event history as Recordings, not Automation #929, Split the Automation catch-all into six real domains #930) had to edit all of them, and Split the Automation catch-all into six real domains #930's notes record that one table's usefulness depends on staying "eye-diffable" — a human-maintenance property standing in for a machine-checked one.additionalOperationsbe skipped silently in four of them (A refusal must not destroy generated output: fixed in Kotlin and TypeScript, swept across the rest #932).The pattern is the same each time: the parity checks prove the six copies agree, but nothing prevents them from encoding the rule six ways in the first place, and a checker that compares copies cannot see a rule that every copy gets wrong identically.
The question worth deciding
For each policy below, should it keep N hand-written expressions with parity checks, or have one definition that the generators consume without re-deriving?
Not a proposal to collapse the generators. The generators should stay hand-written and idiomatic — that is why the SDKs are worth using. The question is only whether a rule that is the same in every language should be written in every language.
Why this is filed rather than fixed in passing
Each instance is individually small, which is how all four got written, and fixing them opportunistically inside whatever PR happens to surface one produces half-migrations. Worth deciding as a set, then sequencing.