[agent/codex:gpt-5.4-mini] Read docs/RFC.md fully. Find ONE feature described in the sp... #41

Merged
Virgil merged 1 commit from main into dev 2026-04-03 21:23:32 +00:00
3 changed files with 157 additions and 0 deletions

View file

@ -35,6 +35,13 @@ type ActionRegistrar interface {
RegisterAction(name string, invoke func(map[string]any) (any, bool, error))
}
// ActionCaller resolves named actions from another Core surface.
//
// payload, ok, err := caller.CallAction(context.Background(), "blockchain.chain.aliases", nil)
type ActionCaller interface {
CallAction(ctx context.Context, name string, values map[string]any) (any, bool, error)
}
// ActionDefinitions returns the complete DNS action surface in registration order.
//
// definitions := service.ActionDefinitions()

View file

@ -50,6 +50,7 @@ type Service struct {
zoneApex string
hsdClient *HSDClient
mainchainAliasClient *MainchainAliasClient
chainAliasActionCaller ActionCaller
chainAliasAction func(context.Context) ([]string, error)
discoverer func() (map[string]NameRecords, error)
fallbackDiscoverer func() (map[string]NameRecords, error)
@ -66,6 +67,7 @@ type ServiceOptions struct {
FallbackDiscoverer func() (map[string]NameRecords, error)
MainchainAliasClient *MainchainAliasClient
HSDClient *HSDClient
ChainAliasActionCaller ActionCaller
ChainAliasAction func(context.Context) ([]string, error)
ChainAliasDiscoverer func(context.Context) ([]string, error)
FallbackChainAliasDiscoverer func(context.Context) ([]string, error)
@ -106,6 +108,7 @@ func NewService(options ServiceOptions) *Service {
zoneApex: computeZoneApex(cached),
hsdClient: options.HSDClient,
mainchainAliasClient: options.MainchainAliasClient,
chainAliasActionCaller: options.ChainAliasActionCaller,
chainAliasAction: options.ChainAliasAction,
discoverer: options.Discoverer,
fallbackDiscoverer: options.FallbackDiscoverer,
@ -133,6 +136,7 @@ func (service *Service) DiscoverFromChainAliases(ctx context.Context, client *HS
aliases, err := service.discoverAliasesFromSources(
ctx,
service.chainAliasActionCaller,
service.chainAliasAction,
service.chainAliasDiscoverer,
service.fallbackChainAliasDiscoverer,
@ -149,11 +153,16 @@ func (service *Service) DiscoverFromChainAliases(ctx context.Context, client *HS
func (service *Service) discoverAliasesFromSources(
ctx context.Context,
actionCaller ActionCaller,
action func(context.Context) ([]string, error),
discoverer func(context.Context) ([]string, error),
fallback func(context.Context) ([]string, error),
mainchainClient *MainchainAliasClient,
) ([]string, error) {
if aliases, ok := service.discoverAliasesFromActionCaller(ctx, actionCaller); ok {
return aliases, nil
}
if action != nil {
aliases, err := action(ctx)
if err == nil {
@ -199,6 +208,51 @@ func (service *Service) discoverAliasesFromSources(
return mainchainClient.GetAllAliasDetails(ctx)
}
func (service *Service) discoverAliasesFromActionCaller(ctx context.Context, actionCaller ActionCaller) ([]string, bool) {
if actionCaller == nil {
return nil, false
}
result, ok, err := actionCaller.CallAction(ctx, "blockchain.chain.aliases", map[string]any{})
if err != nil || !ok {
return nil, false
}
aliases, err := parseActionAliasList(result)
if err != nil {
return nil, false
}
return aliases, true
}
func parseActionAliasList(value any) ([]string, error) {
switch aliases := value.(type) {
case nil:
return nil, fmt.Errorf("blockchain.chain.aliases action returned no value")
case []string:
return normalizeAliasList(aliases), nil
case []any:
parsed := make([]string, 0, len(aliases))
for _, item := range aliases {
name, ok := item.(string)
if !ok {
return nil, fmt.Errorf("blockchain.chain.aliases action returned non-string alias")
}
parsed = append(parsed, name)
}
return normalizeAliasList(parsed), nil
case map[string]any:
if rawAliases, ok := aliases["aliases"]; ok {
return parseActionAliasList(rawAliases)
}
if rawResult, ok := aliases["result"]; ok {
return parseActionAliasList(rawResult)
}
}
return nil, fmt.Errorf("blockchain.chain.aliases action returned unsupported result type %T", value)
}
// DiscoverFromMainchainAliases updates records from main-chain aliases resolved through HSD.
//
// service.DiscoverFromMainchainAliases(context.Background(), dns.NewMainchainAliasClient(dns.MainchainClientOptions{
@ -219,6 +273,7 @@ func (service *Service) DiscoverFromMainchainAliases(ctx context.Context, chainC
aliases, err := service.discoverAliasesFromSources(
ctx,
service.chainAliasActionCaller,
nil,
func(ctx context.Context) ([]string, error) {
if service.chainAliasDiscoverer != nil {

View file

@ -516,6 +516,95 @@ func TestServiceDiscoverAliasesUsesConfiguredAliasDiscovery(t *testing.T) {
}
}
func TestServiceDiscoverAliasesUsesConfiguredActionCaller(t *testing.T) {
var treeRootCalls int32
var nameResourceCalls int32
actionCalled := false
discovererCalled := false
server := httptest.NewServer(http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
var payload struct {
Method string `json:"method"`
Params []any `json:"params"`
}
if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
t.Fatalf("unexpected request payload: %v", err)
}
switch payload.Method {
case "getblockchaininfo":
atomic.AddInt32(&treeRootCalls, 1)
responseWriter.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
"result": map[string]any{
"tree_root": "action-caller-root",
},
})
case "getnameresource":
atomic.AddInt32(&nameResourceCalls, 1)
switch payload.Params[0] {
case "gateway.charon.lthn":
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
"result": map[string]any{
"a": []string{"10.10.10.10"},
},
})
case "node.charon.lthn":
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
"result": map[string]any{
"aaaa": []string{"2600:1f1c:7f0:4f01::2"},
},
})
default:
t.Fatalf("unexpected alias lookup: %#v", payload.Params)
}
default:
t.Fatalf("unexpected method: %s", payload.Method)
}
}))
defer server.Close()
service := NewService(ServiceOptions{
ChainAliasActionCaller: actionCallerFunc(func(ctx context.Context, name string, values map[string]any) (any, bool, error) {
actionCalled = true
if name != "blockchain.chain.aliases" {
t.Fatalf("unexpected action name: %s", name)
}
return map[string]any{
"aliases": []any{"gateway.charon.lthn", "node.charon.lthn"},
}, true, nil
}),
ChainAliasDiscoverer: func(_ context.Context) ([]string, error) {
discovererCalled = true
return nil, errors.New("discoverer should not run when action caller succeeds")
},
HSDClient: NewHSDClient(HSDClientOptions{URL: server.URL}),
})
if err := service.DiscoverAliases(context.Background()); err != nil {
t.Fatalf("expected DiscoverAliases to complete through action caller: %v", err)
}
if !actionCalled {
t.Fatal("expected action caller to be invoked")
}
if discovererCalled {
t.Fatal("expected chain alias discoverer to be skipped after action caller success")
}
gateway, ok := service.Resolve("gateway.charon.lthn")
if !ok || len(gateway.A) != 1 || gateway.A[0] != "10.10.10.10" {
t.Fatalf("expected gateway A record, got %#v (ok=%t)", gateway, ok)
}
node, ok := service.Resolve("node.charon.lthn")
if !ok || len(node.AAAA) != 1 || node.AAAA[0] != "2600:1f1c:7f0:4f01::2" {
t.Fatalf("expected node AAAA record, got %#v (ok=%t)", node, ok)
}
if atomic.LoadInt32(&treeRootCalls) != 1 || atomic.LoadInt32(&nameResourceCalls) != 2 {
t.Fatalf("expected discovery to perform chain and name-resource calls, got treeRoot=%d nameResource=%d", atomic.LoadInt32(&treeRootCalls), atomic.LoadInt32(&nameResourceCalls))
}
}
func TestServiceDiscoverAliasesUsesConfiguredChainAliasAction(t *testing.T) {
var treeRootCalls int32
var nameResourceCalls int32
@ -1608,3 +1697,9 @@ func (recorder *actionRecorder) RegisterAction(name string, invoke func(map[stri
recorder.names = append(recorder.names, name)
recorder.handlers[name] = invoke
}
type actionCallerFunc func(context.Context, string, map[string]any) (any, bool, error)
func (caller actionCallerFunc) CallAction(ctx context.Context, name string, values map[string]any) (any, bool, error) {
return caller(ctx, name, values)
}