Implement RenderOp data model and core RenderOp types #304

Closed
opened 2026-03-16 01:59:25 +00:00 by freemo · 1 comment
Owner

Metadata

Key Value
Branch feature/m2-render-ops
Commit Message feat: implement RenderOp data model and core RenderOp types
Parent Epic #302 — Event Projection System

Background and Context

RenderOps are the currency of the render pipeline — they describe what needs to be rendered without specifying how. Each RenderOp is a simple, immutable value object carrying a type, a target window, and type-specific data. The render pipeline consumes these ops and translates them into actual terminal output.

Expected Behavior

RenderOp is a value object (frozen after creation) with:

  • type — one of 7 core types
  • window — target window identifier (:main, :status, :map, :prompt, :chat, etc.)
  • data — a hash of type-specific data

Core RenderOp types:

  1. :text_append — Append text to a window. Data: { text:, style: }
  2. :map_refresh — Refresh the map display. Data: { map_data: }
  3. :bar_update — Update a status bar. Data: { bar:, value:, max: }
  4. :prompt_update — Update the prompt line. Data: { text: }
  5. :window_clear — Clear a window's content. Data: {}
  6. :overlay_show — Show an overlay/modal. Data: { content:, title: }
  7. :overlay_hide — Hide the current overlay. Data: {}

Factory methods for convenience:

RenderOp.text_append(window: :main, text: "Hello", style: :bold)
RenderOp.bar_update(window: :status, bar: :hp, value: 85, max: 100)
RenderOp.map_refresh(window: :map, map_data: grid)

Acceptance Criteria

  • RenderOp is an immutable value object (frozen after creation).
  • All 7 core types are defined: :text_append, :map_refresh, :bar_update, :prompt_update, :window_clear, :overlay_show, :overlay_hide.
  • Each type has a factory method for convenient construction.
  • Factory methods validate required data fields for each type.
  • RenderOp#type, #window, and #data accessors are available.
  • RenderOps support equality comparison (same type + window + data = equal).
  • Invalid type raises an error at creation time.

Subtasks

Code

  • Create RenderOp value object class with type, window, data attributes.
  • Implement freezing after initialization (immutability).
  • Define type constants for all 7 core types.
  • Implement factory methods: .text_append, .map_refresh, .bar_update, .prompt_update, .window_clear, .overlay_show, .overlay_hide.
  • Add data validation per type (required fields check).
  • Implement #== and #hash for equality comparison.

