kairos-chain 3.92.0 → 3.94.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cea3a83409113bb9513f6da35f8e202ed84762f726997b55d4c0807e3764565
4
- data.tar.gz: e88354debd6836834ffcf28b905f361b4e9d0d154d22d68f6112a20076fc45c1
3
+ metadata.gz: 05055bfa3f7c4377e2e88011754c85d8d87c690e07f19837c4dca5a0c1cd033c
4
+ data.tar.gz: 48b9c8a70d27304e21293440f121ec069cb0c7ec47ed41b01573cdd2e3c80505
5
5
  SHA512:
6
- metadata.gz: 811debe565ba6b2815b24860edc7d43a1cec1f3c0da9a8b4d4aed0c52d88052ddbd8f53b544575b253860da2ad669d197f9c5a105ffdc08a8d8e9fb002aade2b
7
- data.tar.gz: 9682dc5d58a0264960323374db889ad4074e0c063685a0062866e811ec04eb1c91a94fef720a4260b58f69d26f12f9640087213c713dc8c9c1438fb0f836089f
6
+ metadata.gz: '08ee4ff5f61407bdcc390eb8c4cda6c286472672a6549ded81d5d0b1c7cf29f8203a472f9cfa5d4cfc811b1b8d923d4ee77ee6746decad1893a33c01187ecc1e'
7
+ data.tar.gz: 0b94dde53ddce2444defb9933515dda0d4e754bb0e6053129927d82032bdb9b73383b5d67234a9b57f3e003e82e1b004c17c94f6e551a45ba2fc5dca412bd340
data/CHANGELOG.md CHANGED
@@ -4,6 +4,105 @@ All notable changes to the `kairos-chain` gem will be documented in this file.
4
4
 
5
5
  This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [3.94.0] - 2026-10-20
