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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/ATTRIBUTION.md +1 -1
  3. data/CHANGELOG.md +125 -1
  4. data/lib/rubik/ast/cache_store.rb +33 -0
  5. data/lib/rubik/ast/graph.rb +2 -1
  6. data/lib/rubik/benchmark/runner.rb +14 -0
  7. data/lib/rubik/benchmark/vakanuvis_adoption.rb +439 -0
  8. data/lib/rubik/config/defaults.rb +7 -1
  9. data/lib/rubik/log.rb +4 -3
  10. data/lib/rubik/orchestrator/budget_manager.rb +2 -0
  11. data/lib/rubik/orchestrator/loop.rb +1 -0
  12. data/lib/rubik/orchestrator/shell_deps.rb +4 -0
  13. data/lib/rubik/orchestrator/step_executor.rb +3 -3
  14. data/lib/rubik/orchestrator/subagent/tool_dispatch.rb +31 -11
  15. data/lib/rubik/orchestrator/turn_executor/user_channel.rb +2 -0
  16. data/lib/rubik/prompt/doctrine.rb +10 -15
  17. data/lib/rubik/prompt/emergency_compactor.rb +7 -3
  18. data/lib/rubik/prompt/tool_teachings.rb +29 -35
  19. data/lib/rubik/repl/commands/agent_context.rb +1 -0
  20. data/lib/rubik/repl/commands/agent_execution.rb +7 -0
  21. data/lib/rubik/repl/commands/system.rb +2 -0
  22. data/lib/rubik/repl/input_execution.rb +5 -1
  23. data/lib/rubik/repl/turn_recorder.rb +3 -0
  24. data/lib/rubik/security/redactor.rb +13 -9
  25. data/lib/rubik/storage/vakanuvis/annal_writer.rb +51 -4
  26. data/lib/rubik/storage/vakanuvis/distill_gate.rb +14 -2
  27. data/lib/rubik/storage/vakanuvis/gate.rb +23 -15
  28. data/lib/rubik/storage/vakanuvis/harness.rb +149 -121
  29. data/lib/rubik/storage/vakanuvis/job.rb +25 -0
  30. data/lib/rubik/storage/vakanuvis/orientation.rb +277 -0
  31. data/lib/rubik/storage/vakanuvis/service.rb +5 -1
  32. data/lib/rubik/storage/vakanuvis.rb +20 -1
  33. data/lib/rubik/tools/builtins/vakanuvis.rb +13 -15
  34. data/lib/rubik/tools/truncator.rb +53 -0
  35. data/lib/rubik/version.rb +1 -1
  36. metadata +4 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8907beb9d8441f6f497af9bd1b65a998c5dfa1d2857552943809ace7270e3759
4
- data.tar.gz: a4b938aa55ff08037d63fc00d545a5039c06319c2ecee309e85d369d5d752621
3
+ metadata.gz: cd6a93a2277eebd80ce20dbf33ceba1ba7354d6540a6906740b4d58274736847
4
+ data.tar.gz: 2f46b92bbf23cbcea71767c433ffd45dd55b821e6bb8f1b18cb8c2e7310c5be0
5
5
  SHA512:
6
- metadata.gz: a034a02d012190d0f6fe02c1b7977628d60617fb0bca562c3b4799dd6512e5cb77809540d57ebe4eede099a0c8e724a679579cc75f4db85f9a8e59bd535d59ea
7
- data.tar.gz: bc8162afcace2ab99fca16b749a5291abeac662e2255f5d798277931a7295a447bdc981bb5d9bc897afa80a15db8fe836771536c3441c110208546442b280622
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 3,900+ unit, integration, and contract tests. |
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.4.2...HEAD
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
@@ -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
- cache_store.save(snapshot, statuses: statuses)
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 |"