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.
## Current Status — v0.2.46
## Current Status — v0.2.47
**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
- 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
#define DIDACTYL_VERSION_MAJOR 0
#define DIDACTYL_VERSION_MINOR 2
#define DIDACTYL_VERSION_PATCH 46
#define DIDACTYL_VERSION "v0.2.46"
#define DIDACTYL_VERSION_PATCH 47
#define DIDACTYL_VERSION "v0.2.47"
// Agent metadata
#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) {
if (!event || !cJSON_IsObject(event)) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: event missing or not object");
return;
}
@@ -1517,36 +1518,51 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
cJSON* pubkey = cJSON_GetObjectItemCaseSensitive(event, "pubkey");
cJSON* tags = cJSON_GetObjectItemCaseSensitive(event, "tags");
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) ||
!pubkey || !cJSON_IsString(pubkey) || !pubkey->valuestring ||
!tags || !cJSON_IsArray(tags)) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: missing required kind/pubkey/tags");
return;
}
int kind_val = (int)kind->valuedouble;
if (kind_val != 31123 && kind_val != 31124 && kind_val != 10123) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: kind not in {31123,31124,10123}");
return;
}
if (!g_cfg) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: config unavailable");
return;
}
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);
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;
}
}
if (is_admin_author && kind_val == 31124) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: admin cannot own private skill (31124)");
return;
}
const char* d_tag = find_tag_value_local(tags, "d");
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;
}
@@ -1554,12 +1570,11 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
cJSON_Delete(g_self_skill_events);
g_self_skill_events = cJSON_CreateArray();
if (!g_self_skill_events) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: failed to create cache array");
return;
}
}
double created = (created_at && cJSON_IsNumber(created_at)) ? created_at->valuedouble : 0.0;
int n = cJSON_GetArraySize(g_self_skill_events);
for (int i = 0; i < n; 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");
double ex_created = (ex_created_at && cJSON_IsNumber(ex_created_at)) ? ex_created_at->valuedouble : 0.0;
if (created < ex_created) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: stale (existing created_at=%.0f >= new created_at=%.0f)",
ex_created,
created);
return;
}
cJSON* dup = cJSON_Duplicate(event, 1);
if (!dup) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: failed to duplicate event");
return;
}
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;
}
cJSON* dup = cJSON_Duplicate(event, 1);
if (!dup) {
DEBUG_INFO("[didactyl] self-skill upsert rejected: failed to duplicate event");
return;
}
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]) {
@@ -2775,6 +2823,10 @@ int nostr_handler_subscribe_self_skills(void) {
cJSON_AddItemToObject(filter, "authors", authors);
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);
managed_subscriptions_init_defaults();
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_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_AddNumberToObject(filter, "limit", 500);