kairos-chain 3.93.0 → 3.95.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -0
  3. data/bin/kairos-chain +2 -0
  4. data/lib/kairos_mcp/kairos_chain/landed_probe.rb +62 -0
  5. data/lib/kairos_mcp/knowledge_provider.rb +473 -15
  6. data/lib/kairos_mcp/l0_proposal_store.rb +82 -0
  7. data/lib/kairos_mcp/l1_history.rb +257 -0
  8. data/lib/kairos_mcp/safe_evolver.rb +399 -126
  9. data/lib/kairos_mcp/skillset.rb +21 -0
  10. data/lib/kairos_mcp/skillset_manager.rb +58 -13
  11. data/lib/kairos_mcp/storage/importer.rb +50 -0
  12. data/lib/kairos_mcp/tools/chain_import.rb +15 -3
  13. data/lib/kairos_mcp/tools/knowledge_update.rb +37 -3
  14. data/lib/kairos_mcp/tools/skills_evolve.rb +34 -8
  15. data/lib/kairos_mcp/tools/skills_rollback.rb +94 -6
  16. data/lib/kairos_mcp/tools/system_upgrade.rb +2 -0
  17. data/lib/kairos_mcp/version.rb +1 -1
  18. data/lib/kairos_mcp/version_manager.rb +29 -14
  19. data/templates/knowledge/design_to_implementation_workflow/design_to_implementation_workflow.md +4 -1
  20. data/templates/knowledge/multi_llm_review_workflow/multi_llm_review_workflow.md +40 -5
  21. data/templates/skillsets/agent/bin/agent_harvest.rb +28 -0
  22. data/templates/skillsets/agent/config/policies/masa_2026_10_20.rb +17 -0
  23. data/templates/skillsets/agent/hooks/agent_hook.rb +139 -0
  24. data/templates/skillsets/agent/lib/agent/confinement.rb +107 -239
  25. data/templates/skillsets/agent/lib/agent/dsl.rb +219 -0
  26. data/templates/skillsets/agent/lib/agent/guard.rb +799 -0
  27. data/templates/skillsets/agent/lib/agent/harvest.rb +145 -0
  28. data/templates/skillsets/agent/lib/agent/hooks.rb +785 -0
  29. data/templates/skillsets/agent/lib/agent/journal.rb +118 -0
  30. data/templates/skillsets/agent/lib/agent/policies.rb +153 -0
  31. data/templates/skillsets/agent/lib/agent/precedents.rb +151 -0
  32. data/templates/skillsets/agent/lib/agent/review.rb +507 -0
  33. data/templates/skillsets/agent/lib/agent/run.rb +497 -0
  34. data/templates/skillsets/agent/lib/agent/service.rb +1661 -0
  35. data/templates/skillsets/agent/lib/agent/stand_in.rb +274 -0
  36. data/templates/skillsets/agent/lib/agent/templates.rb +131 -0
  37. data/templates/skillsets/agent/lib/agent/transcript.rb +134 -0
  38. data/templates/skillsets/agent/lib/agent.rb +34 -22
  39. data/templates/skillsets/agent/plugin/SKILL.md +138 -171
  40. data/templates/skillsets/agent/plugin/hooks.json +94 -0
  41. data/templates/skillsets/agent/report_kit/KIT_SHA256.txt +5 -0
  42. data/templates/skillsets/agent/report_kit/check.py +23 -0
  43. data/templates/skillsets/agent/report_kit/kit.py +364 -0
  44. data/templates/skillsets/agent/report_kit/make_report_deck.py +159 -0
  45. data/templates/skillsets/agent/report_kit/render.py +19 -0
  46. data/templates/skillsets/agent/report_kit/viz.py +203 -0
  47. data/templates/skillsets/agent/skillset.json +99 -14
  48. data/templates/skillsets/agent/test/test_agent1_dsl.rb +89 -0
  49. data/templates/skillsets/agent/test/test_agent1_guard.rb +127 -0
  50. data/templates/skillsets/agent/test/test_agent1_hooks_service.rb +401 -0
  51. data/templates/skillsets/agent/test/test_agent1_journal_run.rb +93 -0
  52. data/templates/skillsets/agent/test/test_agent1_r1_check.rb +571 -0
  53. data/templates/skillsets/agent/test/test_agent1_r1_guard.rb +475 -0
  54. data/templates/skillsets/agent/test/test_agent1_r1_hookscript.rb +410 -0
  55. data/templates/skillsets/agent/test/test_agent1_r1_lifecycle.rb +556 -0
  56. data/templates/skillsets/agent/test/test_agent1_r1_report.rb +588 -0
  57. data/templates/skillsets/agent/test/test_agent1_r1_review.rb +689 -0
  58. data/templates/skillsets/agent/test/test_agent1_r1_words.rb +614 -0
  59. data/templates/skillsets/agent/test/test_agent1_r1b_fixes.rb +258 -0
  60. data/templates/skillsets/agent/test/test_agent1_r2_guard.rb +565 -0
  61. data/templates/skillsets/agent/test/test_agent1_r2_words.rb +349 -0
  62. data/templates/skillsets/agent/test/test_agent1_r2v_checkreview.rb +725 -0
  63. data/templates/skillsets/agent/test/test_agent1_r2v_decisions.rb +756 -0
  64. data/templates/skillsets/agent/test/test_agent1_r2v_progress.rb +539 -0
  65. data/templates/skillsets/agent/test/test_agent1_r2v_sessions.rb +770 -0
  66. data/templates/skillsets/agent/test/test_agent1_r3_guard.rb +354 -0
  67. data/templates/skillsets/agent/test/test_agent1_r3_words.rb +367 -0
  68. data/templates/skillsets/agent/test/test_agent1_r3v_checkreview.rb +854 -0
  69. data/templates/skillsets/agent/test/test_agent1_r3v_guardwords.rb +730 -0
  70. data/templates/skillsets/agent/test/test_agent1_r3v_lifecycle.rb +1096 -0
  71. data/templates/skillsets/agent/test/test_agent1_selfreview_fixes.rb +75 -0
  72. data/templates/skillsets/agent/test/test_agent1_stand_in_precedents.rb +113 -0
  73. data/templates/skillsets/agent/test/test_agent1_v06.rb +1129 -0
  74. data/templates/skillsets/agent/tools/agent_advance.rb +51 -0
  75. data/templates/skillsets/agent/tools/agent_finish.rb +50 -0
  76. data/templates/skillsets/agent/tools/agent_items.rb +56 -0
  77. data/templates/skillsets/agent/tools/agent_start.rb +17 -224
  78. data/templates/skillsets/agent/tools/agent_status.rb +9 -89
  79. data/templates/skillsets/agent/tools/agent_stop.rb +8 -122
  80. data/templates/skillsets/introspection/lib/introspection/safety_inspector.rb +28 -14
  81. data/templates/skillsets/llm_client/lib/llm_client/call_router.rb +7 -1
  82. data/templates/skillsets/llm_client/lib/llm_client/claude_code_adapter.rb +21 -2
  83. data/templates/skillsets/llm_client/skillset.json +1 -1
  84. data/templates/skillsets/llm_client/test/test_no_fallback_and_isolation.rb +113 -0
  85. data/templates/skillsets/llm_client/tools/llm_call.rb +20 -2
  86. metadata +57 -62
  87. data/templates/skillsets/agent/bin/agent_distill.rb +0 -124
  88. data/templates/skillsets/agent/bin/agent_rule.rb +0 -215
  89. data/templates/skillsets/agent/bin/agent_shadow_judge.rb +0 -70
  90. data/templates/skillsets/agent/bin/agent_step_worker.rb +0 -321
  91. data/templates/skillsets/agent/config/agent.yml +0 -171
  92. data/templates/skillsets/agent/lib/agent/act_classification.rb +0 -336
  93. data/templates/skillsets/agent/lib/agent/act_classification.yml +0 -54
  94. data/templates/skillsets/agent/lib/agent/admission.rb +0 -384
  95. data/templates/skillsets/agent/lib/agent/adoption.rb +0 -340
  96. data/templates/skillsets/agent/lib/agent/advance_gate.rb +0 -357
  97. data/templates/skillsets/agent/lib/agent/answer_ruling.rb +0 -491
  98. data/templates/skillsets/agent/lib/agent/cognitive_loop.rb +0 -452
  99. data/templates/skillsets/agent/lib/agent/delegation.rb +0 -372
  100. data/templates/skillsets/agent/lib/agent/delegation_table.yml +0 -44
  101. data/templates/skillsets/agent/lib/agent/distill_run.rb +0 -197
  102. data/templates/skillsets/agent/lib/agent/distiller.rb +0 -313
  103. data/templates/skillsets/agent/lib/agent/distiller_prompt.rb +0 -130
  104. data/templates/skillsets/agent/lib/agent/mandate_adapter.rb +0 -69
  105. data/templates/skillsets/agent/lib/agent/mediator.rb +0 -211
  106. data/templates/skillsets/agent/lib/agent/message_format.rb +0 -33
  107. data/templates/skillsets/agent/lib/agent/native_body/main.rb +0 -166
  108. data/templates/skillsets/agent/lib/agent/native_body/model_client.rb +0 -135
  109. data/templates/skillsets/agent/lib/agent/native_body/spend_meter.rb +0 -131
  110. data/templates/skillsets/agent/lib/agent/native_body/tool_layer.rb +0 -195
  111. data/templates/skillsets/agent/lib/agent/point_facts.rb +0 -231
  112. data/templates/skillsets/agent/lib/agent/review_hint.rb +0 -84
  113. data/templates/skillsets/agent/lib/agent/session.rb +0 -282
  114. data/templates/skillsets/agent/lib/agent/shadow_judge.rb +0 -564
  115. data/templates/skillsets/agent/lib/agent/staging.rb +0 -267
  116. data/templates/skillsets/agent/lib/agent/step_delegation.rb +0 -450
  117. data/templates/skillsets/agent/lib/agent/trigger_validator.rb +0 -69
  118. data/templates/skillsets/agent/lib/agent/verdict.rb +0 -177
  119. data/templates/skillsets/agent/plugin/agents/monitor.md +0 -24
  120. data/templates/skillsets/agent/test/test_agent_act_hardening.rb +0 -488
  121. data/templates/skillsets/agent/test/test_agent_admission.rb +0 -112
  122. data/templates/skillsets/agent/test/test_agent_allowlist.rb +0 -724
  123. data/templates/skillsets/agent/test/test_agent_answer_rulings.rb +0 -949
  124. data/templates/skillsets/agent/test/test_agent_capability_discovery.rb +0 -307
  125. data/templates/skillsets/agent/test/test_agent_complexity_review.rb +0 -852
  126. data/templates/skillsets/agent/test/test_agent_confinement.rb +0 -184
  127. data/templates/skillsets/agent/test/test_agent_distillation.rb +0 -539
  128. data/templates/skillsets/agent/test/test_agent_guard_integration.rb +0 -218
  129. data/templates/skillsets/agent/test/test_agent_guard_verdict_record.rb +0 -446
  130. data/templates/skillsets/agent/test/test_agent_halt_semantics.rb +0 -370
  131. data/templates/skillsets/agent/test/test_agent_human_mark_gate.rb +0 -486
  132. data/templates/skillsets/agent/test/test_agent_interruption_resilience.rb +0 -729
  133. data/templates/skillsets/agent/test/test_agent_m1.rb +0 -329
  134. data/templates/skillsets/agent/test/test_agent_m2.rb +0 -625
  135. data/templates/skillsets/agent/test/test_agent_m3.rb +0 -719
  136. data/templates/skillsets/agent/test/test_agent_m4.rb +0 -545
  137. data/templates/skillsets/agent/test/test_agent_native_body.rb +0 -788
  138. data/templates/skillsets/agent/test/test_agent_shadow_judge.rb +0 -1233
  139. data/templates/skillsets/agent/test/test_agent_verdict.rb +0 -119
  140. data/templates/skillsets/agent/test/test_agent_worker_exit_and_review_parse.rb +0 -622
  141. data/templates/skillsets/agent/test/test_agent_worker_process.rb +0 -386
  142. data/templates/skillsets/agent/test/test_decide_prompt_contract.rb +0 -158
  143. data/templates/skillsets/agent/test/test_review_hint.rb +0 -168
  144. data/templates/skillsets/agent/tools/agent_execute.rb +0 -627
  145. data/templates/skillsets/agent/tools/agent_step.rb +0 -3909
  146. data/templates/skillsets/agent/tools/agent_wait.rb +0 -195
  147. data/templates/skillsets/agent/tools/operator_report.rb +0 -130
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1624b7fa2adf2856c0f55ca0012dc527870d5649cdcad7ebe2d8ae90cda1d4a
4
- data.tar.gz: 12cdc74b57b87266ca3364654468fa077774665e9b1bef090dea9806907c4b1b
3
+ metadata.gz: 3bce3f299f0bb91ecbb6199e464a2ea24602ede6e9d4e972c1a7b5905ec447c5
4
+ data.tar.gz: 4986b9e4f8c87ff233b67586791d8b3068aed4decaecb1319f5c0553b4a5445c
5
5
  SHA512:
