rubik 0.4.2 → 0.6.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/ATTRIBUTION.md +1 -1
- data/CHANGELOG.md +125 -1
- data/lib/rubik/ast/cache_store.rb +33 -0
- data/lib/rubik/ast/graph.rb +2 -1
- data/lib/rubik/benchmark/runner.rb +14 -0
- data/lib/rubik/benchmark/vakanuvis_adoption.rb +439 -0
- data/lib/rubik/config/defaults.rb +7 -1
- data/lib/rubik/log.rb +4 -3
- data/lib/rubik/orchestrator/budget_manager.rb +2 -0
- data/lib/rubik/orchestrator/loop.rb +1 -0
- data/lib/rubik/orchestrator/shell_deps.rb +4 -0
- data/lib/rubik/orchestrator/step_executor.rb +3 -3
- data/lib/rubik/orchestrator/subagent/tool_dispatch.rb +31 -11
- data/lib/rubik/orchestrator/turn_executor/user_channel.rb +2 -0
- data/lib/rubik/prompt/doctrine.rb +10 -15
- data/lib/rubik/prompt/emergency_compactor.rb +7 -3
- data/lib/rubik/prompt/tool_teachings.rb +29 -35
- data/lib/rubik/repl/commands/agent_context.rb +1 -0
- data/lib/rubik/repl/commands/agent_execution.rb +7 -0
- data/lib/rubik/repl/commands/system.rb +2 -0
- data/lib/rubik/repl/input_execution.rb +5 -1
- data/lib/rubik/repl/turn_recorder.rb +3 -0
- data/lib/rubik/security/redactor.rb +13 -9
- data/lib/rubik/storage/vakanuvis/annal_writer.rb +51 -4
- data/lib/rubik/storage/vakanuvis/distill_gate.rb +14 -2
- data/lib/rubik/storage/vakanuvis/gate.rb +23 -15
- data/lib/rubik/storage/vakanuvis/harness.rb +149 -121
- data/lib/rubik/storage/vakanuvis/job.rb +25 -0
- data/lib/rubik/storage/vakanuvis/orientation.rb +277 -0
- data/lib/rubik/storage/vakanuvis/service.rb +5 -1
- data/lib/rubik/storage/vakanuvis.rb +20 -1
- data/lib/rubik/tools/builtins/vakanuvis.rb +13 -15
- data/lib/rubik/tools/truncator.rb +53 -0
- data/lib/rubik/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cd6a93a2277eebd80ce20dbf33ceba1ba7354d6540a6906740b4d58274736847
|
|
4
|
+
data.tar.gz: 2f46b92bbf23cbcea71767c433ffd45dd55b821e6bb8f1b18cb8c2e7310c5be0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 258d3631c684bfdd719a3b341197dd02da8fc64789c30645b8df0cd4814fc7546392c371737582adab36ff4d46052828fe8d0fed536a1efb592b2c5dcca34571
|
|
7
|
+
data.tar.gz: d9a517f0f4b7026d666d3ac0e2f880805ce40d2341613e5cc75ed72b5b37df3eabf60f07cee9cdf2d8a491b3758b0871edc43b62e501b423bde817b814b1edaf
|
data/ATTRIBUTION.md
CHANGED
|
@@ -121,7 +121,7 @@ SOFTWARE.
|
|
|
121
121
|
| **`strings-ansi`** | Piotr Murach | MIT | ANSI-aware string truncation and alignment for REPL formatters. |
|
|
122
122
|
| **`reline`** | Hiroshi SHIBATA & Ruby Team | Ruby License / BSD-2-Clause | Line-editing, history navigation, autocompletion hooks, and headless terminal adaptation. |
|
|
123
123
|
| **`prism`** | Kevin Newton & Ruby Core Team | MIT | High-performance Ruby parsing and AST extraction ([`Rubik::AST::RubyExtractor`](lib/rubik/ast/ruby_extractor.rb)). |
|
|
124
|
-
| **`minitest`** | Ryan Davis & seattlerb | MIT | Fast, modular test suite powering Rubik's
|
|
124
|
+
| **`minitest`** | Ryan Davis & seattlerb | MIT | Fast, modular test suite powering Rubik's 4,000+ unit, integration, and contract tests. |
|
|
125
125
|
| **`rubocop`** | Bozhidar Batsov & contributors | MIT | Static code analysis, style enforcement, and architectural hygiene gates. |
|
|
126
126
|
| **`benchmark`, `logger`, `pstore`, `reline`, `fiddle`** | Ruby core / rubygems teams | Ruby License / BSD-2-Clause | Ruby stdlib gems pinned explicitly in `rubik.gemspec` as they are unbundled from the default set in Ruby 3.4/3.5. |
|
|
127
127
|
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,128 @@ commits, 2026-08-23 → 2026-10-09, see `git log`).
|
|
|
6
6
|
|
|
7
7
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
8
8
|
|
|
9
|
+
## [0.6.0] - 2026-11-02
|
|
10
|
+
|
|
11
|
+
A measurement-and-honesty minor: the planned vakanüvis fixes gain their
|
|
12
|
+
baseline with a tool-adoption bench scenario, goal suspensions finally
|
|
13
|
+
reach the chronicle through a typed digest contract, interleaved-goal
|
|
14
|
+
suspend rows stop mispairing their records, the annal dedupe can no
|
|
15
|
+
longer be poisoned by free-text `event=` markers, and a typo'd
|
|
16
|
+
truncation strategy warns instead of silently no-oping.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **Goal suspension chronicling:** the chronicler now subscribes to
|
|
21
|
+
`:goal_suspended` (previously posted by `GoalState` but bus-orphaned —
|
|
22
|
+
the producer comment promised a consumption that never existed) and
|
|
23
|
+
appends a `goal.<n>.suspended` row to the session annal; the ordinal is
|
|
24
|
+
peeked rather than minted, so the eventual finish shares the same
|
|
25
|
+
`goal.<n>` record and no duplicate goal note is born from a suspension.
|
|
26
|
+
- **vakanüvis tool-adoption bench scenario (#338, #354):** a two-plane
|
|
27
|
+
measurement of whether models actually adopt recall/record — a
|
|
28
|
+
deterministic replay (default, runs in `rake bench` and CI) driving the
|
|
29
|
+
real tool plane through adopter/wrong-path/struggler profiles, and an
|
|
30
|
+
opt-in live plane (`rake bench:vakanuvis_adoption MODELS=...`) looping
|
|
31
|
+
real provider completions with both tools available; per-model metrics
|
|
32
|
+
cover recall adoption, Keywords usage, record-via-vakanüvis vs direct
|
|
33
|
+
storage put, answer grounding and turn-cap hits, with honest Skip
|
|
34
|
+
(quota) vs Error rows and a fresh seeded store per driver.
|
|
35
|
+
`:goal_suspended` (previously posted by `GoalState` but bus-orphaned —
|
|
36
|
+
the producer comment promised a consumption that never existed) and
|
|
37
|
+
appends a `goal.<n>.suspended` row to the session annal; the ordinal is
|
|
38
|
+
peeked rather than minted, so the eventual finish shares the same
|
|
39
|
+
`goal.<n>` record and no duplicate goal note is born from a suspension.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- **Digest contract typed:** the digest job is one `DistillGate::Job`
|
|
44
|
+
Struct (the queue's two Hash literals collapse into a keyword-minted
|
|
45
|
+
shape), the orphaned `:goal_id` read that no site ever set becomes a
|
|
46
|
+
live `goal_ordinal` carried from goal-end auto-digest — the distiller
|
|
47
|
+
brief now cites the goal record for goal-tied digests — and the digest
|
|
48
|
+
receipt text is single-homed in the DistillGate rules module
|
|
49
|
+
(`receipt` / `duplicate_receipt` / `full_receipt`) instead of three
|
|
50
|
+
templates across two files.
|
|
51
|
+
- **Truncation strategy parity:** `tools.truncation_strategy` was honored
|
|
52
|
+
by exactly one of the Truncator call sites while the subagent tool
|
|
53
|
+
dispatch hard-coded `head_tail` under a comment claiming the two planes
|
|
54
|
+
cannot drift; both orchestrator planes now fetch the knob (fallback
|
|
55
|
+
`Truncator::DEFAULT_STRATEGY`), the restated 12_000/300 literals resolve
|
|
56
|
+
from `Truncator::DEFAULT_MAX_CHARS/LINES`, and a parity pin test turns
|
|
57
|
+
the prose invariant into a test invariant (classification, truncation
|
|
58
|
+
and the strategy knob are asserted equal across the two planes, oracle-
|
|
59
|
+
anchored against Truncator directly). The configuration docs now name
|
|
60
|
+
the honoring consumers.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- **Goal-identity suspend keys and honest logs (#350, #351):** suspend
|
|
65
|
+
rows key on goal identity (ledger id, else slug) plus steps and an
|
|
66
|
+
error digest instead of a peeked ordinal — interleaved goals no longer
|
|
67
|
+
mispair A's suspend row to B's finish and two suspensions sharing a
|
|
68
|
+
peek no longer dedupe into one row; `AnnalWriter.event_context` adds
|
|
69
|
+
status + goal so a dropped suspension and a dropped finish are
|
|
70
|
+
distinguishable in the logs; a `:duplicate` auto-digest admission warns
|
|
71
|
+
with the topic and unattached ordinal instead of silently succeeding;
|
|
72
|
+
the append dedupe anchors on line ends so free-text fields carrying
|
|
73
|
+
`(event=...)` cannot plant phantom keys that suppress genuine rows; the
|
|
74
|
+
chronicler worker gains a per-iteration last-ditch rescue with a
|
|
75
|
+
backtrace frame, the ledger id is stamped before `suspend!`, and a
|
|
76
|
+
spawn-disabled flush warns honestly instead of queueing in silence.
|
|
77
|
+
- **Unrecognized truncation strategy values warn once (#349):** a typo'd
|
|
78
|
+
`tools.truncation_strategy` (or `context.emergency_truncate_strategy`)
|
|
79
|
+
previously fell into the `head_tail` else branch with no signal in
|
|
80
|
+
either plane; `Truncator::STRATEGIES` is now the honest frontier, all
|
|
81
|
+
three config-fetch sites resolve through it, and each distinct unknown
|
|
82
|
+
value warns exactly once per knob+value pair with a UTF-8-scrubbed
|
|
83
|
+
message that can never turn tool results into errors.
|
|
84
|
+
|
|
85
|
+
## [0.5.0] - 2026-10-31
|
|
86
|
+
|
|
87
|
+
A vakanüvis minor: the memory system gains a harness-owned auto-digest
|
|
88
|
+
loop and a deterministic topics orientation injected at session start
|
|
89
|
+
and after compaction, the prompt doctrine's recall/record contradiction
|
|
90
|
+
is closed with a single storage write path, duck-typed AST cache stores
|
|
91
|
+
stop breaking `save_to_cache`, and the security redactor's clean-text
|
|
92
|
+
path skips its intermediate allocations.
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
|
|
96
|
+
- **Harness-owned auto-digest of touched topics (#346, #348):** topics
|
|
97
|
+
recorded or updated since the last digest are tracked in the Harness
|
|
98
|
+
and auto-digested at goal completion and queued (spawn-free) at
|
|
99
|
+
shutdown, gated by the `subagents.vakanuvis.auto_digest` knob
|
|
100
|
+
(default on); per-topic error isolation re-arms failed or refused
|
|
101
|
+
topics for the next flush instead of losing them, the drain window
|
|
102
|
+
between store write and touched-topic tracking is closed with one
|
|
103
|
+
monitor section, and shutdown always joins/kills the digest worker
|
|
104
|
+
with an honest dmesg listing parked topics.
|
|
105
|
+
- **Deterministic topics orientation (#343):** session start and budget
|
|
106
|
+
compaction inject a compact, deterministic overview of the memory
|
|
107
|
+
topics so the model is oriented without a recall round-trip.
|
|
108
|
+
|
|
109
|
+
### Fixed
|
|
110
|
+
|
|
111
|
+
- **Keywords-in-query contradiction closed (#342):** the vakanüvis
|
|
112
|
+
teaching now separates the recall and record directions, stops
|
|
113
|
+
telling the model to add Keywords to recall queries, renders a single
|
|
114
|
+
write-path storage variant when vakanüvis is active, and folds the
|
|
115
|
+
doctrine down to two core duties with the duplicated
|
|
116
|
+
`goal_storage_rule` wording removed (SSOT).
|
|
117
|
+
- **Duck-typed AST cache stores (#347):** `save_to_cache` probes
|
|
118
|
+
`store.method(:save).parameters` once and dispatches deterministically
|
|
119
|
+
instead of rescuing `ArgumentError` (which swallowed genuine errors
|
|
120
|
+
and double-fired side-effecting stores); 1-arity stores get the
|
|
121
|
+
snapshot without statuses plus a warn naming the store class, while
|
|
122
|
+
stores declaring the canonical kwarg signature keep the full-map
|
|
123
|
+
delivery — including in the clean-graph case.
|
|
124
|
+
|
|
125
|
+
### Performance
|
|
126
|
+
|
|
127
|
+
- **Redactor clean-text fast path (#337):** `Redactor.redact` no longer
|
|
128
|
+
allocates an intermediate scrub/dup string before testing
|
|
129
|
+
`QUICK_CHECK_REGEX` on valid-encoding clean input.
|
|
130
|
+
|
|
9
131
|
## [0.4.2] - 2026-10-29
|
|
10
132
|
|
|
11
133
|
A reliability patch: plugin file loads become transactional with
|
|
@@ -961,7 +1083,9 @@ installation section.
|
|
|
961
1083
|
- Context: serialized index mutations, snapshot-outside-lock reconcile,
|
|
962
1084
|
streaming-first truncation.
|
|
963
1085
|
|
|
964
|
-
[Unreleased]: https://github.com/ozgurulukir/rubik/compare/v0.
|
|
1086
|
+
[Unreleased]: https://github.com/ozgurulukir/rubik/compare/v0.6.0...HEAD
|
|
1087
|
+
[0.6.0]: https://github.com/ozgurulukir/rubik/compare/v0.5.0...v0.6.0
|
|
1088
|
+
[0.5.0]: https://github.com/ozgurulukir/rubik/compare/v0.4.2...v0.5.0
|
|
965
1089
|
[0.4.2]: https://github.com/ozgurulukir/rubik/compare/v0.4.1...v0.4.2
|
|
966
1090
|
[0.4.1]: https://github.com/ozgurulukir/rubik/compare/v0.4.0...v0.4.1
|
|
967
1091
|
[0.1.0]: https://github.com/ozgurulukir/rubik/releases/tag/v0.1.0
|
|
@@ -110,6 +110,39 @@ module Rubik
|
|
|
110
110
|
false
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
+
# Dispatch a cache save across duck-typed stores. The canonical #save
|
|
114
|
+
# contract is (hash, statuses: {}) with a FULL statuses map (every
|
|
115
|
+
# snapshot file present, :ok or not), but gem consumers may hand the
|
|
116
|
+
# graph a narrower store. The signature is probed instead of rescuing
|
|
117
|
+
# ArgumentError around the call — a genuine ArgumentError raised inside
|
|
118
|
+
# a store's save must surface, and a failing save must never be
|
|
119
|
+
# silently retried single-arg (double side effects).
|
|
120
|
+
#
|
|
121
|
+
# Classification: a `statuses:` keyword (or **kwargs) means the kwarg
|
|
122
|
+
# call; otherwise the store is treated as 1-arity and non-ok statuses
|
|
123
|
+
# are dropped with a warn (such entries reload as :ok). When the
|
|
124
|
+
# signature cannot be read at all — save resolves through
|
|
125
|
+
# method_missing, or the object has no save — the canonical kwarg call
|
|
126
|
+
# is kept: the call itself surfaces any problem, exactly as the
|
|
127
|
+
# pre-probe code did. respond_to_missing?-backed proxies report
|
|
128
|
+
# [[:rest]] and are therefore treated as 1-arity: behavioral probing
|
|
129
|
+
# would risk double invocation.
|
|
130
|
+
def self.save_via(store, snapshot, statuses)
|
|
131
|
+
accepts_statuses = begin
|
|
132
|
+
store.method(:save).parameters.any? do |param|
|
|
133
|
+
kind, name = param
|
|
134
|
+
kind == :keyrest || ([:key, :keyreq].include?(kind) && name == :statuses)
|
|
135
|
+
end
|
|
136
|
+
rescue NameError
|
|
137
|
+
nil
|
|
138
|
+
end
|
|
139
|
+
return store.save(snapshot, statuses: statuses) if accepts_statuses != false
|
|
140
|
+
|
|
141
|
+
non_ok = statuses.count { |_, status| status != :ok }
|
|
142
|
+
Rubik::Log.warn(:ast, "#{store.class}#save cannot carry extraction statuses; #{non_ok} file(s) will reload as :ok") if non_ok.positive?
|
|
143
|
+
store.save(snapshot)
|
|
144
|
+
end
|
|
145
|
+
|
|
113
146
|
def load
|
|
114
147
|
load_with_statuses[0]
|
|
115
148
|
end
|
data/lib/rubik/ast/graph.rb
CHANGED
|
@@ -139,7 +139,8 @@ module Rubik
|
|
|
139
139
|
end
|
|
140
140
|
skipped = "cache snapshot excluded #{skipped_failed} file(s) with failed extractions; they re-extract on next boot"
|
|
141
141
|
Rubik::Log.warn(:ast, skipped) if skipped_failed.positive?
|
|
142
|
-
|
|
142
|
+
|
|
143
|
+
CacheStore.save_via(cache_store, snapshot, statuses)
|
|
143
144
|
end
|
|
144
145
|
|
|
145
146
|
def smart_context_for(symbol_name)
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require "benchmark"
|
|
4
4
|
require "tmpdir"
|
|
5
5
|
|
|
6
|
+
require_relative "vakanuvis_adoption"
|
|
7
|
+
|
|
6
8
|
module Rubik
|
|
7
9
|
module Benchmark
|
|
8
10
|
class MetricResult
|
|
@@ -38,9 +40,21 @@ module Rubik
|
|
|
38
40
|
results << bench_grep_tool
|
|
39
41
|
results << bench_cold_scan
|
|
40
42
|
results << bench_search_ranking
|
|
43
|
+
results.concat(bench_vakanuvis_adoption)
|
|
41
44
|
results
|
|
42
45
|
end
|
|
43
46
|
|
|
47
|
+
# issue #338: araç-benimseme taban çizgisi. Ana süit YALNIZ deterministik
|
|
48
|
+
# replay düzlemini koşar (canlı model çağrısı asla default olamaz);
|
|
49
|
+
# canlı ölçüm rake bench:vakanuvis_adoption MODELS=... ile açık istektir.
|
|
50
|
+
def bench_vakanuvis_adoption
|
|
51
|
+
rows = Rubik::Benchmark::VakanuvisAdoption.run(
|
|
52
|
+
Rubik::Benchmark::VakanuvisAdoption::REPLAY_PROFILES.map { |p| Rubik::Benchmark::VakanuvisAdoption::ReplayDriver.new(p) },
|
|
53
|
+
io: nil
|
|
54
|
+
)
|
|
55
|
+
Rubik::Benchmark::VakanuvisAdoption.metric_results(rows, io: nil)
|
|
56
|
+
end
|
|
57
|
+
|
|
44
58
|
def generate_markdown_report(results)
|
|
45
59
|
lines = []
|
|
46
60
|
lines << "| Metric | Target | Measured | Status |"
|