Repository navigation
feat(ir)!: type the secrecy and stability a document states - #1229
Conversation
The IR could say an operation was deprecated, and could not say how stable it is: a tier survived only as a verbatim Unmodeled entry, so each emitter would derive it from a vendor key its own way. A parameter had no redaction field at all, so `format: password` at a parameter stayed under Unmodeled while a property took Secret from the same schema. Operation and OperationGroup gain Stability, a closed alpha | beta | stable that is empty where a source states none, and irverify reports a tier the IR does not declare. Parameter gains Secret, the per-use form Property.Secret already is: a parameter never hoists a node, so a Sensitive scalar would have to be minted for it. The OpenAPI compiler now lowers `format: password` at a parameter that owns no node to Parameter.Secret, inherited from a $ref target as at a property, and keeps no openapi:format entry beside it. docs/ir/boundaries.md#access states the rule that separates TypeCommon.Access from client-shaping `@access`. BREAKING CHANGE: IRVersion moves to 0.23.0. A consumer pinned to 0.22.0 cannot decode a document that sets either field, and one reading openapi:format on a parameter no longer finds it.
Two keys mapped to one field resolved by how the keys sort, and nothing was reported: the policy was a map from key to target, which could not state an order, so the walk sorted the keys and the last one won. Targets is now a map from target to an ordered list of sources, and the list is the precedence: the first source stating a value fills the field, and a later one stating another is reported at its own key. A source can name a member of an object value, so one key that holds two facts can fill two fields. Reading moves off Ctx to a Promoter holding the policy. Ctx was one method short of the cap on a type's methods, and promotion reads nothing of it but the policy. The policy's lists are copied with the map, which maps.Clone alone left shared with the caller. BREAKING CHANGE: ExtensionPromotions.Targets changes from map[string]ExtensionTarget to map[ExtensionTarget][]ExtensionSource, and DefaultExtensionPromotions returns the new shape.
An extension stating a tier, a redaction or a deprecation reached only a verbatim Unmodeled entry, so an operation deprecated by a vendor key alone read as live, and a value marked sensitive read as plain. Three targets join the promotion policy. TargetDeprecation creates the Deprecation the member targets fill, at every carrier a keyword can. TargetStability fills Operation.Stability from a closed set of words. TargetRedaction sets Sensitive on a node and Secret on a property, header or parameter, where `format: password` lands. The default mapping gains the keys the golden spec writes for each, and for a deprecation's message and removal date, two of them objects read by member. A key mapped to both deprecation and stability reports one defect once: the word `deprecated` and a value neither can hold are the deprecation reader's to answer for.
Secret folds by OR, so a redeclared field takes it from a later declaration as readily as from the first, while the field keeps the first declaration's provenance. A redaction a promotion read on a later declaration would then carry no marker saying a heuristic made it, which the promotion contract requires of every node it writes. The fold joins the marker of each redacting declaration, which gives the same answer in either branch order.
Annotations merge from a $ref's target onto the property, parameter or
header naming it, field by field, but a promotion read only the node it
ran on. So `Old: {deprecated: true, x-sunset: D}` kept its date on the
node while `{$ref: Old}` lowered to an empty Deprecation, and a key that
deprecates a target left its uses live, though an allOf decorator over
the same target reaches the emitter deprecated through the fold.
A carrier now reads the target's mapped keys beneath its own. A key on
the target counts as the target's `deprecated`, so a `deprecated` beside
the $ref decides over it as it does over the keyword. Only the keys the
policy maps are looked up, and the target reports its own misfits, so a
use reports nothing a declaration already has.
Promotion moves to the caller of each carrier, after the object around a
header's or parameter's schema has spoken: that object decides what is
deprecated, and so what a member can fill.
A key on an allOf branch, on a path item, a tag or a content entry, or
inside a oneOf kept verbatim is still read by nothing, since a promotion
reads the top level of a carrier's Unmodeled. The rule's Status says so,
with the issues that track each.
A use read its target's mapped keys afresh, so a key's value was read once per use. A value as large as the document times as many uses as the document names it is their product: 84 KB with a 20,000 item key and 500 uses retired 58G instructions where main takes 0.9G. What a target lends is now read once per target and shared by every copy of the context, which puts the promoter behind one pointer. Three readings change with it. A target lends a member only where it is deprecated itself. A date on a live target annotates nothing there, and a use deprecated on its own read it anyway, while a 3.0 decorator over the same target could not: the fold that stands for it reads the Deprecation the node holds, and the node has none. The two spellings of one use now agree on what the target lends. Empty text states nothing. A field holding "" reads as unset, so such a key filled nothing, left a marker saying it had, and stood in front of a later source with something to say. Where the two stability keys disagree the order decides and not the tiers, which is what the code did and the text did not say. That it reads the less stable statement holds of what the golden spec writes.
Secret merges from a $ref target onto a parameter as it does onto a property, so the three comments listing what a use site holds of its target were one short, and the one in ir/typeref.go says everything else is read from the target. A schema between a use and the end of its chain lends nothing because that is what the keyword does, which #1029 tracks as a defect, so the rule cites it rather than settling it. And a key written on both a parameter or a header and its schema shares one entry (#396), so the schema's is not read. That is a limit on the rule that false clears no redaction, and it belongs where the rule is.
A limitation belongs at the code or rule that has it, and these sat in the PR text or nowhere: a key a parameter and its schema both write (#396), a stability key's boolean (#654), the facts the default leaves (#656), a key inside a verbatim oneOf (#661), a target read past the schema a use names (#1029), and what no refine step reads yet (#895, #1222). The use-site rule gains the Status it lacked, and the test holding a decorator to its $ref says which two spellings it does not cover, one of them newly filed as #1258. The cost test stops quoting a size it never measured. The promoter holds a memo now, so its comment says what makes that safe.
What a target lends is remembered by position, and two documents can hold one pointer, so the use read second must not take the first one's answer. No promotion test read a target in another document.
A parameter was said never to hoist a node of its own, though a schema with an enum does, and the sentence went on to count the parameters that own one. What holds is that a carrier never hoists an alias, so a parameter whose schema owns no node has none to hold a Sensitive.
The fold joins the marker of a later redaction, but the rule said only that a merged field names the heuristic behind its deprecation, and its pin was not cited. Name both. The version history records what each bump changed, and a lowering that starts filling a member is a change of meaning the shape cannot show. This bump has one: keys now state a deprecation and a redaction, and a use reads its target's. Record it beside the two shape changes. The list in ir.Constraints of what a $ref's use reads was the last of its kind to omit redaction.
Findings from merging
|
Golden spec, compile --verify with GOMAXPROCS=1 GOGC=off, two alternated runs |
Instructions retired |
|---|---|
| Merge as it stands | 118.88G (118.80 to 118.96) |
Returning streamingPath[v.Type()] in place of true |
118.25G (118.07 to 118.44) |
That is about 0.5%, from a small sample. The pruned build's golden IR and diagnostics are byte-identical, and ./ir/irverify passes on it. The cost of pruning is real, though: this check's comment says the by-type walk holds a new carrier at once, and TestStreamingPath_ListsEveryCarrier counts only StreamingMode's carriers, so sharing the path needs a matching count for Stability. This is a decision to make either way, since the two checks now sit side by side with opposite designs.
Outside this change: nothing enforces "a row on main is never edited". Putting this branch's old hash on the 0.23.0 row leaves ./ir green, so a wrong resolution of this very conflict would pass.
The merge
It conflicts only on the version claim, in docs/ir/version-history.md and ir/irversion_test.go. #1191 took 0.23.0, so this change moves to 0.24.0. main's row and entry stay as they are, the history entry's three "pinned to 0.22.0" become 0.23.0, and the new row is:
{version: "0.24.0", format: 1, shape: "9bafa2deb68d14c36771cb98a76474130e781e9e7f5090214633a6a8c2ae48c0"},That hash holds only while nothing else lands first. #1226 also claims 0.24.0 and #1219 still claims 0.23.0, so whichever lands later takes the next version.
No golden or census line needed regenerating. Across the 22 files both sides changed, every line count matches branch + main - base, apart from those version lines and the reflect and require imports both sides added. The shape golden's diff is this change's additions against main, and main's StreamingNone against the branch.
What was checked on the merge
- Gate:
make gatedid not pass as one command on this machine, so this is the step-by-step result.fmt,vet,lint(0 issues),lint-planted,build,fuzzandbench-smokeall passed.- Coverage ran with
-timeout 1500s, as the test plan does.ir,loadandarchtesttook 706s, 766s and 344s under a load average near 200. - Two packages failed that run, and neither failure comes from the code.
canarychildren reportedhungat that load, and the package passes alone in 11.7s. Twoharnesssocket tests failed because the temp directory used for that run made the socket path too long, and they pass with the default one. morphic-covergatereported 3 of 16,972 statements uncovered, all ininternal/harness/path.go. Rerunning that package covers all three and passes the coverage gate alone. So 100% rests on those two runs together, not on one green run.
- Golden spec: every row of the Test plan table is unchanged, and
compile --verifystill exits 1 on the same 9unresolved-referrors. The IR differs frommain's only in the fields this change owns, and the diagnostics only by the same 47 infos. - Oracles: the golden copy declaring the three missing schemes comes back
ok. Overtestdata,morphic-harnessgives 170okand 49error-diagnostic, the extra one each being fix!: lower file bodies, enums, unions and streams as declared #1191's new fixtures. - What
mainchanged around this code: the following all behave as both sides state.- An enum keeps its
ValueTypebeside a redaction, and noopenapi:formatentry returns. - A non-exclusive enum union takes
Sensitive. - A file body's schema node keeps
Sensitive. - A stream's frame is unchanged.
- An enum keeps its
- Planted defects: 43 at the sites the merge touched, beside a no-op control that survived. 37 went red and 6 survived. Three survivors are findings 1 and 2, and
go test ./...stays green with all three planted together. A fourth is the published row above. The other two aren't gaps: the join at the redaction site is equivalent today, because no other marker reaches those carriers, and dropping a second witness from theredactionrow is fine, because a row needs only one.
Not rerun on the merge: the 1,954-spec sweep, the two grids, the order reversals, the cost figures and the mutant sets the Test plan lists. Those claims still stand at 346c6b6.
PR body, once a merge is pushed
**IR, 0.23.0**becomes 0.24.0, and under Breaking,IRVersionmoves to 0.24.0 and a consumer pinned to 0.23.0 refuses.- "Open fix!: lower file bodies, enums, unions and streams as declared #1191, feat(ir)!: settle doc references, promotion records and names #1219 and fix!: keep a security requirement naming no scheme #1226 also claim 0.23.0" is stale: fix!: lower file bodies, enums, unions and streams as declared #1191 landed, fix!: keep a security requirement naming no scheme #1226 claims 0.24.0, and feat(ir)!: settle doc references, promotion records and names #1219 still claims 0.23.0.
- The trial-merge paragraph, as measured against the merge:
- fix(compilers/openapi): keep a keyword at every schema outcome #1217 conflicts in
census.go,property.goanddocs/compilers/openapi.md. - feat(ir)!: settle doc references, promotion records and names #1219 conflicts in
promotion.go,promotion_test.go,docs/compilers/openapi.md,docs/ir/unmodeled.md,docs/ir/version-history.md,ir/document.go,irverify.goandir/irversion_test.go. - fix!: keep a security requirement naming no scheme #1226 conflicts in
auth/schemes.go,docs/ir/version-history.mdandir/irversion_test.go. - fix(compilers/openapi)!: lower allOf by what its conjuncts say #1269 conflicts in
params.go,docs/compilers/openapi.mdand thesecret-formatgolden. - test(archtest): widen what two style checks see #1199, test: give every covered child its own coverage directory #1233, test(compilers/openapi): keep the external order oracle offline #1235, fix(compilers/openapi): report allOf conjuncts sharing no value #1277 and fix(compilers/openapi): treat a restated union branch as bare #1278 merge clean. feat(compilers/openapi): read each document's schema identifiers #1227 conflicts with
mainalone, inlowering_test.go.
- fix(compilers/openapi): keep a keyword at every schema outcome #1217 conflicts in
- The Test plan's revisions (
main @deda5731,@346c6b67),all 16873 statements(16,972 on the merge) and themorphic-harnesscounts (170 and 49).
Two promotion sites had no test that a wrong answer would turn red. Promoter.Stability joins its marker onto an operation's Inferred list. Assigning it instead dropped the streaming and grouping markers on the ten golden-spec operations that state a tier and stream by media type, so an inferred stream read as declared, with the suite green. The marker-list test now states a tier as well as a deprecation reason. A parameter or header whose content map holds several entries promotes from the entry the election takes, the lowest key. Promoting from the first declared entry instead left every test green at both carriers. The new test declares text/plain first and application/json second, with the target on each in turn.
#1219 took 0.24.0 and #1226 0.25.0, so this change moves to 0.26.0, keeps both rows and history entries, and appends its own. #1219 turned the field list of docs/ir/unmodeled.md#promotion into a table held to the code both ways. It gains the fields this change fills: a Deprecation itself at each carrier, Operation.Stability and Parameter.Secret, with TypeCommon named among the nodes keeping a deprecation's or a Secret's extension, as a $ref's target lends both to a use. TestExtensionTarget_EveryTargetIsInThePromotionTable now names every field a target fills rather than one, since TargetRedaction fills three. OperationGroup joins Variant and EnumMember as a node rule 4 names, and TestPromotionTable_EveryNodeCanRecord holds it there. #1219's rule 3 records a promotion on the node keeping the extension. A field a $ref's target lends a use is the one case this change records twice: the target keeps the entry and its marker, and the use lists the marker too, since a use is read without resolving its target and its type reaches the entry. Rule 3, extension-promotion and the 0.26.0 history entry say so. #1217 ended fillPropertyAnnotations in PreserveCarriedKeywords; the promotion this change moved to PromoteUse stays out of it. #1226 rewrote lowerSecurityScheme's return, which now calls the Promoter. The two new conformance goldens gain the unresolved auth namespace every OpenAPI document declares since #1226.
#1302 took 0.26.0 for a change of meaning, with the shape of 0.25.0, so this change moves to 0.27.0 and keeps its shape hash. Its history entry now names 0.26.0 as the version an older consumer is pinned to.
An allOf fold took a later declaration's whole marker whenever that declaration was secret. A property's marker covers every fact a promotion read into it, so a declaration redacted by format: password whose promoted removal date lost to an earlier deprecation marked the field, which then kept neither promoted fact. Each declaration now tells the merge which heuristics set its Secret, empty where a keyword declared it, and the fold joins that alone.
The fold's marker was held only from e2e, which the coverage gate does not count for compilers/openapi/internal/schema, so the line naming a promoted Secret's heuristic stood uncovered. The case moves beside the other allOf redeclaration tests, where both of its sites redden under a mutant.
A message #1219 wrote on main named PromoteDeprecation, which this change replaced with Promoter.Deprecation, and the merge kept it.
A use a $ref's target lends a promoted fact to lists the marker, though the entry the heuristic read is the target's, not its own. The field's definition named only the node's own Unmodeled.
checkStability was shown every value of a document, though its type sits only on Operation and OperationGroup. That cost a verified compile of the golden spec about 0.5%, and Verify alone on its IR about 4% (spec @319dc756). It now prunes to the path checkStreamingModes already prunes to, renamed operationPath as it serves both, and TestOperationPath_ListsEveryCarrier counts Stability's carriers, so a field of that type off the path fails there rather than passing unread.
readStability's comment called a key's boolean the deprecation target's statement, which reads as both values. Only true is: a false names no tier and is reported here, as the extension-promotion rule states and TestPromoter_OneKeyTwoTargetsReportsOnce holds.
#1229 listed, under extension-promotion's status, that a flattened member reads no redaction off a declaration it overrides. FlatProperty.Secret now accumulates over every declaration, so the item no longer holds.
#1229 took IRVersion 0.27.0, so this change moves to 0.28.0: main's row and history entry stand, and this change's follow under the new number, with the shape hash of the merged tree. fillParamType returns the elected spelling, as #1229 has it, and reads its schema in the context declaring it, as this change has it.
Brings in #1229 and #1325. - Both bump IRVersion, to 0.27.0 and 0.28.0, so this branch's bump moves to 0.29.0. Its row takes main's new shape and keeps this branch's names and meaning; the version history entry moves with it. - #1229 gives ir.Parameter a Secret, so a parameter's redaction has a home and xml is the one keyword left with none. fillParamSchema keeps xml for each voice and the schema, and the wrapper that also kept format: password goes. The secret-format golden is regenerated: it differs from main's by this branch's cases, and from this branch's by the parameter's Secret. - #1229 reads a target's mapped keys onto a carrier at the end of a $ref only. A refinement is a use of what it names, so {allOf: [{$ref: T}], description: d} read T's deprecated keyword but not its x-stability, where {$ref: T, description: d} read both. KeysLentTo now reads the keys along the chain the keywords are read along (Use.Referents), nearest first: the nearest link stating a deprecation, by a keyword or a key, decides it and lends its members, and any link asking for redaction asks it of the use. A position owning a node lends its carrier none, as it lends no keyword. Promoter.Referent keys what it remembers by the schema's identity, as an inline link has no binding position. TestPromotion_ARefinementLendsWhatItRefines pins it. - TestPromotion_ADecoratorMatchesTheRefItStandsFor assumed an allOf of one $ref over a string is a decorator. It is a refinement here, so the test now holds its carriers to the $ref spelling's, and keeps the fold comparison over object targets, where it is still a decorator. - #1258's example, deprecated: false on such an allOf over a string, now reads as beside the $ref, so its status names the object case that still parts, and extension-promotion's #1220 entry names what is left of it.
#1229, merged in fd37a88, gives ir.Parameter a Secret and holds a parameter's format: password there rather than under openapi:format. TestParameter_ABranchSpeaksAsItsSchemaDoes still expected the verbatim entry for a branch writing it, so it failed on the merge. It now holds the branch's redaction to Secret and the entry's absence, beside the readOnly and xml the parameter still keeps verbatim at the branch.
Summary
An operation's stability tier, a parameter's redaction and most of what a deprecation can say reached the IR only as verbatim
Unmodeledentries, so every consumer would derive them from a vendor key its own way. An operation deprecated by a key alone read as live, and a value marked sensitive read as plain. This gives each fact a typed home and reads it by the promotion policy, with the entry kept beside it and the node markedextension-promotion.IR, 0.27.0
Operation.StabilityandOperationGroup.Stability: a closedalpha | beta | stable, empty where a source states none and never read as stable. A group's tier applies to members stating none, read through the group.irverifyreports any other value (ir/unknown-stability).Parameter.Secret, the per-use formProperty.Secretalready is. A carrier never hoists an alias, so where a parameter's schema owns no node aSensitivescalar would have to be minted at a pointer a$refcan name.format: passwordat a parameter that owns no node now lands there, inherited from a$reftarget as at a property, and keeps noopenapi:formatentry.docs/ir/boundaries.md#accessstates the rule that separatesTypeCommon.Accessfrom client shaping: a fact true for every target is IR, and one SDK's surface is not. So protobuf'sexport/localand Smithy@internalare facts, the second with no operation field yet (no_ir_home, a gap and not a boundary), and TCGC@accessisout_of_scopeon types and operations alike.Promotion policy
ExtensionPromotions.Targetsis now ordered sources per target. The list is the precedence: the first source stating a value fills the field, and a later one stating another is reported at its own key. This ends two keys resolving by how they sort.TargetDeprecationcreates theDeprecationthe members fill, at every carrier a keyword can.TargetStabilityfills the tier.TargetRedactionsetsSensitiveon a node andSecreton a property, header or parameter, whereformat: passwordlands.lowering.Ctx, which was one method short of the type cap when this began (608a5a4), to aPromoterholding the policy.A case no issue names. Annotations merge from a
$ref's target onto its use field by field, but a promotion read only its own node:Old: {deprecated: true, x-sunset: D}kept its date while{$ref: Old}lowered todeprecation: {}. A property, header or parameter now reads what the target's mapped keys state beneath its own, read once per target however many uses name it, since a key's value can be as large as the document. A key on the target counts as the target'sdeprecated, so adeprecatedbeside the$refdecides over it, asdocs/compilers/openapi.md#ref-use-sitesays of the keyword. A target lends a member only where it is deprecated itself: a date on a live target annotates nothing there or at a use, whatever the use says of itself. That is what keeps the 3.1$refin step with the 3.0allOfdecorator an emitter folds, which reads theDeprecationthe target's node holds. Two spellings still part, a member key beside theallOf(#1220) and adeprecated: falseon the decorator (#1258). A target's misfit is reported once, at the target.Where a lent fact is recorded. #1219 records a promotion on the node keeping the extension, so that an auditor finds the marker beside the entry explaining it. A fact a
$ref's target lends a use is the one case this records twice: the target keeps the entry and listsextension-promotion, and the use lists it too, though it keeps no entry. A use is read without resolving its target (docs/ir/annotations.md#what-a-reference-carries-down), so an unmarked use would state a guessed deprecation or redaction as declared, and its type reaches the entry, which a marker on an ancestor, the design #1219 rejected, does not. On the golden spec 78 properties are marked this way, and each one's type target holds the key and the marker itself. Rule 3 ofdocs/ir/unmodeled.md#promotion,extension-promotionand the history entry say so.A folded field is marked for what it keeps. An
allOffold takesSecretfrom any declaration, so a later declaration's promoted redaction has to bring its marker. A property's marker covers every fact a promotion read into it, so the fold cannot take the whole marker: a declaration redacted byformat: password, marked for a promoted date the field drops with that declaration's deprecation, would mark a field keeping no promoted fact. Each declaration tells the merge which heuristics set itsSecret, and the fold joins that alone (schema.TestAllOf_RedeclarationMarksAPromotedSecretOnly).Where the two stability keys disagree, the order decides.
x-stabilityis read first, whichever tier each key names, sox-stability: stablewins overx-fern-availability: beta. On the golden spec that reads the less stable statement: all 47 disagreements arebetaagainstgenerally-available. It is right where the text can tell (2 descriptions say beta, and none of the 2,636 operations marked generally available alone does). It over-reports where the mark sits on one method of a resource and not its neighbours, asGETandPUTof/accounts/{account_id}/access/apps/{app_id}carry it andDELETEdoes not, so a consumer gating on the tier hides such an operation. The info on each disagreement and the kept entries are what let it audit that, and no other order is shown to do better: reversing it loses the two the text confirms.Left open, each stated in the code or
docs/compilers/openapi.mdtruereads as a deprecation.allOfbranch reaches no field, a redaction beside anallOfmakes a node of its own where beside a$refit setsSecret, asformat: passworddoes onmain, and a member key beside anallOfover a deprecated target annotates nothing.x-sensitive: falseon the object hides atrueon its schema.OperationGrouphas noProvenance, so OpenAPI cannot promote into it, and itsStabilityis for Smithy and TypeSpec.x-sensitiveinside aoneOfkept verbatim wait for those branches to lower.docs/emitterssays what a target does with a tier. WhereParameter.Secretis redacted joins docs/emitters: no refine step reads TypeCommon.Sensitive #895.deprecated: falseon anallOfdecorator reaches no carrier, where beside a$refit decides, as it does onmainfor a keyword.x-sensitiveis read past as an overriddenformat: passwordis.main.This stacks on nothing and holds
main@7f849127, and #1340 stacks on it. #1219, #1226 and #1302 took 0.24.0, 0.25.0 and 0.26.0, so this takes 0.27.0, which #1269 (@fbebf329), #1325 (@894e65bb) and #1333 (@0f044362) claim as well. The constant merges between them in silence and only thegenerationsrow and the history entry conflict, so each that lands after another moves to the next free version, keeping the rows and entriesmainhas. A trial merge of this head against each open PR: #1269 conflicts inparams.go,docs/compilers/openapi.md,docs/ir/version-history.md,ir/irversion_test.goand thesecret-formatgolden, and merges clean withmain; #1325 conflicts indocs/ir/version-history.mdandir/irversion_test.go, the version claim; #1333 conflicts there and inparams.go, and merges clean withmain; and #1278 conflicts indocs/compilers/openapi.md, as it does withmain. #1199, #1227, #1233, #1235, #1277, #1301, #1311, #1322, #1327, #1329, #1331, #1332, #1334, #1335, #1336, #1337, #1339, #1340 and #1351 merge clean. #1333 reads a parameter's elected schema under the context of the document its media type sits in, and the conflict is one return line: with it resolved toward #1333, a parameter and a header whosecontentnames a$ref'd media type, in this document or another, read their schema's target as one written in place does, and are marked for it. #1269 rewritesfillParamSchemaAnnotationsincompilers/openapi/internal/operation/params.goaround this change'sSecret, theref-use-siterule indocs/compilers/openapi.mdand thesecret-formatgolden, and has a carrier read through a refinement to its target, so the later of the two hasreferentOfread the same target.Test plan
main@7f849127, and CI runs the gate on it. Its compiler is d38453f's, as every commit since changes a test, a document, a comment or the valuesirverifywalks to its findings, or mergesmain's test: cut the work make gate does that no check reads #1313 and its bump ofgo.yaml.in/yaml/v3(build: bump go.yaml.in/yaml/v3 from 3.0.5 to 3.0.6 in the go group #1342).--verifyof the golden spec writes the same document and the same 1,862 diagnostics on either side of each, and the stability, cross-document and unquoted-date probes give the same output. So the golden table below is re-derived at d38453f againstmain@b206dc99, and every row of the IR is unchanged from the earlier measurement; the diagnostic totals moved withmain, by the same 47 infos, and none is removed.sweep.pyover the 1,954 specs of a real-world corpus and the 227 oftestdata, against b206dc9: exit codes 0 for 1,661 and 1 for 520 on both sides, and 5 differ past the version stamp, the 4 conformance cases this change writes and one real-world parameter writingformat: password, which now lands inSecretwith itsno_ir_homeentry and info gone. Mutants at the sites the merges resolved, each red at the test named: the security scheme's promotion dropped (TestConformance),Parameter.Secretdropped from the promotion table (TestExtensionTarget_EveryTargetIsInThePromotionTable),OperationGroupgiven aProvenance(TestPromotionTable_EveryNodeCanRecord), and at the fold's marker, the merge passing no marker for a promotedSecretand the fold joining a declaration's whole marker (both atTestAllOf_RedeclarationMarksAPromotedSecretOnly, the second atTestFold_ThePromotionMarkerFollowsTheSecretTakentoo). The bullets after this one stand at the revision each names.main@608a5a46 (827e7ed), where only the version claim conflicted and no golden or census line needed regenerating:make fmt vet lint lint-planted build fuzz bench-smokeeach exit 0. Coverage with-timeout 1500sreached all 16,972 statements only over two runs together: at a load average near 200,canarychildren reportedhungand twoharnesssocket tests failed on a long temp directory (test: two harness tests fail when TMPDIR is long #1295), and each package passes alone. Every row of the golden table below is unchanged,--verifyexits 1 on the same 9 errors, and the diagnostics differ frommain's by the same 47 infos.morphic-harnessovertestdatagives 170okand 49error-diagnostic, the extra one each being fix!: lower file bodies, enums, unions and streams as declared #1191's fixtures. 43 mutants at the sites the merge touched, beside a no-op control that survived: 37 went red. Three survivors were promotion sites no test held: the join atPromoter.Stability, which on 10 golden operations would read an inferred stream as declared, and the entry a parameter's and a header's promotion read from acontentmap holding several.TestStreaming_MarkerListKeepsAPromotionBesideBothnow states a tier, andTestPromotion_AContentCarrierReadsTheEntryItElectsdeclarestext/plainbeforeapplication/json; each goes red under its mutant, at the parameter and the header alike, and a no-op control stays green. A fourth survivor was a published row ofgenerationsrewritten with this change's hash, which nothing enforces (test: a published IRVersion row can be rewritten with ./ir green #1314). The other two are equivalent. The sweep, grids, order reversals, cost figures and mutant sets below were not rerun on the merge, and stand at 346c6b6.make fmt vet lint lint-planted build fuzz bench-smokeon this tree, each exit 0, and the command ofmake coveragewith-timeout 1500sfor its300s, which-raceruns ofirandpasscould not meet on a loaded machine: "Coverage gate passed: all 16873 statements covered."cloudflare/api-schemas@319dc756, main @b206dc99 against this branch @d38453f2.morphic compile --verifyexits 1 on both for the same 9unresolved-referrors.degraded-constructUnmodeledentriesstable/beta/alpha/ unsetAll 47 new diagnostics are the disagreement above. The golden IR was also rebuilt, at 346c6b6, from main's by a script applying these rules, field by field: it differs from the branch's in nothing but the source path and those 47 diagnostics. Each
x-sensitive: trueentry among the 140 kept at a carrier has its field set and its marker, and the 2 others are theoneOfabove.sweep.py, the script of themorphic-verifying-changesskill, plain and with--verify: no exit code changes, 1,242 error diagnostics on both sides, and one spec differs past the version stamp, a parameter writingformat: passwordthat now lands inSecret. The corpus writes none of the new default keys, so this shows the change touches nothing else. The golden spec is what reaches it.go run ./cmd/morphic-harness: overtestdata, 169okand 48error-diagnostic, the fixtures written to draw one. The golden spec stops at its 9unresolved-referrors, so a copy declaring the three schemes they name ran through every oracle and came backok, which puts the two-order and idempotence oracles over what this promotes.extension-stabilityandextension-redaction, withextension-promotionandsecret-formatextended, andstability,redactionanddeprecationwitnessed inmatrix.md.testdata/unwitnessed.golden.txtgainsOperationGroup.stabilityalone, which no OpenAPI construct sets.e2e, since the order oracle reads no operation or parameter, and a test that runs each use-site case at all three carriers and by both spellings of a parameter and a header.alphais a valid tier. One survived at first, abreakfor acontinueinExtensionsNamedthat dropped the keys after one that cannot be serialized, which has a test.PromoteUsetakes, beside a no-op control that survived. Reading a parameter's or a header's ownschemain place of the one elected fromschemaandcontentsurvived at first, so every use-site case now runs throughcontenttoo, and both go red.cfordcat a header is equivalent, as both read one bindings table: a header and a parameter declared in another document over a schema there compile alike on both builds.schemaat 3.0 and 3.1 and throughcontentat 3.1, the first also at 3.2: 2,808 carriers crossing the keyword, key and member on each side of a$ref, and 648 crossingformat: passwordwithx-sensitiveon the object, the schema and the target. None differs here, and onmain810 and 288 of the 3.1schemarows do.x-stability: 3, an unknown word,legacy,x-sensitive: "yes", a disagreement, and on a deprecated nodex-cfDeprecation: textandx-forge-sunset: {date: 7}, which a live node has no field to read into. Empty text states nothing, so it fills no field, marks nothing and does not stand before a later source.$refand beside anallOfdecorator, with the fold computed from the IR: a date on a live target no longer parts them, and the 20 of its 70 pairs that do are the two left open above, a member key (openapi: a promoted key on an allOf reads apart from its $ref spelling #1220) anddeprecated: false(openapi: a decorator's deprecated: false reads apart from one beside a $ref #1258), neither of which the golden spec writes.e2ediff: reversing every mapping of a spec holding each target at each carrier, and eachallOf, changes nothing but theallOfindex in two pointers, diagnostics compared as a sorted multiset. A build planted so the first reader's answer wins differs at dozens of carriers. Reversing every mapping of the golden spec itself changes the stability, redaction, deprecation and marker of none of its 106,713 operations, parameters, headers, types and properties, and its diagnostics match but for the order a message lists keywords in.checkStabilityinirverifyprunes to the pathcheckStreamingModesprunes to, namedoperationPathnow that it serves both, andTestOperationPath_ListsEveryCarriercountsStability's carriers, so a field of that type off the path fails there, as a third one planted with the shape regenerated does. Shown every value, the check cost a verified golden compile about 0.5% (118.88G against 118.25G instructions pruned, two runs each, identical output) andVerifyalone on the golden IR 3.9% (medians of 1,109 ms against 1,067 ms over ten alternated runs, at 6cb8cef). Each of four mutants goes red: walking every value, pruning everything, and the path losing nested groups orOperation. irverify: two walk checks of one operation field are shown every value #1267 proposes the same table for the two other checks of one operation field, and names it and its tests as they were before the rename. On a spec of 8,000$refcarriers with the collector off, three alternated runs give medians of 13.7G on main and 13.5G here, inside each side's spread. On the golden spec the same runs give 90.80G on main (90.61 to 90.95) and 91.10G here (90.93 to 91.37), 0.3% more.Breaking
IRVersionmoves to 0.27.0, and a consumer pinned to 0.26.0 refuses every document this writes, whether or not it setsstabilityor a parameter'ssecret.openapi:formaton a parameter no longer finds it, and readsParameter.Secret.Deprecationis now set from a key alone: 137 golden operations that read as live now read as deprecated, as do uses of a target a key deprecates.SensitiveandSecretare now set fromx-sensitive: 36 golden nodes and 170 properties that read as plain now ask for redaction.compilers/openapi:ExtensionPromotions.Targetschanges frommap[string]ExtensionTargettomap[ExtensionTarget][]ExtensionSource,DefaultExtensionPromotionsreturns that shape, and a caller stating a mapping restates it by target.Closes #578
Closes #581
Closes #655