fix(openai): artifact receipt의 중복 history gate를 제거한다
This commit is contained in:
parent
af96a1e03a
commit
450522186b
3 changed files with 63 additions and 2 deletions
|
|
@ -645,7 +645,7 @@ func (s *artifactFrontierStore) consume(
|
|||
return logicalRequestSnapshot{}, artifactDisposition{}, true, fmt.Errorf("artifact receipt rejected: result contains an explicit error signal")
|
||||
}
|
||||
|
||||
snap, err := coordinator.consumeContinuationByLineage(ownerEdgeID, principalRef, lineage)
|
||||
snap, err := coordinator.consumeArtifactContinuationByLineage(record.requestID, ownerEdgeID, principalRef, lineage)
|
||||
if err != nil {
|
||||
return logicalRequestSnapshot{}, artifactDisposition{}, true, err
|
||||
}
|
||||
|
|
@ -712,7 +712,11 @@ func (s *artifactFrontierStore) matchRecordLocked(
|
|||
if record.protocol != protocol {
|
||||
return nil, true, fmt.Errorf("%w: protocol changed", errLogicalRequestLineage)
|
||||
}
|
||||
if record.lineage != lineage.Prefix {
|
||||
// Artifact receipts are already bound to the owner, principal, protocol,
|
||||
// toolset, exact issued-call hash, call ids, and result matcher. The light
|
||||
// flow also retains the immutable task independently, so caller SDK history
|
||||
// reserialization is not an additional receipt boundary.
|
||||
if record.lineage.Endpoint != lineage.Prefix.Endpoint || record.lineage.ToolsetDigest != lineage.Prefix.ToolsetDigest {
|
||||
return nil, true, describeArtifactPrefixMismatch(record.lineage, lineage.Prefix)
|
||||
}
|
||||
return record, true, nil
|
||||
|
|
|
|||
|
|
@ -234,6 +234,28 @@ func TestArtifactPairFrontierMatrix(t *testing.T) {
|
|||
}
|
||||
fixture.assertPhase(artifactPhaseLocalEligible)
|
||||
})
|
||||
|
||||
t.Run("exact receipt tolerates caller history reserialization", func(t *testing.T) {
|
||||
fixture := newArtifactPairFixture(t, endpoint, true)
|
||||
ids := fixture.issuePair()
|
||||
body := fixture.continuationBody([]artifactTestResult{
|
||||
{id: ids[0], body: `{"written":true}`},
|
||||
{id: ids[1], body: `{"written":true}`},
|
||||
}, nil)
|
||||
var envelope map[string]any
|
||||
if err := json.Unmarshal(body, &envelope); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
messages := envelope["messages"].([]any)
|
||||
messages[0].(map[string]any)["content"] = []any{map[string]any{
|
||||
"type": "text", "text": "task", "cache_control": map[string]any{"type": "ephemeral"},
|
||||
}}
|
||||
body, _ = json.Marshal(envelope)
|
||||
if _, _, err := fixture.continueRaw(body); err != nil {
|
||||
t.Fatalf("exact receipt rejected reserialized history: %v", err)
|
||||
}
|
||||
fixture.assertPhase(artifactPhaseLocalEligible)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,6 +427,41 @@ func (c *logicalRequestCoordinator) consumeContinuationByLineage(ownerEdgeID, pr
|
|||
return target.snapshot(), nil
|
||||
}
|
||||
|
||||
func (c *logicalRequestCoordinator) consumeArtifactContinuationByLineage(
|
||||
requestID, ownerEdgeID, principalRef string,
|
||||
lineage logicalRequestContinuationLineage,
|
||||
) (logicalRequestSnapshot, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
record, ok := c.requests[requestID]
|
||||
if !ok || record.state != logicalRequestStateWaiting {
|
||||
return logicalRequestSnapshot{}, errLogicalRequestNotFound
|
||||
}
|
||||
if record.ownerEdgeID != ownerEdgeID {
|
||||
return logicalRequestSnapshot{}, errLogicalRequestOwnerMismatch
|
||||
}
|
||||
if record.principalRef != principalRef {
|
||||
return logicalRequestSnapshot{}, errLogicalRequestPrincipal
|
||||
}
|
||||
if record.lineage.Endpoint != lineage.Prefix.Endpoint || record.lineage.ToolsetDigest != lineage.Prefix.ToolsetDigest {
|
||||
return logicalRequestSnapshot{}, errLogicalRequestLineage
|
||||
}
|
||||
if record.expected == nil {
|
||||
return logicalRequestSnapshot{}, errLogicalRequestNoFrontier
|
||||
}
|
||||
if record.expectedIssuedCallHash != lineage.IssuedCallHash || !sameLogicalRequestResultIDs(record.expected, lineage.ResultIDs) {
|
||||
return logicalRequestSnapshot{}, errLogicalRequestFrontier
|
||||
}
|
||||
|
||||
record.expected = nil
|
||||
record.expectedIssuedCallHash = ""
|
||||
record.lineage = lineage.Committed
|
||||
record.activeStageID = ""
|
||||
record.state = logicalRequestStateResumed
|
||||
record.updatedAt = c.now()
|
||||
return record.snapshot(), nil
|
||||
}
|
||||
|
||||
func (c *logicalRequestCoordinator) snapshot(requestID string) (logicalRequestSnapshot, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
|
|
|||
Loading…
Reference in a new issue