@@ -55,14 +55,19 @@ type Execution struct {
5555 moduleLoadStack []string
5656 moduleStack []moduleContext
5757 capabilityContracts map [* Builtin ]CapabilityMethodContract
58- capabilityContractScopes map [* Builtin ]map [ string ] CapabilityMethodContract
58+ capabilityContractScopes map [* Builtin ]* capabilityContractScope
5959 capabilityContractsByName map [string ]CapabilityMethodContract
6060 receiverStack []Value
6161 envStack []* Env
6262 strictEffects bool
6363 allowRequire bool
6464}
6565
66+ type capabilityContractScope struct {
67+ contracts map [string ]CapabilityMethodContract
68+ roots []Value
69+ }
70+
6671type moduleContext struct {
6772 key string
6873 path string
@@ -625,14 +630,19 @@ func (exec *Execution) invokeCallable(callee Value, receiver Value, args []Value
625630 return NewNil (), exec .wrapError (err , pos )
626631 }
627632 }
628- scopeContracts := exec .capabilityContractScopes [builtin ]
629- if len (scopeContracts ) > 0 {
633+ scope := exec .capabilityContractScopes [builtin ]
634+ if scope != nil && len (scope . contracts ) > 0 {
630635 // Capability methods can lazily publish additional builtins at runtime
631636 // (e.g. through factory return values or receiver mutation). Re-scan
632637 // these values so future calls still enforce declared contracts.
633- bindCapabilityContracts (result , scopeContracts , exec .capabilityContracts , exec .capabilityContractScopes )
638+ bindCapabilityContracts (result , scope , exec .capabilityContracts , exec .capabilityContractScopes )
634639 if receiver .Kind () != KindNil {
635- bindCapabilityContracts (receiver , scopeContracts , exec .capabilityContracts , exec .capabilityContractScopes )
640+ bindCapabilityContracts (receiver , scope , exec .capabilityContracts , exec .capabilityContractScopes )
641+ }
642+ // Methods can mutate sibling scope roots via captured references; refresh
643+ // all adapter roots so newly exposed builtins also get bound.
644+ for _ , root := range scope .roots {
645+ bindCapabilityContracts (root , scope , exec .capabilityContracts , exec .capabilityContractScopes )
636646 }
637647 }
638648 return result , nil
@@ -3413,7 +3423,7 @@ func (s *Script) Call(ctx context.Context, name string, args []Value, opts CallO
34133423 moduleLoadStack : make ([]string , 0 , 8 ),
34143424 moduleStack : make ([]moduleContext , 0 , 8 ),
34153425 capabilityContracts : make (map [* Builtin ]CapabilityMethodContract ),
3416- capabilityContractScopes : make (map [* Builtin ]map [ string ] CapabilityMethodContract ),
3426+ capabilityContractScopes : make (map [* Builtin ]* capabilityContractScope ),
34173427 capabilityContractsByName : make (map [string ]CapabilityMethodContract ),
34183428 receiverStack : make ([]Value , 0 , 8 ),
34193429 envStack : make ([]* Env , 0 , 8 ),
@@ -3427,7 +3437,9 @@ func (s *Script) Call(ctx context.Context, name string, args []Value, opts CallO
34273437 if adapter == nil {
34283438 continue
34293439 }
3430- adapterContracts := map [string ]CapabilityMethodContract {}
3440+ scope := & capabilityContractScope {
3441+ contracts : map [string ]CapabilityMethodContract {},
3442+ }
34313443 if provider , ok := adapter .(CapabilityContractProvider ); ok {
34323444 for methodName , contract := range provider .CapabilityContracts () {
34333445 name := strings .TrimSpace (methodName )
@@ -3438,7 +3450,7 @@ func (s *Script) Call(ctx context.Context, name string, args []Value, opts CallO
34383450 return NewNil (), fmt .Errorf ("duplicate capability contract for %s" , name )
34393451 }
34403452 exec .capabilityContractsByName [name ] = contract
3441- adapterContracts [name ] = contract
3453+ scope . contracts [name ] = contract
34423454 }
34433455 }
34443456 globals , err := adapter .Bind (binding )
@@ -3448,7 +3460,8 @@ func (s *Script) Call(ctx context.Context, name string, args []Value, opts CallO
34483460 for name , val := range globals {
34493461 rebound := rebinder .rebindValue (val )
34503462 root .Define (name , rebound )
3451- bindCapabilityContracts (rebound , adapterContracts , exec .capabilityContracts , exec .capabilityContractScopes )
3463+ scope .roots = append (scope .roots , rebound )
3464+ bindCapabilityContracts (rebound , scope , exec .capabilityContracts , exec .capabilityContractScopes )
34523465 }
34533466 }
34543467 }
0 commit comments