Module: Deja::RequirementsCache
- Defined in:
- lib/deja/requirements_cache.rb
Overview
Cache layer behind the ‘meet_requirements` matcher (defined in deja/rspec.rb). Stores confirmed requirement/value pairs keyed by a hash of the requirements text. One file per test: `<cache_root>/meets_requirements/<suite>/<id>.yaml`.
test_suite: <derived from spec file path>
test_name: <full RSpec description>
summary: <human-readable counts: assertions / total confirmed values>
assertions:
- hash: <12-char fingerprint of the requirements text — used for lookup>
requirements: <the requirements text — auditable from the file alone>
confirmed_values:
- <values previously approved by the LLM judge>
Pruning mirrors Deja::Cache: at the end of a passing example (when ALLOW_LLM_CALL=1), assertions whose hash wasn’t touched are dropped — so changing the requirements text blows away the now-stale confirmed values.
Class Method Summary collapse
- .append!(requirements, value) ⇒ Object
- .build_summary(assertions) ⇒ Object
- .cache_dir ⇒ Object
- .cache_file ⇒ Object
- .load_assertion(requirements) ⇒ Object
- .load_or_init ⇒ Object
- .prune_untouched_in_current_example! ⇒ Object
- .record_touched(requirements) ⇒ Object
- .requirements_hash(requirements) ⇒ Object
- .touched_hashes ⇒ Object
- .upsert_assertion(data, requirements, value) ⇒ Object
- .values_for(requirements) ⇒ Object
Class Method Details
.append!(requirements, value) ⇒ Object
35 36 37 38 39 40 41 |
# File 'lib/deja/requirements_cache.rb', line 35 def append!(requirements, value) record_touched(requirements) data = load_or_init upsert_assertion(data, requirements, value) data["summary"] = build_summary(data["assertions"]) cache_file.write(YAML.dump(Deja::Cache.stringify(data))) end |
.build_summary(assertions) ⇒ Object
103 104 105 106 107 |
# File 'lib/deja/requirements_cache.rb', line 103 def build_summary(assertions) total_values = assertions.sum {|a| a["confirmed_values"].size } "#{assertions.size} #{assertions.size == 1 ? 'assertion' : 'assertions'}, " \ "#{total_values} confirmed #{total_values == 1 ? 'value' : 'values'} total." end |
.cache_dir ⇒ Object
25 26 27 |
# File 'lib/deja/requirements_cache.rb', line 25 def cache_dir Deja.configuration.cache_root.join("meets_requirements") end |
.cache_file ⇒ Object
60 61 62 |
# File 'lib/deja/requirements_cache.rb', line 60 def cache_file cache_dir.join(Deja::Cache.test_suite, "#{Deja::Cache.current_id!}.yaml") end |
.load_assertion(requirements) ⇒ Object
68 69 70 71 72 73 |
# File 'lib/deja/requirements_cache.rb', line 68 def load_assertion(requirements) return nil unless cache_file.exist? hash = requirements_hash(requirements) YAML.safe_load(cache_file.read).fetch("assertions").find {|a| a["hash"] == hash } end |
.load_or_init ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/deja/requirements_cache.rb', line 75 def load_or_init if cache_file.exist? YAML.safe_load(cache_file.read) else FileUtils.mkdir_p(cache_file.dirname) { "test_suite" => Deja::Cache.test_suite, "test_name" => Deja::Cache.current_test_name, "summary" => "", "assertions" => [], } end end |
.prune_untouched_in_current_example! ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/deja/requirements_cache.rb', line 43 def prune_untouched_in_current_example! return unless cache_file.exist? data = YAML.safe_load(cache_file.read) touched = touched_hashes fresh_assertions = data["assertions"].select {|a| touched.include?(a["hash"]) } return if fresh_assertions.size == data["assertions"].size if fresh_assertions.empty? cache_file.delete else data["assertions"] = fresh_assertions data["summary"] = build_summary(fresh_assertions) cache_file.write(YAML.dump(Deja::Cache.stringify(data))) end end |
.record_touched(requirements) ⇒ Object
109 110 111 |
# File 'lib/deja/requirements_cache.rb', line 109 def record_touched(requirements) touched_hashes << requirements_hash(requirements) end |
.requirements_hash(requirements) ⇒ Object
64 65 66 |
# File 'lib/deja/requirements_cache.rb', line 64 def requirements_hash(requirements) Digest::SHA256.hexdigest(requirements.strip)[0, 12] end |
.touched_hashes ⇒ Object
113 114 115 |
# File 'lib/deja/requirements_cache.rb', line 113 def touched_hashes Deja::Cache.current_example!.[:touched_meet_requirements_hashes] ||= Set.new end |
.upsert_assertion(data, requirements, value) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/deja/requirements_cache.rb', line 89 def upsert_assertion(data, requirements, value) hash = requirements_hash(requirements) existing = data["assertions"].find {|a| a["hash"] == hash } if existing existing["confirmed_values"] = existing.fetch("confirmed_values") + [ value ] else data["assertions"] << { "hash" => hash, "requirements" => requirements.strip, "confirmed_values" => [ value ], } end end |
.values_for(requirements) ⇒ Object
29 30 31 32 33 |
# File 'lib/deja/requirements_cache.rb', line 29 def values_for(requirements) record_touched(requirements) assertion = load_assertion(requirements) assertion ? assertion.fetch("confirmed_values") : [] end |