v0.2.47 - nostr: exclude admin from kind 10123 self-skill adoption and add self-skill upsert debug logs

This commit is contained in:
Didactyl User
2026-04-21 06:35:53 -04:00
parent 73c368e4e5
commit b6ca2bf3bf
3 changed files with 60 additions and 11 deletions

View File

@@ -54,11 +54,11 @@ Skills compose by adoption-list order (`10123`) and trigger tags carry runtime e
Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers. Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.
## Current Status — v0.2.46 ## Current Status — v0.2.47
**Active build — this project is barely working. Experiment at your own risk.** **Active build — this project is barely working. Experiment at your own risk.**
> Last release update: v0.2.46Finalize skill_list formatting cleanup and adopted-author cache refresh improvements > Last release update: v0.2.47nostr: exclude admin from kind 10123 self-skill adoption and add self-skill upsert debug logs
- Connects to configured relays with auto-reconnect and relay state transition logging - Connects to configured relays with auto-reconnect and relay state transition logging
- Publishes configured startup events per relay as each relay becomes connected - Publishes configured startup events per relay as each relay becomes connected

View File

@@ -12,8 +12,8 @@
// Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros // Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros
#define DIDACTYL_VERSION_MAJOR 0 #define DIDACTYL_VERSION_MAJOR 0
#define DIDACTYL_VERSION_MINOR 2 #define DIDACTYL_VERSION_MINOR 2
#define DIDACTYL_VERSION_PATCH 46 #define DIDACTYL_VERSION_PATCH 47
#define DIDACTYL_VERSION "v0.2.46" #define DIDACTYL_VERSION "v0.2.47"
// Agent metadata // Agent metadata
#define DIDACTYL_NAME "Didactyl" #define DIDACTYL_NAME "Didactyl"

View File

