Skip to content

Commit 987bb62

Browse files
Update jellyfish.c
1 parent c6ef387 commit 987bb62

File tree

1 file changed

+111
-80
lines changed

1 file changed

+111
-80
lines changed

code/logic/jellyfish.c

Lines changed: 111 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <stdlib.h>
1919
#include <ctype.h>
2020
#include <time.h>
21+
#include <math.h>
2122

2223

2324
// HASH Algorithm magic
@@ -168,6 +169,17 @@ static bool skip_comma(const char **ptr) {
168169
return false;
169170
}
170171

172+
int parse_hex_field(const char **ptr, const char *key, uint8_t *out, size_t len) {
173+
if (!skip_key(ptr, key) || !skip_symbol(ptr, '"')) return 0;
174+
for (size_t i = 0; i < len; ++i) {
175+
unsigned int val = 0;
176+
if (sscanf(*ptr, "%2x", &val) != 1) return 0;
177+
if (out) out[i] = (uint8_t)val;
178+
*ptr += 2;
179+
}
180+
return skip_symbol(ptr, '"');
181+
}
182+
171183
static bool parse_string_field(const char **ptr, const char *key, char *out, size_t max) {
172184
if (!skip_key(ptr, key)) return false;
173185
if (!skip_symbol(ptr, '"')) return false;
@@ -392,80 +404,68 @@ int fossil_jellyfish_load(fossil_jellyfish_chain *chain, const char *filepath) {
392404
fclose(fp);
393405

394406
const char *ptr = buffer;
395-
if (!match_key_value(&ptr, "signature", "JFS1")) {
396-
free(buffer);
397-
return 0;
398-
}
407+
int ok = 1; // unified success flag
399408

400-
if (!skip_key(&ptr, "blocks") || !skip_symbol(&ptr, '[')) {
401-
free(buffer);
402-
return 0;
409+
if (!match_key_value(&ptr, "signature", "JFS1")) ok = 0;
410+
if (ok) skip_key_value(&ptr, "version");
411+
412+
if (ok && (!skip_key(&ptr, "origin_device_id") || !skip_symbol(&ptr, '"'))) ok = 0;
413+
if (ok) {
414+
for (size_t i = 0; i < FOSSIL_DEVICE_ID_SIZE && ok; ++i) {
415+
unsigned int val = 0;
416+
if (sscanf(ptr, "%2x", &val) != 1) ok = 0;
417+
chain->device_id[i] = (uint8_t)val;
418+
ptr += 2;
419+
}
420+
if (!skip_symbol(&ptr, '"')) ok = 0;
403421
}
404422

423+
if (ok) ok = parse_number_field(&ptr, "created_at", NULL, &chain->created_at, NULL, NULL);
424+
if (ok) ok = parse_number_field(&ptr, "updated_at", NULL, &chain->updated_at, NULL, NULL);
425+
426+
if (ok && (!skip_key(&ptr, "blocks") || !skip_symbol(&ptr, '['))) ok = 0;
427+
405428
size_t count = 0;
406-
while (*ptr && *ptr != ']' && count < FOSSIL_JELLYFISH_MAX_MEM) {
429+
while (ok && *ptr && *ptr != ']' && count < FOSSIL_JELLYFISH_MAX_MEM) {
407430
fossil_jellyfish_block *b = &chain->memory[count];
408431
memset(b, 0, sizeof(*b));
409432

410-
if (!skip_symbol(&ptr, '{')) break;
411-
if (!parse_string_field(&ptr, "input", b->input, sizeof(b->input))) break;
412-
if (!parse_string_field(&ptr, "output", b->output, sizeof(b->output))) break;
433+
if (!skip_symbol(&ptr, '{')) { ok = 0; break; }
434+
if (!parse_number_field(&ptr, "block_index", NULL, NULL, NULL, NULL)) { ok = 0; break; }
435+
if (!parse_string_field(&ptr, "input", b->input, sizeof(b->input))) { ok = 0; break; }
436+
if (!parse_string_field(&ptr, "output", b->output, sizeof(b->output))) { ok = 0; break; }
413437

414-
// Parse hash as hex string
415-
if (!skip_key(&ptr, "hash") || !skip_symbol(&ptr, '"')) break;
416-
for (size_t i = 0; i < FOSSIL_JELLYFISH_HASH_SIZE; ++i) {
417-
unsigned int val = 0;
418-
if (sscanf(ptr, "%2x", &val) != 1) break;
419-
b->hash[i] = (uint8_t)val;
420-
ptr += 2;
421-
}
422-
if (!skip_symbol(&ptr, '"')) break;
438+
if (!parse_hex_field(&ptr, "hash", b->hash, FOSSIL_JELLYFISH_HASH_SIZE)) { ok = 0; break; }
439+
if (!parse_hex_field(&ptr, "previous_hash", NULL, FOSSIL_JELLYFISH_HASH_SIZE)) { ok = 0; break; }
423440

424-
if (!parse_number_field(&ptr, "timestamp", NULL, &b->timestamp, NULL, NULL)) break;
425-
if (!parse_number_field(&ptr, "delta_ms", NULL, NULL, NULL, &b->delta_ms)) break;
426-
if (!parse_number_field(&ptr, "duration_ms", NULL, NULL, NULL, &b->duration_ms)) break;
427-
if (!parse_number_field(&ptr, "valid", NULL, NULL, &b->valid, NULL)) break;
441+
if (!parse_number_field(&ptr, "timestamp", NULL, &b->timestamp, NULL, NULL)) { ok = 0; break; }
442+
if (!parse_number_field(&ptr, "delta_ms", NULL, NULL, NULL, &b->delta_ms)) { ok = 0; break; }
443+
if (!parse_number_field(&ptr, "duration_ms", NULL, NULL, NULL, &b->duration_ms)) { ok = 0; break; }
444+
if (!parse_number_field(&ptr, "valid", NULL, NULL, &b->valid, NULL)) { ok = 0; break; }
428445

429-
double temp_conf = 0;
430-
if (!parse_number_field(&ptr, "confidence", &temp_conf, NULL, NULL, NULL)) break;
446+
double temp_conf = 0.0;
447+
if (!parse_number_field(&ptr, "confidence", &temp_conf, NULL, NULL, NULL)) { ok = 0; break; }
431448
b->confidence = (float)temp_conf;
432449

433-
if (!parse_number_field(&ptr, "usage_count", NULL, NULL, NULL, &b->usage_count)) break;
434-
435-
// Parse device_id as hex string
436-
if (!skip_key(&ptr, "device_id") || !skip_symbol(&ptr, '"')) break;
437-
for (size_t i = 0; i < FOSSIL_DEVICE_ID_SIZE; ++i) {
438-
unsigned int val = 0;
439-
if (sscanf(ptr, "%2x", &val) != 1) break;
440-
b->device_id[i] = (uint8_t)val;
441-
ptr += 2;
442-
}
443-
if (!skip_symbol(&ptr, '"')) break;
450+
if (!parse_number_field(&ptr, "usage_count", NULL, NULL, NULL, &b->usage_count)) { ok = 0; break; }
444451

445-
// Parse signature as hex string
446-
if (!skip_key(&ptr, "signature") || !skip_symbol(&ptr, '"')) break;
447-
for (size_t i = 0; i < FOSSIL_SIGNATURE_SIZE; ++i) {
448-
unsigned int val = 0;
449-
if (sscanf(ptr, "%2x", &val) != 1) break;
450-
b->signature[i] = (uint8_t)val;
451-
ptr += 2;
452-
}
453-
if (!skip_symbol(&ptr, '"')) break;
452+
if (!parse_hex_field(&ptr, "device_id", b->device_id, FOSSIL_DEVICE_ID_SIZE)) { ok = 0; break; }
453+
if (!parse_hex_field(&ptr, "signature", b->signature, FOSSIL_SIGNATURE_SIZE)) { ok = 0; break; }
454454

455-
if (!skip_symbol(&ptr, '}')) break;
455+
if (!skip_symbol(&ptr, '}')) { ok = 0; break; }
456456

457457
skip_comma(&ptr);
458458
++count;
459459
}
460460

461-
if (!skip_symbol(&ptr, ']') || !skip_symbol(&ptr, '}')) {
462-
free(buffer);
463-
return 0;
461+
if (ok && (!skip_symbol(&ptr, ']') || !skip_symbol(&ptr, '}'))) ok = 0;
462+
463+
if (ok) {
464+
chain->count = count;
464465
}
465466

466-
chain->count = count;
467467
free(buffer);
468-
return 1;
468+
return ok;
469469
}
470470

471471
int fossil_jellyfish_save(const fossil_jellyfish_chain *chain, const char *filepath) {
@@ -474,11 +474,22 @@ int fossil_jellyfish_save(const fossil_jellyfish_chain *chain, const char *filep
474474

475475
fprintf(fp, "{\n");
476476
fprintf(fp, " \"signature\": \"JFS1\",\n");
477+
fprintf(fp, " \"version\": \"1.0.0\",\n");
478+
479+
// Write origin_device_id as hex
480+
fprintf(fp, " \"origin_device_id\": \"");
481+
for (size_t i = 0; i < FOSSIL_DEVICE_ID_SIZE; ++i)
482+
fprintf(fp, "%02x", chain->device_id[i]);
483+
fprintf(fp, "\",\n");
484+
485+
fprintf(fp, " \"created_at\": %" PRIu64 ",\n", chain->created_at);
486+
fprintf(fp, " \"updated_at\": %" PRIu64 ",\n", chain->updated_at);
477487
fprintf(fp, " \"blocks\": [\n");
478488

479489
for (size_t i = 0; i < chain->count; ++i) {
480490
const fossil_jellyfish_block *b = &chain->memory[i];
481491

492+
// Escape input/output strings
482493
char input_escaped[2 * FOSSIL_JELLYFISH_INPUT_SIZE] = {0};
483494
char output_escaped[2 * FOSSIL_JELLYFISH_OUTPUT_SIZE] = {0};
484495

@@ -497,66 +508,75 @@ int fossil_jellyfish_save(const fossil_jellyfish_chain *chain, const char *filep
497508
*dst = '\0';
498509

499510
fprintf(fp, " {\n");
511+
fprintf(fp, " \"block_index\": %zu,\n", i);
500512
fprintf(fp, " \"input\": \"%s\",\n", input_escaped);
501513
fprintf(fp, " \"output\": \"%s\",\n", output_escaped);
514+
515+
// hash
502516
fprintf(fp, " \"hash\": \"");
503-
for (size_t j = 0; j < FOSSIL_JELLYFISH_HASH_SIZE; ++j) {
517+
for (size_t j = 0; j < FOSSIL_JELLYFISH_HASH_SIZE; ++j)
504518
fprintf(fp, "%02x", b->hash[j]);
519+
fprintf(fp, "\",\n");
520+
521+
// previous_hash
522+
fprintf(fp, " \"previous_hash\": \"");
523+
if (i > 0) {
524+
for (size_t j = 0; j < FOSSIL_JELLYFISH_HASH_SIZE; ++j)
525+
fprintf(fp, "%02x", chain->memory[i - 1].hash[j]);
526+
} else {
527+
fprintf(fp, "00000000000000000000000000000000");
505528
}
506529
fprintf(fp, "\",\n");
530+
531+
// timestamps and timing
507532
fprintf(fp, " \"timestamp\": %" PRIu64 ",\n", b->timestamp);
508533
fprintf(fp, " \"delta_ms\": %" PRIu32 ",\n", b->delta_ms);
509534
fprintf(fp, " \"duration_ms\": %" PRIu32 ",\n", b->duration_ms);
535+
536+
// metrics
510537
fprintf(fp, " \"valid\": %d,\n", b->valid);
511538
fprintf(fp, " \"confidence\": %.6f,\n", b->confidence);
512539
fprintf(fp, " \"usage_count\": %" PRIu32 ",\n", b->usage_count);
513540

514-
// Write device_id as hex string
541+
// device_id
515542
fprintf(fp, " \"device_id\": \"");
516-
for (size_t j = 0; j < FOSSIL_DEVICE_ID_SIZE; ++j) {
543+
for (size_t j = 0; j < FOSSIL_DEVICE_ID_SIZE; ++j)
517544
fprintf(fp, "%02x", b->device_id[j]);
518-
}
519545
fprintf(fp, "\",\n");
520546

521-
// Write signature as hex string
547+
// signature
522548
fprintf(fp, " \"signature\": \"");
523-
for (size_t j = 0; j < FOSSIL_SIGNATURE_SIZE; ++j) {
549+
for (size_t j = 0; j < FOSSIL_SIGNATURE_SIZE; ++j)
524550
fprintf(fp, "%02x", b->signature[j]);
525-
}
526551
fprintf(fp, "\"\n");
527552

528553
fprintf(fp, " }%s\n", (i < chain->count - 1) ? "," : "");
529554
}
530555

531556
fprintf(fp, " ]\n");
532557
fprintf(fp, "}\n");
533-
534558
fclose(fp);
535559
return 1;
536560
}
537561

538562
static int fossil_jellyfish_similarity(const char *a, const char *b) {
539-
int cost = 0;
563+
if (!a || !b) return -1; // invalid input
564+
540565
size_t i = 0, j = 0;
566+
int cost = 0;
541567

542568
while (a[i] && b[j]) {
543-
char ac = a[i];
544-
char bc = b[j];
545-
546-
// case-insensitive match
547-
if (ac >= 'A' && ac <= 'Z') ac += 32;
548-
if (bc >= 'A' && bc <= 'Z') bc += 32;
569+
char ac = tolower((unsigned char)a[i]);
570+
char bc = tolower((unsigned char)b[j]);
549571

550-
if (ac != bc) {
551-
cost++;
552-
}
572+
if (ac != bc) cost++;
553573
i++;
554574
j++;
555575
}
556576

557-
// Penalty for remaining characters
558-
while (a[i++]) cost++;
559-
while (b[j++]) cost++;
577+
// Add cost for leftover characters
578+
cost += (int)strlen(a + i);
579+
cost += (int)strlen(b + j);
560580

561581
return cost;
562582
}
@@ -592,21 +612,32 @@ const char* fossil_jellyfish_reason(fossil_jellyfish_chain *chain, const char *i
592612
}
593613

594614
void fossil_jellyfish_decay_confidence(fossil_jellyfish_chain *chain, float decay_rate) {
615+
if (!chain || chain->count == 0) return;
616+
595617
const float MIN_CONFIDENCE = 0.05f;
618+
const float MAX_CONFIDENCE = 1.0f;
619+
620+
// Half-life of confidence in seconds (e.g. 24 hours = 86400s)
621+
const double HALF_LIFE_SECONDS = 86400.0;
622+
623+
// Current time in seconds
624+
time_t now = time(NULL);
596625

597626
for (size_t i = 0; i < chain->count; ++i) {
598627
fossil_jellyfish_block *block = &chain->memory[i];
599628
if (!block->valid) continue;
600629

601-
// Apply exponential decay
602-
block->confidence *= (1.0f - decay_rate);
630+
// Convert timestamps to seconds
631+
time_t block_time = (time_t)(block->timestamp / 1000); // assuming ms
632+
time_t age_seconds = now - block_time;
633+
if (age_seconds <= 0) continue; // future or zero-age blocks aren't decayed
603634

604-
// Clamp to zero
605-
if (block->confidence < 0.0f) {
606-
block->confidence = 0.0f;
607-
}
635+
// Compute decay factor: confidence *= 0.5^(age / half-life)
636+
double decay_factor = pow(0.5, (double)age_seconds / HALF_LIFE_SECONDS);
637+
block->confidence *= (float)decay_factor;
608638

609-
// Invalidate if confidence too low
639+
// Clamp and check
640+
block->confidence = fmaxf(0.0f, fminf(block->confidence, MAX_CONFIDENCE));
610641
if (block->confidence < MIN_CONFIDENCE) {
611642
block->valid = 0;
612643
}

0 commit comments

Comments
 (0)