kairos-chain 3.61.0 → 3.61.1
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 +23 -0
- data/lib/kairos_mcp/version.rb +1 -1
- data/templates/skillsets/multi_llm_review/lib/multi_llm_review/prompt_builder.rb +26 -0
- data/templates/skillsets/multi_llm_review/skillset.json +2 -2
- data/templates/skillsets/multi_llm_review/test/test_multi_llm_review.rb +20 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c28f2a9c842f5082b555797ea60f24d1435df8fcf80738556c88ffe341358468
|
|
4
|
+
data.tar.gz: 2cc735c1cf6c0cf86599c287cf1e9b095bad22e3de2f0e9055cf2bdf346a6b1c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e31b37f68c678274b1d3ea35dd5f9ce056971dc3e85f7697ee8203d8100a18261bb87ff425718f8bd7b4ce2c9d0b2c200b2b890aaf14dd6bd9e2367c722fc6e
|
|
7
|
+
data.tar.gz: af1ff31f3b3a8eac300e77b40d33fc8d41fa783be45c1cade91c88259dd9d456cd26a125b477127c869b324129357b0081d8bbfd12ee6b7a9bc73552eeb92f35
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ 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.61.1] - 2026-08-06
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **`multi_llm_review` (SkillSet 0.9.1) — a sandboxed reviewer seat is told it has no file
|
|
12
|
+
access.** The `claude_cli_opus4.6` subprocess seat left four consecutive implementation-review
|
|
13
|
+
rounds as `no_verdict`: launched with all tools disabled in an empty working directory
|
|
14
|
+
(deliberate — it keeps CLAUDE.md out of the reviewer's context), it tried to read the file
|
|
15
|
+
paths the artifact cited, opening two rounds with pseudo-tool-call markup and one with "the
|
|
16
|
+
repository is not accessible" before its verdict line — which the positional verdict reader
|
|
17
|
+
correctly refuses. The same seat counted every round on design artifacts in the same period,
|
|
18
|
+
so the seat was healthy and the prompt was the gap.
|
|
19
|
+
|
|
20
|
+
`PromptBuilder` now emits a `<seat_access>` block beside the inline artifact: a seat that
|
|
21
|
+
cannot read the repository must not attempt tool calls and must not open by saying it will
|
|
22
|
+
read files; it reviews the artifact text alone, marks unverifiable claims `[INFERRED]`, and
|
|
23
|
+
still opens with its verdict line. The wording is conditional because seats differ (codex
|
|
24
|
+
runs `--sandbox read-only` and can read the repository), and the block is not emitted for
|
|
25
|
+
by_reference delivery, whose existing cannot-read instruction it would contradict. One test
|
|
26
|
+
pins both directions. `<seat_access>` is not in `Sanitizer::WRAPPER_TAGS`; it sits in the
|
|
27
|
+
documented unescaped prompt-frame gap alongside `<task>` and `<grounding_rules>` — widening
|
|
28
|
+
that set is a recorded backlog question, not part of this fix.
|
|
29
|
+
|
|
7
30
|
## [3.61.0] - 2026-08-06
|
|
8
31
|
|
|
9
32
|
### Fixed
|
data/lib/kairos_mcp/version.rb
CHANGED
|
@@ -128,6 +128,8 @@ module KairosMcp
|
|
|
128
128
|
parts << "<artifact>"
|
|
129
129
|
parts << artifact_content
|
|
130
130
|
parts << "</artifact>"
|
|
131
|
+
parts << ""
|
|
132
|
+
parts << seat_access_note
|
|
131
133
|
end
|
|
132
134
|
parts << ""
|
|
133
135
|
parts << grounding_rules
|
|
@@ -173,6 +175,30 @@ module KairosMcp
|
|
|
173
175
|
CONTRACT
|
|
174
176
|
end
|
|
175
177
|
|
|
178
|
+
# Why this note exists (2026-08-06): the claude_code subprocess seat
|
|
179
|
+
# runs with tools disabled in an empty working directory, and on
|
|
180
|
+
# implementation artifacts that cite file paths it tried to read the
|
|
181
|
+
# code before judging — two rounds opened with pseudo-tool-call markup
|
|
182
|
+
# and one with "the repository is not accessible", so the verdict
|
|
183
|
+
# header never came first and the seat left the denominator as
|
|
184
|
+
# no_verdict four rounds in a row (the same seat counted every round
|
|
185
|
+
# on design artifacts in the same period). The wording is conditional
|
|
186
|
+
# because seats differ — codex runs `--sandbox read-only` and can
|
|
187
|
+
# verify against the repository — and the note is emitted only with an
|
|
188
|
+
# inline artifact: by_reference delivery already instructs a seat that
|
|
189
|
+
# cannot read the file to say so instead of reviewing.
|
|
190
|
+
def seat_access_note
|
|
191
|
+
<<~NOTE
|
|
192
|
+
<seat_access>
|
|
193
|
+
Your seat may have no file-system or tool access. If you cannot
|
|
194
|
+
read the repository, do not attempt tool calls and do not open by
|
|
195
|
+
saying you will read files: review the artifact text above on its
|
|
196
|
+
own, mark claims you cannot verify as [INFERRED], and still put
|
|
197
|
+
your verdict line first.
|
|
198
|
+
</seat_access>
|
|
199
|
+
NOTE
|
|
200
|
+
end
|
|
201
|
+
|
|
176
202
|
def grounding_rules
|
|
177
203
|
<<~RULES
|
|
178
204
|
<grounding_rules>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "multi_llm_review",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"description": "v0.9.0 (evidence fidelity, frozen 2026-08-06 after six review rounds): a finding reaches the record whole. It used to be cut at 201 bytes by an inclusive Range in aggregation and bounded again by the 500-character display limit, so a downstream instance measured 18 of 21 findings arriving at exactly 201 bytes with reviews[].raw_text empty on every row. Findings are now bounded in BYTES at FINDING_RECORD_MAX_LEN = 8000 for the record, with DEFAULT_MAX_LEN = 500 still applied by every path that takes a finding into a prompt. Deduplication still keys on the first 80 characters — widening it would stop two reviewers describing one defect from merging, moving the finding count and the convergence denominator — but the surviving text is no longer arbitrary: issue comes from a member whose severity equals the merged severity, distinct texts survive in issue_variants (capped at MAX_ISSUE_VARIANTS = 8, with issue_variants_omitted naming what the cap dropped). Every row now carries raw_text_excerpt unconditionally (4096 bytes) and the reviewer's reply in raw_text on request (include_raw_text, 65536 bytes). Both are SANITISED TRANSCRIPTIONS, not verbatim records, and both tool schemas say so: the text is byte-clamped, NFKC-normalised, stripped of invisible characters, tag-escaped, then byte-clamped again. No field states whether they hold the whole reply, because nothing in this SkillSet can know — a completeness flag was implemented, measured wrong in both directions, and removed. On delegated runs the pending-state record keeps each subprocess reply as it arrived; on single-phase runs the returned payload is the only form there is. Findings carried into a later round's prompt are sanitised and folded to one line, a path that previously took reviewer text into a prompt with no sanitisation at all. v0.8.0 (v0.7 record schema, design frozen 2026-08-01): the verdict vocabulary is the three canonical words plus tense forms only (INV-R1); the ratio and threshold are recorded reference values, not the run's conclusion — the top-level verdict field became reference_verdict and the run is closed by the operator's declaration outside the record (INV-R2); the persona team occupies one seat, its derivation rule is recorded, and a submission smaller than convened — including empty — is accepted with the shortfall on the record (INV-R3/R4); every run writes an existence marker at dispatch, completed records are never garbage-collected, and expired runs are reduced to a minimal trace instead of erased (INV-R4); a divergence-excluded tally is carried beside the main one (INV-R5); the record names its pre-declared spec and carries transport diagnostics as state tags (INV-R6); artifact delivery is a per-seat attribute (inline | by_reference) and an unreachable delivery is refused rather than dispatched (INV-R7). Parallel multi-LLM review orchestration. Dispatches review prompts to N LLM backends via llm_client, collects verdicts, and computes consensus. v0.6.0: reserve observers (escalate) and a declarable persona execution model; the observer set is built in one pass with explicit precedence (ObserverSet); every slot must name its model and role_label, and duplicate names — including the persona team's own — are refused. A reply's verdict is no longer inferred from its prose: it is read from a declared field, from the header the reply opens with when that header carries a verdict name and nothing else, or not at all, in which case the reply leaves the denominator with no_verdict recorded beside its name. The record says why every observer did or did not count (denominator_composition, five skip_reason values, observers_reporting), and the per-reviewer row is written by one mapping rather than two. v0.5.2: the cursor reviewer pins model composer-2.5 instead of inheriting the cursor CLI default, which is operator-editable and had silently become an Anthropic model. v0.5.1: Fable 5 retired from the roster (five consecutive silent returns), convergence 3/5; orchestrator_model description now states the bare-ID rule so a caller does not review its own output. v0.5.0: adds multi_llm_review_wait (Phase 1.5) for explicit subprocess completion gating with next_action recovery hints, and Path A/B doc disambiguation. v0.4.0 (Phase 12): feedback_text + schema_version, sanitization contract for prompt-injection defense, and multi_llm_review_bundle tool for human-handoff paths without dispatch.",
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "v0.9.1 (seat access, frozen 2026-08-06 after a one-round review): reviewer prompts carry a <seat_access> block beside the inline artifact — a seat that cannot read the repository must not attempt tool calls and must not open by saying it will read files; it reviews the artifact text alone, marks unverifiable claims [INFERRED], and still opens with its verdict line. The wording is conditional because seats differ (codex runs --sandbox read-only and can read the repository), and the block is not emitted for by_reference delivery, whose existing cannot-read instruction it would contradict. Root cause fixed: the claude subprocess seat runs with tools disabled in an empty working directory, and on implementation artifacts citing file paths it opened with pseudo-tool-call markup or a cannot-access preamble instead of its verdict line, leaving four consecutive rounds as no_verdict while counting every round on design artifacts. v0.9.0 (evidence fidelity, frozen 2026-08-06 after six review rounds): a finding reaches the record whole. It used to be cut at 201 bytes by an inclusive Range in aggregation and bounded again by the 500-character display limit, so a downstream instance measured 18 of 21 findings arriving at exactly 201 bytes with reviews[].raw_text empty on every row. Findings are now bounded in BYTES at FINDING_RECORD_MAX_LEN = 8000 for the record, with DEFAULT_MAX_LEN = 500 still applied by every path that takes a finding into a prompt. Deduplication still keys on the first 80 characters — widening it would stop two reviewers describing one defect from merging, moving the finding count and the convergence denominator — but the surviving text is no longer arbitrary: issue comes from a member whose severity equals the merged severity, distinct texts survive in issue_variants (capped at MAX_ISSUE_VARIANTS = 8, with issue_variants_omitted naming what the cap dropped). Every row now carries raw_text_excerpt unconditionally (4096 bytes) and the reviewer's reply in raw_text on request (include_raw_text, 65536 bytes). Both are SANITISED TRANSCRIPTIONS, not verbatim records, and both tool schemas say so: the text is byte-clamped, NFKC-normalised, stripped of invisible characters, tag-escaped, then byte-clamped again. No field states whether they hold the whole reply, because nothing in this SkillSet can know — a completeness flag was implemented, measured wrong in both directions, and removed. On delegated runs the pending-state record keeps each subprocess reply as it arrived; on single-phase runs the returned payload is the only form there is. Findings carried into a later round's prompt are sanitised and folded to one line, a path that previously took reviewer text into a prompt with no sanitisation at all. v0.8.0 (v0.7 record schema, design frozen 2026-08-01): the verdict vocabulary is the three canonical words plus tense forms only (INV-R1); the ratio and threshold are recorded reference values, not the run's conclusion — the top-level verdict field became reference_verdict and the run is closed by the operator's declaration outside the record (INV-R2); the persona team occupies one seat, its derivation rule is recorded, and a submission smaller than convened — including empty — is accepted with the shortfall on the record (INV-R3/R4); every run writes an existence marker at dispatch, completed records are never garbage-collected, and expired runs are reduced to a minimal trace instead of erased (INV-R4); a divergence-excluded tally is carried beside the main one (INV-R5); the record names its pre-declared spec and carries transport diagnostics as state tags (INV-R6); artifact delivery is a per-seat attribute (inline | by_reference) and an unreachable delivery is refused rather than dispatched (INV-R7). Parallel multi-LLM review orchestration. Dispatches review prompts to N LLM backends via llm_client, collects verdicts, and computes consensus. v0.6.0: reserve observers (escalate) and a declarable persona execution model; the observer set is built in one pass with explicit precedence (ObserverSet); every slot must name its model and role_label, and duplicate names — including the persona team's own — are refused. A reply's verdict is no longer inferred from its prose: it is read from a declared field, from the header the reply opens with when that header carries a verdict name and nothing else, or not at all, in which case the reply leaves the denominator with no_verdict recorded beside its name. The record says why every observer did or did not count (denominator_composition, five skip_reason values, observers_reporting), and the per-reviewer row is written by one mapping rather than two. v0.5.2: the cursor reviewer pins model composer-2.5 instead of inheriting the cursor CLI default, which is operator-editable and had silently become an Anthropic model. v0.5.1: Fable 5 retired from the roster (five consecutive silent returns), convergence 3/5; orchestrator_model description now states the bare-ID rule so a caller does not review its own output. v0.5.0: adds multi_llm_review_wait (Phase 1.5) for explicit subprocess completion gating with next_action recovery hints, and Path A/B doc disambiguation. v0.4.0 (Phase 12): feedback_text + schema_version, sanitization contract for prompt-injection defense, and multi_llm_review_bundle tool for human-handoff paths without dispatch.",
|
|
5
5
|
"author": "Masaomi Hatakeyama",
|
|
6
6
|
"layer": "L1",
|
|
7
7
|
"depends_on": [
|
|
@@ -426,6 +426,26 @@ module KairosMcp
|
|
|
426
426
|
assert_includes messages[0]['content'], 'Initial review'
|
|
427
427
|
end
|
|
428
428
|
|
|
429
|
+
def test_seat_access_note_inline_only
|
|
430
|
+
inline = PromptBuilder.build_messages(
|
|
431
|
+
artifact_content: 'test code here',
|
|
432
|
+
artifact_name: 'test_artifact',
|
|
433
|
+
review_type: 'implementation',
|
|
434
|
+
review_round: 1
|
|
435
|
+
)
|
|
436
|
+
assert_includes inline[0]['content'], '<seat_access>'
|
|
437
|
+
assert_includes inline[0]['content'], 'verdict line first'
|
|
438
|
+
|
|
439
|
+
by_ref = PromptBuilder.build_messages(
|
|
440
|
+
artifact_name: 'test_artifact',
|
|
441
|
+
review_type: 'implementation',
|
|
442
|
+
review_round: 1,
|
|
443
|
+
artifact_reference: { path: 'log/x.md', sha256: 'a' * 64 }
|
|
444
|
+
)
|
|
445
|
+
refute_includes by_ref[0]['content'], '<seat_access>',
|
|
446
|
+
'by_reference delivery keeps its own cannot-read instruction; the note must not contradict it'
|
|
447
|
+
end
|
|
448
|
+
|
|
429
449
|
def test_build_messages_with_prior_findings
|
|
430
450
|
prior = [
|
|
431
451
|
{ severity: 'P0', issue: 'Missing validation', cited_by: ['r1', 'r2'] }
|