10
+
11
+ ### Added — L0 changes proposed for later approval, L0 restores on the record, L1 body history
12
+
13
+ - **L0 proposals.** `skills_evolve` keeps a pending L0 change as (base, result,
14
+ content) without evaluating it; `command: "pending"` lists the proposals and
15
+ `apply` takes a `proposal_id`. Applying writes exactly the stored bytes under
16
+ an exclusive lock, only while the base is still the L0 in force and the
17
+ content hashes to its result. A failed load, an interrupt or a killed thread
18
+ never leaves an unrecorded L0 on disk.
19
+ - **L0 restore on the record.** `skills_rollback` restores a snapshot only if
20
+ its hash appears in a transition recorded on the chain. Without
21
+ `approved: true` it writes nothing and returns a pending proposal; with
22
+ `proposal_id` the approval applies exactly the proposal that was shown.
23
+ - **L1 body history.** `knowledge_update` gains `history`, `restore` and
24
+ `erase_body` (the last is irreversible and needs `approved: true`). Bodies
25
+ are kept by content address from a recorded activation point, and restore and
26
+ erasure decide from the chain whether their record landed.
27
+
28
+ ### Changed — read before upgrading
29
+
30
+ - `VersionManager.rollback` is removed; nothing shipped calls it. Code that
31
+ called it should use `skills_rollback` with a `proposal_id`.
32
+ - `chain_import` never overwrites an existing chain: it is refused when the
33
+ target already holds chain data. Import into a new data directory instead.
34
+
35
+ ## [3.93.0] - 2026-10-19
36
+
37
+ ### Added — `proactive_tutorial`, an opt-in mode that suggests KairosChain's own workflow
38
+
39
+ Claude Code passes only the head of an MCP server's instructions to the model
40
+ (4,096 characters by default, 2,048 in older builds). Until a mode is projected
41
+ into CLAUDE.md, the `tutorial` mode's "Proactive Tool Usage" section (line 82 of
42
+ 309) never reaches the model.
43
+
44
+ - New shipped mode `proactive_tutorial`. Its first section, which fits inside
45
+ the 2,048-character cap after the first-run hint, has the model offer to save
46
+ L2 contexts, promote L1 knowledge, tidy up (`dream_scan`, `skills_audit`),
47
+ run multi-LLM review on hard-to-undo changes, point at installed skills, and
48
+ draft a project mode once L1 shows a theme (or, in the first session, the
49
+ project has docs). Writes happen only after the user says yes. Switch with
50
+ `instructions_update(command: "set_mode", mode_name: "proactive_tutorial")`;
51
+ the default stays `tutorial`. Existing instances receive the file on the next
52
+ `system_upgrade`.
53
+ - `instructions_update set_mode` now warns when CLAUDE.md still imports a mode
54
+ body projected for a different mode, and names the command that fixes it
55
+ (`kairos-chain mode project`, or `kairos-chain mode remove` for `none`).
56
+
57
+ ### Fixed — projected hooks run against the data directory they were projected from
58
+
59
+ A project whose `.mcp.json` starts kairos-chain with another project's data
60
+ directory (`--data-dir /…/KairosChain_2026/.kairos` in GenomicsChain_2025; 16
61
+ projects on the reporting machine point at that one directory) got the shared
62
+ directory's SkillSet hooks projected into its own `.claude/settings.json`. Each
63
+ hook resolved its script as `${KAIROS_DATA_DIR:-$CLAUDE_PROJECT_DIR/.kairos}/…`
64
+ with `KAIROS_DATA_DIR` unset, so it looked in the wrong project:
65
+ model_provenance failed with `LoadError` on every Stop, SubagentStop and model
66
+ switch (46 times across two sessions, 2026-10-06 and 10-18) and observed
67
+ nothing; project_manager's session-start report failed the same way. A harness
68
+ tells a hook where the project is, never where the data directory is.
69
+
70
+ - When the data directory is not `<project root>/.kairos`, PluginProjector now
71
+ prefixes every projected hook command with the pair it projected from:
72
+ `export KAIROS_DATA_DIR=<dir> KAIROS_PROJECT_ROOT=<root>;`, shell-escaped.
73
+ The project root goes with it because `kairos-plugin-project` otherwise falls
74
+ back to the data dir's parent — the other project — when the hook's working
75
+ directory is not a plausible root. The two are always set together: the
76
+ agent SkillSet hands children both as a pair, and half a pair cross-wires a
77
+ re-projection. The default layout is projected exactly as before, and
78
+ hand-written hooks are never touched.
79
+ - Plugin mode is left as declared: `hooks/hooks.json` is distributable, and a
80
+ data directory on the projecting machine means nothing on the consumer's.
81
+ - `system_upgrade` and `kairos-chain upgrade` re-projected without `data_dir:`,
82
+ so in a project sharing a data directory they wrote the hooks as if it were
83
+ local and dropped the fix until the next server start; both now pass it.
84
+ - The Codex host's `--host` rewrite now applies only to what follows the pinned
85
+ prefix, so a data-directory or project path containing `kairos-plugin-project`
86
+ or `--host` is never rewritten.
87
+ - No SkillSet changes: model_provenance and project_manager keep their bare
88
+ `ruby` commands, which run under whatever Ruby the project selects. A gem
89
+ executable would not: under rbenv a project pinned to another Ruby (two of the
90
+ 16 above run 3.3.7 / 3.3.10) cannot find it.
91
+
92
+ To pick this up, install this gem under the Ruby each project's MCP server runs
93
+ on — for most projects the usual one; for a project whose `.ruby-version` or
94
+ `.mcp.json` command selects another Ruby, that Ruby too — then restart the
95
+ project's session so projection runs again.
96
+
97
+ ### Added — llm_client 0.2.2: `llm_call` reports the model ID it asked for
98
+
99
+ The success payload gains `requested_model` (the per-call `model` override, else
100
+ the configured `model`) beside `model` (what the provider answered with). On
101
+ Bedrock the two differ — `eu.anthropic.claude-sonnet-5-5` is sent and
102
+ `claude-sonnet-5-5` comes back — and only the first names the inference profile,
103
+ and with it the region. gc_tier1_assess records it in a report's
104
+ `assessor_stack.llm.model_requested`. Additive; no field changed or removed.
105
+
7
106
  ## [3.92.0] - 2026-10-13
8
107
 
9
108
  ### Added — agent: judgment precedents the shadow judge reads, distilled from your answers
data/bin/kairos-chain CHANGED
@@ -187,7 +187,9 @@ when 'skillset'
187
187
  require 'kairos_mcp/plugin_projector'
188
188
  project_root = KairosMcp.project_root
189
189
  mode = KairosMcp.projection_mode
190
- projector = KairosMcp::PluginProjector.new(project_root, mode: mode)
190
+ # data_dir: see system_upgrade.rb — the projector must know where the
191
+ # SkillSets live, or a shared data dir is projected as if it were local.
192
+ projector = KairosMcp::PluginProjector.new(project_root, mode: mode, data_dir: KairosMcp.data_dir)
191
193
  enabled = manager.enabled_skillsets
192
194
  knowledge = KairosMcp.collect_knowledge_entries
193
195
  if projector.project_if_changed!(enabled, knowledge_entries: knowledge)
@@ -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