Skip to content

Commit 9fa77b0

Browse files
authored
Merge pull request #81 from AdaWorldAPI/claude/ogar-northstar-plan-no-ts
docs(ogar): askama IS the output — drop TS codegen path from the kit (+anti-pattern #8)
2 parents 6e7011f + a3f34a4 commit 9fa77b0

3 files changed

Lines changed: 109 additions & 35 deletions

File tree

‎crates/ogar-render-askama/src/lib.rs‎

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
1-
//! `ogar-render-askama` — build-time codegen harness over the calcified
1+
//! `ogar-render-askama` — askama rendering harness over the calcified
22
//! canonical layer.
33
//!
44
//! Structurally a mirror of [`AdaWorldAPI/woa-rs`](https://github.com/AdaWorldAPI/woa-rs)
5-
//! `crates/codegen` (RFC-v02-006): one [`ArtifactKind`] enum dispatched
5+
//! `crates/codegen` + `templates/`: one [`ArtifactKind`] enum dispatched
66
//! through a per-kind [`ArtifactEmitter`] trait, with one askama template
7-
//! per kind. The canonical input here is [`ogar_vocab::Class`] instead of
7+
//! per kind. The canonical input is [`ogar_vocab::Class`] instead of
88
//! WoA's `RouteSpec`, but the kit shape is the same.
99
//!
10+
//! # Two flavours of artifact (no TypeScript layer)
11+
//!
12+
//! - **Codegen** — emit `.rs` / `.surql` source files. The downstream
13+
//! compiler / DB engine is the final consumer (Northstar plan §3:
14+
//! T1 `RustStruct`, T5 `SurrealqlTable`).
15+
//! - **Render** — emit HTML the human reads directly via `askama_axum` or
16+
//! equivalent (T2–T4: `HtmlListView` / `HtmlDetailView` / `HtmlForm`).
17+
//! Askama **is** the output; nothing transcodes it further.
18+
//!
19+
//! There is no TypeScript codegen path. Askama as a producer of `.ts`
20+
//! source files is anti-pattern #8 in the Northstar plan — askama is
21+
//! the rendering layer in WoA-rs's pattern, not a producer of other
22+
//! languages the consumer transcompiles. PR #80 (TsInterface) was closed
23+
//! for this reason.
24+
//!
1025
//! # The 800 → 7-70 collapse
1126
//!
1227
//! The number of templates is bounded by **artifact kind**, never by
@@ -25,9 +40,11 @@
2540
//! ▼
2641
//! ogar-render-askama (THIS CRATE — askama-bound emitters per kind)
2742
//! │
28-
//! │ .rs / .ts / .surql / .json source text
43+
//! │ .rs / .surql source text (codegen flavour, T1 / T5)
44+
//! │ rendered HTML strings (render flavour, T2–T4 via askama_axum)
2945
//! ▼
30-
//! downstream consumers (op-codegen-projection, rm-codegen, medcare, …)
46+
//! downstream consumers (op-codegen-projection, rm-codegen, medcare, …,
47+
//! OR the user's browser for the render flavour)
3148
//! ```
3249
//!
3350
//! `ClassView` (the **run-time** projection layer in `lance-graph-contract`)

‎crates/ogar-render-askama/src/spec.rs‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,27 @@ use ogar_vocab::Class;
1414
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1515
pub enum ArtifactKind {
1616
/// Rust `struct` definition + `pub const CLASS_ID: u16` constant.
17+
/// Codegen flavour — downstream compiler is the final consumer.
1718
RustStruct,
18-
/// TypeScript `interface` declaration + matching `class_ids.ts` entry.
19+
/// **Deprecated** — to be removed when T2 lands. Anti-pattern #8 in
20+
/// the Northstar plan: askama is the rendering layer (server-side
21+
/// HTML), not a producer of TypeScript source. The frontend in the
22+
/// WoA-rs pattern reads askama-rendered HTML directly. PR #80
23+
/// (TsInterface emitter) was closed for this reason. Variant kept
24+
/// for one merge cycle so the dispatcher's stub fallback still has
25+
/// something to fall back to; T2 replaces this variant with
26+
/// `HtmlListView`.
1927
TsInterface,
2028
/// SurrealQL `DEFINE TABLE` + per-field `DEFINE FIELD` statements.
29+
/// Codegen flavour — DB engine is the final consumer.
2130
SurrealqlTable,
22-
/// OpenAPI 3.1 `components.schemas.{Class}` JSON object.
31+
/// **Deprecated** — to be removed when T2 lands. See Anti-pattern #8.
32+
/// OpenAPI schemas serve TS / external SDK consumers the canonical
33+
/// pattern doesn't have; demand-driven, not in the +5 kit.
2334
OpenapiSchema,
2435
/// Rust `match` arm dispatching on `ClassId` — useful for routing on
25-
/// `NodeGuid::classid` in graph consumers.
36+
/// `NodeGuid::classid` in graph consumers. Codegen flavour. Moves to
37+
/// the Northstar roadmap (post-+5+5); not in the bootstrap kit.
2638
NodeGuidRoutingArm,
2739
}
2840

‎docs/integration/CLASSVIEW-MATERIALIZATION-PLAN.md‎

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,29 @@
2020
ogar_vocab::Class (typed: attributes + family edges + canonical_concept)
2121
│
2222
─────────┼─────────────────────────────────────────────────────
23-
│ BUILD-TIME (codegen) │ RUN-TIME (SoA projection) │
24-
▼ ▼ │
25-
ogar-render-askama ogar-class-view (OgarClassView) │
26-
consumes &Class consumes ClassView trait │
27-
emits .rs / .ts / .surql produces RenderRow stream │
28-
via askama templates via lance-graph-contract::ClassView │
29-
│ │ │
30-
▼ ▼ │
31-
source files late-bound display rows │
32-
(calibrated by (calibrated by │
33-
target compilers) consumer renderers) │
34-
└──────────────┬───────────────┘ │
35-
▼ │
36-
same canonical contract │
37-
(codebook id, N3 field order) │
38-
─────────────────────────────────────────────────────────────────
23+
│ │
24+
▼ ogar-render-askama (one crate, two flavours) │
25+
│ │ │
26+
│ ├── codegen-flavour templates │
27+
│ │ consume &Class, emit .rs / .surql source files │
28+
│ │ for downstream compilers / DB engines │
29+
│ │ (T1 RustStruct ✅, T5 SurrealqlTable) │
30+
│ │ │
31+
│ └── render-flavour templates │
32+
│ consume &Class (+ rows at run time), │
33+
│ emit final HTML output read directly by the user │
34+
│ via askama_axum or equivalent │
35+
│ (T2 HtmlListView, T3 HtmlDetailView, T4 HtmlForm) │
36+
│ │
37+
│ No TypeScript codegen layer. Askama IS the output, per │
38+
│ the WoA-rs pattern. See Anti-pattern #8. │
39+
│ │
40+
│ Sister concern (run-time SoA projection on rows-from-cache): │
41+
│ ogar-class-view → ClassView trait → Vec<RenderRow> │
42+
│ (when the SoA row has no `Class` in scope, only class_id + │
43+
│ presence mask; the cache resolves labels late) │
44+
│ │
45+
└─── same canonical contract (codebook id, N3 field order) ─────
3946
```
4047

4148
**Two pipelines, one canonical source, one codebook. They do not compete.
@@ -174,17 +181,32 @@ respective `NamespaceBridge`s, both hit `entity_type_id() == 0x0102`
174181

175182
### +5 askama templates — the artifact-kind kit (in `ogar-render-askama`)
176183

177-
| PR | ArtifactKind | Template | Target syntax |
178-
|---|---|---|---|
179-
| T1 ✅ | `RustStruct` | `dispatch/rust_struct.askama` | Rust struct + `pub const CLASS_ID` (PR #78 ships this as proof-of-shape) |
180-
| T2 | `TsInterface` | `dispatch/ts_interface.askama` | TypeScript `interface` + matching `class_ids.ts` entry |
181-
| T3 | `SurrealqlTable` | `dispatch/surrealql_table.askama` | `DEFINE TABLE` + per-field `DEFINE FIELD` |
182-
| T4 | `OpenapiSchema` | `dispatch/openapi_schema.askama` | OpenAPI 3.1 `components.schemas.{X}` JSON |
183-
| T5 | `NodeGuidRoutingArm` | `dispatch/node_guid_routing_arm.askama` | Rust `match` arm dispatching on `ClassId` |
184+
**Two flavours of "artifact"** the kit handles, per the WoA-rs pattern:
185+
186+
- **Build-time codegen** — emit `.rs` / `.surql` source files. The compiler
187+
/ DB engine downstream is the final consumer. Example: WoA's
188+
`crates/codegen` emitting axum handler stubs.
189+
- **Run-time HTML render** — render the canonical shape directly to the
190+
user's browser via `askama_axum` or equivalent. The askama template
191+
body **is** the output the human reads. Example: WoA's
192+
`templates/_dispatch/list_view.html` rendering a tenant list page.
193+
194+
**There is no TypeScript codegen layer.** Askama is the output, not a
195+
producer of `.ts` source files. The OP / Redmine frontend in the
196+
canonical pattern is server-rendered HTML through askama, not a separate
197+
TS app the codegen feeds. See Anti-pattern #8.
198+
199+
| PR | ArtifactKind | Template | Flavour | What it emits |
200+
|---|---|---|---|---|
201+
| T1 ✅ | `RustStruct` | `dispatch/rust_struct.askama` | codegen | Rust `struct` + `pub const CLASS_ID` (proof-of-shape, PR #78) |
202+
| T2 | `HtmlListView` | `dispatch/html_list_view.askama` | render | Tabular HTML over a `(class, rows)` pair — WoA list_view shape |
203+
| T3 | `HtmlDetailView` | `dispatch/html_detail_view.askama` | render | Definition-list HTML for one canonical instance, with family-edge sections |
204+
| T4 | `HtmlForm` | `dispatch/html_form.askama` | render | Create/edit form, input element per attribute keyed by typed slot (text/number/checkbox/datetime) |
205+
| T5 | `SurrealqlTable` | `dispatch/surrealql_table.askama` | codegen | `DEFINE TABLE` + per-field `DEFINE FIELD` |
184206

185207
Each PR: 1 template + 1 binding struct + 1 emitter impl + tests
186-
(round-trip + target-toolchain compile + golden-snapshot of the first
187-
emitted concept).
208+
(target-toolchain compile or HTML well-formedness check + golden-snapshot
209+
of the first emitted concept).
188210

189211
### +5 consumer wirings (across repos)
190212

@@ -293,9 +315,32 @@ exactly this. Fixed; future surfaces should iterate
293315
ones. `project_actor()` declares `type` (Rails STI); the unescaped form
294316
emits `pub type:` (illegal). Codex P1 on PR #78 caught this. Fix is
295317
`escape_rust_ident` mapping reserved words to `r#name`. Same hazard on
296-
other targets (TS reserved words, SurrealQL keywords); every emitter
318+
other targets (SurrealQL keywords); every emitter that produces source
297319
needs the equivalent.
298320

321+
### Anti-pattern #8: Generate TypeScript source from askama
322+
323+
**Form**: "emit `.ts` interface files / type declarations / class-id
324+
consts from askama so the frontend imports typed canonical shapes".
325+
326+
**Why wrong**: askama **is** the rendering layer in the WoA-rs pattern.
327+
The consumer reads askama-rendered HTML directly (server-side via
328+
`askama_axum` or equivalent); there is no separate TypeScript frontend
329+
in the canonical architecture. Generating TS source means treating
330+
askama as a codegen-to-other-language pipeline, which contradicts its
331+
role as the output layer.
332+
333+
Codegen flavour (T1 `RustStruct`, T5 `SurrealqlTable`) is fine — those
334+
target compilers / DB engines that consume Rust / SQL. **TS / OpenAPI
335+
schemas are not in that set**, because the consumer of those would be a
336+
JS-side frontend the pattern doesn't have. PR #80 (TsInterface) was
337+
closed for this reason; T2 was rewritten as `HtmlListView` (a render-side
338+
template).
339+
340+
If a downstream actually wants typed TS (e.g. a third-party SDK
341+
consumer outside the WoA pattern), they can implement their own
342+
`ClassView`-based generator — but it sits *outside* the canonical kit.
343+
299344
## 5. Epiphany log — high-signal architectural moments
300345

301346
Captured verbatim because future sessions will ask "why".
@@ -361,7 +406,7 @@ These repos converged on the same northstar from different angles:
361406

362407
| Item | What | When |
363408
|---|---|---|
364-
| T6 | `A2uiPayload` artifact kind — emit any promoted concept as an A2UI v0.8 intent payload. A2UI's "catalog of trusted components" maps 1:1 to the OGAR codebook. Existing A2UI renderers (Flutter/Angular/Lit) consume the canonical layer with zero Ruby/Rails coupling. | After T1–T5 stabilises |
409+
| T6 | `A2uiPayload` artifact kind — emit any promoted concept as an A2UI v0.8 intent payload. **Strict: only if a consumer outside the WoA-pattern actually asks** (Flutter/Angular/Lit frontends). The default canonical UI is server-rendered HTML via T2–T4; A2UI is an alternative output for non-server-rendered consumers. Same canonical input; new bag-of-variables shaped to A2UI's component schema. | Demand-driven, after T1–T5 stabilises |
365410
| T7 | Calibration-loop receipt aggregator — collect every PR's three gates into one CI artifact so coverage can be reasoned about as a ratio | After several Cn land |
366411
| T8 | DOLCE upper-category live wiring — `OgarClassView::dolce_category_id` currently returns `0`; live values come from `lance-graph-ontology` when the consumer chooses to wire them | Independent; opportunistic |
367412
| T9 | Promote more OpenProject-only concepts (Costs, Budgets, BIM, Meetings, Storages — the 880 OP-only classes from the corpus diff). Each gets its own codebook block (likely `0x03XX`+) | Demand-driven |

0 commit comments

Comments
 (0)