Module: Senren::Rails::MarkerBlock
- Defined in:
- lib/senren/rails/marker_block.rb
Overview
Replaces the content between a START/END marker pair, preserving everything outside it.
These markers delimit generated instructions inside files that humans and AI agents also edit (CLAUDE.md, AGENTS.md, .senren/skill.md). A tampered or duplicated marker pair is treated as an error rather than something to work around: silently "repairing" it produces a block that regeneration can never clean up again, which is indistinguishable from a persistent prompt injection.
Defined Under Namespace
Classes: MalformedMarkers
Class Method Summary collapse
- .append(existing, block) ⇒ Object
-
.assert_body_is_marker_free!(body, start_marker, end_marker, label) ⇒ Object
A generated block that contains its own delimiters produces a file this module then refuses to parse: the writer corrupts its own output and the error blames the user for hand-editing.
-
.assert_well_formed!(existing, start_marker, end_marker, label) ⇒ Object
A file is well formed when it has either no markers at all, or exactly one START followed by exactly one END.
-
.inject(existing, generated, start_marker:, end_marker:, label: nil) ⇒ Object
Returns
existingwith the marker block replaced bygenerated.
Class Method Details
.append(existing, block) ⇒ Object
53 54 55 56 |
# File 'lib/senren/rails/marker_block.rb', line 53 def append(existing, block) head = existing.rstrip head.empty? ? "#{block}\n" : "#{head}\n\n#{block}\n" end |
.assert_body_is_marker_free!(body, start_marker, end_marker, label) ⇒ Object
A generated block that contains its own delimiters produces a file this module then refuses to parse: the writer corrupts its own output and the error blames the user for hand-editing. Fail at the source instead.
43 44 45 46 47 48 49 50 51 |
# File 'lib/senren/rails/marker_block.rb', line 43 def assert_body_is_marker_free!(body, start_marker, end_marker, label) found = [start_marker, end_marker].select { |marker| body.include?(marker) } return if found.empty? where = label ? " for #{label}" : '' raise MalformedMarkers, "Generated content#{where} contains #{found.join(' and ')}. " \ 'The data this block is rendered from must not contain the markers themselves.' end |
.assert_well_formed!(existing, start_marker, end_marker, label) ⇒ Object
A file is well formed when it has either no markers at all, or exactly one START followed by exactly one END.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/senren/rails/marker_block.rb', line 60 def assert_well_formed!(existing, start_marker, end_marker, label) starts = existing.scan(start_marker).size ends = existing.scan(end_marker).size return if starts.zero? && ends.zero? where = label ? " in #{label}" : '' if starts != 1 || ends != 1 raise MalformedMarkers, "Expected exactly one #{start_marker} and one #{end_marker}#{where}, " \ "found #{starts} and #{ends}. Fix the markers by hand, then re-run the sync." end return if existing.index(start_marker) < existing.index(end_marker) raise MalformedMarkers, "#{end_marker} appears before #{start_marker}#{where}. " \ 'Fix the marker order by hand, then re-run the sync.' end |
.inject(existing, generated, start_marker:, end_marker:, label: nil) ⇒ Object
Returns existing with the marker block replaced by generated.
Appends a fresh block when no markers are present yet.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/senren/rails/marker_block.rb', line 21 def inject(existing, generated, start_marker:, end_marker:, label: nil) existing = existing.to_s body = generated.to_s.strip assert_body_is_marker_free!(body, start_marker, end_marker, label) assert_well_formed!(existing, start_marker, end_marker, label) block = "#{start_marker}\n\n#{body}\n\n#{end_marker}" return append(existing, block) unless existing.include?(start_marker) pattern = /#{Regexp.escape(start_marker)}.*?#{Regexp.escape(end_marker)}/m # Block form is required. Given a replacement *string*, String#sub # expands \0, \1 and \& as backreferences: a body containing one would # splice the old block — markers and all — back into the new one, # resurrecting stale content and duplicating the delimiters. The block # form takes the return value literally. existing.sub(pattern) { block } end |