From 50af7930fb1eb998289ba46d22eeac5978a70856 Mon Sep 17 00:00:00 2001 From: mnoah1 Date: Wed, 2 Sep 2026 23:06:13 +0000 Subject: [PATCH 1/3] feat(stovepipe): define request history read model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Intent: - Make retained request logs the authority for history availability. - Establish the public and domain projections used by history reads. Changes: - Return not found when no request log records are retained. - Reserve metadata-backed proto fields and add history entity and mapper coverage. - Align the request history RFC with log-only lookup semantics. --- Generated by the 🪄 [pr-create](https://sg.uberinternal.com/code.uber.internal/uber-code/devexp-agent-marketplace/-/blob/claude-code/plugins/dev/uber-dev/skills/pr-create/SKILL.md) skill in devexp-agent-marketplace --- api/stovepipe/proto/stovepipe.proto | 6 +- api/stovepipe/protopb/stovepipe.pb.go | 26 +-- api/stovepipe/protopb/stovepipe.pb.yarpc.go | 77 ++++---- doc/rfc/stovepipe/request-history-api.md | 22 +-- service/stovepipe/server/mapper/BUILD.bazel | 10 +- .../server/mapper/request_history.go | 61 ++++++ .../server/mapper/request_history_test.go | 174 ++++++++++++++++++ stovepipe/entity/BUILD.bazel | 1 + stovepipe/entity/request_history.go | 39 ++++ .../storage/mysql/request_log_store.go | 3 + .../storage/mysql/request_log_store_test.go | 15 +- .../extension/storage/request_log_store.go | 2 +- .../stovepipe/extension/storage/suite.go | 9 + 13 files changed, 360 insertions(+), 85 deletions(-) create mode 100644 service/stovepipe/server/mapper/request_history.go create mode 100644 service/stovepipe/server/mapper/request_history_test.go create mode 100644 stovepipe/entity/request_history.go diff --git a/api/stovepipe/proto/stovepipe.proto b/api/stovepipe/proto/stovepipe.proto index ef2571e35..589725f02 100644 --- a/api/stovepipe/proto/stovepipe.proto +++ b/api/stovepipe/proto/stovepipe.proto @@ -83,10 +83,8 @@ message HistoryEvent { // Event that occurred without changing the request state. string event = 4; } - // Newer request that caused a superseded state. Empty when not applicable. - string superseded_by_request_id = 5; - // Build associated with the occurrence. Empty when no build applies. - string build_id = 6; + reserved 5, 6; + reserved "superseded_by_request_id", "build_id"; // Stable domain reason for a terminal request outcome. Empty otherwise. string outcome_reason = 7; } diff --git a/api/stovepipe/protopb/stovepipe.pb.go b/api/stovepipe/protopb/stovepipe.pb.go index ef4c02ad8..2963b3c61 100644 --- a/api/stovepipe/protopb/stovepipe.pb.go +++ b/api/stovepipe/protopb/stovepipe.pb.go @@ -374,10 +374,6 @@ type HistoryEvent struct { // *HistoryEvent_RequestState // *HistoryEvent_Event Occurrence isHistoryEvent_Occurrence `protobuf_oneof:"occurrence"` - // Newer request that caused a superseded state. Empty when not applicable. - SupersededByRequestId string `protobuf:"bytes,5,opt,name=superseded_by_request_id,json=supersededByRequestId,proto3" json:"superseded_by_request_id,omitempty"` - // Build associated with the occurrence. Empty when no build applies. - BuildId string `protobuf:"bytes,6,opt,name=build_id,json=buildId,proto3" json:"build_id,omitempty"` // Stable domain reason for a terminal request outcome. Empty otherwise. OutcomeReason string `protobuf:"bytes,7,opt,name=outcome_reason,json=outcomeReason,proto3" json:"outcome_reason,omitempty"` unknownFields protoimpl.UnknownFields @@ -453,20 +449,6 @@ func (x *HistoryEvent) GetEvent() string { return "" } -func (x *HistoryEvent) GetSupersededByRequestId() string { - if x != nil { - return x.SupersededByRequestId - } - return "" -} - -func (x *HistoryEvent) GetBuildId() string { - if x != nil { - return x.BuildId - } - return "" -} - func (x *HistoryEvent) GetOutcomeReason() string { if x != nil { return x.OutcomeReason @@ -661,17 +643,15 @@ const file_stovepipe_proto_rawDesc = "" + "request_id\x18\x02 \x01(\tR\trequestId\"G\n" + "\x1dGetRequestHistoryByURIRequest\x12\x14\n" + "\x05queue\x18\x01 \x01(\tR\x05queue\x12\x10\n" + - "\x03uri\x18\x02 \x01(\tR\x03uri\"\x94\x02\n" + + "\x03uri\x18\x02 \x01(\tR\x03uri\"\xf0\x01\n" + "\fHistoryEvent\x12\x19\n" + "\bevent_id\x18\x01 \x01(\tR\aeventId\x12!\n" + "\ftimestamp_ms\x18\x02 \x01(\x03R\vtimestampMs\x12%\n" + "\rrequest_state\x18\x03 \x01(\tH\x00R\frequestState\x12\x16\n" + - "\x05event\x18\x04 \x01(\tH\x00R\x05event\x127\n" + - "\x18superseded_by_request_id\x18\x05 \x01(\tR\x15supersededByRequestId\x12\x19\n" + - "\bbuild_id\x18\x06 \x01(\tR\abuildId\x12%\n" + + "\x05event\x18\x04 \x01(\tH\x00R\x05event\x12%\n" + "\x0eoutcome_reason\x18\a \x01(\tR\routcomeReasonB\f\n" + "\n" + - "occurrence\"q\n" + + "occurrenceJ\x04\b\x05\x10\x06J\x04\b\x06\x10\aR\x18superseded_by_request_idR\bbuild_id\"q\n" + "\x0eRequestHistory\x12\x1d\n" + "\n" + "request_id\x18\x01 \x01(\tR\trequestId\x12@\n" + diff --git a/api/stovepipe/protopb/stovepipe.pb.yarpc.go b/api/stovepipe/protopb/stovepipe.pb.yarpc.go index 21d15d13d..a4b8d8deb 100644 --- a/api/stovepipe/protopb/stovepipe.pb.yarpc.go +++ b/api/stovepipe/protopb/stovepipe.pb.yarpc.go @@ -376,45 +376,44 @@ var ( var yarpcFileDescriptorClosurefabdb6b3c0b09022 = [][]byte{ // stovepipe.proto []byte{ - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4f, 0x6f, 0xd3, 0x4e, - 0x10, 0xad, 0xe3, 0x36, 0xad, 0x27, 0x69, 0x7e, 0x3f, 0xad, 0x68, 0x65, 0xac, 0xb6, 0x2a, 0x96, - 0xaa, 0x86, 0x1e, 0x1c, 0x51, 0x0e, 0xfc, 0x39, 0xa1, 0x08, 0xd4, 0xf8, 0x00, 0xaa, 0x5c, 0x71, - 0x81, 0x83, 0xe5, 0x3f, 0xa3, 0x74, 0x11, 0xf6, 0xba, 0xde, 0x75, 0xa5, 0x7c, 0x00, 0xae, 0x48, - 0x48, 0x7c, 0x50, 0x3e, 0x02, 0xf2, 0x7a, 0xed, 0x24, 0x55, 0x62, 0x20, 0x37, 0xcf, 0xf8, 0xbd, - 0x37, 0x6f, 0x67, 0x76, 0x6c, 0xf8, 0x8f, 0x0b, 0x76, 0x8f, 0x19, 0xcd, 0xd0, 0xc9, 0x72, 0x26, - 0x18, 0xb1, 0x8a, 0x10, 0x73, 0x87, 0x17, 0x61, 0x42, 0xc5, 0x5d, 0x81, 0x05, 0x3a, 0x0d, 0xc2, - 0x3e, 0x87, 0xde, 0x35, 0x4d, 0xa7, 0x1e, 0xde, 0x15, 0xc8, 0x05, 0x31, 0x61, 0x37, 0x41, 0xce, - 0x83, 0x29, 0x9a, 0xda, 0xa9, 0x36, 0x34, 0xbc, 0x3a, 0xb4, 0xbf, 0x69, 0xd0, 0xaf, 0x90, 0x3c, - 0x63, 0x29, 0xc7, 0xf5, 0x50, 0xf2, 0x04, 0xfa, 0x1c, 0xf3, 0x7b, 0x1a, 0xa1, 0x9f, 0x06, 0x09, - 0x9a, 0x1d, 0xf9, 0xba, 0xa7, 0x72, 0x1f, 0x82, 0x04, 0xc9, 0x11, 0x18, 0x82, 0x26, 0xc8, 0x45, - 0x90, 0x64, 0xa6, 0x7e, 0xaa, 0x0d, 0x75, 0x6f, 0x9e, 0x20, 0x16, 0xec, 0xdd, 0x32, 0x2e, 0x24, - 0x79, 0x5b, 0x92, 0x9b, 0xd8, 0x3e, 0x83, 0x7d, 0x37, 0x9d, 0x22, 0x17, 0xb5, 0xe5, 0x47, 0xb0, - 0x23, 0x0f, 0xa5, 0x5c, 0x54, 0x81, 0x7d, 0x0a, 0x83, 0x1a, 0xa6, 0xfc, 0x0e, 0xa0, 0x43, 0x63, - 0x05, 0xea, 0xd0, 0xd8, 0xbe, 0x81, 0xa3, 0x2b, 0xac, 0x55, 0x26, 0x94, 0x0b, 0x96, 0xcf, 0xc6, - 0x33, 0xf7, 0x6d, 0xab, 0x2e, 0x39, 0x06, 0xc8, 0x2b, 0x80, 0x4f, 0x63, 0x75, 0x32, 0x43, 0x65, - 0xdc, 0xd8, 0xbe, 0x82, 0xe3, 0x15, 0xa2, 0x1f, 0x3d, 0xb7, 0x5d, 0xf5, 0x7f, 0xd0, 0x8b, 0x9c, - 0x2a, 0xb9, 0xf2, 0xd1, 0xfe, 0xd9, 0x81, 0xbe, 0xe2, 0xbf, 0xbb, 0xc7, 0x54, 0x90, 0xc7, 0xb0, - 0x87, 0xe5, 0x83, 0xdf, 0x1c, 0x62, 0x57, 0xc6, 0x6e, 0x5c, 0xf6, 0xbb, 0xe9, 0x9d, 0x9f, 0x70, - 0x29, 0xa3, 0x7b, 0xbd, 0x26, 0xf7, 0x9e, 0x93, 0x33, 0xd8, 0xaf, 0x6d, 0x73, 0x11, 0x08, 0x94, - 0x3d, 0x37, 0x26, 0x5b, 0x5e, 0x5f, 0xa5, 0x6f, 0xca, 0x2c, 0x39, 0x84, 0x1d, 0x29, 0x5a, 0x75, - 0x7d, 0xb2, 0xe5, 0x55, 0x21, 0x79, 0x01, 0x26, 0x2f, 0x32, 0xcc, 0x39, 0xc6, 0x18, 0xfb, 0xe1, - 0xcc, 0x5f, 0xe8, 0xc1, 0x8e, 0x34, 0x73, 0x30, 0x7f, 0x3f, 0x9e, 0x79, 0x75, 0x3f, 0x4a, 0xd7, - 0x61, 0x41, 0xbf, 0xc6, 0x25, 0xb0, 0x5b, 0xb9, 0x96, 0xb1, 0x1b, 0x93, 0x33, 0x18, 0xb0, 0x42, - 0x44, 0x2c, 0x41, 0x3f, 0xc7, 0x80, 0xb3, 0xd4, 0xdc, 0x95, 0x80, 0x7d, 0x95, 0xf5, 0x64, 0x72, - 0xdc, 0x07, 0x60, 0x51, 0x54, 0xe4, 0x39, 0xa6, 0x11, 0xda, 0x77, 0x30, 0x58, 0x6e, 0xee, 0x83, - 0x81, 0x68, 0x0f, 0x06, 0x42, 0xde, 0x40, 0x57, 0x1e, 0xa1, 0xec, 0x8a, 0x3e, 0xec, 0x5d, 0x0e, - 0x9d, 0xf5, 0xcb, 0xe0, 0x2c, 0x36, 0xdc, 0x53, 0x3c, 0x3b, 0x58, 0x39, 0xd2, 0xf2, 0x9e, 0xa8, - 0x8b, 0x35, 0x2f, 0xa1, 0x6d, 0x58, 0xe2, 0x0b, 0x9c, 0xac, 0xbb, 0x35, 0xaa, 0xc6, 0x04, 0x8c, - 0x5b, 0x99, 0xa7, 0x58, 0x97, 0xb9, 0x68, 0x2b, 0xb3, 0xac, 0xe5, 0xcd, 0xc9, 0x97, 0xbf, 0x74, - 0x30, 0x6e, 0x6a, 0x1c, 0xf9, 0x0c, 0xdb, 0xe5, 0x52, 0x93, 0xf3, 0x36, 0xb1, 0x85, 0x0f, 0x84, - 0x35, 0xfc, 0x33, 0xb0, 0xb2, 0x6c, 0x6f, 0x91, 0x00, 0xba, 0xd5, 0x0e, 0x92, 0xa7, 0x6d, 0xac, - 0xa5, 0x75, 0xb6, 0x2e, 0xfe, 0x06, 0xda, 0x94, 0xf8, 0xae, 0xc1, 0xc1, 0xca, 0xe9, 0x90, 0x97, - 0x6d, 0x3a, 0x6d, 0x8b, 0x6f, 0xbd, 0xda, 0x80, 0xd9, 0x18, 0xfa, 0xa1, 0xc1, 0xe1, 0xea, 0x59, - 0x92, 0x7f, 0xd5, 0x9d, 0x7f, 0x35, 0xac, 0xd7, 0x9b, 0x50, 0x6b, 0x4f, 0x63, 0x84, 0x93, 0x88, - 0x25, 0x2d, 0x12, 0xe3, 0x41, 0x73, 0x23, 0xae, 0xcb, 0x3f, 0xc6, 0xb5, 0xf6, 0xe9, 0xd9, 0x94, - 0x8a, 0xdb, 0x22, 0x74, 0x22, 0x96, 0x8c, 0x4a, 0xe2, 0x68, 0x81, 0x38, 0x0a, 0x32, 0x3a, 0x6a, - 0xc8, 0x23, 0xf9, 0x93, 0xc9, 0xc2, 0xb0, 0x2b, 0x1f, 0x9e, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, - 0x91, 0x90, 0xfc, 0xc7, 0x80, 0x06, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4d, 0x6f, 0xd3, 0x40, + 0x10, 0xad, 0xeb, 0x34, 0x89, 0x27, 0x69, 0xa8, 0x56, 0x50, 0x19, 0xab, 0xad, 0x8a, 0xa5, 0xaa, + 0xa1, 0x07, 0x47, 0x94, 0x0b, 0x70, 0x42, 0x11, 0xa8, 0x49, 0x25, 0x50, 0xb5, 0x15, 0x17, 0x38, + 0x58, 0xfe, 0x18, 0xa5, 0x8b, 0xb0, 0xd7, 0xf5, 0xae, 0x2b, 0xf5, 0x07, 0x70, 0x45, 0xe2, 0x9f, + 0xf6, 0x27, 0x20, 0xaf, 0xd7, 0x4e, 0x5b, 0xa5, 0x06, 0x7a, 0xdb, 0x99, 0xcc, 0x7b, 0xf3, 0xf6, + 0xed, 0x4c, 0x0c, 0x4f, 0x84, 0xe4, 0x57, 0x98, 0xb1, 0x0c, 0xbd, 0x2c, 0xe7, 0x92, 0x13, 0xa7, + 0x08, 0x31, 0xf7, 0x44, 0x11, 0x26, 0x4c, 0x5e, 0x16, 0x58, 0xa0, 0xd7, 0x54, 0xb8, 0x87, 0x30, + 0x38, 0x63, 0xe9, 0x82, 0xe2, 0x65, 0x81, 0x42, 0x12, 0x1b, 0x7a, 0x09, 0x0a, 0x11, 0x2c, 0xd0, + 0x36, 0xf6, 0x8d, 0xb1, 0x45, 0xeb, 0xd0, 0xfd, 0x69, 0xc0, 0xb0, 0xaa, 0x14, 0x19, 0x4f, 0x05, + 0x3e, 0x5c, 0x4a, 0x5e, 0xc0, 0x50, 0x60, 0x7e, 0xc5, 0x22, 0xf4, 0xd3, 0x20, 0x41, 0x7b, 0x5d, + 0xfd, 0x3c, 0xd0, 0xb9, 0xcf, 0x41, 0x82, 0x64, 0x07, 0x2c, 0xc9, 0x12, 0x14, 0x32, 0x48, 0x32, + 0xdb, 0xdc, 0x37, 0xc6, 0x26, 0x5d, 0x26, 0x88, 0x03, 0xfd, 0x0b, 0x2e, 0xa4, 0x02, 0x77, 0x14, + 0xb8, 0x89, 0xdd, 0x03, 0xd8, 0x9c, 0xa7, 0x0b, 0x14, 0xb2, 0x96, 0xfc, 0x14, 0x36, 0xd4, 0xa5, + 0xb4, 0x8a, 0x2a, 0x70, 0xf7, 0x61, 0x54, 0x97, 0x69, 0xbd, 0x23, 0x58, 0x67, 0xb1, 0x2e, 0x5a, + 0x67, 0xb1, 0x7b, 0x0e, 0x3b, 0x27, 0x58, 0xb3, 0xcc, 0x98, 0x90, 0x3c, 0xbf, 0x9e, 0x5e, 0xcf, + 0x3f, 0xb4, 0xf2, 0x92, 0x5d, 0x80, 0xbc, 0x2a, 0xf0, 0x59, 0xac, 0x6f, 0x66, 0xe9, 0xcc, 0x3c, + 0x76, 0x4f, 0x60, 0x77, 0x05, 0xe9, 0x17, 0x3a, 0x6f, 0x67, 0xdd, 0x02, 0xb3, 0xc8, 0x99, 0xa6, + 0x2b, 0x8f, 0xee, 0x8d, 0x01, 0x43, 0x8d, 0xff, 0x78, 0x85, 0xa9, 0x24, 0xcf, 0xa1, 0x8f, 0xe5, + 0xc1, 0x6f, 0x2e, 0xd1, 0x53, 0xf1, 0x3c, 0x2e, 0xfd, 0x6e, 0xbc, 0xf3, 0x13, 0xa1, 0x68, 0x4c, + 0x3a, 0x68, 0x72, 0x9f, 0x04, 0x39, 0x80, 0xcd, 0x5a, 0xb6, 0x90, 0x81, 0x44, 0xe5, 0xb9, 0x35, + 0x5b, 0xa3, 0x43, 0x9d, 0x3e, 0x2f, 0xb3, 0x64, 0x1b, 0x36, 0x14, 0x69, 0xe5, 0xfa, 0x6c, 0x8d, + 0x56, 0x21, 0x39, 0x80, 0x11, 0x2f, 0x64, 0xc4, 0x13, 0xf4, 0x73, 0x0c, 0x04, 0x4f, 0xed, 0x9e, + 0x92, 0xb0, 0xa9, 0xb3, 0x54, 0x25, 0xa7, 0x43, 0x00, 0x1e, 0x45, 0x45, 0x9e, 0x63, 0x1a, 0xe1, + 0x69, 0xa7, 0xbf, 0xb1, 0xd5, 0x3d, 0xed, 0xf4, 0xbb, 0x5b, 0x3d, 0x6a, 0x8b, 0x22, 0xc3, 0x5c, + 0x60, 0x8c, 0xb1, 0x1f, 0x5e, 0xfb, 0x4b, 0x0b, 0x69, 0x3f, 0x2c, 0xd8, 0x8f, 0xd8, 0x67, 0xb1, + 0x7b, 0x09, 0xa3, 0xbb, 0xc6, 0xdd, 0x33, 0xdb, 0xb8, 0x67, 0x36, 0x79, 0x0f, 0x5d, 0x25, 0xaf, + 0xbc, 0xb1, 0x39, 0x1e, 0x1c, 0x8f, 0xbd, 0x87, 0x07, 0xdd, 0xbb, 0x6d, 0x26, 0xd5, 0x38, 0x37, + 0x58, 0xf9, 0x5c, 0xe5, 0x0c, 0xe8, 0xa1, 0x59, 0xb6, 0x30, 0x1e, 0xd9, 0xe2, 0x3b, 0xec, 0x3d, + 0x34, 0x11, 0xba, 0xc7, 0x0c, 0xac, 0x0b, 0x95, 0x67, 0x58, 0xb7, 0x39, 0x6a, 0x6b, 0x73, 0x97, + 0x8b, 0x2e, 0xc1, 0xc7, 0x37, 0x26, 0x58, 0xe7, 0x75, 0x1d, 0xf9, 0x06, 0x9d, 0x72, 0x61, 0xc9, + 0x61, 0x1b, 0xd9, 0xad, 0xe5, 0x77, 0xc6, 0x7f, 0x2f, 0xac, 0x24, 0xbb, 0x6b, 0x24, 0x80, 0x6e, + 0xb5, 0x5f, 0xe4, 0x65, 0x1b, 0xea, 0xce, 0xaa, 0x3a, 0x47, 0xff, 0x52, 0xda, 0xb4, 0xf8, 0x65, + 0xc0, 0xb3, 0x95, 0xaf, 0x43, 0xde, 0xb4, 0xf1, 0xb4, 0x2d, 0xb5, 0xf3, 0xf6, 0x11, 0xc8, 0x46, + 0xd0, 0x6f, 0x03, 0xb6, 0x57, 0xbf, 0x25, 0xf9, 0x5f, 0xde, 0xe5, 0x3f, 0x82, 0xf3, 0xee, 0x31, + 0xd0, 0x5a, 0xd3, 0x14, 0x61, 0x2f, 0xe2, 0x49, 0x0b, 0xc5, 0x74, 0xd4, 0x4c, 0xc4, 0x59, 0xf9, + 0x35, 0x38, 0x33, 0xbe, 0xbe, 0x5a, 0x30, 0x79, 0x51, 0x84, 0x5e, 0xc4, 0x93, 0x49, 0x09, 0x9c, + 0xdc, 0x02, 0x4e, 0x82, 0x8c, 0x4d, 0x1a, 0xf0, 0x44, 0x7d, 0x40, 0xb2, 0x30, 0xec, 0xaa, 0xc3, + 0xeb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x5f, 0x2b, 0xfd, 0x5c, 0x06, 0x00, 0x00, }, } diff --git a/doc/rfc/stovepipe/request-history-api.md b/doc/rfc/stovepipe/request-history-api.md index 79b5b33b2..12696f2d8 100644 --- a/doc/rfc/stovepipe/request-history-api.md +++ b/doc/rfc/stovepipe/request-history-api.md @@ -19,7 +19,7 @@ SubmitQueue's URI method returns several histories because the same change may b ## Representative Contract -The final protobuf receives a separate compatibility review before implementation. Its representative shape is: +The protobuf contract is: ```proto message GetRequestHistoryByIDRequest { @@ -39,8 +39,8 @@ message HistoryEvent { string request_state = 3; string event = 4; } - string superseded_by_request_id = 5; - string build_id = 6; + reserved 5, 6; + reserved "superseded_by_request_id", "build_id"; string outcome_reason = 7; } @@ -69,11 +69,11 @@ Event IDs are opaque. Clients may compare them but never parse their format. Req ## Selection Flow -Request-ID lookup validates the queue and ID, loads the queue's `Request` to validate the selector, and lists its `RequestLogStore` records. Its response projects only the ordered events, matching SubmitQueue's equivalent API. +Request-ID lookup validates the queue and ID and lists the queue's `RequestLogStore` records. At least one retained log record defines the existence of a history; the API does not consult the operational `Request` entity. Its response projects only the ordered events, matching SubmitQueue's equivalent API. -URI lookup currently resolves one request ID from the existing `RequestURIStore` primary key and delegates to the same request-ID path. Supporting multiple retained attempts later requires the URI index to enumerate their request IDs; each history still uses primary-key reads for its Request and log. The API does not scan the request log by URI. A missing mapping is not found; a mapping whose Request is missing is an internal consistency error. +URI lookup currently resolves one request ID from the existing `RequestURIStore` primary key and delegates to the same retained-log read. Supporting multiple retained attempts later requires the URI index to enumerate their request IDs; each history still uses a primary-key log read. The API does not scan the request log by URI. A missing mapping or a mapped request ID with no retained log is not found. -Every request-URI mapping must be repaired and retained with its Request and history. Otherwise URI lookup could lose coverage while request-ID lookup still succeeds. Each `RequestHistory` contains only the selected request ID and its events; URI, build strategy, and base URI remain resolvable from the Request rather than being duplicated in the history response. +Every request-URI mapping must be retained for the same advertised period as its history. Otherwise URI lookup could lose coverage while request-ID lookup still succeeds. Each `RequestHistory` contains only the selected request ID and its events; operational request context is not duplicated in the history response. ## Public Projection @@ -92,9 +92,9 @@ History events representing state changes set `request_state` and preserve each These strings intentionally match the current domain states one-to-one, but they are a stable public history vocabulary: an internal refactor cannot rename or reinterpret an existing wire value. In particular, `succeeded` and `failed` remain distinct rather than collapsing into a derived snapshot phase such as `finalizing`. -Build events set `event` and decode `build_id` from the reserved request-log metadata key. `validation_fact_recorded` records that a fact was established, while its degree remains internal metadata until a typed public projection is designed. Superseded state events similarly decode `superseded_by_request_id`. The `occurrence` oneof makes state and event mutually exclusive without a redundant type field. A terminal Request state entry never substitutes for the fact event. +Build and validation-fact occurrences set `event`. The `occurrence` oneof makes state and event mutually exclusive without a redundant type field. A terminal Request state entry never substitutes for the fact event. -The raw `RequestLog.Metadata` map, unknown metadata keys, dependency errors, credentials, and stack traces are not exposed. `outcome_reason` uses a bounded public vocabulary. +The raw `RequestLog.Metadata` map, request version, dependency errors, credentials, and stack traces are not exposed. Typed metadata projections can be added later when a concrete client need defines their contract. `outcome_reason` uses a bounded public vocabulary. ## Materialization @@ -123,13 +123,13 @@ Request-ID lookup and the corresponding history within URI lookup return the sam Request-ID lookup returns all currently retained events for the selected request. URI lookup returns every retained request history associated with the exact URI. This matches SubmitQueue's request-history response shapes. The bounded lifecycle vocabulary and reasonable per-request build limits keep each history modest. -History, `Request`, and request-URI mapping retention must support the same advertised lookup period. The API does not promise a lifetime longer than every record required by its selector. The initial rollout exposes only requests accepted after all history writers and repair paths are active; older requests are outside the lookup period and are not backfilled. +History and request-URI mapping retention must support the same advertised lookup period. The API does not promise a lifetime longer than every record required by its selector. The initial rollout exposes only requests accepted after all history writers and repair paths are active; older requests without retained logs are outside the lookup period and are not backfilled. ## Errors and Authorization - Empty queue or selector is invalid. - An unknown request ID or URI, including one scoped to the wrong queue, is not found. -- A URI mapping whose Request is missing and a request within the advertised history lookup period whose required history is missing are internal consistency errors. +- A request ID or URI with no retained history is not found, including a URI mapping whose request ID has no retained log rows. - Retryable storage failures are unavailable; context cancellation and deadline errors retain their canonical codes. Authorization follows the same queue policy as other Stovepipe reads. Possession of a request ID alone does not bypass queue authorization. @@ -142,7 +142,7 @@ Contract and controller tests cover: - deterministic equal-timestamp ordering; - state, build-event, and fact-event public mapping; - queue isolation and cross-queue not found; -- unknown selectors versus dangling mappings; +- unknown selectors and URI mappings without retained logs; - a repaired older occurrence appearing in chronological position; - unknown future request-state and event strings remaining readable. diff --git a/service/stovepipe/server/mapper/BUILD.bazel b/service/stovepipe/server/mapper/BUILD.bazel index 88d60b597..e78b6a4df 100644 --- a/service/stovepipe/server/mapper/BUILD.bazel +++ b/service/stovepipe/server/mapper/BUILD.bazel @@ -2,7 +2,10 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = ["ingest.go"], + srcs = [ + "ingest.go", + "request_history.go", + ], importpath = "github.com/uber/submitqueue/service/stovepipe/server/mapper", visibility = ["//visibility:public"], deps = [ @@ -13,7 +16,10 @@ go_library( go_test( name = "go_default_test", - srcs = ["ingest_test.go"], + srcs = [ + "ingest_test.go", + "request_history_test.go", + ], embed = [":go_default_library"], deps = [ "//api/stovepipe/protopb:go_default_library", diff --git a/service/stovepipe/server/mapper/request_history.go b/service/stovepipe/server/mapper/request_history.go new file mode 100644 index 000000000..551648d35 --- /dev/null +++ b/service/stovepipe/server/mapper/request_history.go @@ -0,0 +1,61 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mapper + +import ( + pb "github.com/uber/submitqueue/api/stovepipe/protopb" + "github.com/uber/submitqueue/stovepipe/entity" +) + +// ProtoToGetRequestHistoryByIDRequest maps a wire request to its domain value. +func ProtoToGetRequestHistoryByIDRequest(req *pb.GetRequestHistoryByIDRequest) entity.GetRequestHistoryByIDRequest { + return entity.GetRequestHistoryByIDRequest{ID: req.GetRequestId(), Queue: req.GetQueue()} +} + +// ProtoToGetRequestHistoryByURIRequest maps a wire request to its domain value. +func ProtoToGetRequestHistoryByURIRequest(req *pb.GetRequestHistoryByURIRequest) entity.GetRequestHistoryByURIRequest { + return entity.GetRequestHistoryByURIRequest{URI: req.GetUri(), Queue: req.GetQueue()} +} + +// HistoryEventsToProto maps retained request-log events to wire history events. +func HistoryEventsToProto(logs []entity.RequestLog) []*pb.HistoryEvent { + events := make([]*pb.HistoryEvent, len(logs)) + for i, log := range logs { + event := &pb.HistoryEvent{ + EventId: log.ID, + TimestampMs: log.TimestampMs, + OutcomeReason: string(log.OutcomeReason), + } + if log.State != entity.RequestStateUnknown { + event.Occurrence = &pb.HistoryEvent_RequestState{RequestState: string(log.State)} + } else { + event.Occurrence = &pb.HistoryEvent_Event{Event: string(log.Event)} + } + events[i] = event + } + return events +} + +// RequestHistoriesToProto maps grouped retained histories to their wire representation. +func RequestHistoriesToProto(histories []entity.RequestHistory) []*pb.RequestHistory { + result := make([]*pb.RequestHistory, len(histories)) + for i, history := range histories { + result[i] = &pb.RequestHistory{ + RequestId: history.RequestID, + Events: HistoryEventsToProto(history.Events), + } + } + return result +} diff --git a/service/stovepipe/server/mapper/request_history_test.go b/service/stovepipe/server/mapper/request_history_test.go new file mode 100644 index 000000000..6292b4651 --- /dev/null +++ b/service/stovepipe/server/mapper/request_history_test.go @@ -0,0 +1,174 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mapper + +import ( + "testing" + + "github.com/stretchr/testify/assert" + pb "github.com/uber/submitqueue/api/stovepipe/protopb" + "github.com/uber/submitqueue/stovepipe/entity" +) + +func TestProtoToGetRequestHistoryByIDRequest(t *testing.T) { + tests := []struct { + name string + req *pb.GetRequestHistoryByIDRequest + want entity.GetRequestHistoryByIDRequest + }{ + { + name: "maps selector", + req: &pb.GetRequestHistoryByIDRequest{Queue: "monorepo/main", RequestId: "request/monorepo/main/1"}, + want: entity.GetRequestHistoryByIDRequest{Queue: "monorepo/main", ID: "request/monorepo/main/1"}, + }, + { + name: "empty request yields zero value", + req: &pb.GetRequestHistoryByIDRequest{}, + want: entity.GetRequestHistoryByIDRequest{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, ProtoToGetRequestHistoryByIDRequest(tt.req)) + }) + } +} + +func TestProtoToGetRequestHistoryByURIRequest(t *testing.T) { + tests := []struct { + name string + req *pb.GetRequestHistoryByURIRequest + want entity.GetRequestHistoryByURIRequest + }{ + { + name: "maps selector", + req: &pb.GetRequestHistoryByURIRequest{Queue: "monorepo/main", Uri: "git://remote/monorepo/main/abc"}, + want: entity.GetRequestHistoryByURIRequest{Queue: "monorepo/main", URI: "git://remote/monorepo/main/abc"}, + }, + { + name: "empty request yields zero value", + req: &pb.GetRequestHistoryByURIRequest{}, + want: entity.GetRequestHistoryByURIRequest{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, ProtoToGetRequestHistoryByURIRequest(tt.req)) + }) + } +} + +func TestHistoryEventsToProto(t *testing.T) { + state := entity.RequestLog{ + ID: "state/2", + TimestampMs: 20, + State: entity.RequestStateFailed, + RequestVersion: 2, + OutcomeReason: entity.RequestOutcomeReasonProcessingFailed, + Metadata: map[string]string{"debug": "not public"}, + } + occurrence := entity.RequestLog{ + ID: "event/build-finished", + TimestampMs: 30, + Event: entity.RequestEventBuildFinished, + } + futureState := entity.RequestLog{ID: "state/future", TimestampMs: 40, State: entity.RequestState("future_state")} + futureEvent := entity.RequestLog{ID: "event/future", TimestampMs: 50, Event: entity.RequestEvent("future_event")} + + tests := []struct { + name string + logs []entity.RequestLog + want []*pb.HistoryEvent + }{ + { + name: "maps state and event vocabulary without internal fields", + logs: []entity.RequestLog{state, occurrence, occurrence, futureState, futureEvent}, + want: []*pb.HistoryEvent{ + { + EventId: "state/2", + TimestampMs: 20, + Occurrence: &pb.HistoryEvent_RequestState{RequestState: "failed"}, + OutcomeReason: "processing_failed", + }, + { + EventId: "event/build-finished", + TimestampMs: 30, + Occurrence: &pb.HistoryEvent_Event{Event: "build_finished"}, + }, + { + EventId: "event/build-finished", + TimestampMs: 30, + Occurrence: &pb.HistoryEvent_Event{Event: "build_finished"}, + }, + { + EventId: "state/future", + TimestampMs: 40, + Occurrence: &pb.HistoryEvent_RequestState{RequestState: "future_state"}, + }, + { + EventId: "event/future", + TimestampMs: 50, + Occurrence: &pb.HistoryEvent_Event{Event: "future_event"}, + }, + }, + }, + {name: "nil input", logs: nil, want: []*pb.HistoryEvent{}}, + {name: "empty input", logs: []entity.RequestLog{}, want: []*pb.HistoryEvent{}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, HistoryEventsToProto(tt.logs)) + }) + } +} + +func TestRequestHistoriesToProto(t *testing.T) { + logs := []entity.RequestLog{{ID: "state/1", TimestampMs: 10, State: entity.RequestStateAccepted}} + tests := []struct { + name string + histories []entity.RequestHistory + want []*pb.RequestHistory + }{ + { + name: "maps groups in order", + histories: []entity.RequestHistory{ + {RequestID: "request/monorepo/main/1", Events: logs}, + {RequestID: "request/monorepo/main/2", Events: []entity.RequestLog{}}, + }, + want: []*pb.RequestHistory{ + { + RequestId: "request/monorepo/main/1", + Events: []*pb.HistoryEvent{{ + EventId: "state/1", + TimestampMs: 10, + Occurrence: &pb.HistoryEvent_RequestState{RequestState: "accepted"}, + }}, + }, + {RequestId: "request/monorepo/main/2", Events: []*pb.HistoryEvent{}}, + }, + }, + {name: "nil input", histories: nil, want: []*pb.RequestHistory{}}, + {name: "empty input", histories: []entity.RequestHistory{}, want: []*pb.RequestHistory{}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, RequestHistoriesToProto(tt.histories)) + }) + } +} diff --git a/stovepipe/entity/BUILD.bazel b/stovepipe/entity/BUILD.bazel index 19518f9e1..d47984694 100644 --- a/stovepipe/entity/BUILD.bazel +++ b/stovepipe/entity/BUILD.bazel @@ -8,6 +8,7 @@ go_library( "queue.go", "queue_config.go", "request.go", + "request_history.go", "request_id.go", "request_log.go", "validation_fact.go", diff --git a/stovepipe/entity/request_history.go b/stovepipe/entity/request_history.go new file mode 100644 index 000000000..6c2313417 --- /dev/null +++ b/stovepipe/entity/request_history.go @@ -0,0 +1,39 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package entity + +// GetRequestHistoryByIDRequest identifies one retained request history by request ID. +type GetRequestHistoryByIDRequest struct { + // ID is the globally unique identifier of the request. + ID string + // Queue is the logical queue containing the request and scopes the lookup. + Queue string +} + +// GetRequestHistoryByURIRequest identifies retained histories by an exact commit URI. +type GetRequestHistoryByURIRequest struct { + // URI is the exact VCS-agnostic commit URI associated with the request. + URI string + // Queue is the logical queue containing the request and scopes the lookup. + Queue string +} + +// RequestHistory groups retained events for one request. +type RequestHistory struct { + // RequestID is the globally unique identifier of the request. + RequestID string + // Events are retained request-log events ordered by occurrence time and stable identity. + Events []RequestLog +} diff --git a/stovepipe/extension/storage/mysql/request_log_store.go b/stovepipe/extension/storage/mysql/request_log_store.go index 54ed16774..85e567282 100644 --- a/stovepipe/extension/storage/mysql/request_log_store.go +++ b/stovepipe/extension/storage/mysql/request_log_store.go @@ -134,6 +134,9 @@ func (r *requestLogStore) List(ctx context.Context, requestID string) (ret []ent if err := rows.Err(); err != nil { return nil, fmt.Errorf("failed to iterate request log request_id=%q: %w", requestID, err) } + if len(logs) == 0 { + return nil, fmt.Errorf("no request log records for queue=%q request_id=%q: %w", r.queue, requestID, storage.ErrNotFound) + } return logs, nil } diff --git a/stovepipe/extension/storage/mysql/request_log_store_test.go b/stovepipe/extension/storage/mysql/request_log_store_test.go index 8b42aad9f..1c46a5678 100644 --- a/stovepipe/extension/storage/mysql/request_log_store_test.go +++ b/stovepipe/extension/storage/mysql/request_log_store_test.go @@ -275,10 +275,11 @@ func TestRequestLogStoreList(t *testing.T) { second.RequestVersion = 2 tests := []struct { - name string - setup func(sqlmock.Sqlmock) - want []entity.RequestLog - wantErr bool + name string + setup func(sqlmock.Sqlmock) + want []entity.RequestLog + wantErrIs error + wantErr bool }{ { name: "all records", @@ -297,7 +298,8 @@ func TestRequestLogStoreList(t *testing.T) { WithArgs(testLogQueue, testLogRequestID). WillReturnRows(sqlmock.NewRows(requestLogColumnNames)) }, - want: []entity.RequestLog{}, + wantErr: true, + wantErrIs: storage.ErrNotFound, }, { name: "database failure", @@ -321,6 +323,9 @@ func TestRequestLogStoreList(t *testing.T) { got, err := store.List(context.Background(), testLogRequestID) if tt.wantErr { require.Error(t, err) + if tt.wantErrIs != nil { + assert.ErrorIs(t, err, tt.wantErrIs) + } } else { require.NoError(t, err) assert.Equal(t, tt.want, got) diff --git a/stovepipe/extension/storage/request_log_store.go b/stovepipe/extension/storage/request_log_store.go index cd19b8698..a80ce7c04 100644 --- a/stovepipe/extension/storage/request_log_store.go +++ b/stovepipe/extension/storage/request_log_store.go @@ -30,6 +30,6 @@ type RequestLogStore interface { // Get returns one record identified by requestID and logID, or ErrNotFound when absent. Get(ctx context.Context, requestID, logID string) (entity.RequestLog, error) - // List returns all records for one request ordered by timestamp and log ID ascending. + // List returns all records for one request ordered by timestamp and log ID ascending, or ErrNotFound when none are retained. List(ctx context.Context, requestID string) ([]entity.RequestLog, error) } diff --git a/test/integration/stovepipe/extension/storage/suite.go b/test/integration/stovepipe/extension/storage/suite.go index 0b660ac29..8e5665093 100644 --- a/test/integration/stovepipe/extension/storage/suite.go +++ b/test/integration/stovepipe/extension/storage/suite.go @@ -288,6 +288,12 @@ func (s *RequestLogStoreContractSuite) TestRequestLogStore_List() { assert.Equal(s.T(), []entity.RequestLog{first, second, last}, logs) } +// TestRequestLogStore_ListNotFound verifies a request with no retained records returns ErrNotFound. +func (s *RequestLogStoreContractSuite) TestRequestLogStore_ListNotFound() { + _, err := s.storeFor("contract/history-list-missing").List(s.ctx, "request/shared/1") + assert.ErrorIs(s.T(), err, storage.ErrNotFound) +} + // TestRequestLogStore_QueueIsolation verifies identical request and entry IDs remain queue-scoped. func (s *RequestLogStoreContractSuite) TestRequestLogStore_QueueIsolation() { const requestID = "request/shared/1" @@ -303,6 +309,9 @@ func (s *RequestLogStoreContractSuite) TestRequestLogStore_QueueIsolation() { gotB, err := s.storeFor(entryB.Queue).Get(s.ctx, requestID, entryB.ID) require.NoError(s.T(), err) assert.Equal(s.T(), entryB, gotB) + + _, err = s.storeFor("contract/history-c").List(s.ctx, requestID) + assert.ErrorIs(s.T(), err, storage.ErrNotFound) } // BuildStoreContractSuite defines contract tests for storage.BuildStore. From fbf24999bb5dc581e5d53503ed8a8ebcc5c37108 Mon Sep 17 00:00:00 2001 From: mnoah1 Date: Thu, 3 Sep 2026 00:34:41 +0000 Subject: [PATCH 2/3] fix(stovepipe): drop undeployed history field reservations --- api/stovepipe/proto/stovepipe.proto | 2 - api/stovepipe/protopb/stovepipe.pb.go | 4 +- api/stovepipe/protopb/stovepipe.pb.yarpc.go | 74 ++++++++++----------- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/api/stovepipe/proto/stovepipe.proto b/api/stovepipe/proto/stovepipe.proto index 589725f02..6837fecf2 100644 --- a/api/stovepipe/proto/stovepipe.proto +++ b/api/stovepipe/proto/stovepipe.proto @@ -83,8 +83,6 @@ message HistoryEvent { // Event that occurred without changing the request state. string event = 4; } - reserved 5, 6; - reserved "superseded_by_request_id", "build_id"; // Stable domain reason for a terminal request outcome. Empty otherwise. string outcome_reason = 7; } diff --git a/api/stovepipe/protopb/stovepipe.pb.go b/api/stovepipe/protopb/stovepipe.pb.go index 2963b3c61..cd95a44a9 100644 --- a/api/stovepipe/protopb/stovepipe.pb.go +++ b/api/stovepipe/protopb/stovepipe.pb.go @@ -643,7 +643,7 @@ const file_stovepipe_proto_rawDesc = "" + "request_id\x18\x02 \x01(\tR\trequestId\"G\n" + "\x1dGetRequestHistoryByURIRequest\x12\x14\n" + "\x05queue\x18\x01 \x01(\tR\x05queue\x12\x10\n" + - "\x03uri\x18\x02 \x01(\tR\x03uri\"\xf0\x01\n" + + "\x03uri\x18\x02 \x01(\tR\x03uri\"\xc0\x01\n" + "\fHistoryEvent\x12\x19\n" + "\bevent_id\x18\x01 \x01(\tR\aeventId\x12!\n" + "\ftimestamp_ms\x18\x02 \x01(\x03R\vtimestampMs\x12%\n" + @@ -651,7 +651,7 @@ const file_stovepipe_proto_rawDesc = "" + "\x05event\x18\x04 \x01(\tH\x00R\x05event\x12%\n" + "\x0eoutcome_reason\x18\a \x01(\tR\routcomeReasonB\f\n" + "\n" + - "occurrenceJ\x04\b\x05\x10\x06J\x04\b\x06\x10\aR\x18superseded_by_request_idR\bbuild_id\"q\n" + + "occurrence\"q\n" + "\x0eRequestHistory\x12\x1d\n" + "\n" + "request_id\x18\x01 \x01(\tR\trequestId\x12@\n" + diff --git a/api/stovepipe/protopb/stovepipe.pb.yarpc.go b/api/stovepipe/protopb/stovepipe.pb.yarpc.go index a4b8d8deb..71c971ecf 100644 --- a/api/stovepipe/protopb/stovepipe.pb.yarpc.go +++ b/api/stovepipe/protopb/stovepipe.pb.yarpc.go @@ -376,44 +376,42 @@ var ( var yarpcFileDescriptorClosurefabdb6b3c0b09022 = [][]byte{ // stovepipe.proto []byte{ - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0xad, 0xeb, 0x34, 0x89, 0x27, 0x69, 0xa8, 0x56, 0x50, 0x19, 0xab, 0xad, 0x8a, 0xa5, 0xaa, - 0xa1, 0x07, 0x47, 0x94, 0x0b, 0x70, 0x42, 0x11, 0xa8, 0x49, 0x25, 0x50, 0xb5, 0x15, 0x17, 0x38, - 0x58, 0xfe, 0x18, 0xa5, 0x8b, 0xb0, 0xd7, 0xf5, 0xae, 0x2b, 0xf5, 0x07, 0x70, 0x45, 0xe2, 0x9f, - 0xf6, 0x27, 0x20, 0xaf, 0xd7, 0x4e, 0x5b, 0xa5, 0x06, 0x7a, 0xdb, 0x99, 0xcc, 0x7b, 0xf3, 0xf6, - 0xed, 0x4c, 0x0c, 0x4f, 0x84, 0xe4, 0x57, 0x98, 0xb1, 0x0c, 0xbd, 0x2c, 0xe7, 0x92, 0x13, 0xa7, - 0x08, 0x31, 0xf7, 0x44, 0x11, 0x26, 0x4c, 0x5e, 0x16, 0x58, 0xa0, 0xd7, 0x54, 0xb8, 0x87, 0x30, - 0x38, 0x63, 0xe9, 0x82, 0xe2, 0x65, 0x81, 0x42, 0x12, 0x1b, 0x7a, 0x09, 0x0a, 0x11, 0x2c, 0xd0, - 0x36, 0xf6, 0x8d, 0xb1, 0x45, 0xeb, 0xd0, 0xfd, 0x69, 0xc0, 0xb0, 0xaa, 0x14, 0x19, 0x4f, 0x05, - 0x3e, 0x5c, 0x4a, 0x5e, 0xc0, 0x50, 0x60, 0x7e, 0xc5, 0x22, 0xf4, 0xd3, 0x20, 0x41, 0x7b, 0x5d, - 0xfd, 0x3c, 0xd0, 0xb9, 0xcf, 0x41, 0x82, 0x64, 0x07, 0x2c, 0xc9, 0x12, 0x14, 0x32, 0x48, 0x32, - 0xdb, 0xdc, 0x37, 0xc6, 0x26, 0x5d, 0x26, 0x88, 0x03, 0xfd, 0x0b, 0x2e, 0xa4, 0x02, 0x77, 0x14, - 0xb8, 0x89, 0xdd, 0x03, 0xd8, 0x9c, 0xa7, 0x0b, 0x14, 0xb2, 0x96, 0xfc, 0x14, 0x36, 0xd4, 0xa5, - 0xb4, 0x8a, 0x2a, 0x70, 0xf7, 0x61, 0x54, 0x97, 0x69, 0xbd, 0x23, 0x58, 0x67, 0xb1, 0x2e, 0x5a, - 0x67, 0xb1, 0x7b, 0x0e, 0x3b, 0x27, 0x58, 0xb3, 0xcc, 0x98, 0x90, 0x3c, 0xbf, 0x9e, 0x5e, 0xcf, - 0x3f, 0xb4, 0xf2, 0x92, 0x5d, 0x80, 0xbc, 0x2a, 0xf0, 0x59, 0xac, 0x6f, 0x66, 0xe9, 0xcc, 0x3c, - 0x76, 0x4f, 0x60, 0x77, 0x05, 0xe9, 0x17, 0x3a, 0x6f, 0x67, 0xdd, 0x02, 0xb3, 0xc8, 0x99, 0xa6, - 0x2b, 0x8f, 0xee, 0x8d, 0x01, 0x43, 0x8d, 0xff, 0x78, 0x85, 0xa9, 0x24, 0xcf, 0xa1, 0x8f, 0xe5, - 0xc1, 0x6f, 0x2e, 0xd1, 0x53, 0xf1, 0x3c, 0x2e, 0xfd, 0x6e, 0xbc, 0xf3, 0x13, 0xa1, 0x68, 0x4c, - 0x3a, 0x68, 0x72, 0x9f, 0x04, 0x39, 0x80, 0xcd, 0x5a, 0xb6, 0x90, 0x81, 0x44, 0xe5, 0xb9, 0x35, - 0x5b, 0xa3, 0x43, 0x9d, 0x3e, 0x2f, 0xb3, 0x64, 0x1b, 0x36, 0x14, 0x69, 0xe5, 0xfa, 0x6c, 0x8d, - 0x56, 0x21, 0x39, 0x80, 0x11, 0x2f, 0x64, 0xc4, 0x13, 0xf4, 0x73, 0x0c, 0x04, 0x4f, 0xed, 0x9e, - 0x92, 0xb0, 0xa9, 0xb3, 0x54, 0x25, 0xa7, 0x43, 0x00, 0x1e, 0x45, 0x45, 0x9e, 0x63, 0x1a, 0xe1, - 0x69, 0xa7, 0xbf, 0xb1, 0xd5, 0x3d, 0xed, 0xf4, 0xbb, 0x5b, 0x3d, 0x6a, 0x8b, 0x22, 0xc3, 0x5c, - 0x60, 0x8c, 0xb1, 0x1f, 0x5e, 0xfb, 0x4b, 0x0b, 0x69, 0x3f, 0x2c, 0xd8, 0x8f, 0xd8, 0x67, 0xb1, - 0x7b, 0x09, 0xa3, 0xbb, 0xc6, 0xdd, 0x33, 0xdb, 0xb8, 0x67, 0x36, 0x79, 0x0f, 0x5d, 0x25, 0xaf, - 0xbc, 0xb1, 0x39, 0x1e, 0x1c, 0x8f, 0xbd, 0x87, 0x07, 0xdd, 0xbb, 0x6d, 0x26, 0xd5, 0x38, 0x37, - 0x58, 0xf9, 0x5c, 0xe5, 0x0c, 0xe8, 0xa1, 0x59, 0xb6, 0x30, 0x1e, 0xd9, 0xe2, 0x3b, 0xec, 0x3d, - 0x34, 0x11, 0xba, 0xc7, 0x0c, 0xac, 0x0b, 0x95, 0x67, 0x58, 0xb7, 0x39, 0x6a, 0x6b, 0x73, 0x97, - 0x8b, 0x2e, 0xc1, 0xc7, 0x37, 0x26, 0x58, 0xe7, 0x75, 0x1d, 0xf9, 0x06, 0x9d, 0x72, 0x61, 0xc9, - 0x61, 0x1b, 0xd9, 0xad, 0xe5, 0x77, 0xc6, 0x7f, 0x2f, 0xac, 0x24, 0xbb, 0x6b, 0x24, 0x80, 0x6e, - 0xb5, 0x5f, 0xe4, 0x65, 0x1b, 0xea, 0xce, 0xaa, 0x3a, 0x47, 0xff, 0x52, 0xda, 0xb4, 0xf8, 0x65, - 0xc0, 0xb3, 0x95, 0xaf, 0x43, 0xde, 0xb4, 0xf1, 0xb4, 0x2d, 0xb5, 0xf3, 0xf6, 0x11, 0xc8, 0x46, - 0xd0, 0x6f, 0x03, 0xb6, 0x57, 0xbf, 0x25, 0xf9, 0x5f, 0xde, 0xe5, 0x3f, 0x82, 0xf3, 0xee, 0x31, - 0xd0, 0x5a, 0xd3, 0x14, 0x61, 0x2f, 0xe2, 0x49, 0x0b, 0xc5, 0x74, 0xd4, 0x4c, 0xc4, 0x59, 0xf9, - 0x35, 0x38, 0x33, 0xbe, 0xbe, 0x5a, 0x30, 0x79, 0x51, 0x84, 0x5e, 0xc4, 0x93, 0x49, 0x09, 0x9c, - 0xdc, 0x02, 0x4e, 0x82, 0x8c, 0x4d, 0x1a, 0xf0, 0x44, 0x7d, 0x40, 0xb2, 0x30, 0xec, 0xaa, 0xc3, - 0xeb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x5f, 0x2b, 0xfd, 0x5c, 0x06, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x5d, 0x8f, 0xd2, 0x40, + 0x14, 0xa5, 0x74, 0x17, 0xb6, 0x97, 0x0f, 0xcd, 0x44, 0x37, 0xd8, 0xec, 0x6e, 0xb0, 0x09, 0x59, + 0xdc, 0x87, 0x12, 0xd7, 0x17, 0xf5, 0xc9, 0x10, 0xcd, 0xc2, 0x83, 0x86, 0x94, 0xf8, 0xa2, 0x0f, + 0xa4, 0xb4, 0x37, 0x30, 0x26, 0xed, 0x94, 0xce, 0x94, 0x64, 0x7f, 0x80, 0xaf, 0x26, 0xfe, 0x23, + 0x7f, 0x92, 0x3f, 0xc1, 0x74, 0x3a, 0x2d, 0xb0, 0x81, 0xaa, 0xbc, 0xcd, 0x1c, 0xce, 0x39, 0xf7, + 0xce, 0x99, 0xb9, 0x14, 0x1e, 0x71, 0xc1, 0xd6, 0x18, 0xd1, 0x08, 0xed, 0x28, 0x66, 0x82, 0x11, + 0x33, 0x99, 0x63, 0x6c, 0xf3, 0x64, 0x1e, 0x50, 0xb1, 0x4a, 0x30, 0x41, 0xbb, 0x60, 0x58, 0xd7, + 0xd0, 0x98, 0xd0, 0x70, 0xe1, 0xe0, 0x2a, 0x41, 0x2e, 0x48, 0x07, 0xea, 0x01, 0x72, 0xee, 0x2e, + 0xb0, 0xa3, 0x75, 0xb5, 0xbe, 0xe1, 0xe4, 0x5b, 0xeb, 0xbb, 0x06, 0xcd, 0x8c, 0xc9, 0x23, 0x16, + 0x72, 0x3c, 0x4c, 0x25, 0xcf, 0xa1, 0xc9, 0x31, 0x5e, 0x53, 0x0f, 0x67, 0xa1, 0x1b, 0x60, 0xa7, + 0x2a, 0x7f, 0x6e, 0x28, 0xec, 0x93, 0x1b, 0x20, 0xb9, 0x00, 0x43, 0xd0, 0x00, 0xb9, 0x70, 0x83, + 0xa8, 0xa3, 0x77, 0xb5, 0xbe, 0xee, 0x6c, 0x00, 0x62, 0xc2, 0xd9, 0x92, 0x71, 0x21, 0xc5, 0x27, + 0x52, 0x5c, 0xec, 0xad, 0x1e, 0xb4, 0xc6, 0xe1, 0x02, 0xb9, 0xc8, 0x5b, 0x7e, 0x02, 0xa7, 0xf2, + 0x50, 0xaa, 0x8b, 0x6c, 0x63, 0x75, 0xa1, 0x9d, 0xd3, 0x54, 0xbf, 0x6d, 0xa8, 0x52, 0x5f, 0x91, + 0xaa, 0xd4, 0xb7, 0xa6, 0x70, 0x71, 0x87, 0xb9, 0xcb, 0x88, 0x72, 0xc1, 0xe2, 0xfb, 0xe1, 0xfd, + 0xf8, 0x7d, 0xa9, 0x2f, 0xb9, 0x04, 0x88, 0x33, 0xc2, 0x8c, 0xfa, 0xea, 0x64, 0x86, 0x42, 0xc6, + 0xbe, 0x75, 0x07, 0x97, 0x7b, 0x4c, 0x3f, 0x3b, 0xe3, 0x72, 0xd7, 0xc7, 0xa0, 0x27, 0x31, 0x55, + 0x76, 0xe9, 0xd2, 0xfa, 0xa5, 0x41, 0x53, 0xe9, 0x3f, 0xac, 0x31, 0x14, 0xe4, 0x19, 0x9c, 0x61, + 0xba, 0x98, 0x15, 0x87, 0xa8, 0xcb, 0xfd, 0xd8, 0x4f, 0xf3, 0x2e, 0xb2, 0x9b, 0x05, 0x5c, 0xda, + 0xe8, 0x4e, 0xa3, 0xc0, 0x3e, 0x72, 0xd2, 0x83, 0x56, 0xde, 0x36, 0x17, 0xae, 0x40, 0x99, 0xb9, + 0x31, 0xaa, 0x38, 0x4d, 0x05, 0x4f, 0x53, 0x94, 0x9c, 0xc3, 0xa9, 0x34, 0xcd, 0x52, 0x1f, 0x55, + 0x9c, 0x6c, 0x4b, 0x7a, 0xd0, 0x66, 0x89, 0xf0, 0x58, 0x80, 0xb3, 0x18, 0x5d, 0xce, 0xc2, 0x4e, + 0x5d, 0xb6, 0xd0, 0x52, 0xa8, 0x23, 0xc1, 0x61, 0x13, 0x80, 0x79, 0x5e, 0x12, 0xc7, 0x18, 0x7a, + 0x68, 0xad, 0xa0, 0xbd, 0x1b, 0xc4, 0x83, 0xf0, 0xb4, 0x07, 0xe1, 0x91, 0x77, 0x50, 0x93, 0xe5, + 0xd2, 0x13, 0xe8, 0xfd, 0xc6, 0x6d, 0xdf, 0x3e, 0xfc, 0x70, 0xed, 0xed, 0x70, 0x1c, 0xa5, 0xb3, + 0xdc, 0xbd, 0xf1, 0xa7, 0x77, 0xaa, 0x1e, 0xc1, 0xa6, 0x84, 0x76, 0x64, 0x89, 0x6f, 0x70, 0x75, + 0xe8, 0x86, 0x55, 0x8d, 0x11, 0x18, 0x4b, 0x89, 0x53, 0xcc, 0xcb, 0xdc, 0x94, 0x95, 0xd9, 0xf5, + 0x72, 0x36, 0xe2, 0xdb, 0xdf, 0x3a, 0x18, 0xd3, 0x9c, 0x47, 0xbe, 0xc2, 0x49, 0x3a, 0x80, 0xe4, + 0xba, 0xcc, 0x6c, 0x6b, 0x98, 0xcd, 0xfe, 0xdf, 0x89, 0x59, 0xcb, 0x56, 0x85, 0xb8, 0x50, 0xcb, + 0xe6, 0x85, 0xbc, 0x28, 0x53, 0xed, 0x8c, 0x9e, 0x79, 0xf3, 0x2f, 0xd4, 0xa2, 0xc4, 0x0f, 0x0d, + 0x9e, 0xee, 0xbd, 0x1d, 0xf2, 0xba, 0xcc, 0xa7, 0x6c, 0x48, 0xcd, 0x37, 0x47, 0x28, 0x8b, 0x86, + 0x7e, 0x6a, 0x70, 0xbe, 0xff, 0x2e, 0xc9, 0xff, 0xfa, 0x6e, 0x26, 0xdc, 0x7c, 0x7b, 0x8c, 0x34, + 0xef, 0x69, 0x88, 0x70, 0xe5, 0xb1, 0xa0, 0xc4, 0x62, 0xd8, 0x2e, 0x5e, 0xc4, 0x24, 0xfd, 0x77, + 0x9f, 0x68, 0x5f, 0x5e, 0x2e, 0xa8, 0x58, 0x26, 0x73, 0xdb, 0x63, 0xc1, 0x20, 0x15, 0x0e, 0xb6, + 0x84, 0x03, 0x37, 0xa2, 0x83, 0x42, 0x3c, 0x90, 0x1f, 0x84, 0x68, 0x3e, 0xaf, 0xc9, 0xc5, 0xab, + 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x4a, 0x85, 0xe6, 0x2c, 0x06, 0x00, 0x00, }, } From a24636a858cec907a55cc497ca4f65bff4772dfe Mon Sep 17 00:00:00 2001 From: mnoah1 Date: Thu, 3 Sep 2026 00:38:39 +0000 Subject: [PATCH 3/3] docs(stovepipe): align undeployed history fields --- doc/rfc/stovepipe/request-history-api.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/rfc/stovepipe/request-history-api.md b/doc/rfc/stovepipe/request-history-api.md index 12696f2d8..ccdefd9a5 100644 --- a/doc/rfc/stovepipe/request-history-api.md +++ b/doc/rfc/stovepipe/request-history-api.md @@ -39,8 +39,6 @@ message HistoryEvent { string request_state = 3; string event = 4; } - reserved 5, 6; - reserved "superseded_by_request_id", "build_id"; string outcome_reason = 7; }