Telemetry Pipeline

SkillDev tools

Use when working on the silken_net telemetry / Proof-of-Growth pipeline, the uplink→verification→minting flow (CoAP intake → UnpackTelemetryWorker / TelemetryUnpackerService → IoTeX verify → Chainlink oracle → mint), the Sidekiq strict-priority queues, TelemetryLog (RANGE-partitioned, KENOSIS, validations live in valid_sensor_data?, not the model), and the dual-computation integrity (server Float Lorenz ≡ firmware mruby). Knows the gotchas, DID=0 in a batch is DEAD (ARCH.54: Queen pulse rides the signed QATT-v2 header → enqueue_envelope_health, both eras drop DID=0), oracle_status_*? enum methods, strict queue drain (uplink fully before alerts), partition-pruning One-Home (TelemetryLog.partition_pruned, NOT find_with_partition_pruning, which is BlockchainTransaction's). Routes to CLAUDE.md §5/§6 + the 05_02 canon, does not restate. Examples: \"add a telemetry field\", \"change minting logic / guards\", \"why is an alert delayed\", \"decode the uplink packet\", \"why does server Z differ from device Z\".

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Telemetry Pipeline skill

What this skill tells your AI

The instructions your AI receives, as published by alexey-lukin/silken_net in .claude/skills/telemetry-pipeline/SKILL.md and read by ahel’s review.

SSOT Documents — Read These First

DocumentWhat it covers
CLAUDE.md §1Proof of Growth pipeline — full A→D flow (sense→…→mint SCC)
CLAUDE.md §5Sidekiq strict-priority queues + Lorenz/StatusByte + AES invariants
CLAUDE.md §6Telemetry cross-domain gotchas (oracle_status prefix · KENOSIS · partitions)
docs/05_02_Proof_of_Growth_Pipeline.mdExact worker ordering with queue assignments
docs/05_03_Tokenomics_SCC_and_SFC.mdGrowth points, SCC minting (slashing → 05_05)
docs/03_05_Hardware_Symmetric_Crypto_and_Security.md §3AES decrypt chain, key management

Gotchas Not Obvious From Docs

  1. DID 0x00000000 in a batch is DEAD (ARCH.54, 2026-07-03) — the old Queen-Sentinel pseudo-tree is dropped on BOTH paths (ECB and CCM): the pulse rides the SIGNED QATT-v2 envelope header (8B health block, firmware/common/queen_attest.h) → UnpackTelemetryWorker#enqueue_envelope_healthGatewayTelemetryWorker. Never re-add gateway metrics as a fake tree — it eats a CIFO slot, breaks the CCM stride, and health without a valid Ed25519 must not exist (masking-attack). Canon: 03_02 §7 + 06_08 §1.3. ⊕ [FW.59, 2026-09-08] The 8B block's flags byte is NOT homogeneous, so never read it as a flat bitmask: bits 0..3 are era/drop flags, bit4 is BOOKED (SEC.21 canary, enforced by a _Static_assert — do not take it), and bits 5..7 carry the reset cause (GatewayTelemetryLog#reset_cause). 🔴 Code 0 there means NOT REPORTED, never «cold start» — every pulse row older than FW.59 carries zeros, so reading 0 as a cause back-dates a verdict onto the whole history. Layout home firmware/common/queen_attest.h, codes firmware/common/reset_cause.h, prose 03_02 §7.1.

  2. oracle_status prefix — call log.oracle_status_fulfilled? not log.oracle_status == "fulfilled". String-backed enum with oracle_status_ prefix.

  3. Dual computation — server Lorenz (Float) must match firmware mruby (Float). Was BigDecimal before FW.7 — old to_d code is a bug now.

  4. Queue drain is strictuplink (#1) drains COMPLETELY before alerts (#2). Telemetry flood blocks alerts. By design.

  5. Validations removed from TelemetryLog — KENOSIS TITAN. Check is in TelemetryUnpackerService.valid_sensor_data?. Don't add validations back to model.

  6. Partition-aware lookupsTelemetryLog is RANGE-partitioned by created_at (monthly leaves; +1 every month, no drop/detach mechanism exists YET). ⛔ Рядкового retention тут НЕ БУДЕ — це присуд, не прогалина (⚖️ 2026-08-21, 00_07 ARCH.59): ретеншн робить ВИКЛЮЧНО дроп місячних партицій, будь-який delete_all над telemetry_logs — регресія, і її ловить spec/quality/telemetry_retention_home_spec.rb. Підстава — прилад: тракт архіву вже очікує саме дропу й має для нього чесний стан (TelemetryArchiveBatch.retention_expired = «листя менше, бо партиції дропнуто — НЕ tamper»), тож ДРУГИЙ механізм зникнення рядків зробив би цей статус неоднозначним. ⚠️ Знятий cleanup_old_logs! був НЕДОСЯЖНИЙ (єдиний викликач — мертвий Sidekiq::Batch-колбек), і саме тому небезпечний: покупка Pro-ліцензії озброїла б його мовчки, без окремого рішення. ⚠️ telemetry_logs_default is pruned or not depending on the SHAPE of the predicate, and this skill used to say flatly "never" — re-measured 2026-08-07: a closed window (created_at: t...t+1) prunes to exactly 1 leaf, so the default goes too; an open lower bound (>= cutoff) and an unbounded query cannot prune it, and there the default is a permanent extra probe. Say which form you mean. The One-Home set is three methods over two of the three models — pick by CARDINALITY, not by habit: TelemetryLog.partition_pruned(created_at_iso, metric_caller:) (chainable scope) · BlockchainTransaction.find_with_partition_pruning(id, created_at, metric_caller:) (ONE row) · BlockchainTransaction.where_ids_pruned(ids, span, metric_caller:) (a SET of known ids — span = the created_at of those same rows, so the row set is unchanged; a planner hint, never a filter). Both BlockchainTransaction forms now count their degraded path (silkennet_blockchain_transaction_unpruned_lookups_total) — the old silent-fallback asymmetry is closed. GatewayTelemetryLog has no helper, deliberately: zero id-lookups exist on it, so one would be a lever with no puller. 🔴 Never hand-roll the narrowing — exact equality on created_at misses by construction (ISO-8601 carries seconds, the column microseconds) and that form shipped three times; on the mint path the miss is silent (return unless log → the job succeeds having done nothing). ⛔ But a status-scan is NOT this class and a bound there is HARMFUL (ARCH.52: reset-to-pending keeps an OLD created_at, so a lower bound orphans stranded funds; the lever is a partial index). Rule of thumb: a window prunes a lookup for a KNOWN row; an index prunes a set of unknown size. The invariant now has a carrier — spec/quality/partition_key_discipline_spec.rb (declaration required per .reload and per id-lookup). Canon: 04_01 ⚡ PARTITION PRUNING INVARIANT [S6.16].

  7. «Wire = вхід GP» contract (E.63 (г), wire-rev2.1) — the CCM frame carries BOTH dT fields: raw (bytes 12..13, diagnostics/server-EMA) and ema_delta_t_s (bytes 20..21) = the EXACT number metabolic_health consumed on the device → check_metabolic_divergence! recomputes GP statelessly via Attractor.expected_homeostasis_gp(ema) (byte-identical mirror of bio_contract.rb §4.3 — edit the formula/thresholds THERE first, mirror second, regen lorenz_bytecode.h). The branch is observational (warn+metric) until the bench calibrates DELTA_T_FAST_S/DELTA_T_SLOW_S; ema_delta_t_s is transient (stripped pre-persist, like lorenz_temperature_c/device_z). ECB frames carry no ema → branch honestly skips. Canon: 03_04 §4.3 + 03_01 §13.6.

  8. firmware_version_id = wire-ЗВІТ, не FK (SEC.20, 2026-07-12) — post-SEC.20 семантика [semantic:1|reverted:1|contract_id&0x3FFF] (дзеркало firmware/common/fw_report.h): читай через TelemetryLog#firmware_report_semantic?/reverted?/contract_id (id ПО МОДУЛЮ 14 біт — НЕ join і не пряме порівняння з BioContractFirmware.id); legacy-кадри (без semantic-біта) несуть C-image константу — contract-версії НЕ мають. reverted?EwsAlert firmware_reverted (термінальний: re-issue лише версією > спаленої — 03_06 §4 bump-інваріант).

  9. TelemetryLog тепер несе MRV-lineage сліди (ARCH.12/E.60, 2026-07-19) — mint-інтенти отримують детерміновані вікна вимірів (Wallet watermark-курсор → telemetry_window_* на tx), а pin-воркер стемпить telemetry_logs.{archive_root, merkle_leaf} (E.60 Фаза 1б). Перший AR-колбек моделі: before_update seal-guard — мутація z_value/bio_status/created_at/tree_id стемпнутого рядка = raise (KENOSIS недоторканий: intake = insert_all, колбек не стріляє; oracle_status/verified_by_iotex — не leaf-поля, вільні). Leaf-формула One-Home = 05_02 §E.60 (Mrv::TelemetryLeaf, LEAF_VERSION). Не додавай у leaf-payload нове поле без LEAF_VERSION-bump.

  10. Device-event 0x57 = ОКРЕМИЙ L1-канал, не телеметрія (SEC.21, 2026-07-12) — рідкісні security-події (canary-trip) НЕ їдуть телеметрійним трактом: окремий CoAP PUT device/event/<uid>DeviceEventWorker (не UnpackTelemetryWorker). Королева підписує cleartext-конверт власним EDSK (тег SLKN-QEVT1, окремий від QATT2) → worker verify gateway-origin (HardwareKey.ed25519_public_key_hex, як QATT-батч), Rails LoRa-ключа НЕ торкається. Не плутай з CCM blind-courier телеметрії (там per-DID decrypt на Rails); тут — L1-підпис Королеви. Trust L1-observational, НІКОЛИ не money-path. Дім 03_05 §2.2а + 03_02 §7а.

  11. 🔴 Детекція OTA-mismatch гейтована колонкою, якої доти не писав НІХТО — тож гілка ніколи не виконувалась, і оживить її не телеметрія, а фікс форми. TelemetryUnpackerService#latest_tree_firmware_id бере BioContractFirmware.active.where(target_hardware_type: "Tree"), а check_firmware_mismatch! виходить на власний return if latest_id.nil?. Писальників тієї колонки в app/ було нуль (форма завантаження слала ключ без колонки), тобто при суто-nil популяції детекція мовчить за побудовою, а не через дані. Наслідок для читача цього тракту: щойно з'явиться перший типізований реліз, кожен аплінк із розбіжним contract-id почне ставити деревам firmware_update_status: :fw_pending — це зміна поведінки гарячого шляху, спричинена сусіднім доменом. Рефлекс: перед тим як довіритись будь-якій гілці, гейтованій значенням колонки, перелічи ПИСАЛЬНИКІВ, а не читачів — колонка, яку ніхто не пише, робить гілку декоративною, і читацький бік при цьому виглядає справним. ✅ ПРИСУД 2026-08-14 (ARCH.85, §🗄️): гілка лишається СПОСТЕРЕЖНОЮ, не дієвою — вона пише logger.info про розбіжність і firmware_update_status НЕ міняє. Дієвий update_all знято, не закоментовано. Підстава — blast-radius першого прогону: тракт не біг жодного разу, тож перший запуск стався б одразу в полі, на гарячому шляху, і при хибній деривації позначив би fw_pending весь флот, а ретрансміту в цього стану немає (FW.63). ⚠️ Прапорця-перемикача свідомо НЕМА (забутий прапорець = тихо вимкнений захист, прецедент INF.11), тож оживлення = зняти один рядок ПІСЛЯ того, як лічильник покаже правдоподібні числа на живому флоті. ⊕ Заразом закрито сусідній зомбі: deploy_globally! не гасив БЕЗТИПНИХ предків (where(col: X) це SQL = X, а NULL не дорівнює нічому) — скіл backend #44.

  12. 🔴 acoustic_events змінив wire-семантику (ARCH.102, 2026-08-16): тепер це «детекції від останнього УСПІШНОГО uplink'а» — а доти на дроті було завжди 0 або 1, і бекендні пороги писались під семантику «подій за вікно», якої прошивка не мала. Фаза 2 Солдата знімала І ОБНУЛЯЛА лічильник на кожному проході while(1), а три інкременти взаємовиключні (if/else if по зоні впевненості й класу) → максимум +1 на пробудження; тож обидва пороги AlertDispatchServiceinsect_epidemic (> 50) і seismic_anomaly (>= 200) — були недосяжні з реального заліза і стріляли лише на наших-таки сідах/HIL-профілях. Після фіксу лічильник споживає ЛИШЕ успішна передача телеметрії (віднімання знімка, не обнулення) — детекції deferred-TX-циклів (мороз) і grace-hello більше не зникають, незʼїдений залишок переживає STOP2 у DR0 — тож багатоциклове накопичення тепер легальний wire-вхід (0xFE лишається time-uncertain-сентинелом, який unpacker нейтралізує ДО DCI). 🔴 Обидві вердикт-гілки на цьому лічильнику ЗНЯТО тим самим присудом, і підстава пережила фікс: поріг став досяжним, а вимірювача так і немає — класу «комаха» в TinyML нема взагалі, сейсмічного каналу теж, лічильник рахує кавітацію та пилку. Тобто «полагодити семантику» і «зробити вердикт чесним» — різні роботи, і перша другої не дає. Живих споживачів цього поля лишилось два, обидва справжні: DCI-парність σ (03_04) і panic-канал пилки. ⛔ Не додавай нової гілки на це поле без відповіді на «а звідки ти це знаєш» → 00_07 ARCH.102 + 04_02 §2.

  13. 🔴 telemetry_logs.sap_flow не пише НІХТО — колонки нема в жодному wire-форматі (PAYLOAD_FORMAT, CCM_SENSOR_PAYLOAD_FORMAT), писальників у app/ нуль — а читачі живі, і найгостріший тихо вимикає антифрод. Виміряний ланцюг, яким клас знайдено: fraud-базлайн InsightGeneratorService брав AVG(sap_flow) по суцільних NULL → nil.to_f0.0detect_fraud? коротко замикався на baseline[:sap].zero?, тобто sap+temp-гілка антифроду в проді не могла спрацювати ВЗАГАЛІ; зеленою її тримали лише фабрики/сіди, що виставляють колонку руками (клас «фікстура виготовляє вимір», TEST.12 / 04_06 §B.2 BP #14). Це друге живе втілення рефлексу з #11: гілку, гейтовану значенням колонки, спершу звіряй із переліком ПИСАЛЬНИКІВ, не читачів.

  14. 🔴 Enqueue телеметрії мусить нести момент ПРИЙОМУ — інакше доба cold-derive Лоренца тихо з'їжджає на добу ОБРОБКИ [ARCH.41, 2026-08-28]. UnpackTelemetryWorker#perform має ЧЕТВЕРТИЙ аргумент received_at_iso, який їде далі як TelemetryUnpackerService.call(received_at:) і читається One-Home-методом derivation_epoch_day. ⚠️ Обидві опції, які здаються очевидними, ХИБНІ: Time.now рухається зі спробою, а telemetry_log.created_at ставиться при ВСТАВЦІ, тобто на Sidekiq-ретраї він такий самий новий. Єдина величина тракту, стабільна між спробами, — момент прийому, зафіксований інтейком і серіалізований у job-аргументи. Ціна промаху: ретрай через межу півночі UTC дає інший epoch_day → інший (x₀,y₀,z₀) → категоричний DCI-мисматч на ЧЕСНОМУ дереві, і ловити його НІКОМУ: try_time_sync_recovery (ARCH.41-A) гейтований !cold_start_flag, тобто страхувальна сітка структурно відсутня рівно на cold-start, де деривація й відбувається; -B/-C стережуть НЕсинхронізований пристрій, а тут час пристрою правильний. 🔒 Аргумент ОПЦІОНАЛЬНИЙ за побудовою (nil = «прийом зараз», легально для bench/HIL/спек), тож його ВТРАТА на прод-сайті нічого видимого не ламає — це тримає гейт spec/quality/telemetry_received_at_propagation_spec.rb із ліхтарем периметра, що червоніє на НОВОМУ продовому enqueuer'і. ⛔ Додаєш enqueue-сайт — передавай Time.current.utc.iso8601 четвертим; lib/silken_net/load_test/** свідомо поза периметром (bench не моделює прийом). ✅ Стан переміряно 2026-08-17, і він змінився двічі: той fraud-читач ЗНЯТО (нуль хітів на AVG(sap_flow)/baseline[:sap]), а 04_01 §2 тепер несе DEAD-маркер, якого тут доти «не було». 🔴 Але живий читач лишився РІВНО ОДИН, і попередній свіп його не бачив: OracleVisionsController#calculate_expected_yield бере колонку через мапу TelemetryLog.latest_per_tree, тож next if sap_index.nil? спрацьовує на КОЖНОМУ дереві — покриття прогнозу структурно 0 з N, а «Projected 24h Emission» є константою 0.0. Урок про сам свіп, ширший за випадок: перелічувати читачів за ІМЕНЕМ колонки недостатньо — сайт, що заходить за спільним ВХОДОМ (мапа tree_id → log, pluck, select), імені моделі поруч не має. Читача лишено свідомо з названою умовою оживлення (поле sap_flow у wire-форматі), бо число не бреше — покриття їде поруч → 00_07 ARCH.102/ARCH.103.

  15. 🫁 Soldier-pulse НЕ є окремим кадром і не потребує гілки в розпакувальнику [SILENCE-1, ⚖️ 2026-09-04]. Кадр «я тут, але нічого не міряв» — це той самий 30B CCM-пакет із delta_t = DELTA_T_UNKNOWN_S, що дає на дроті пару status = 0, GP = 0, якої у ВИМІРЯНОГО гомеостазу не буває (той починається з GP_HOMEO_MIN) — тобто регістр оголошений даними, без нового опкоду, довжини чи прапорця. Присуд обрано виміром: найближчий вільний розмір (17 Б проти 30) виграє лише ≈61 мс airtime ≈ 8 мДж ≈ 1.6 % добового балансу, тоді як коштував би гілки в Queen_Rx_Classify (він розрізняє кадри СУТО за довжиною: 16 → ECB, 30 → CCM, решта → тихий дроп), нового опкоду, вектора й гілки декрипту. ⛔ Тож не додавай pulse?-предиката й не роздвоюй шлях: будь-яка гілка «це pulse» відтворює той самий поділ на рівні, де його немає в даних. Що ВАРТО тримати — ТРИ піни: pulse штампує last_seen_at (інакше він не розвʼязує конфаунд «мовчазне здоровʼя ↔ мертвий вузол», задля якого існує) · НЕ дає балів (інакше вузол отримує гроші за відмову міряти — рівно ціна BASELINE_DELTA_T_S) · і НЕ кричить fraud. 🔴 Третій дописано 2026-09-06, і саме його бракування тримало ЖИВИЙ дефект: check_metabolic_divergence! вимагав GP ∈ 5..31 при гомеостазі, тобто читав ОГОЛОШЕНУ пару status = 0, GP = 0 як порушення смуги й інкрементував TELEMETRY_FRAUD_DETECTED_TOTAL на ЧЕСНІЙ відмові вузла — при тому, що прошивка власним коментарем каже: бекенд розрізняє «зрив» від «не міряли» за СТАТУСОМ, не за балами. ⚠️ Дві половини ОДНОГО присуду розійшлись тихо — ТОЧНА гілка (expected_homeostasis_gp(0) → 0) сентинел знала, СТРУКТУРНА ні. Ціна щоденна: Wall_Seconds_Now() віддає 0 до LSE/RTC bring-up (FW.49), тож на кремнії сентинел іде щоцикла — вічно-червоний fraud-канал є безмовним (S2.4-закон). 🔑 І урок про сам пін: він був ЗЕЛЕНИЙ на прикладі, який САМЕ ЦЕЙ кадр і шле — міряв живість і бали, а мовчання третього каналу не міряв узагалі. ⚠️ Перша спроба це виправити виміряла МОК: файловий before тієї спеки пінить calculate_z_from_state у [0.5, …], тобто server_z поза смугою, і Z-канал кричав ЗАКОННО; лік — повернути z у смугу локально, а не «полагодити» код під фікстуру. Дім — 06_08 §1.3; сусідній писач-інваріант — скіл backend #83.

  16. Z у продові читає РІВНО ОДИН споживач — check_z_divergence! (DCI). Не заводити з z_value/Attractor-предикатів жодного вердикту про ЗДОРОВʼЯ [E.64 (A), ⚖️ 2026-09-05]. Лоренц є печаткою обчислювальної цілісності: те саме обчислення повторюється на пристрої й на сервері з того самого секретного зерна й мусить збігтись категорично. Про фізіологію він не свідчить ЗА ПОБУДОВОЮ — детермінована функція від входів, які верифікатор і так має в plaintext, тож за data-processing inequality не додає інформації понад них (05_05 §8.1). 🔴 І це не теорія — так уже сталось ТРИЧІ, на трьох рівнях агрегації, щоразу з ВИМІРЯНОЮ ціною: (1) серверна гілка Attractor.homeostatic?severe_drought спрацьовувала на ЧЕСНИХ деревах у 1.4 % (MAX-бік, тепла погода); (2) кластерна entropy_anomaly давала «здорову» смугу 0.908 на лісі з НУЛЬОВОЮ біологічною різницею (⚖️ 2026-09-05 тракт знято ЦІЛКОМ — писач, сервіс, cron, gauge, Grafana й сама колонка clusters.entropy_score; enum-значення й локаль-ключ лишені історичними заради рендеру архівних рядків); (3) найдорожча й знайдена ОСТАННЬОЮ — avg_z як ФІЧА RandomForest у InsightGeneratorService#calculate_stress_index (знято 2026-09-05, дім → 00_07 E.52): через ML це не мʼякше, а ГІРШЕ, бо евристична гілка має стелю 0.6 < 0.83, а predict_proba не має жодної — тоді як stress_index іде ПРЯМО в BlockchainBurningService (slashUpTo), Celo-виплату й страховий Trigger-1. ⛔ Тож заборона накриває не лише предикати, а й НАВЧАННЯ: avg_z у фіча-векторі є тим самим вердиктом, лише схованим у вагах, де його вже не видно ані грепом, ані ревʼю. Спільна причина всіх трьох — розкид Z між деревами породжений їхніми K_seed, які ми ПРИЗНАЧИЛИ, а не мікросередовищем. 🔑 Дискримінатор, що ловить наступний випадок: питай не «чи прилад справний», а «про ЧИЙ предмет він свідчить» — про дерево чи про наше власне слово, сказане дереву. ⊕ Легальний біо-гейт лишається один — ПРИСТРІЙНИЙ bio_status (він теж вироджений: stress = z < 2.0 недосяжний за ρ-clamp, тож перил посухи сьогодні не має авто-писача, і це оголошено в 00_04 §2). Здоровʼя мусить прийти з ПРЯМИХ вимірювачів (вологість · sap-flow · VPD · акустика) — їх у залізі ще немає, і доти чесна відповідь: «ніхто не міряв».

  17. 📡 TelemetryUnpackerService#perform ПОВЕРТАЄ Summary, а трансляція в UI стоїть ПІСЛЯ нього — і обидві половини несучі [UI.16, 2026-09-06]. Доти UnpackTelemetryWorker кликав broadcast_to_matrix перед розпакуванням і слав binary_data.unpack1("H*") — сирий hex конверта, під заголовком колонки, що це прямо називав; лісгосп бачив шістнадцятковий дамп на клієнт-фейсній сторінці в головній навігації. 🔴 Дорожчою була не семантика, а ПОЛОЖЕННЯ: зовнішній rescue у perform виняток не ковтає, а ПЕРЕКИДАЄ його заради Sidekiq-retry, тож стабільно падаюча ПРИКРАСА робила батч таким, що ніколи не розпакується (ретраї вичерпуються → dead set, черга №1, найдорожчі дані платформи) — саме тому [UI.4] мусив рятувати виклик rescue-ізоляцією. Перенесення знімає hazard СТРУКТУРНО: після коміту рядків збій рендера фізично не має чому завадити. ⛔ rescue при цьому НЕ знімати — його предмет ЗВУЗИВСЯ (не дати збою кабелю зіпсувати COAP_PACKETS_RECEIVED_TOTAL{status="success"} і фіналізацію QATT-nonce), а не зник; без нього повертається пере-обробка вже закоміченого конверта. 🔑 Summary родиться в сервісі, бо лише він знає, скільки записів ЛЯГЛО, і dropped там виводиться (records − committed), а не лічиться на місцях відкидання: тих шість, вони ростуть, і будь-який перелік старів би лише в бік ЗАНИЖЕННЯ — тобто зведення тихо казало б «усе гаразд». Єдина точка накопичення — commit_telemetry, впритул до TELEMETRY_PROCESSED_TOTAL (тотожна семантика). ⚠️ Порожній конверт (empty-flush heartbeat) стрічку не смикає: пульс Королеви має власний дім (гоча 1). ⛔ BACKFILL зведень — присуд «НЕ БУДУВАТИ»: «флаш» не є сутністю в БД, а реконструкція по queen_uid + секунді розриває частину батчів навпіл, тобто HUD брехав би про кількість флашів; порожнеча лікується ВИМІРОМ у плейсхолдері, не відтворенням стрічки. ⚠️ І пам'ятай про стаби: будь-яка спека, що мокає TelemetryUnpackerService.call, мусить віддавати Summary — голий receive(:call) дає nil, броадкаст падає в rescue, і приклади про скоуп стріму лишаються зелені на порожній множині.

  18. 🌲 bin/forest_simulator тепер РАХУЄ bio_status, і DCI на демо-прогонах перестала бути завжди-червоною [E.64, 2026-09-06]. Доти обидва поля StatusByte бралися rand(), тобто сторона, яку DCI звіряє з серверним Z, ГЕНЕРУВАЛАСЬ — і перший multi-node прогін на canopy запалив критичний Telemetry fraud detected, істинно-позитивний: «шахраєм» був наш власний симулятор. ⚠️ rand ламав ДВІ звірки, не одну: growth_points = rand(0..31) окремо порушував check_metabolic_divergence! (homeostasis → GP ∈ 5..31, stress → GP == 1). Модель вузла живе в Hil::SoldierNode (сусід Hil::QueenSimulator; скрипт — тонкий викликач, бо спек у bin/ не буває): власний Lorenz-ланцюг, cold-start із K_seed через SeedDerivation тим самим виразом доби, що й derivation_epoch_day, далі продовження з ВЛАСНОГО хвоста. 🔑 Ланцюг власний СВІДОМО: симулятор, що читає серверний хвіст із telemetry_logs, зелений за побудовою — та сама беззмістовність, лише протилежного знаку до rand. ⚠️ Стеля названа: це НЕ доказ незалежності обчислень (обидві сторони крутять SilkenNet::Attractor) — доводиться ТРАКТ; байт-парність тримають sweep проти СПРАВЖНЬОГО контракту (tools/firmware/contract_runner.rb, підпроцес) і FW.55. ⛔ Той міст у симулятор не переноситься: /firmware і /tools не їдуть у Docker-образ ([OPS.10]), а на canopy симулятор біжить у job-контейнері. 🔴 І живий слот одразу знайшов дефект, якого аналіз не бачив: ланцюг двійника живе в ПАМʼЯТІ ПРОЦЕСУ, а RTC справжнього Солдата переживає перезавантаження. Тож ПЕРЕЗАПУСК симулятора — артефакт емуляції, не подія пристрою: вузол cold-стартував із K_seed, тоді як сервер мав хвіст попереднього прогону й продовжував ТЕПЛО → категоричний DCI-mismatch на ЧЕСНОМУ дереві. Виміряно на canopy: time_unsynced_fallback = 2 на 147 рядків, і кожен такий кадр ще й ставив TimeSyncDownlinkWorker, який ретраївся в Королеву, якої там немає за конструкцією, аж у DeadSet. 🔑 Розрізнення несуче й не інтуїтивне: читати серверний хвіст на КОЖНОМУ пакеті — циркулярність (зелене за побудовою); читати його ОДИН РАЗ на процес — відновлення памʼяті двійника, бо серверний хвіст і Є записом того самого RTC. Далі ланцюг знову незалежний. ⚠️ Стеля названа: перший кадр на дерево після рестарту продовження НЕ доводить — вакуумно, але чесно, тоді як доти було хибно-червоно. ⚠️ І це звужує читання fraud-лічильника: try_time_sync_recovery поглинає категоричний mismatch і робить return true БЕЗ інкременту, тож «0 фроду» означає «не було АБО поглинуто» — чесний вимір бере ще й time_unsynced_fallback.

Common Tasks

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
22
Forks
1
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
telemetry-pipeline
Source
github.com/alexey-lukin/silken_net