kairos-chain 3.80.0 → 3.81.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: e2c2d4657c313e3452dbdfaa619a7949d9682961fe4e9ccc15e772ff580f300a
4
- data.tar.gz: f276e35c55991a4ea269309e7ff6f2a94208a4e86967dc9754685a258525645c
3
+ metadata.gz: 0bc251869ebf7ce64e94fbae5baf21ef0eea655b6d1c42d55dfb2f7ee7c2ccc0
4
+ data.tar.gz: aea009fc75974ff42a05e2bc54a352c19b1192157b9fe8eefa311ae9fd096c65
5
5
  SHA512:
6
- metadata.gz: d10d880b482015c17e13014e432bf383cb8003f947ce1caabc4f3f24e775228facb81f042466917f530aa4c4018443cb33567c7fd8ba41c2e3a56149a4db2417
7
- data.tar.gz: 2f4b29826187f483df3a95d601623f587e28eb5575670a235706c4bc7bc8bbc73d285f3ab60f9012fd0ae391a36f294c6a28866fb9a777d60bd1b361c7e9e987
6
+ metadata.gz: 498212b88feb4e563e745be00467f8e206aff2c2103761c12d21695a1829201f2edae98295f61e2aaf6695f9d5e82be4f9f24a2c3ff10e868965a8cc1f1eae91
7
+ data.tar.gz: efe4a6d07531e77648bd175452e72036a0261d0bfb3b426b5f571b54b14a1f3f1695acc3b7d0136b64f04c33eac0e9c04dcebfb58481373af0ddbed355a8d1c4
data/CHANGELOG.md CHANGED
@@ -4,6 +4,44 @@ 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
+ ## [3.81.0] - 2026-08-27
8
+
9
+ ### Changed
10
+
11
+ - **`project_manager` ships its L2 comparison in Ruby, 0.7.0 -> 0.8.0.** The
12
+ three hook-side scripts move from Python to Ruby (`pm_l2_report.rb`,
13
+ `l2_scan.rb`, and the ported test), and the SessionStart hook it contributes
14
+ now invokes `ruby` rather than `python3`. python3 was never guaranteed on a
15
+ host the gem ships to; the interpreter the rest of the SkillSet already runs
16
+ on is. The port itself was committed before this release (`1ec9bd5`) and is
17
+ unchanged here — 505 execution comparisons over 101 input classes with zero
18
+ undeclared differences, 100 unit runs / 485 assertions green, 6/6 mutations
19
+ killed.
20
+
21
+ The version move is the load-bearing part of this release. Without it
22
+ `skillset upgrade` compares versions, finds them equal, reports UNCHANGED and
23
+ copies nothing, so an instance would take the new gem and keep the Python
24
+ scripts while the projected hook still names them.
25
+
26
+ - **`project_manager/plugin/hooks.json`: the bare `ruby` is now a ruling, not
27
+ an open question.** The comment block previously said the resolution was
28
+ undecided and named two candidates — the projector embedding an absolute
29
+ interpreter path, or this file checking `RUBY_VERSION`. Neither ships
30
+ (operator ruling, 2026-08-27). The comment now records why each was declined:
31
+ an embedded path has to be written by the projector, which turns an
32
+ interpreter choice into a core change and pins every host to one machine's
33
+ layout; a version check in this file trades the loud failure for a quiet one;
34
+ and `rbenv exec` fails outright wherever rbenv is absent — a Docker ruby
35
+ image, a homebrew install, asdf — which is strictly worse than the bare form,
36
+ since those hosts run the bare form fine.
37
+
38
+ Resolution therefore stays with the host's PATH, and the residual risk is
39
+ stated rather than hidden: `/usr/bin/ruby` 2.6.10 fails this script at parse
40
+ time with a 43-line syntax error and writes no page (measured). That failure
41
+ is visible at session start rather than silent, and the visibility is what
42
+ makes the bare form acceptable rather than merely convenient. The command
43
+ string is unchanged by this release; only the comment moved.
44
+
7
45
  ## [3.80.0] - 2026-08-27
8
46
 
9
47
  ### Changed
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "3.80.0"
2
+ VERSION = "3.81.0"
3
3
  CHANGELOG_URL = "https://github.com/masaomi/KairosChain_2026/blob/main/CHANGELOG.md"
4
4
  end
@@ -64,7 +64,7 @@ Prefer the sub-agent for "what needs attention?", at session start, and for sche
64
64
 
65
65
  ## The session-start L2 comparison
66
66
 
67
- `scripts/pm_l2_report.py` compares the memo against the L2 context store and writes one HTML page,
67
+ `scripts/pm_l2_report.rb` compares the memo against the L2 context store and writes one HTML page,
68
68
  to `<data dir>/log/pm_l2_report.html`. `plugin/hooks.json` declares it as a `SessionStart` hook.
69
69
 
70
70
  **Read-only by having no aim, not by checking one.** There is no output-path argument, so nothing
@@ -72,14 +72,11 @@ can point a write at the memo, the mapping, an L2 context, or `config/pm.yml`. A
72
72
  took `-o` and guarded it by comparing resolved paths; that guard failed three ways — a case-only
73
73
  difference on a case-insensitive filesystem, a hardlink, and any read input it did not know about —
74
74
  and each failure destroyed the memo while the run printed that nothing had been written to it.
75
- Deleting the argument closed all three. `sys.dont_write_bytecode` is set around the derivation
76
- import for the same reason a second guard was not added: a `.pyc` inside the SkillSet sits inside
77
- `Skillset#all_file_hashes` and therefore inside `content_hash`, the value recorded on chain.
75
+ Deleting the argument closed all three.
78
76
 
79
- **Paths come from this file's own location**, three levels up from `scripts/`, not from the name
80
- `.kairos`. `l2_scan` derives its own by appending that literal, which reported a populated instance
81
- as empty on every session whenever the data dir had been relocated, so its four path constants are
82
- re-pointed after import.
77
+ **Paths come from each file's own location**, three levels up from `scripts/`, not from the name
78
+ `.kairos`. Both files derive their own; appending that literal reported a populated instance as
79
+ empty on every session whenever the data dir had been relocated under another name.
83
80
 
84
81
  **Nothing is trusted to have a type.** `pm_item` writes `due` and `touched_at` through with no check
85
82
  beyond a JSON type, and this SkillSet's own Ruby suite writes the integer `20260701` to both. Dates
@@ -140,13 +137,28 @@ the headline figures shrank without saying so.
140
137
 
141
138
  ### Tests
142
139
 
143
- `test/test_pm_l2_report.py`. The bar is mutation, not redness against an older commit: breaking a
144
- guard by one line must make the suite red. An audit of an earlier version applied 65 one-line
145
- mutations and 36 survived, so guards are now exercised through `main()` in a subprocess, fixtures
146
- are checked not to satisfy their own assertion, aggregation is tested with several items, and
147
- messages and exit codes are asserted by content. Of the 30 mutations that map to a reported finding,
148
- 29 are killed; the survivor is equivalent (deleting the absent-derivation branch leaves the generic
149
- handler producing the same message, exit code and absence of a traceback).
140
+ `test/test_pm_l2_report.rb` (minitest, 75 cases). The bar is mutation, not redness against an older
141
+ commit: breaking a guard by one line must make the suite red. Guards are exercised through `main` in
142
+ a subprocess, fixtures are checked not to satisfy their own assertion, aggregation is tested with
143
+ several items, and messages and exit codes are asserted by content.
144
+
145
+ The 2026-08-20 port to Ruby was audited that way twice, and the second audit is the one worth
146
+ recording. The author's own harness ran 36 mutations and killed 36. Reviewers then ran 12 chosen to
147
+ be disjoint from it and **11 survived** — the harness was not wrong, it was self-authored and
148
+ therefore blind in exactly the places its author was. Ten distinct guards were unheld. The
149
+ structural cause: `L2Scan.derive`, `report` and `main` — 112 of `l2_scan.rb`'s lines — had never
150
+ been called by either suite, so every mutation there survived by construction, and three real
151
+ defects were hiding in that region. All ten are now killed, and `derive`, `report` and
152
+ `marker_string` have their own cases.
153
+
154
+ Some cases pin measured Ruby/Python differences rather than a design constraint, and each names the
155
+ measurement in place. `\w` is ASCII-only in Ruby, which dropped a Japanese tag out of the haystack.
156
+ `String#split`'s limit counts parts where Python's `maxsplit` counted splits, which made a whole
157
+ document its own frontmatter. `File.read(encoding:)` tags an encoding without validating it, where
158
+ Python's `open(encoding=)` decoded and raised — so a memo with one bad byte could write a page that
159
+ was not valid UTF-8 at exit 0. `sort_by` is unstable where Python's `sorted` is stable, and only
160
+ once two distinct key values are present: a first attempt at that case used forty rows of one delta
161
+ and passed against an unstable sort.
150
162
 
151
163
  Nothing runs this suite automatically — `rake test` collects Ruby files only.
152
164
 
@@ -23,7 +23,24 @@
23
23
  "into exit 0 with empty output, which is indistinguishable from a session",
24
24
  "where nothing had drifted. The script now handles its own absences and",
25
25
  "reports each in one line on stdout, so what is left uncaught is a genuine",
26
- "defect and should be visible. Measured at 0.18s over 1172 contexts.",
26
+ "defect and should be visible. Measured at 0.27s over 1192 contexts.",
27
+ "",
28
+ "ruby, not python3. python3 was not guaranteed on any host the gem ships",
29
+ "to. The bare `ruby` is not guaranteed either, and saying otherwise here",
30
+ "would be false: /usr/bin/ruby 2.6.10 fails on this script with a 43-line",
31
+ "syntax error and writes no page (measured). The bare form ships anyway,",
32
+ "ruled 2026-08-27 after both alternatives were measured and each costs",
33
+ "more than it buys. An embedded absolute path has to be written by the",
34
+ "projector, which turns an interpreter choice into a core change and pins",
35
+ "every host to the layout this one happens to have. A version check in",
36
+ "this file trades the loud failure above for a quiet one. `rbenv exec`",
37
+ "fails outright wherever rbenv is absent -- a Docker ruby image, a",
38
+ "homebrew install, asdf -- which is strictly worse than the bare form,",
39
+ "since those hosts run the bare form fine. So resolution stays with the",
40
+ "host's PATH. When a host resolves it wrong the result is a visible",
41
+ "syntax error at session start, not a silent empty page, and that",
42
+ "visibility is what makes the bare form acceptable rather than merely",
43
+ "convenient. Ported 2026-08-20, ruled 2026-08-27.",
27
44
  "",
28
45
  "The command does not begin with kairos-, so projection prints one",
29
46
  "non-standard-command warning. That is the projector asking a human to look,",
@@ -36,7 +53,7 @@
36
53
  "hooks": [
37
54
  {
38
55
  "type": "command",
39
- "command": "python3 \"${KAIROS_DATA_DIR:-$CLAUDE_PROJECT_DIR/.kairos}/skillsets/project_manager/scripts/pm_l2_report.py\" --quiet",
56
+ "command": "ruby \"${KAIROS_DATA_DIR:-$CLAUDE_PROJECT_DIR/.kairos}/skillsets/project_manager/scripts/pm_l2_report.rb\" --quiet",
40
57
  "timeout": 20
41
58
  }
42
59
  ]