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

Merged
Virgil merged 1 commit from main into dev 2026-04-03 21:32:44 +00:00
2 changed files with 142 additions and 4 deletions

View file

@ -229,16 +229,20 @@ 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([]string{aliases}), nil
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")
name, err := parseActionAliasValue(item)
if err != nil {
return nil, err
}
if name != "" {
parsed = append(parsed, name)
}
parsed = append(parsed, name)
}
return normalizeAliasList(parsed), nil
case map[string]any:
@ -248,11 +252,57 @@ func parseActionAliasList(value any) ([]string, error) {
if rawResult, ok := aliases["result"]; ok {
return parseActionAliasList(rawResult)
}
name, err := parseActionAliasRecord(aliases)
if err != nil {
return nil, err
}
if name != "" {
return []string{name}, nil
}
}
return nil, fmt.Errorf("blockchain.chain.aliases action returned unsupported result type %T", value)
}
func parseActionAliasValue(value any) (string, error) {
switch alias := value.(type) {
case string:
return normalizeName(alias), nil
case map[string]any:
return parseActionAliasRecord(alias)
default:
return "", fmt.Errorf("blockchain.chain.aliases action returned unsupported alias item type %T", value)
}
}
func parseActionAliasRecord(record map[string]any) (string, error) {
if hns, ok := record["hns"]; ok {
if name, ok := hns.(string); ok {
return normalizeName(name), nil
}
return "", fmt.Errorf("blockchain.chain.aliases action returned non-string hns value")
}
if comment, ok := record["comment"]; ok {
if text, ok := comment.(string); ok {
return extractAliasFromComment(text), nil
}
return "", fmt.Errorf("blockchain.chain.aliases action returned non-string comment value")
}
if alias, ok := record["alias"]; ok {
if name, ok := alias.(string); ok {
return normalizeName(name), nil
}
return "", fmt.Errorf("blockchain.chain.aliases action returned non-string alias value")
}
if name, ok := record["name"]; ok {
if text, ok := name.(string); ok {
return normalizeName(text), nil
}
return "", fmt.Errorf("blockchain.chain.aliases action returned non-string name value")
}
return "", nil
}
// DiscoverFromMainchainAliases updates records from main-chain aliases resolved through HSD.
//
// service.DiscoverFromMainchainAliases(context.Background(), dns.NewMainchainAliasClient(dns.MainchainClientOptions{

View file

@ -677,6 +677,94 @@ func TestServiceDiscoverAliasesUsesConfiguredChainAliasAction(t *testing.T) {
}
}
func TestServiceDiscoverAliasesParsesAliasDetailRecordsFromActionCaller(t *testing.T) {
var treeRootCalls int32
var nameResourceCalls int32
actionCalled := 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)
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
"result": map[string]any{
"tree_root": "record-root-1",
},
})
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{
map[string]any{
"name": "gateway",
"comment": "gateway alias hns=gateway.charon.lthn",
},
map[string]any{
"name": "node",
"hns": "node.charon.lthn",
},
},
}, true, nil
}),
HSDClient: NewHSDClient(HSDClientOptions{URL: server.URL}),
})
if err := service.DiscoverAliases(context.Background()); err != nil {
t.Fatalf("expected DiscoverAliases to parse alias detail records: %v", err)
}
if !actionCalled {
t.Fatal("expected action caller to be invoked")
}
if atomic.LoadInt32(&treeRootCalls) != 1 || atomic.LoadInt32(&nameResourceCalls) != 2 {
t.Fatalf("expected one tree-root and two name-resource RPC calls, got treeRoot=%d nameResource=%d", atomic.LoadInt32(&treeRootCalls), atomic.LoadInt32(&nameResourceCalls))
}
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)
}
}
func TestServiceDiscoverFallsBackWhenPrimaryDiscovererFails(t *testing.T) {
primaryCalled := false
fallbackCalled := false