kairos-chain 3.47.0 → 3.50.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 +4 -4
- data/CHANGELOG.md +130 -0
- data/bin/kairos-chain +30 -7
- data/lib/kairos_mcp/skillset.rb +10 -0
- data/lib/kairos_mcp/tool_registry.rb +42 -9
- data/lib/kairos_mcp/version.rb +1 -1
- data/templates/skillsets/chain_distillation/config/chain_distillation.yml +13 -0
- data/templates/skillsets/chain_distillation/lib/chain_distillation/canon.rb +44 -0
- data/templates/skillsets/chain_distillation/lib/chain_distillation/certificate.rb +308 -0
- data/templates/skillsets/chain_distillation/lib/chain_distillation/distiller.rb +305 -0
- data/templates/skillsets/chain_distillation/lib/chain_distillation/recorder.rb +144 -0
- data/templates/skillsets/chain_distillation/skillset.json +18 -0
- data/templates/skillsets/chain_distillation/test/test_chain_distillation.rb +464 -0
- data/templates/skillsets/chain_distillation/tools/cd_distill.rb +67 -0
- data/templates/skillsets/chain_distillation/tools/cd_revoke.rb +57 -0
- data/templates/skillsets/chain_distillation/tools/cd_verify.rb +56 -0
- data/templates/skillsets/confidentiality_guard/config/confidentiality_guard.yml +18 -0
- data/templates/skillsets/confidentiality_guard/config/profile.example.yml +43 -0
- data/templates/skillsets/confidentiality_guard/lib/confidentiality_guard/canon.rb +52 -0
- data/templates/skillsets/confidentiality_guard/lib/confidentiality_guard/policy.rb +152 -0
- data/templates/skillsets/confidentiality_guard/lib/confidentiality_guard/recorder.rb +117 -0
- data/templates/skillsets/confidentiality_guard/lib/confidentiality_guard/regime.rb +321 -0
- data/templates/skillsets/confidentiality_guard/lib/confidentiality_guard/surfaces.rb +131 -0
- data/templates/skillsets/confidentiality_guard/lib/confidentiality_guard/verdict.rb +100 -0
- data/templates/skillsets/confidentiality_guard/skillset.json +20 -0
- data/templates/skillsets/confidentiality_guard/test/test_cg_guard.rb +613 -0
- data/templates/skillsets/confidentiality_guard/tools/cg_status.rb +51 -0
- data/templates/skillsets/synoptis/bin/sda_verify.rb +260 -0
- data/templates/skillsets/synoptis/lib/synoptis/anchoring/aggregate_disclosure.rb +221 -0
- data/templates/skillsets/synoptis/lib/synoptis/anchoring/ec_group.rb +196 -0
- data/templates/skillsets/synoptis/lib/synoptis/anchoring/pedersen.rb +133 -0
- data/templates/skillsets/synoptis/lib/synoptis/anchoring/range_proof.rb +266 -0
- data/templates/skillsets/synoptis/test/test_sda_aggregate.rb +214 -0
- data/templates/skillsets/synoptis/test/test_sda_range_proof.rb +238 -0
- metadata +29 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 826aabda2632b42bb5e4c688f443616faf29b9b97daba55aa02fa6834bf1629d
|
|
4
|
+
data.tar.gz: 2a743cfa76eb0d56db2220ed40c11ea0cc52f88c9b16ed8dfb84855d54b15981
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e0ab6e95d0f527e738053fe45e9899e761820809c0f26ab37dd55eacadf13b387b22737475a8685b894d095aa9ba4529df142ab3809adf917c2ff275b46f403
|
|
7
|
+
data.tar.gz: 1272d3d2ffd8cc80615dc1990346758982cb64cb78d947965d754d3ae5d0e148524044c8197efbb836e0ecf067cfcae69f51aa90a934a71da691525c0b190da2
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,136 @@ 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.50.0] - 2026-07-23
|
|
8
|
+
|
|
9
|
+
### Chain Distillation SkillSet — slice 1 (CD-1..CD-6)
|
|
10
|
+
|
|
11
|
+
New `chain_distillation` SkillSet implementing design v0.5 (review-converged
|
|
12
|
+
5/6 APPROVE + persona unanimity): provenance-certified distillation of the
|
|
13
|
+
instance chain into distributable SkillSets.
|
|
14
|
+
|
|
15
|
+
- `cd_distill`: closed-world integer designation (genesis excluded,
|
|
16
|
+
decline-not-coerce), guard-judged distillate and certificate crossings
|
|
17
|
+
(separate, in order, single-encoded presentation), CD-6 constitutive
|
|
18
|
+
record before release (salted sdp-1-style commitments over the distillate
|
|
19
|
+
and the claim core excluding the record citation), content-independent
|
|
20
|
+
pre-assigned certificate identity, attestation-carrier seam
|
|
21
|
+
(`proof_id` = certificate identity), designation-overlap re-issuance
|
|
22
|
+
citation against then-revoked predecessors.
|
|
23
|
+
- `cd_verify`: full-citation positive grounding (claim-core commitment
|
|
24
|
+
opening, identity, designation digest, guard policy sha, distillate
|
|
25
|
+
commitment, predecessors, citation block hash) plus chain-identity /
|
|
26
|
+
head-binding checks; pinned checkability-status table with
|
|
27
|
+
both-direction mislabeling fatal; closed claim-core vocabulary at every
|
|
28
|
+
depth; revocation folds into validity.
|
|
29
|
+
- `cd_revoke`: identity-keyed chain-wide revocation, closed reason
|
|
30
|
+
vocabulary (`superseded|defective|withdrawn|other`).
|
|
31
|
+
- Requires an active confidentiality-guard regime (CD-1: decline, never
|
|
32
|
+
degrade). 60 design-constraint tests incl. production-wiring and
|
|
33
|
+
real-Chain regressions (KAIROS_DATA_DIR-isolated).
|
|
34
|
+
|
|
35
|
+
### Confidentiality Guard — slice-2 first increment (distillation crossing)
|
|
36
|
+
|
|
37
|
+
- New `:distillation_outward` crossing class (`cd_release_distillate`,
|
|
38
|
+
`cd_release_certificate`): conjunctive per-destination verdict
|
|
39
|
+
(closed-world `distillation_crossings` profile designation AND content
|
|
40
|
+
classes), outward verdicts recorded pass or deny (CG-4); the general
|
|
41
|
+
outward class stays denied wholesale.
|
|
42
|
+
- Certificate-crossing verdict records cite the certificate identity
|
|
43
|
+
(identifier-only, CG-4-compatible).
|
|
44
|
+
- Template-layout require-path parity fix in `regime.rb` / `recorder.rb`.
|
|
45
|
+
- Guard test suite: 75 design-constraint + regression tests.
|
|
46
|
+
|
|
47
|
+
## [3.49.1] - 2026-07-22
|
|
48
|
+
|
|
49
|
+
### CLI fix — `skillset upgrade` messaging for non-core new SkillSets
|
|
50
|
+
|
|
51
|
+
`kairos-chain skillset upgrade --apply` always runs with `core_only: true`
|
|
52
|
+
(the plain CLI form has no way to pass explicit `names`), so a new,
|
|
53
|
+
non-core SkillSet (e.g. `confidentiality_guard`, `daemon_runtime`,
|
|
54
|
+
`kairos_hook_projector`) was never installed by `--apply`, regardless of
|
|
55
|
+
how many times it was run — but the check-mode display mislabeled these as
|
|
56
|
+
"files changed" and told the user to run `--apply`, which silently did
|
|
57
|
+
nothing for them.
|
|
58
|
+
|
|
59
|
+
- Detected upgrades are now split into "applicable" (existing-installed
|
|
60
|
+
diffs + core new SkillSets, which `--apply` does handle) and "manual"
|
|
61
|
+
(non-core new SkillSets, which require explicit
|
|
62
|
+
`kairos-chain skillset install <name>`). Both the check-mode listing and
|
|
63
|
+
the post-`--apply` summary report each group accurately.
|
|
64
|
+
- Added the missing `upgrade` line to `kairos-chain skillset -h`.
|
|
65
|
+
|
|
66
|
+
## [3.49.0] - 2026-07-22
|
|
67
|
+
|
|
68
|
+
### ZK aggregate reproducibility spike (AUD-L4, Phases 1+2) — KairosChain's first genuine zero-knowledge proof
|
|
69
|
+
|
|
70
|
+
Additive demonstrator in the `synoptis` SkillSet (candidate convention id
|
|
71
|
+
`sda-1` if later promoted). Proves, over a public DOI set, that an auditor's
|
|
72
|
+
published aggregate (mean reproducibility) is honestly computed from
|
|
73
|
+
per-item scores that stay secret — with each hidden score proven in-range
|
|
74
|
+
via a genuine zero-knowledge proof. Pure-Ruby secp256k1; no trusted setup;
|
|
75
|
+
no new runtime dependency (OpenSSL is a test-only oracle).
|
|
76
|
+
|
|
77
|
+
- Phase 1 — `ec_group.rb` (hand-rolled prime-order secp256k1, NUMS second
|
|
78
|
+
generator H), `pedersen.rb` (perfectly-hiding commitments, additive
|
|
79
|
+
homomorphism, aggregate opening + Σr-hiding Schnorr proof),
|
|
80
|
+
`aggregate_disclosure.rb` (SDP-2 dual-commitment score binding to rpr-1
|
|
81
|
+
endorsements, DOI-set commitment, mean verification).
|
|
82
|
+
- Phase 2 — `range_proof.rb` (`Synoptis::Anchoring::RangeProof`):
|
|
83
|
+
bit-decomposition range proof for s ∈ [0, 7] (3-bit band). Per-bit
|
|
84
|
+
Cramer-Damgård-Schoenmakers '94 Schnorr OR proofs (b ∈ {0,1}) plus the
|
|
85
|
+
reconstruction invariant Σ 2^j·B_j = C; Fiat-Shamir (SHA-256) with
|
|
86
|
+
metadata- and index-bound transcripts. Fail-closed verifier admission
|
|
87
|
+
(closed schema, type-strict vmax/bits, point/scalar canonicality,
|
|
88
|
+
identity rejection) closes range-escape and encoding-malleability.
|
|
89
|
+
- CLI: `sda_verify.rb` gains `commit`, `aggregate-verify`,
|
|
90
|
+
`aggregate-schnorr`, `binding`, `doi-set`, `range-verify`,
|
|
91
|
+
`full-audit-verify` (C1 coverage + C3 aggregate + C4 range in one pass).
|
|
92
|
+
- Tests: 93 new (52 Phase 1 + 41 Phase 2) incl. the mandatory forgery
|
|
93
|
+
negatives (an out-of-range 32000 score cannot yield an accepting proof);
|
|
94
|
+
scalar-mul cross-validated against OpenSSL. Existing suites unchanged
|
|
95
|
+
(507 total green).
|
|
96
|
+
- Design memos under `docs/drafts/`; design and implementation each
|
|
97
|
+
converged through philosophy-briefed multi-LLM review (impl round 2:
|
|
98
|
+
6/6 APPROVE).
|
|
99
|
+
|
|
100
|
+
## [3.48.0] - 2026-07-22
|
|
101
|
+
|
|
102
|
+
### Confidentiality Guard SkillSet — slice 1 (CG-1..CG-6)
|
|
103
|
+
|
|
104
|
+
New `confidentiality_guard` SkillSet implementing design v0.3 (FROZEN,
|
|
105
|
+
review-converged). A fail-closed, selectable-off data-confidentiality regime
|
|
106
|
+
for enterprise environments. Slice 1 covers inward (L2/L1 write) and
|
|
107
|
+
restricted-storage-read surfaces; outward crossings and unmapped
|
|
108
|
+
resource-scheme reads are denied wholesale under the CG-1 coverage clause.
|
|
109
|
+
|
|
110
|
+
- `lib/confidentiality_guard/regime.rb`: regime lifecycle + tool-surface
|
|
111
|
+
interception via a `ToolRegistry` gate (verdict precedes effect, CG-2).
|
|
112
|
+
Activation is environment-level (`KAIROS_CONFIDENTIALITY_GUARD` env >
|
|
113
|
+
config), read at load time via the skillset `activation_hook` (independent
|
|
114
|
+
of tool instantiation) with an eager `cg_status` belt-and-suspenders call;
|
|
115
|
+
policy pinned at activation; activation AND cessation recorded; gate
|
|
116
|
+
registered only after the regime is active (no fail-open window).
|
|
117
|
+
- `policy.rb`: pinned, content-addressed policy profile; `File.realpath`-
|
|
118
|
+
matching path resolution (symlink- and `..`-safe, parity with the
|
|
119
|
+
external-tools readers). `surfaces.rb`: crossing classification with a
|
|
120
|
+
release-gated enrollment manifest. `verdict.rb`: deterministic LLM-free
|
|
121
|
+
conjunctive verdict (designation closed-world + content detection),
|
|
122
|
+
versioned verdict basis. `recorder.rb`: constitutive chain records bound
|
|
123
|
+
by salted commitments (sdp-1-aligned), never containing content; read
|
|
124
|
+
records carry the designation id, not the raw path. `canon.rb`: shared
|
|
125
|
+
canonical serialization faithful to false/nil and mixed string/symbol keys.
|
|
126
|
+
- `tools/cg_status.rb`: read-only regime-state tool (CG-1).
|
|
127
|
+
- 67 design-constraint + regression tests (`test/test_cg_guard.rb`); 75 as of the chain_distillation guard slice-2 first increment (distillation crossing).
|
|
128
|
+
|
|
129
|
+
Core (minimal, guard-enabling): `tool_registry.rb` adds `FailClosedError`
|
|
130
|
+
(re-raised by the loader, never swallowed), per-skillset isolated loading,
|
|
131
|
+
and fail-closed `activation_hook` invocation; `skillset.rb` adds the
|
|
132
|
+
`activation_hook` accessor. Impl review: 3 rounds with executable-probe
|
|
133
|
+
personas; every deployment-grounded finding (enabled-but-unguarded start,
|
|
134
|
+
copy source-read bypass, path-resolution parity, symlink+`..` bypass, loader
|
|
135
|
+
fail-closed) resolved.
|
|
136
|
+
|
|
7
137
|
## [3.47.0] - 2026-07-22
|
|
8
138
|
|
|
9
139
|
### Synoptis — selective disclosure sdp-1 (AUD-L4 slice 1)
|
data/bin/kairos-chain
CHANGED
|
@@ -134,6 +134,12 @@ when 'skillset'
|
|
|
134
134
|
when 'upgrade'
|
|
135
135
|
apply = ARGV.delete('--apply')
|
|
136
136
|
upgrades = manager.upgrade_check
|
|
137
|
+
# --apply always runs with core_only: true (no way to pass names from this
|
|
138
|
+
# CLI form), so a new, non-core SkillSet is NEVER installed by --apply,
|
|
139
|
+
# no matter how many times it is run. Split the two groups so the
|
|
140
|
+
# displayed guidance matches what --apply will actually do.
|
|
141
|
+
manual = upgrades.select { |u| u[:new_skillset] && !KairosMcp::SkillSetManager::CORE_SKILLSETS.include?(u[:name]) }
|
|
142
|
+
applicable = upgrades - manual
|
|
137
143
|
|
|
138
144
|
if upgrades.empty?
|
|
139
145
|
puts "All SkillSets are up to date."
|
|
@@ -144,6 +150,12 @@ when 'skillset'
|
|
|
144
150
|
end
|
|
145
151
|
puts "Done. #{results.size} SkillSet(s) upgraded."
|
|
146
152
|
|
|
153
|
+
if manual.any?
|
|
154
|
+
puts ""
|
|
155
|
+
puts "Not installed (optional, requires explicit approval):"
|
|
156
|
+
manual.each { |u| puts " kairos-chain skillset install #{u[:name]}" }
|
|
157
|
+
end
|
|
158
|
+
|
|
147
159
|
# Re-project plugin artifacts if any SkillSets changed
|
|
148
160
|
if results.any?
|
|
149
161
|
begin
|
|
@@ -162,15 +174,25 @@ when 'skillset'
|
|
|
162
174
|
end
|
|
163
175
|
end
|
|
164
176
|
else
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
177
|
+
if applicable.any?
|
|
178
|
+
puts "SkillSet upgrades available:"
|
|
179
|
+
puts ""
|
|
180
|
+
applicable.each do |u|
|
|
181
|
+
label = u[:version_bump] ? "v#{u[:installed_version]} -> v#{u[:available_version]}" : "files changed"
|
|
182
|
+
puts " #{u[:name]}: #{label}"
|
|
183
|
+
u[:changed_files].each { |f| puts " Modified: #{f}" }
|
|
184
|
+
puts ""
|
|
185
|
+
end
|
|
186
|
+
puts "Run 'kairos-chain skillset upgrade --apply' to apply updates."
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
if manual.any?
|
|
190
|
+
puts "" if applicable.any?
|
|
191
|
+
puts "Optional SkillSets available (not auto-installed; require explicit approval):"
|
|
192
|
+
manual.each { |u| puts " #{u[:name]} v#{u[:available_version]} — #{u[:description]}" }
|
|
171
193
|
puts ""
|
|
194
|
+
puts "Install with: kairos-chain skillset install <name>"
|
|
172
195
|
end
|
|
173
|
-
puts "Run 'kairos-chain skillset upgrade --apply' to apply updates."
|
|
174
196
|
end
|
|
175
197
|
|
|
176
198
|
when 'remove'
|
|
@@ -258,6 +280,7 @@ when 'skillset'
|
|
|
258
280
|
puts " install <path> [--layer L0|L1|L2] Install a SkillSet from path"
|
|
259
281
|
puts " enable <name> Enable a SkillSet"
|
|
260
282
|
puts " disable <name> Disable a SkillSet"
|
|
283
|
+
puts " upgrade [--apply] Check for/apply SkillSet updates from gem templates"
|
|
261
284
|
puts " remove <name> Remove a SkillSet"
|
|
262
285
|
puts " info <name> Show SkillSet details"
|
|
263
286
|
puts " package <name> Package a knowledge-only SkillSet as JSON archive"
|
data/lib/kairos_mcp/skillset.rb
CHANGED
|
@@ -87,6 +87,16 @@ module KairosMcp
|
|
|
87
87
|
@metadata['config_files'] || []
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
+
# Optional fail-closed activation hook: a fully-qualified class name
|
|
91
|
+
# whose `activate_on_load!` runs at skillset-load time, independent of
|
|
92
|
+
# whether any of the SkillSet's tools are instantiated. Used by
|
|
93
|
+
# fail-closed regimes (confidentiality_guard) so an enabled guard
|
|
94
|
+
# registers its enforcement even if no tool is ever constructed.
|
|
95
|
+
def activation_hook
|
|
96
|
+
name = @metadata['activation_hook']
|
|
97
|
+
name.is_a?(String) && !name.empty? ? name : nil
|
|
98
|
+
end
|
|
99
|
+
|
|
90
100
|
def knowledge_dir_names
|
|
91
101
|
@metadata['knowledge_dirs'] || []
|
|
92
102
|
end
|
|
@@ -5,6 +5,12 @@ require_relative 'lifecycle_hook'
|
|
|
5
5
|
|
|
6
6
|
module KairosMcp
|
|
7
7
|
class ToolRegistry
|
|
8
|
+
# Raised by SkillSets whose activation must never be swallowed
|
|
9
|
+
# (fail-closed regimes, e.g. confidentiality_guard): the loader
|
|
10
|
+
# re-raises instead of degrading to a warn, so an enabled regime can
|
|
11
|
+
# never be silently skipped and leave the server unguarded.
|
|
12
|
+
class FailClosedError < StandardError; end
|
|
13
|
+
|
|
8
14
|
# Authorization denial raised by registered gates
|
|
9
15
|
class GateDeniedError < StandardError
|
|
10
16
|
attr_reader :tool_name, :role
|
|
@@ -273,17 +279,44 @@ module KairosMcp
|
|
|
273
279
|
|
|
274
280
|
manager = SkillSetManager.new
|
|
275
281
|
manager.enabled_skillsets.each do |skillset|
|
|
276
|
-
skillset
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
# Per-skillset isolation: one failing SkillSet must not abort the
|
|
283
|
+
# loop and silently skip later ones (a fail-closed regime loaded
|
|
284
|
+
# later would otherwise never register its gate).
|
|
285
|
+
begin
|
|
286
|
+
skillset.load!
|
|
287
|
+
# Fail-closed activation hook (before tool registration): a
|
|
288
|
+
# regime that ships enabled must register its enforcement at load
|
|
289
|
+
# time, not as a side effect of some tool being instantiated.
|
|
290
|
+
# ANY failure to resolve or run the hook is fail-closed: a
|
|
291
|
+
# missing/typo'd hook constant must not degrade to a warn and
|
|
292
|
+
# leave an enabled regime unguarded.
|
|
293
|
+
if (hook = skillset.activation_hook)
|
|
294
|
+
begin
|
|
295
|
+
LifecycleHook.validate_class_name!(hook)
|
|
296
|
+
Object.const_get(hook).activate_on_load!(registry_class: self.class)
|
|
297
|
+
rescue FailClosedError
|
|
298
|
+
raise
|
|
299
|
+
rescue StandardError => e
|
|
300
|
+
raise FailClosedError,
|
|
301
|
+
"activation_hook '#{hook}' (skillset '#{skillset.name}') failed to activate: " \
|
|
302
|
+
"#{e.class}: #{e.message}"
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
skillset.tool_class_names.each do |cls|
|
|
306
|
+
# Phase 1.5: thread source attribution for capability_status manifest
|
|
307
|
+
register_if_defined(cls, source: "skillset:#{skillset.name}")
|
|
308
|
+
end
|
|
309
|
+
# 24/7 v0.4 §2.3 — register lifecycle hooks declared by this SkillSet.
|
|
310
|
+
skillset.lifecycle_hooks.each do |hook_name, class_name|
|
|
311
|
+
register_lifecycle_hook(hook_name, class_name, skillset_name: skillset.name)
|
|
312
|
+
end
|
|
313
|
+
rescue LifecycleHook::Conflict, FailClosedError
|
|
314
|
+
raise # never swallow — integrity/fail-closed regimes depend on detection
|
|
315
|
+
rescue StandardError => e
|
|
316
|
+
warn "[ToolRegistry] Failed to load SkillSet '#{skillset.name}': #{e.message}"
|
|
284
317
|
end
|
|
285
318
|
end
|
|
286
|
-
rescue LifecycleHook::Conflict
|
|
319
|
+
rescue LifecycleHook::Conflict, FailClosedError
|
|
287
320
|
raise # never swallow — Bootstrap integrity depends on detection
|
|
288
321
|
rescue StandardError => e
|
|
289
322
|
warn "[ToolRegistry] Failed to load SkillSet tools: #{e.message}"
|
data/lib/kairos_mcp/version.rb
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Chain Distillation SkillSet configuration (design v0.5 slice 1).
|
|
2
|
+
#
|
|
3
|
+
# The distiller carries no activation switch of its own: CD-1 couples
|
|
4
|
+
# certified distillation to the confidentiality guard regime, whose
|
|
5
|
+
# activation is environment-level (KAIROS_CONFIDENTIALITY_GUARD / the
|
|
6
|
+
# guard's own config). With the regime inactive the distiller declines.
|
|
7
|
+
#
|
|
8
|
+
# The guard-side designation for the distillation crossings lives in the
|
|
9
|
+
# GUARD's profile (distillation_crossings key) — the guard track owns
|
|
10
|
+
# that surface; see confidentiality_guard/config/profile.example.yml.
|
|
11
|
+
distillation:
|
|
12
|
+
# Reserved for slice-2 (distribution) settings.
|
|
13
|
+
{}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module KairosMcp
|
|
6
|
+
module SkillSets
|
|
7
|
+
module ChainDistillation
|
|
8
|
+
# Canonical serialization for commitments and claim-core hashing
|
|
9
|
+
# (design v0.5 CD-2/CD-6). Same faithfulness rules as the guard's
|
|
10
|
+
# Canon (impl review R1 lineage): false/nil preserved distinctly;
|
|
11
|
+
# mixed string/symbol keys both emitted, sorted by stringified key
|
|
12
|
+
# with original order as tiebreak. One encoder for designation
|
|
13
|
+
# digests, artifact commitments, and claim-core commitments so no
|
|
14
|
+
# two bindings can drift apart.
|
|
15
|
+
module Canon
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def canonical(obj)
|
|
19
|
+
case obj
|
|
20
|
+
when Hash
|
|
21
|
+
entries = obj.map.with_index { |(k, v), i| [k.to_s, i, v] }
|
|
22
|
+
entries.sort_by! { |key, i, _| [key, i] }
|
|
23
|
+
"{#{entries.map { |key, _, v| "#{key.to_json}:#{canonical(v)}" }.join(',')}}"
|
|
24
|
+
when Array
|
|
25
|
+
"[#{obj.map { |v| canonical(v) }.join(',')}]"
|
|
26
|
+
else
|
|
27
|
+
obj.to_json
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def stringify(obj)
|
|
32
|
+
case obj
|
|
33
|
+
when Hash
|
|
34
|
+
obj.each_with_object({}) { |(k, v), acc| acc[k.to_s] = stringify(v) }
|
|
35
|
+
when Array
|
|
36
|
+
obj.map { |v| stringify(v) }
|
|
37
|
+
else
|
|
38
|
+
obj
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|