Skip to content

feat(doc-ir): the dual-render vertical slice — resolve (rail walk) + ogar-render-typst#222

Merged
AdaWorldAPI merged 2 commits into
mainfrom
claude/ogar-docir-architecture-jjzlig
Jul 21, 2026
Merged

feat(doc-ir): the dual-render vertical slice — resolve (rail walk) + ogar-render-typst#222
AdaWorldAPI merged 2 commits into
mainfrom
claude/ogar-docir-architecture-jjzlig

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

What — the document IR slice, closed

The composition brick (DocNode/ObjectSlot, #219) gains its missing verb and its second surface. One composed document is resolved once and rendered through two genuinely different projections from the same rows — the renderer-independence proof the DocIr architecture demanded.

ogar-doc-ir::resolve (feature classview)

  • resolve_doc/resolve_slot: every ObjectSlot resolves through the contract's rail walk (lance_graph_contract::selection::walk_rails) — the slot's named view governs its root; nested hops resolve per-class. No query document anywhere: nesting = masks × the walk.
  • DocObjectSource — dependency inversion, house shape: the consumer owns the graph (RailGraph), the values, and the view bindings; the resolver owns only the procedure.
  • Missing target → explicit snapshot fallback (hex sha256) or Unresolvable — never silence (the ActionText missing-object path, mechanized).

ogar-render-typst (new crate)

Typst source emitter over the same FieldView rows the askama surface renders — the paged/@revision projection (ResolutionMode pairing: living screen ↔ Live, page ↔ Revision/Snapshot). Markup escaping proven. Deliberately no typst compiler dependency.typ→PDF is consumer egress.

The proof (tests/dual_render.rs, output inspected)

One DocCompose — User + WorkPackage + Attachment slots, a tesseract-rs doc.v1 invoice as an ObjectSlot (the retina participates as a plain graph node whose presence/values are project::{field_mask, masked_values} — same walk as live objects), plus a deleted target — rendered to both surfaces:

  • identical facts in both (subject/status/progress, attachment, the retina's netto+IBAN);
  • the assignee rail hop lands at depth 1 in both (name (nested) → Alice Muster);
  • user.inline masks email/role out of both;
  • the retina's unread ust is absent from both (cleared presence bit — C2, no sentinel);
  • the deleted slot shows its sha256 fallback in both.

Sample of the inspected Typst output:

= Install fire door — work record
#block[
*Install fire door* #text(size: 0.8em)[(work_package.summary)]
#table(
  columns: 2,
  [subject], [Install fire door],
  [status], [in progress],
  [progress], [60%],
  [name (nested)], [Alice Muster],
)
]
…
#block[
_unresolved work_package.inline_ — snapshot #raw("sha256:abab…")
]

Float note

Contract deps FLOAT on the lance-graph #776 branch (the selection module); flip back to main on its merge — commented at every dep site (ogar-class-view, ogar-doc-ir, ogar-from-ruff, ogar-render-askama, ogar-render-typst). Merge order: lance-graph #776 first, then flip, then this.

Verification (Rust 1.95)

  • cargo test -p ogar-doc-ir --features classview → 26/26.
  • cargo test -p ogar-render-typst → 6/6 (4 emitter + 2 E2E).
  • clippy -D warnings clean on both; fmt clean.
  • E2E output printed and inspected (--nocapture), snippet above.

Board

DISCOVERY-MAP: D-DOCIR-DUAL-RENDER appended [G] (built + inspected), deferred items named (DocOp, Lance-versioned Revision(n) lookup, FieldView enum widening).

🤖 Generated with Claude Code


Generated by Claude Code

…ogar-render-typst, one document → two projections

The composition brick gains its missing verb and its second surface:

- ogar-doc-ir::resolve (feature classview): resolve_doc/resolve_slot — each
  ObjectSlot resolves through lance-graph-contract's selection rail walk
  (named view governs the root, nested hops resolve per-class via the
  DocObjectSource dependency inversion; consumer owns graph/values/bindings).
  Missing target → explicit snapshot fallback (hex sha256) or Unresolvable —
  never silence. 4 new unit tests.
- ogar-render-typst (NEW crate): Typst SOURCE emitter over the same FieldView
  rows the askama surface renders — the paged/@revision projection. Escaping
  proven; deliberately NO typst compiler dep (.typ→PDF is consumer egress).
  4 unit tests.
- tests/dual_render.rs — THE PROOF, output inspected: one DocCompose (User +
  WorkPackage + Attachment + a tesseract-rs doc.v1 invoice slot + a deleted
  target) resolved once, rendered through askama HTML AND Typst source with
  identical facts: the assignee rail hop lands at depth 1 in both; user.inline
  masks email/role out of both; the retina's unread ust is absent from both
  (cleared presence bit, via project::field_mask/masked_values — the
  observation is just a graph node); the deleted slot shows its sha256
  fallback in both. 2 E2E tests.
- Contract deps FLOAT on the lance-graph #776 branch (selection module);
  flip back to main on merge — commented at every site.
- DISCOVERY-MAP: D-DOCIR-DUAL-RENDER appended [G].

Gates: ogar-doc-ir 26/26 (classview), ogar-render-typst 6/6, clippy -D
warnings clean on both, fmt clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCghCf6rxf2wcqi2cor6RD
@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_c3807831-53e6-4a8c-b18b-348c9868fdc9)

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review July 21, 2026 05:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 462e127f51

ℹ️ 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".

Comment thread crates/ogar-doc-ir/src/resolve.rs
Comment thread crates/ogar-render-typst/src/lib.rs
…st marker escaping

Review fixes on #222:

- resolve_slot now verifies the slot's named view projects the ROOT's
  own class before walking. A stale or cross-class view name previously
  produced a silently-EMPTY Resolved (the walker prunes the foreign mask
  fail-closed); it now takes the fallback/unresolvable arm so the
  outcome says what actually happened. (codex P2)
- escape_typst escapes the Typst BLOCK markers '=', '-', '+' in
  line-start position (start of string or after a newline), so user data
  cannot become a heading/list/enum in the emitted page; mid-line they
  stay inert and unescaped. (codex P2)
- Pinned lance-graph-contract rev refreshed to 241c7ef (picks up the
  walker's path-local cycle guard + view/class agreement + depth
  ceiling from lance-graph #776).

Falsifier tests: cross-class root view → Unresolvable and → Fallback
when a snapshot is attached; line-start markers escaped at string start,
after embedded newlines, and inside field-view values, while mid-line
occurrences stay untouched.
@AdaWorldAPI
AdaWorldAPI merged commit b22ad8f into main Jul 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants