canon + feat: E-KEEP-AR-REMOVE-ORM + compile_graph_ruby (the Rails CompiledClass keystone)#144
Conversation
… (OGAR=AR) Corrects a session inversion: the consumer pivot removes the hand-rolled ORM (op-db SQL/FromRow plumbing) and KEEPS ActiveRecord — OGAR is named after AR in OpenProject. AR re-wires onto the OGAR graph (pure AR on Rails, no ORM intermediary); the ClassView IS the active record. Redmine-as-root: fieldview/erb → classview/askama. Guard against re-inversion; additive-then-subtractive only. Cross-refs the 6-agent convergence assessment + the compile_graph_ruby keystone gap.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76dbc8b2e2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| **Status:** FRAMING (`[G]` for the name origin + the keep/remove split, operator-stated 2026-06-30; the convergence wiring it implies is `[H]`, gated per the OP assessment). Corrects a session inversion (mine) that read the consumer pivot as "castrate the hand-rolled Rails ActiveRecord betrayal" — **backwards**. | ||
|
|
||
| **The correction (operator):** *"We don't remove Active Record — that's exactly what we keep. We just do an open-heart operation to remove the ORM and wire pure AR on Rails. Hence OGAR (Open Graph Active Record) — the name was literally inspired by AR in OpenProject."* |
There was a problem hiding this comment.
Add the required Scope line to this epiphany
The .claude/AGENTS.md instructions for this log require each EPIPHANIES entry to have ## ... plus a **Status:** line, a **Scope:** line, body, and **Cross-ref:**; this new entry goes directly from Status to the correction text. Please add the missing Scope line so the append-only log keeps the documented structure future agents are told to rely on.
Useful? React with 👍 / 👎.
…sembler
Adds the keystone gap named in E-KEEP-AR-REMOVE-ORM / the OP convergence
assessment: a Rails-correct sibling of compile_graph_python. Identical
shape (mint_graph::<P> + per-class facet resolution) but routes through
the existing lift_model_graph (Language::Ruby) instead of
lift_model_graph_python — pure operator-reuse, no new lift, and
project_odoo_fields is correctly never invoked for Rails (it would
double-count; lift_model_graph_python's own doc-comment says so).
Proves the convergence claim in code: compile_graph_ruby::<OpenProjectPort>
on a WorkPackage graph and compile_graph_ruby::<RedminePort> on an Issue
graph mint to the SAME low-u16 concept (0x0102 project_work_item) and
DIFFERENT high-u16 render prefixes (0x0001 vs 0x0007) — one canonical
concept, two render skins, machine-checked rather than asserted.
Drive-by fix: 3 pre-existing Function{...} literal constructions
(emit.rs, mint.rs's account_move fixture, lib.rs) broke against the
already-merged ruff#38 (writes/calls fields) because this crate's
ruff_spo_triplet dep floats on branch=main. Added ..Default::default()
to each — no behavior change, restores compilation.
Verification: standalone probe workspace (path-dep ogar-vocab +
ogar-from-ruff, git-dep ruff branch=main) — the OGAR workspace itself
can't resolve in-sandbox (ogar-adapter-surrealql's surrealdb-ast git dep
403s), the same pattern prior PRs (#131/#132/#136/#138/#141) used.
44/44 tests pass (3 new + 41 pre-existing unbroken); clippy --no-deps
-D warnings clean at the pinned 1.95.0 toolchain (ogar-vocab itself has
pre-existing unrelated clippy debt from never being --workspace-gated,
out of scope here); doc-links resolve.
…oc/attr nits) ogar-vocab has never been workspace-clippy-gated — the same surrealdb-ast 403 root cause that blocks the whole OGAR workspace from resolving in-sandbox also meant 'cargo clippy --workspace' has never run here. The probe workspace used to verify compile_graph_ruby (PR #144) made this debt visible for the first time. Mechanical fixes only, no behavior change: - 9 manual impl Default blocks (MethodKind/RecordSemantics/ GuardFailurePolicy/ActionSubject/TemporalSpec/ModalSpec/ActionState/ AssociationKind/Language) replaced with #[derive(Default)] + #[default] on the already-documented default variant (clippy::derivable_impls). Language's impl lived at the very end of the file, after #[cfg(test)] mod tests — also tripped items_after_test_module; moving the derive to the enum's declaration (already well before the test module) fixes both at once. - One blank line between #[non_exhaustive] and removed (clippy::empty_line_after_outer_attr). - Two doc-comment lines re-indented to read as a paragraph continuation rather than an unindented markdown list item — the actual cause is a '+' at the start of a wrapped sentence ('... seeds X + BillingCore (0x61); ...') being parsed as a list bullet by rustdoc's CommonMark parser (clippy::doc_lazy_continuation). Verification (same probe workspace as PR #144's compile_graph_ruby): clippy -D warnings clean for ogar-vocab AND the full probe workspace (both crates) at the pinned 1.95.0 toolchain; 95/95 ogar-vocab unit tests + 2/3 doctests (1 pre-existing #[ignore]) pass; 44/44 ogar-from-ruff tests still pass (Class::language: Language construction unaffected — Default::default() now resolves through the derive instead of the manual impl, same value). cargo fmt --check clean.
…oc/attr nits) ogar-vocab has never been workspace-clippy-gated — the same surrealdb-ast 403 root cause that blocks the whole OGAR workspace from resolving in-sandbox also meant 'cargo clippy --workspace' has never run here. The probe workspace used to verify compile_graph_ruby (PR #144) made this debt visible for the first time. Mechanical fixes only, no behavior change: - 9 manual impl Default blocks (MethodKind/RecordSemantics/ GuardFailurePolicy/ActionSubject/TemporalSpec/ModalSpec/ActionState/ AssociationKind/Language) replaced with #[derive(Default)] + #[default] on the already-documented default variant (clippy::derivable_impls). Language's impl lived at the very end of the file, after #[cfg(test)] mod tests — also tripped items_after_test_module; moving the derive to the enum's declaration (already well before the test module) fixes both at once. - One blank line between #[non_exhaustive] and the ActionDef struct declaration removed (clippy::empty_line_after_outer_attr). - Two doc-comment lines re-indented to read as a paragraph continuation rather than an unindented markdown list item — the actual cause is a '+' at the start of a wrapped sentence ('... seeds X + BillingCore (0x61); ...') being parsed as a list bullet by rustdoc's CommonMark parser (clippy::doc_lazy_continuation). Verification (same probe workspace as PR #144's compile_graph_ruby): clippy -D warnings clean for ogar-vocab AND the full probe workspace (both crates) at the pinned 1.95.0 toolchain; 95/95 ogar-vocab unit tests + 2/3 doctests (1 pre-existing #[ignore]) pass; 44/44 ogar-from-ruff tests still pass (Class.language construction unaffected — Default::default() now resolves through the derive instead of the manual impl, same value). cargo fmt --check clean.
308a347 to
8508a49
Compare
Step 2 of the gating order in the OP+Redmine convergence handover (openproject-nexgen-rs .claude/handovers/2026-06-30-1200-...md §4): before this commit, emit_rust/csharp/python had only ever run on an Odoo-lifted CompiledClass (compile_graph_python, in emit.rs's own tests). This adds a Rails fixture (compile_graph_ruby::<OpenProjectPort> on a WorkPackage graph with a typed attribute, an untyped attribute, a belongs_to with a class_name override, and a has_many) and asserts emit_rust renders it correctly — closing the "pull-back codegen leg unproven on Rails" gap named in the handover's risk list. Fully offline, OGAR-only — no openproject-nexgen-rs change. Found and fixed a real (if narrow) bug along the way: screaming_snake() only split on '.'/'_', so it silently produced WORKPACKAGE_CLASSID instead of WORK_PACKAGE_CLASSID for any already-PascalCase Rails class name (Rails class names carry no separator at all — Odoo's underscored names happened to mask this). Fixed to also split on a lower->upper case transition; added a direct unit test (screaming_snake_splits_bare_pascal_case_rails_names) covering WorkPackage/TimeEntry/Project plus the original dotted-Odoo-name case. Verification: standalone probe workspace (same as the rest of this PR). 46/46 tests pass (2 new). clippy -D warnings clean, both --no-deps and full workspace, at the pinned 1.95.0 toolchain. cargo fmt --check clean for the lines this commit touches (the crate carries pre-existing, unrelated fmt drift from never being cargo-fmt-gated — same root cause as the clippy debt fixed earlier in this PR; left untouched, out of scope here).
Summary
Two commits, one arc — the canon correction and the first concrete brick it names.
1.
canon: E-KEEP-AR-REMOVE-ORM— append-onlyEPIPHANIES.mdentry recording an operator correction: the consumer "open-heart operation" keeps ActiveRecord and removes the ORM. A prior session read it backwards as "castrate the hand-rolled Rails ActiveRecord betrayal." Wrong: KEEP the AR pattern (class = record + behavior — literally what OGAR'sClass/ClassViewis; OGAR = Open Graph Active Record, named after AR in OpenProject); REMOVE the ORM (hand-rolled persistence plumbing —op-dbSQL/FromRow,op-apirow→DTO); WIRE pure AR on Rails directly onto the OGAR graph, no ORM intermediary. Plus Redmine-as-root (fieldview/erb → classview/askama) and a guard against re-inversion.2.
feat(ogar-from-ruff): compile_graph_ruby— the keystone gap the canon entry names: a Rails-correct sibling ofcompile_graph_python. Same shape (mint_graph::<P>+ per-class facet resolution), but routes through the existinglift_model_graph(Language::Ruby) instead oflift_model_graph_python— pure operator-reuse, no new lift, andproject_odoo_fieldsis correctly never invoked for Rails (it would double-count).Proves the convergence claim in code:
compile_graph_ruby::<OpenProjectPort>on aWorkPackagegraph andcompile_graph_ruby::<RedminePort>on anIssuegraph mint to the same low-u16 concept (0x0102project_work_item) and different high-u16 render prefixes (0x0001vs0x0007) — one canonical concept, two render skins, machine-checked rather than asserted.Drive-by fix: 3 pre-existing
Function{...}literal constructions (emit.rs,mint.rs'saccount_movefixture,lib.rs) broke against the already-mergedruff#38(writes/callsfields) because this crate'sruff_spo_tripletdep floats onbranch=main. Added..Default::default()to each — no behavior change, restores compilation.Test Plan
Standalone probe workspace (path-dep
ogar-vocab+ogar-from-ruff, git-dep ruffbranch=main) — the OGAR workspace itself can't resolve in-sandbox (ogar-adapter-surrealql'ssurrealdb-astgit dep 403s), the same pattern prior PRs (#131/#132/#136/#138/#141) used.compile_graph_ruby_stamps_language_ruby_not_python,openproject_work_package_compiles_to_project_work_item_rail_class,openproject_and_redmine_compile_to_the_same_concept_different_render_skin— + 41 pre-existing, unbroken by the drive-by fix).cargo clippy -p ogar-from-ruff --no-deps -D warningsclean at the pinned 1.95.0 toolchain. (ogar-vocabitself has pre-existing, unrelated clippy debt from never being--workspace-gated — same root cause as thesurrealdb-ast403 — out of scope here.)cargo doc -p ogar-from-ruff --no-deps— doc-links resolve; the 4 pre-existing warnings are inemit.rs, unrelated to this change.🤖 Generated with Claude Code