OSM Rails → OGAR transpile: THINK structs, Geo codebook, DO-arm action rail, map mapping#152
Conversation
…ranscode Add ogar-from-rails/examples/harvest_osm.rs (reusable Rails harvest driver) and park the openstreetmap-website-rs transcode under harvest/osm-website-rs/ (50 classes, full IR + workspace scaffold). Parked here because the target repo AdaWorldAPI/openstreetmap-website-rs is clone-able but not push-able in this session (proxy write-allowlist gap); see harvest/osm-website-rs/PARKED.md for provenance + relocation. Co-Authored-By: Claude <noreply@anthropic.com>
…les green ogar-render-askama render_class_with_methods over the 50-class OSM harvest: associations -> typed edge fields (belongs_to Option<u64> / has_many Vec<u64>) + new() ctor + CANONICAL_CONCEPT. All 50 compile + test green in the parked osm-domain crate. Adds examples/render_osm.rs driver + ogar-from-rails dev-dep. Relocated the parked transcode to .claude/harvest/osm-website-rs/ per request. Co-Authored-By: Claude <noreply@anthropic.com>
Allocate ConceptDomain::Geo (0x0FXX) and mint the OpenStreetMap geodata reference ontology: osm_node/way/relation (0x0F01-03), changeset, element_tag, relation_member, way_node, note, gpx_trace, user (0x0F04-0A). Full codebook contract: CODEBOOK + class_ids consts + ALL + all_promoted_classes() constructors + COUNT_FUSE pin 68->78, all gates green (96 ogar-vocab tests). render_osm.rs gains a Rails-name->concept grounding map; the 20 grounded geodata files now emit CLASS_ID (Node -> 0x0F01, ...). Parked osm-domain compiles green. NOTE: canonical cross-repo codebook mint. The lance-graph mirror (lance-graph-contract ogar_codebook::CODEBOOK + lance-graph-ogar COUNT_FUSE) must land in lockstep before the OGAR side merges to main (see next commit on the lance-graph branch). Operator: confirm the 0x0F/Geo domain allocation. Co-Authored-By: Claude <noreply@anthropic.com>
render_osm.rs now emits harvest/osm_graph.spo — the OSM association graph as 154 classid-keyed SPO edges (node/way/relation as a graph; grounded targets carry classids). NEXT.md records the honest state of the three autoattended steps: (1) classid mint DONE with the lance-graph mirror as a sequenced post-merge follow-up; (2) lance-graph wiring DONE as the SPO manifest; (3) DO-arm methods = a real capability gap (needs a Ruby controller/action harvester; no ActionDefs exist from app/models alone). Co-Authored-By: Claude <noreply@anthropic.com>
OGAR is Open Graph of Active *Record* — Model + Controller — so the DO arm must exist. Add ogar_from_rails::extract_actions: walk app/controllers via the new ruff_ruby_spo::extract_tree_with (rev 45b6e62), lift each controller's actions to ActionDefs (ogar_from_ruff::lift_actions), key by resource model (Api::NodesController -> Node), dedup by predicate. render_osm attaches them as Rust methods: Node now carries CLASS_ID=0x0F01 + fields (THINK) + index/show/ create/update/destroy (DO). 318 actions across 92 controllers; parked crate compiles green. Re-pins both ruff refs to 45b6e62 in lockstep. Co-Authored-By: Claude <noreply@anthropic.com>
…sm-WebGL Grounded mapping (verified against ndarray cesium/*, splat3d/helix_orient.rs, simd_wasm.rs + OGAR 256x256-tile canon): WebMercator z/x/y -> HHTL HEEL/HIP/TWIG via Morton interleave (canon already binds 'OSM: literal x/y' to the tier tile); helix = the equal-area globe-position INDEX (not the display); cesium = the WebMercator + tile I/O half (osm_pbf/esri_crs/tileset, already coded); splat3d + ndarray simd_wasm compute + WebGL surface = the render path (q2 /helix pattern). Fences: Mercator is display, helix is address; falsifier = tile nibble-ancestry. Co-Authored-By: Claude <noreply@anthropic.com>
Actions were a flat REST enum (index/show/create/update/destroy) — not castable. Reshape to the V3 (part_of:is_a) rail: part_of = controller container (incl. view controllers map/overview/site that the resource mapping dropped), is_a = action archetype (CRUD at stable low ids 0x01-07, custom verbs after). Each action is a u8:u8 HHTL tile; cast = fix one axis, walk the other (is_a=show across all containers; part_of=map across all verbs). extract_action_rail + harvest/osm_actions.rail manifest (353 tiles, 92 part_of x 140 is_a). Model methods now named by is_a archetype (index->list, destroy->delete). Co-Authored-By: Claude <noreply@anthropic.com>
… ctor The Rails 'new' action rendered as pub fn new(&self), colliding with the struct's pub fn new(fields) constructor (E0592, 7 dups). Map the archetype new -> new_form (it's the show-new-form action, not construction). Parked osm-domain now compiles + tests green (verified before commit). Co-Authored-By: Claude <noreply@anthropic.com>
… methods
Per the corrected shape: actions are namespaced free functions, not methods on
the data record. generated/actions.rs is the module tree — part_of = module,
is_a = fn: osm::map::show(input), osm::node::{create,delete,list,show,update}
(input) -> Output. Structs are now THINK-arm only (data + CLASS_ID). Input is a
typed request stub (ruff Function has reads/writes, not param types yet — the
param-name harvest is the follow-up). ident sanitiser handles '?' verbs +
keywords; dedup per module. 318 fns / 92 containers; compiles green (verified).
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 744521d. Configure here.
| let mut acts = String::from( | ||
| "//! @generated DO-arm — OSM controller actions as `osm::<part_of>::<is_a>(input)`.\n\ | ||
| //! part_of = container module, is_a = action fn (standalone, not methods on the\n\ | ||
| //! data struct, per OGAR's ActionDef rule). Call: `osm::map::render(Input::default())`.\n\n\ |
There was a problem hiding this comment.
DO-arm drops duplicate rail tiles
High Severity
The actions.rs generation collapses multiple Rails controller actions into a single Rust function when they share the same (part_of, is_a) pair. The tree map's or_insert method keeps only the first entry, leading to missing functions, incorrect source citations, and documentation examples that don't match the actual output.
Reviewed by Cursor Bugbot for commit 744521d. Configure here.
| let mut classes = ogar_from_rails::extract_with(src_path, "osm"); | ||
| if classes.is_empty() { | ||
| classes = ogar_from_rails::extract_with(&src_path.join("app/models"), "osm"); | ||
| } |
There was a problem hiding this comment.
Controller harvest ignores models fallback
Medium Severity
THINK structs fall back to app/models when extract_with on the repo root is empty, but extract_action_rail always uses the original path joined with app/controllers. Passing only the models directory still renders structs while the DO arm and rail stay empty because controllers resolve to a nonexistent app/models/app/controllers tree.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 744521d. Configure here.
| rt.push('\n'); | ||
| if let Some(root) = out.ancestors().nth(4) { | ||
| fs::write(root.join("harvest/osm_actions.rail"), &rt).unwrap(); | ||
| } |
There was a problem hiding this comment.
Harvest manifests skip silently
Medium Severity
osm_graph.spo and osm_actions.rail are written only when out.ancestors().nth(4) resolves. A custom --out-dir that is not five levels under the harvest tree still renders structs and actions.rs but skips updating the manifest files with no warning.
Reviewed by Cursor Bugbot for commit 744521d. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 744521d72b
ℹ️ 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".
| // user are the edit-provenance concepts. Versioned `Old*` Rails classes | ||
| // ground to their base concept (same concept — the temporal axis is not a | ||
| // new id). | ||
| ("osm_node", 0x0F01), |
There was a problem hiding this comment.
Add the Geo terms to the canonical vocab
This mints the new 0x0FXX concepts only in Rust; the commit does not add matching terms to vocab/ogar.ttl or vocab/ogar.surql. The repo instructions in .claude/AGENTS.md say the vocabulary is the contract and new crates/ogar-vocab terms must be added there first, so TTL/SurrealQL consumers will not see osm_node, osm_way, etc. while Rust consumers do.
Useful? React with 👍 / 👎.
| tree.entry(r.part_of.clone()) | ||
| .or_default() | ||
| .entry(r.is_a.clone()) | ||
| .or_insert((r.controller.clone(), r.action.clone())); |
There was a problem hiding this comment.
Preserve API/web actions with the same rail tile
When two controllers produce the same (part_of, is_a) pair, this or_insert silently keeps the first one and drops the rest from generated/actions.rs. The harvested rail already has real collisions such as node:show for both Api::NodesController#show and NodesController#show, so the generated DO arm loses one route/action body before it can be ported.
Useful? React with 👍 / 👎.
| let ir = std::env::args().any(|a| a == "--ir"); | ||
| let root = Path::new(&arg); | ||
|
|
||
| let mut classes = ogar_from_rails::extract_with(root, "osm"); |
There was a problem hiding this comment.
Route OSM harvests through the Geo codebook
Calling the reusable Rails lift with curator "osm" does not assign the new Geo concepts: classify_domain only recognizes OpenProject/Redmine/Odoo/WOA namespaces, source_domain_concept has no Geo mapping, and canonical_concept has no OSM aliases, so this IR dump reports lexical concepts like node/way with no 0x0FXX codebook ids. Only render_osm.rs has a private ground() workaround, leaving harvest_osm and library callers with ungrounded OSM IR.
Useful? React with 👍 / 👎.
The codebook mint (0x0F Geo) landed in ogar-vocab CODEBOOK + class_ids::ALL but not in ogar-class-view's all_canonical_classes() registry, tripping the two drift gates (every_codebook_id_appears_in_class_ids_all + known_class_ids_iterates_in_stable_codebook_order). Add the 10 osm_* entries (import + registry vec) in class_ids::ALL order. ogar-class-view: 12 tests green. Co-Authored-By: Claude <noreply@anthropic.com>
Reconcile the OCR 0x08XX domain to what the lance-graph contract mirror already declares, and address the Bugbot/codex review on #152. network_layer (0x0804) mint — the OGAR-authoritative counterpart of the concept the lance-graph mirror wire-declared first (`class_ids::ALL` 68→…→79 with the 10 OSM/Geo concepts). The KIND "a Tesseract recognizer network layer"; the concrete subclass is the classid custom-low half (a `NetworkType` ordinal), one slot not 27 — the layer graph sinks onto FacetCascade tenants. Added to all four codebook places (CODEBOOK, class_ids::{NETWORK_LAYER, ALL}, all_promoted_classes, constructor) + ogar-class-view all_canonical_classes; OCR domain-set + ALL.len() pins 3→4 / 78→79. 96 ogar-vocab + 12 ogar-class-view tests green. render_osm review fixes: - DO-arm no longer drops colliding rail tiles. The (part_of:is_a) tile is the CANONICAL castable address by design, so multiple source controllers (`Api::NodesController#show` + `NodesController#show` → `node:show`) are ONE action — but provenance was silently lost. Now every source is accumulated and cited in the doc comment (Bugbot High / codex P2). - extract_action_rail resolves the repo ROOT (not the app/models fallback dir) so controllers resolve for a models-only `src` (Bugbot Medium). - manifest writes warn instead of silently skipping when the out-dir isn't ≥5 levels under a harvest tree (Bugbot Medium). Deferred (noted on the PR): vocab/ogar.ttl + ogar.surql are stale across OCR/HR/Genetics/Geo (regenerate wholesale, not osm-only patch, codex P1); moving render_osm's private ground() into a shared lift so harvest_osm + library callers get grounded Geo IR (codex P2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
|
Review response (Bugbot + codex), pushed in Fixed
Also landed (fuse reconciliation) — minted Deferred (with reasons)
Generated by Claude Code |


What
End-to-end ruff → OGAR transpile of
openstreetmap/openstreetmap-website(Ruby/Rails) into
.claude/harvest/osm-website-rs/, plus the reusable drivers.Proves both arms of Open Graph of Active Record — Model and Controller —
on a real corpus. All generated Rust compiles + tests green.
The pipeline
What's in it
generated/*.rs): associations becometyped edge fields (
belongs_to → Option<u64>,has_many → Vec<u64>) + anew(..)ctor +CLASS_ID.ConceptDomain::Geo(0x0FXX) + 10 concepts(
osm_node 0x0F01…osm_user 0x0F0A). Full codebook contract satisfied(CODEBOOK +
class_ids::{consts,ALL}+all_promoted_classes()+ domain map +COUNT_FUSE68→78); 96 ogar-vocab tests green. Render emitsCLASS_IDforthe 20 grounded geodata files.
harvest/osm_graph.spo: the association graph as 154classid-keyed SPO edges (
osm_node[0x0F01] --BelongsTo:changeset--> [0x0F04]).(part_of : is_a)action rail(
harvest/osm_actions.rail, 353 tiles = 92 part_of × 140 is_a), emitted asstandalone
osm::<part_of>::<is_a>(input)functions (e.g.osm::node::{create,show,list,update,delete},osm::map::show) — notmethods on the record. CRUD archetypes at stable low ids; castable by fixing
one axis and walking the other; view controllers (
map,site,dashboard)captured.
docs/MERCATOR-HHTL-HELIX-MAP.md: WebMercator z/x/y→ HHTL Morton (canon already binds "OSM: literal x/y"), helix = the globe
index vs cesium = the display, ndarray
simd_wasm+ WebGL render path.ogar-from-rails(
extract_actions+extract_action_rail),harvest_osm.rs,render_osm.rs.⚠ Operator gate — before merge
0x0F/Geodomain allocation. This is a canonical,cross-repo codebook mint (RBAC-adjacent, consumed by medcare/odoo/woa/…). It is
additive (new domain, no existing concept touched) and test-gated, but the
domain byte is your call.
lance-graph-contract:: ogar_codebook::CODEBOOK+lance-graph-ogar::COUNT_FUSEmust go 68→78 afterthis merges (lance-graph pulls
ogar_vocabvia git main; bumping the mirrorfirst breaks its compile-time parity assert). See
.claude/harvest/.../NEXT.md.Depends on
extract_tree_with) — pinned at rev45b6e62inogar-from-ruffogar-from-rails(lockstep). Must merge/stay reachable for the DO-arm build.Honest gaps (documented, not papered over)
todo!("port <controller>#<action>")— the render liftsthe signature (part_of/is_a), not the Ruby body.
Input— ruff'sFunctioncarriesreads/writes, nottyped params yet;
render(coordinates: Coordinates)needs a param harvest (nextruff brick).
Searches → searche,Capabilities → capabilitie) — a real inflector is the other refinement.AdaWorldAPI/openstreetmap-website-rs(the intended home) could not be pushed(session write-allowlist gap); the full tree is parked here under
.claude/harvest/osm-website-rs/with relocation steps inPARKED.md.Scope
Doc/harvest-area +
ogar-vocabcodebook + producer crates. No consumer-repochanges. The parked
osm-domaincrate is a nested workspace (excluded fromOGAR's build).
🤖 Generated with Claude Code
https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
Generated by Claude Code