Improve scene-aware combat gating
This commit is contained in:
@@ -56,12 +56,13 @@ type Registry struct {
|
||||
}
|
||||
|
||||
// Resolver holds an immutable construction-time view and memoizes immutable
|
||||
// operation-time views by eligibility digest.
|
||||
// operation-time views by raw reference identity and eligibility digest.
|
||||
type Resolver struct {
|
||||
seeded *Registry
|
||||
|
||||
mu sync.Mutex
|
||||
cache map[string]*Registry
|
||||
mu sync.Mutex
|
||||
cache map[string]*Registry
|
||||
rawCache map[string]*Registry
|
||||
}
|
||||
|
||||
// NewResolver validates a materialized construction-time scene reference. An
|
||||
@@ -72,7 +73,11 @@ func NewResolver(references contracts.ReferenceSet) (*Resolver, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Resolver{seeded: seeded, cache: make(map[string]*Registry)}, nil
|
||||
return &Resolver{
|
||||
seeded: seeded,
|
||||
cache: make(map[string]*Registry),
|
||||
rawCache: make(map[string]*Registry),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func constructionReferences(references contracts.ReferenceSet) contracts.ReferenceSet {
|
||||
@@ -106,23 +111,59 @@ func (r *Resolver) Resolve(references contracts.ReferenceSet) (*Registry, error)
|
||||
return r.seeded, nil
|
||||
}
|
||||
|
||||
slot := references.Slots[ReferenceSlot]
|
||||
rawKey := ""
|
||||
if len(slot.Items) == 1 {
|
||||
rawKey = rawReferenceKey(slot.Items[0])
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if rawKey != "" {
|
||||
if cached, ok := r.rawCache[rawKey]; ok {
|
||||
return cached, nil
|
||||
}
|
||||
}
|
||||
resolved, err := Resolve(references)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if sameEligibility(r.seeded, resolved) {
|
||||
if rawKey != "" {
|
||||
r.rawCache[rawKey] = r.seeded
|
||||
}
|
||||
return r.seeded, nil
|
||||
}
|
||||
if cached, ok := r.cache[resolved.EligibilityDigest()]; ok {
|
||||
if rawKey != "" {
|
||||
r.rawCache[rawKey] = cached
|
||||
}
|
||||
return cached, nil
|
||||
}
|
||||
r.cache[resolved.EligibilityDigest()] = resolved
|
||||
if rawKey != "" {
|
||||
r.rawCache[rawKey] = resolved
|
||||
}
|
||||
return resolved, nil
|
||||
}
|
||||
|
||||
func rawReferenceKey(item contracts.ReferenceItem) string {
|
||||
digest := strings.ToLower(strings.TrimSpace(item.Digest))
|
||||
if !validSHA256Digest(digest) {
|
||||
digest = semanticDigest(item.Content)
|
||||
}
|
||||
return strings.ToLower(strings.TrimSpace(item.MediaType)) + "\x00" + digest
|
||||
}
|
||||
|
||||
func validSHA256Digest(value string) bool {
|
||||
if len(value) != len("sha256:")+sha256.Size*2 || !strings.HasPrefix(value, "sha256:") {
|
||||
return false
|
||||
}
|
||||
decoded, err := hex.DecodeString(strings.TrimPrefix(value, "sha256:"))
|
||||
return err == nil && len(decoded) == sha256.Size
|
||||
}
|
||||
|
||||
func sameEligibility(first, second *Registry) bool {
|
||||
if first == nil || second == nil {
|
||||
return first == second
|
||||
|
||||
Reference in New Issue
Block a user