@@ -1510,6 +1510,7 @@ static void register_trigger_from_self_skill_event(cJSON* event) {
static void self_skill_cache_upsert_event_locked(cJSON* event) { static void self_skill_cache_upsert_event_locked(cJSON* event) {
if (!event || !cJSON_IsObject(event)) { if (!event || !cJSON_IsObject(event)) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: event missing or not object");
return; return;
} }
@@ -1517,36 +1518,51 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
cJSON* pubkey = cJSON_GetObjectItemCaseSensitive(event, "pubkey"); cJSON* pubkey = cJSON_GetObjectItemCaseSensitive(event, "pubkey");
cJSON* tags = cJSON_GetObjectItemCaseSensitive(event, "tags"); cJSON* tags = cJSON_GetObjectItemCaseSensitive(event, "tags");
cJSON* created_at = cJSON_GetObjectItemCaseSensitive(event, "created_at"); cJSON* created_at = cJSON_GetObjectItemCaseSensitive(event, "created_at");
cJSON* ev_id = cJSON_GetObjectItemCaseSensitive(event, "id");
int kind_val = (kind && cJSON_IsNumber(kind)) ? (int)kind->valuedouble : -1;
double created = (created_at && cJSON_IsNumber(created_at)) ? created_at->valuedouble : 0.0;
DEBUG_INFO("[didactyl] self-skill upsert candidate: kind=%d author=%.16s... id=%.16s... created_at=%.0f",
kind_val,
(pubkey && cJSON_IsString(pubkey) && pubkey->valuestring) ? pubkey->valuestring : "?",
(ev_id && cJSON_IsString(ev_id) && ev_id->valuestring) ? ev_id->valuestring : "?",
created);
if (!kind || !cJSON_IsNumber(kind) || if (!kind || !cJSON_IsNumber(kind) ||
!pubkey || !cJSON_IsString(pubkey) || !pubkey->valuestring || !pubkey || !cJSON_IsString(pubkey) || !pubkey->valuestring ||
!tags || !cJSON_IsArray(tags)) { !tags || !cJSON_IsArray(tags)) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: missing required kind/pubkey/tags");
return; return;
} }
int kind_val = (int)kind->valuedouble;
if (kind_val != 31123 && kind_val != 31124 && kind_val != 10123) { if (kind_val != 31123 && kind_val != 31124 && kind_val != 10123) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: kind not in {31123,31124,10123}");
return; return;
} }
if (!g_cfg) { if (!g_cfg) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: config unavailable");
return; return;
} }
int is_agent_author = (strcmp(pubkey->valuestring, g_cfg->keys.public_key_hex) == 0); int is_agent_author = (strcmp(pubkey->valuestring, g_cfg->keys.public_key_hex) == 0);
int is_admin_author = (g_cfg->admin.pubkey[0] != '\0' && strcmp(pubkey->valuestring, g_cfg->admin.pubkey) == 0); int is_admin_author = (g_cfg->admin.pubkey[0] != '\0' && strcmp(pubkey->valuestring, g_cfg->admin.pubkey) == 0);
if (kind_val == 10123) { if (kind_val == 10123) {
if (!is_agent_author && !is_admin_author) { if (!is_agent_author) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: kind=10123 author is not self");
return; return;
} }
} }
if (is_admin_author && kind_val == 31124) { if (is_admin_author && kind_val == 31124) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: admin cannot own private skill (31124)");
return; return;
} }
const char* d_tag = find_tag_value_local(tags, "d"); const char* d_tag = find_tag_value_local(tags, "d");
if ((kind_val == 31123 || kind_val == 31124) && (!d_tag || d_tag[0] == '\0')) { if ((kind_val == 31123 || kind_val == 31124) && (!d_tag || d_tag[0] == '\0')) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: parameterized kind missing d-tag");
return; return;
} }
@@ -1554,12 +1570,11 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
cJSON_Delete(g_self_skill_events); cJSON_Delete(g_self_skill_events);
g_self_skill_events = cJSON_CreateArray(); g_self_skill_events = cJSON_CreateArray();
if (!g_self_skill_events) { if (!g_self_skill_events) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: failed to create cache array");
return; return;
} }
} }
double created = (created_at && cJSON_IsNumber(created_at)) ? created_at->valuedouble : 0.0;
int n = cJSON_GetArraySize(g_self_skill_events); int n = cJSON_GetArraySize(g_self_skill_events);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
cJSON* existing = cJSON_GetArrayItem(g_self_skill_events, i); cJSON* existing = cJSON_GetArrayItem(g_self_skill_events, i);
@@ -1591,23 +1606,56 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
cJSON* ex_created_at = cJSON_GetObjectItemCaseSensitive(existing, "created_at"); cJSON* ex_created_at = cJSON_GetObjectItemCaseSensitive(existing, "created_at");
double ex_created = (ex_created_at && cJSON_IsNumber(ex_created_at)) ? ex_created_at->valuedouble : 0.0; double ex_created = (ex_created_at && cJSON_IsNumber(ex_created_at)) ? ex_created_at->valuedouble : 0.0;
if (created < ex_created) { if (created < ex_created) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: stale (existing created_at=%.0f >= new created_at=%.0f)",
ex_created,
created);
return; return;
} }
cJSON* dup = cJSON_Duplicate(event, 1); cJSON* dup = cJSON_Duplicate(event, 1);
if (!dup) { if (!dup) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: failed to duplicate event");
return; return;
} }
cJSON_ReplaceItemInArray(g_self_skill_events, i, dup); cJSON_ReplaceItemInArray(g_self_skill_events, i, dup);
DEBUG_INFO("[didactyl] self-skill upsert accepted: replaced existing (old created_at=%.0f)", ex_created);
if (kind_val == 10123) {
int a_count = 0;
cJSON* t;
cJSON_ArrayForEach(t, tags) {
if (cJSON_IsArray(t) && cJSON_GetArraySize(t) >= 2) {
cJSON* t0 = cJSON_GetArrayItem(t, 0);
if (t0 && cJSON_IsString(t0) && t0->valuestring && strcmp(t0->valuestring, "a") == 0) {
a_count++;
}
}
}
DEBUG_INFO("[didactyl] kind 10123 accepted with %d 'a' tags", a_count);
}
return; return;
} }
cJSON* dup = cJSON_Duplicate(event, 1); cJSON* dup = cJSON_Duplicate(event, 1);
if (!dup) { if (!dup) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: failed to duplicate event");
return; return;
} }
cJSON_AddItemToArray(g_self_skill_events, dup); cJSON_AddItemToArray(g_self_skill_events, dup);
DEBUG_INFO("[didactyl] self-skill upsert accepted: new entry added");
if (kind_val == 10123) {
int a_count = 0;
cJSON* t;
cJSON_ArrayForEach(t, tags) {
if (cJSON_IsArray(t) && cJSON_GetArraySize(t) >= 2) {
cJSON* t0 = cJSON_GetArrayItem(t, 0);
if (t0 && cJSON_IsString(t0) && t0->valuestring && strcmp(t0->valuestring, "a") == 0) {
a_count++;
}
}
}
DEBUG_INFO("[didactyl] kind 10123 accepted with %d 'a' tags", a_count);
}
} }
static int hex_to_pubkey(const char* hex, unsigned char out_pubkey[32]) { static int hex_to_pubkey(const char* hex, unsigned char out_pubkey[32]) {
@@ -2775,6 +2823,10 @@ int nostr_handler_subscribe_self_skills(void) {
cJSON_AddItemToObject(filter, "authors", authors); cJSON_AddItemToObject(filter, "authors", authors);
cJSON_AddNumberToObject(filter, "limit", 300); cJSON_AddNumberToObject(filter, "limit", 300);
char* filter_str = cJSON_PrintUnformatted(filter);
DEBUG_INFO("[didactyl] self-skill subscription filter: %s", filter_str ? filter_str : "(null)");
free(filter_str);
pthread_mutex_lock(&g_subscription_mutex); pthread_mutex_lock(&g_subscription_mutex);
managed_subscriptions_init_defaults(); managed_subscriptions_init_defaults();
if (managed_subscription_register_locked(MANAGED_SUB_SELF_SKILLS, if (managed_subscription_register_locked(MANAGED_SUB_SELF_SKILLS,
@@ -3719,9 +3771,6 @@ int nostr_handler_refresh_self_skill_cache_from_relays(int timeout_ms) {
cJSON_AddItemToObject(filter, "kinds", kinds); cJSON_AddItemToObject(filter, "kinds", kinds);
cJSON_AddItemToArray(authors, cJSON_CreateString(g_cfg->keys.public_key_hex)); cJSON_AddItemToArray(authors, cJSON_CreateString(g_cfg->keys.public_key_hex));
if (g_cfg->admin.pubkey[0] != '\0' && strcmp(g_cfg->admin.pubkey, g_cfg->keys.public_key_hex) != 0) {
cJSON_AddItemToArray(authors, cJSON_CreateString(g_cfg->admin.pubkey));
}
cJSON_AddItemToObject(filter, "authors", authors); cJSON_AddItemToObject(filter, "authors", authors);
cJSON_AddNumberToObject(filter, "limit", 500); cJSON_AddNumberToObject(filter, "limit", 500);