6
- metadata.gz: 9e47baf8089acd2fb9cc4f7f5fc4264d55d4096f8ed21aacb1a736ab27099beebda372d429de1e5a424e66307ccda5a274f5532073e7e21eaa4bc5d58684a718
7
- data.tar.gz: 4deb91c26655f7c6e11a72802635a7c088aa0a7246124785984d2fe2f20fbb0ab02e0b2d27e425948a8107be69fe5cd1f72d4ca90efc069f12731bef9ec36e79
6
+ metadata.gz: a4af517774c9e5e90299d4877190d83659932acf7851bf04275d5c3066298411ca628084a490cfef6348b327d550c05d5cc4f96cab086e5c297e2a169e1f72b3
7
+ data.tar.gz: ba67dc90461e4350615a4ba9e232702efc27b241fa853a2934a80714bb5753c2aa1ebba06921ebe58e4db7145d8f3fb5d747be4ab37f8ad5da25150ab8c7ce8d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,103 @@ This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.95.0] - 2026-10-21
10
+
11
+ ### Changed — the `agent` SkillSet is rebuilt (1.0): long runs in the host session, a stand-in instead of terminal approvals
12
+
13
+ The 0.x agent could not carry the operator's ordinary request (design → design review → implement →
14
+ implementation review): its act route wrote only `docs/drafts/draft_*`, could not reach multi-LLM review or
15
+ tests, and counted only terminal-attested answers (0 counted pairs). Design:
16
+ `log/agent_skillset_rebuild_design_v0.5.1_20261020.md` (five review rounds, frozen as the author's proposal)
17
+ and its delta `log/agent_skillset_rebuild_design_v0.6.3_20261020.md`.
18
+
19
+ - The host session (Claude Code) is the only body. The SkillSet supplies a plan from a Ruby-DSL template, a
20
+ stand-in (isolated `claude -p --safe-mode --tools ""`, Opus 5.5) that answers decision points from the
21
+ operator's own words and the instruction mode, a guard (host hooks: `PreToolUse` on every tool, fail-closed)
22
+ that lets through only what the run created or its worktree and branch hold, a hash-chained journal, and a
23
+ report check. Six tools: `agent_start`, `agent_status`, `agent_advance`, `agent_items`, `agent_finish`,
24
+ `agent_stop`.
25
+ - Runs need an adopted policy (the operator's mandate, `config/policies/*.rb`), adopted by the operator's own
26
+ typed words naming its digest; the adoption is recorded on the chain.
27
+ - Templates: `dev_cycle`, `impl_cycle`, `design_only`, `doc_cycle` (a document kept in git, revised in place,
28
+ optional build check), `survey` (versioned survey files from local sources), `general`.
29
+ - A review closes only when no (a)/(b) P0 is open. Each review may take the policy's `review_rounds`
30
+ (10), counted for that review alone; at the cap it waits for the operator, who grants more rounds or
31
+ freezes it. Revisions follow L1 multi_llm_review_workflow § Revision
32
+ Discipline: each round says which new P0s the actor's last addition drew, and the next step is to undo it.
33
+ Design reviews stay at the design level; implementation-only findings are deferred to the implementation
34
+ review and are operator items at once.
35
+ - Every run ends with a layered-deck report (`report_kit/`, the kit of L1 `layered_visual_pitch_deck`).
36
+ - `bin/agent_harvest.rb` harvests the operator's own answers from host transcripts (hook output, peer
37
+ messages and pasted host output excluded).
38
+ - Removed: the in-server OODA loop, act-route table and terminal rulings, shadow judge, distillation,
39
+ native body, `agent_execute`, `agent_step`, `agent_wait`, `operator_report`, the `agent-monitor` subagent.
40
+ - `agent` is no longer installed automatically in new instances (it needs a policy and projects hooks).
41
+ An installed 0.x agent becomes 1.0 on upgrade. 1.0 needs `multi_llm_review` and `llm_client` >= 0.3.0 in
42
+ the same instance; upgrade does not install a missing one (`kairos-chain skillset install multi_llm_review`).
43
+
44
+ ### Added — `removed_files` in `skillset.json`; `system_upgrade` archives them
45
+
46
+ `upgrade_apply` copied changed files and never deleted one, so a SkillSet that dropped files left them to be
47
+ loaded. A template may now list `removed_files`; upgrade moves each from the installed copy to
48
+ `storage/skillset_removed/<name>/<time>/`, and a forced reinstall no longer restores a retired config file.
49
+
50
+ ### Added — `llm_call` options `no_fallback` and `isolated`
51
+
52
+ `no_fallback` makes an authentication failure on the configured provider a failure instead of a silent switch
53
+ to `claude_code`. `isolated` (claude_code) runs `claude -p --safe-mode --tools ""` in an empty directory, so
54
+ no CLAUDE.md, skills, plugins, hooks, memory or MCP servers reach the call. An isolated call's payload carries
55
+ `isolation` (`safe_mode`, `tools`, `cwd`, as `claude -p` was spawned); llm_client is 0.3.0. The agent's
56
+ stand-in refuses any reply without that evidence (and refuses to call an llm_client too old to isolate), and the
57
+ agent SkillSet declares `llm_client >= 0.3.0`; upgrade both together.
58
+
59
+ ### Added — `user_level_conflicts` in `skillset.json`; install and upgrade report them
60
+
61
+ A SkillSet may list files an earlier version left at user level that it cannot remove itself (e.g. a personal
62
+ skill that shadows the project's). `install`, `upgrade_apply`, `system_upgrade` and `kairos-chain skillset
63
+ install/upgrade` print the ones present as warnings, with a command that moves them to a timestamped backup.
64
+ agent 1.0 lists the 0.x personal skill `~/.claude/skills/agent/SKILL.md` and `~/.claude/agents/agent-monitor.md`.
65
+
66
+ ### Changed — the shipped agent policy needs a new adoption
67
+
68
+ `masa_2026_10_20.rb` sets `review_rounds` to 10 rounds for each review (counted apart, no longer shared by a
69
+ run's reviews) and drops the lookup consent comment (runs never look things up on the web). Its digest
70
+ changed: adopt it with `adopt policy masa_2026_10_20 8846b67e`.
71
+
72
+ ### Changed — L1 `multi_llm_review_workflow` 3.16.0 and `design_to_implementation_workflow` 1.3
73
+
74
+ A new entry-level clause, § Provisional delegation under a mandate: under a pinned, journaled operator policy a
75
+ named delegate — never the context whose work is judged — answers reserved judgments provisionally, and nothing
76
+ resolves, closes, freezes or demotes beyond the run until the operator confirms it in their own words. Pointers
77
+ from INV-U2, INV-U4, INV-U5, Step 0.25 and § Convergence Rules, and from the merge criteria of
78
+ `design_to_implementation_workflow`. An instance's own L1 copy is not rewritten by upgrade.
79
+
80
+ ## [3.94.0] - 2026-10-20
81
+
82
+ ### Added — L0 changes proposed for later approval, L0 restores on the record, L1 body history
83
+
84
+ - **L0 proposals.** `skills_evolve` keeps a pending L0 change as (base, result,
85
+ content) without evaluating it; `command: "pending"` lists the proposals and
86
+ `apply` takes a `proposal_id`. Applying writes exactly the stored bytes under
87
+ an exclusive lock, only while the base is still the L0 in force and the
88
+ content hashes to its result. A failed load, an interrupt or a killed thread
89
+ never leaves an unrecorded L0 on disk.
90
+ - **L0 restore on the record.** `skills_rollback` restores a snapshot only if
91
+ its hash appears in a transition recorded on the chain. Without
92
+ `approved: true` it writes nothing and returns a pending proposal; with
93
+ `proposal_id` the approval applies exactly the proposal that was shown.
94
+ - **L1 body history.** `knowledge_update` gains `history`, `restore` and
95
+ `erase_body` (the last is irreversible and needs `approved: true`). Bodies
96
+ are kept by content address from a recorded activation point, and restore and
97
+ erasure decide from the chain whether their record landed.
98
+
99
+ ### Changed — read before upgrading
100
+
101
+ - `VersionManager.rollback` is removed; nothing shipped calls it. Code that
102
+ called it should use `skills_rollback` with a `proposal_id`.
103
+ - `chain_import` never overwrites an existing chain: it is refused when the
104
+ target already holds chain data. Import into a new data directory instead.
105
+
9
106
  ## [3.93.0] - 2026-10-19
10
107
 
11
108
  ### Added — `proactive_tutorial`, an opt-in mode that suggests KairosChain's own workflow
data/bin/kairos-chain CHANGED
@@ -102,6 +102,7 @@ when 'skillset'
102
102
  result = manager.install(source, layer_override: layer_override, force: force)
103
103
  puts "Installed SkillSet '#{result[:name]}' v#{result[:version]} [#{result[:layer]}]"
104
104
  puts "Path: #{result[:path]}"
105
+ manager.user_level_conflicts(KairosMcp::Skillset.new(result[:path])).each { |w| puts " [WARNING] #{w}" }
105
106
 
106
107
  when 'enable'
107
108
  name = ARGV.shift
@@ -162,6 +163,7 @@ when 'skillset'
162
163
  puts "## SkillSets"
163
164
  results.each do |r|
164
165
  puts " [UPGRADED] #{r[:name].ljust(22)} v#{r[:from]} -> v#{r[:to]} (#{r[:files_updated]} files)"
166
+ Array(r[:warnings]).each { |w| puts " [WARNING] #{w}" }
165
167
  end
166
168
  checkable.reject { |ss| upgraded_names.include?(ss.name) }.each do |ss|
167
169
  puts " [UNCHANGED] #{ss.name.ljust(22)} v#{ss.version}"
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'chain'
5
+
6
+ module KairosMcp
7
+ module KairosChain
8
+ # Answers "did this exact entry reach the ledger?" after an append did not
9
+ # return normally.
10
+ #
11
+ # Chain#add_block raises Storage::Error when it cannot tell whether the
12
+ # write landed, and a thread can be interrupted after the write but before
13
+ # add_block returns. Either way the caller holds a change it must keep
14
+ # (the record is on the chain) or undo (it is not). Looking only at the last
15
+ # block answers wrongly once anything else has been appended since, so the
16
+ # caller takes a mark before appending and the probe scans every block after
17
+ # that mark for an entry equal to the one the caller tried to append.
18
+ module LandedProbe
19
+ # The ledger length now, i.e. the index from which the caller's block can
20
+ # appear. nil when the ledger cannot be read; every later status is then
21
+ # :unknown.
22
+ def self.mark(storage_backend: nil)
23
+ chain = Chain.new(storage_backend: storage_backend)
24
+ case chain.load_state
25
+ when :readable then chain.chain.length
26
+ when :absent then 0
27
+ end
28
+ rescue StandardError
29
+ nil
30
+ end
31
+
32
+ # :landed -- a block after the mark carries an entry equal to entry_json
33
+ # :absent -- the ledger is readable (or absent) and no such entry is there
34
+ # :unknown -- the mark or the ledger could not be read
35
+ #
36
+ # Equality is on the parsed entry, so a backend that re-serialises the JSON
37
+ # still matches. Only StandardError is absorbed: an interrupt during the
38
+ # probe propagates, and callers run their undo in an ensure for that case.
39
+ def self.status(mark, entry_json, storage_backend: nil)
40
+ return :unknown if mark.nil?
41
+
42
+ expected = JSON.parse(entry_json)
43
+ chain = Chain.new(storage_backend: storage_backend)
44
+ return :absent if chain.load_state == :absent
45
+ return :unknown unless chain.load_state == :readable
46
+
47
+ found = chain.chain.drop(mark).any? do |block|
48
+ Array(block.data).any? do |raw|
49
+ begin
50
+ JSON.parse(raw.to_s) == expected
51
+ rescue JSON::ParserError
52
+ false
53
+ end
54
+ end
55
+ end
56
+ found ? :landed : :absent
57
+ rescue StandardError
58
+ :unknown
59
+ end
60
+ end
61
+ end
62
+ end