Why context cancel fans out but not normal channel

why in code below context cancel is received by both go routines but not ‘normal channel’ ?
channels are “point to point” so randomly one or the other goroutine receives from ch channel.
but why both goroutines receive ctx.Done() always ?

package main

import "sync"
import "fmt"
import "time"
import "context"

func main() {
	var wg sync.WaitGroup

	ch := make(chan struct{})
	wg.Add(2)
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		defer wg.Done()
		fmt.Println("start goroutine 1")
		for {
			select {
			case <- ch:
				fmt.Println("got ch at goroutine 1")
			case <- ctx.Done():
				fmt.Println("got done goroutine 1")
				return
			}
		}
	}()
	go func() {
		defer wg.Done()
		fmt.Println("start goroutine 2")
		for {
			select {
			case <- ch:
				fmt.Println("got ch at goroutine 2")
			case <- ctx.Done():
				fmt.Println("got done goroutine 2")
				return
			}
		}
	}()

	time.Sleep(time.Second)
	ch <- struct{}{}
	time.Sleep(time.Second)	
	cancel()
	fmt.Println("wait goroutines")
	wg.Wait()
}

output:

apmattil@penguin:~/src/chan$ go run chan.go
start goroutine 1
start goroutine 2
got ch at goroutine 1
wait goroutines
got done goroutine 1
got done goroutine 2
apmattil@penguin:~/src/chan$ go run chan.go
start goroutine 2
start goroutine 1
got ch at goroutine 2
wait goroutines
got done goroutine 1
got done goroutine 2

I’m answering my own question.

ctx.Done() receive works because context channel is closed.

you can see it if you edit:

	case _, ok := <-ctx.Done():
				fmt.Printf("got done goroutine 1 %t\n", ok)
				return