Quality

  • Docs: Update YARD comments on affected classes and methods. Update relevant Docusaurus documentation pages if applicable.
  • Tests (Cucumber): Add tests/unit/render_ops.feature covering creating each of the 7 RenderOp types via factory methods, immutability verification, data validation for required fields, equality comparison, invalid type rejection, accessing type/window/data.
  • Tests (Cucumber Integration): Add integration feature in tests/integration/ for RenderOp value objects flowing through the render pipeline.
  • Tests (Profiling): Run bundle exec rake unit_profile and verify no performance regressions.
  • Quality: Verify coverage >=97% via bundle exec rake unit. If coverage is <97% then review the current unit test coverage report at build/tests/unit/coverage/ and use it to write new Cucumber based unit tests to improve coverage. Specifically, write Cucumber/Gherkin style unit tests that are descriptively named and specifically improve coverage on whichever file has the most uncovered lines by writing tests that will target the uncovered lines in the report. Once that is done rerun bundle exec rake unit to verify all tests pass and coverage is above >=97%. Only mark this as complete once coverage is >=97%, if not repeat this task as many times as is needed until coverage reaches >=97%.
  • Quality: Run bundle exec rake (default task: unit tests with coverage) and bundle exec rake integration, fix any errors if needed ensuring both pass across entire code base, do not ignore any failure even if it seems unrelated to this commit, fix it.

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
## Metadata | Key | Value | |-----|-------| | **Branch** | `feature/m2-render-ops` | | **Commit Message** | `feat: implement RenderOp data model and core RenderOp types` | | **Parent Epic** | #302 — Event Projection System | ## Background and Context RenderOps are the currency of the render pipeline — they describe what needs to be rendered without specifying how. Each RenderOp is a simple, immutable value object carrying a type, a target window, and type-specific data. The render pipeline consumes these ops and translates them into actual terminal output. ## Expected Behavior `RenderOp` is a value object (frozen after creation) with: - `type` — one of 7 core types - `window` — target window identifier (`:main`, `:status`, `:map`, `:prompt`, `:chat`, etc.) - `data` — a hash of type-specific data Core RenderOp types: 1. `:text_append` — Append text to a window. Data: `{ text:, style: }` 2. `:map_refresh` — Refresh the map display. Data: `{ map_data: }` 3. `:bar_update` — Update a status bar. Data: `{ bar:, value:, max: }` 4. `:prompt_update` — Update the prompt line. Data: `{ text: }` 5. `:window_clear` — Clear a window's content. Data: `{}` 6. `:overlay_show` — Show an overlay/modal. Data: `{ content:, title: }` 7. `:overlay_hide` — Hide the current overlay. Data: `{}` Factory methods for convenience: ```ruby RenderOp.text_append(window: :main, text: "Hello", style: :bold) RenderOp.bar_update(window: :status, bar: :hp, value: 85, max: 100) RenderOp.map_refresh(window: :map, map_data: grid) ``` ## Acceptance Criteria - [ ] `RenderOp` is an immutable value object (frozen after creation). - [ ] All 7 core types are defined: `:text_append`, `:map_refresh`, `:bar_update`, `:prompt_update`, `:window_clear`, `:overlay_show`, `:overlay_hide`. - [ ] Each type has a factory method for convenient construction. - [ ] Factory methods validate required data fields for each type. - [ ] `RenderOp#type`, `#window`, and `#data` accessors are available. - [ ] RenderOps support equality comparison (same type + window + data = equal). - [ ] Invalid type raises an error at creation time. ## Subtasks ### Code - [ ] Create `RenderOp` value object class with `type`, `window`, `data` attributes. - [ ] Implement freezing after initialization (immutability). - [ ] Define type constants for all 7 core types. - [ ] Implement factory methods: `.text_append`, `.map_refresh`, `.bar_update`, `.prompt_update`, `.window_clear`, `.overlay_show`, `.overlay_hide`. - [ ] Add data validation per type (required fields check). - [ ] Implement `#==` and `#hash` for equality comparison. ### Quality - [ ] Docs: Update YARD comments on affected classes and methods. Update relevant Docusaurus documentation pages if applicable. - [ ] Tests (Cucumber): Add `tests/unit/render_ops.feature` covering creating each of the 7 RenderOp types via factory methods, immutability verification, data validation for required fields, equality comparison, invalid type rejection, accessing type/window/data. - [ ] Tests (Cucumber Integration): Add integration feature in `tests/integration/` for RenderOp value objects flowing through the render pipeline. - [ ] Tests (Profiling): Run `bundle exec rake unit_profile` and verify no performance regressions. - [ ] Quality: Verify coverage >=97% via `bundle exec rake unit`. If coverage is <97% then review the current unit test coverage report at `build/tests/unit/coverage/` and use it to write new Cucumber based unit tests to improve coverage. Specifically, write Cucumber/Gherkin style unit tests that are descriptively named and specifically improve coverage on whichever file has the most uncovered lines by writing tests that will target the uncovered lines in the report. Once that is done rerun `bundle exec rake unit` to verify all tests pass and coverage is above >=97%. Only mark this as complete once coverage is >=97%, if not repeat this task as many times as is needed until coverage reaches >=97%. - [ ] Quality: Run `bundle exec rake` (default task: unit tests with coverage) and `bundle exec rake integration`, fix any errors if needed ensuring both pass across **entire** code base, do not ignore any failure even if it seems unrelated to this commit, fix it. ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done.
freemo added this to the v1.1.0 milestone 2026-03-16 01:59:25 +00:00
freemo self-assigned this 2026-03-16 01:59:26 +00:00
Author
Owner

Implementation Notes

Implemented the RenderOp data model as specified. Key design decisions:

Architecture

  • Immutability: RenderOps are frozen after creation, including their data hash. This makes them safe to log, replay, and test against.
  • Factory Methods: Each RenderOp type has a dedicated factory method (e.g., RenderOp.text_append()) that validates required fields before construction.
  • Value Object Semantics: Implemented #==, #eql?, and #hash so RenderOps can be used as hash keys and compared for equality.

Validation

  • Invalid types raise ArgumentError at construction time
  • Required fields per type are validated by factory methods
  • nil window is explicitly rejected

Testing

  • 36 unit test scenarios covering all functionality
  • 3 integration test scenarios for realistic usage
  • All tests pass with 100% coverage on render_op.rb

PR

  • Pull Request #314 submitted for review
## Implementation Notes Implemented the RenderOp data model as specified. Key design decisions: ### Architecture - **Immutability**: RenderOps are frozen after creation, including their data hash. This makes them safe to log, replay, and test against. - **Factory Methods**: Each RenderOp type has a dedicated factory method (e.g., `RenderOp.text_append()`) that validates required fields before construction. - **Value Object Semantics**: Implemented `#==`, `#eql?`, and `#hash` so RenderOps can be used as hash keys and compared for equality. ### Validation - Invalid types raise `ArgumentError` at construction time - Required fields per type are validated by factory methods - `nil` window is explicitly rejected ### Testing - 36 unit test scenarios covering all functionality - 3 integration test scenarios for realistic usage - All tests pass with 100% coverage on `render_op.rb` ### PR - Pull Request #314 submitted for review
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference: aethyr/Aethyr#304
No description provided.