Skip to content

Commit 318b46f

Browse files
authored
Merge pull request #158 from AdaWorldAPI/claude/v3-criticals-woa-parity
V3 criticals: five proofs + WoA 1:1 parity (D-PARITY-PROBE-WOA-1) + PG-facet adapter
2 parents efd3b8e + b2ff812 commit 318b46f

34 files changed

Lines changed: 7956 additions & 41 deletions

File tree

.claude/board/EPIPHANIES.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@
77
88
---
99

10+
## 2026-07-06 — E-BEHAVIOR-AT-COMPILE-TIME — behavior facts are substrate, not runtime beiwerk
11+
12+
**Status:** FRAMING (`[G]` for the effect-annotation facts now wired; `[H]` for source-body lowering).
13+
14+
Operator §3: the sink-in GUID substrate is compile-time-available INCLUDING behavior. Realised minimally in commit `789c7ed` — ruff's `Function.reads/writes/calls` now ride `ActionDef` at lift time, the IR surface signed off against OGAR-AS-IR §3 (test 2). Provenance is kept honest rather than flattened: **writes/calls are authoritative** (the extractor sees assignment and call targets directly), **reads are inferred** (name references, an over-approximation); the annotation records which is which, so no downstream consumer mistakes an inferred read for a proven effect, and no reactive `kausal` is fabricated from a plain read. The remaining `[H]` is source-body lowering (`body_source`, params, value-carrying `on_enter`), gated on a named `ruff_spo_triplet::Function` extension (SPEC-1 Part A — a follow-up). Cross-ref D-BEHAVIOR-ACTION-EDGES, E-OGAR-CONVERGENCE-SHAPE behavior layer ("[G] facts / [H] lowering").
15+
16+
---
17+
18+
## 2026-07-06 — E-ONE-MASK-TWO-ENGINES — one ClassView×FieldMask projection, askama and jinja agree
19+
20+
**Status:** `[G]` on the pinned round-trip; `[H]`→retires the render layer's falsifier #2 for the ≤64-field case.
21+
22+
Falsifier #2 (the classview-mask round-trip named in E-OGAR-CONVERGENCE-SHAPE) RAN and is GREEN: a single fixture's `(fields, mask)` at **mask=45** yields the identical field-name set through askama (Rust) and jinja2 (Python) — the dual-target render Operator §5 asks for, one projection driving both engines rather than two hand-kept templates. Two honesties are pinned alongside the green: (1) the `>64`-field case is **loud-failed** (`RenderError::TooManyFieldsForMask`, D-FIELDMASK-LOUD-FAIL), never silently round-tripped — a loud-fail guard replaced the old field-64+ silent drop; (2) the FULL sentinel **aliases** any genuine all-ones mask at the u64 tier, so "render everything" and "explicitly select all 64" are indistinguishable there — documented as a caveat, and the reason the widening (D-FIELDMASK-WIDENING) carries a canonical form. Companion to E-ONE-MASK-THREE-PORTS; realises Operator §5 (dual-target render) + §6 (identical data model both languages). Cross-ref D-FIELDMASK-LOUD-FAIL, D-FIELDMASK-WIDENING.
23+
24+
---
25+
26+
## 2026-07-06 — E-PYTHON-SUBSTRATE-MIRROR — the emit_python @dataclass IS the Python mirror of CompiledClass
27+
28+
**Status:** FRAMING (`[G]` for the py_compile+instantiate gate on the synthetic WoA class; `[H]` for the persistence adapter).
29+
30+
Operator §6: identical data model in both languages via Classes/ClassView, never a parallel schema truth. Realised: `emit_python` renders the same `CompiledClass` the Rust emitters render, and the emitted `TimesheetActivity` `@dataclass` both **py_compiles and instantiates** (D-PARITY-PROBE-WOA-1). Two findings sharpen the mirror rather than decorate it: the class does not sit on bootstrap classid 0 as the spec assumed — it converges through `WOA_ALIASES` onto `BILLABLE_WORK_ENTRY` (`0x0103_0003`), pinned by test, so the "Python mirror" is an *addressed* mirror, not an anonymous one; and `emit_python` still omits `options.required`, a named emitter follow-up (the mirror is structurally 1:1 on fields / types / associations, honestly short one nullability annotation). The DB format (Operator §4) stays a documented decision — Option C now (dataclass mirror), Option B (SQLAlchemy/SQLite reusable adapter) and the PG facet table (D-PY-PERSIST-PG-FACET) next, Option A (lancedb bindings) as the native substrate. Cross-ref D-PARITY-PROBE-WOA-1, D-PY-PERSIST-PG-FACET, E-ONE-MASK-TWO-ENGINES.
1031
## 2026-07-05 — E-RECIPE-FAMILIES-MINT-ON-EMIT — Scope-kind / Concern-kind are RESERVED (bytes 0x05 / 0x06) but minted ON EMIT, not speculatively
1132

1233
**Status:** FINDING (operator rule, 2026-07-05 — verbatim: *"add scope-kind concern-kind when you see the code wants to emit it (eg ruff dto ast for duplicated routes, or god object split)"*). Recorded in `recipe.rs` module doc (§ Reserved-but-unminted families); no `RecipeFamily` variant, no concept, no codebook row minted — bytes `0x05`/`0x06` resolve to `RecipeFamily::Unassigned` until the emit seam exists.

.claude/harvest/woa-rs/HARVEST.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# HARVEST — WoA sink-in substrate v1
2+
3+
`WoA` (Flask-SQLAlchemy, `/home/user/WoA/models.py`, READ-ONLY corpus) transcoded
4+
through the ruff → OGAR pipeline into the V3 transpile substrate. Produced for
5+
MISSION "OGAR V3: Criticals testen + Python-Arm real machen (WoA 1:1)" as the
6+
concrete SPEC-5 Part B/C/D reality-check artifact set.
7+
8+
## Pipeline (real code path, nothing hand-written)
9+
10+
```
11+
/home/user/WoA/models.py
12+
│ ruff_sqlalchemy_spo::extract_file (frontend, /tmp/wt-gr crates/ruff_sqlalchemy_spo,
13+
│ branch claude/spo-python-main)
14+
15+
ruff_spo_triplet::ModelGraph
16+
│ ogar-from-ruff::sqlalchemy::lift_model_graph_sqlalchemy
17+
18+
Vec<ogar_vocab::Class> (schema stratum: attributes / associations)
19+
│ ogar-from-ruff::mint::compile_graph_sqlalchemy::<WoaPort>
20+
21+
Vec<CompiledClass> (Class + 16-byte rail Facet, classid via WoaPort)
22+
│ ogar-from-ruff::emit::emit_python -> models.py
23+
│ (association walk, classid-annotated) -> woa_graph.spo
24+
│ ogar-adapter-postgres-ddl::emit_facet_table_ddl + emit_postgres_ddl -> woa_facet.sql
25+
26+
this directory
27+
```
28+
29+
Driver: a scratch Cargo binary at `/tmp/harvest-woa` (NOT committed anywhere —
30+
path-deps + a local `[patch]` block only, per the mission's leitplanken). See
31+
"Reproduction" below for the exact commands to regenerate.
32+
33+
## Metrics
34+
35+
| Metric | Value |
36+
|---|---|
37+
| `db.Model` classes harvested | **139** (`ruff_sqlalchemy_spo` corpus-gate test asserts `>= 139`; WoA's own `grep -c 'class.*db.Model'` on `models.py` also gives 139 — exact match, no discrepancy) |
38+
| Attributes (`Attribute` after FK-dedup) | **1961** |
39+
| Associations (`db.relationship`, `BelongsTo`/`HasMany`) | **107** |
40+
| Aliased (resolve through `WOA_ALIASES` convergence pins, concept ≠ 0) | **6** |
41+
| Bootstrap (unmapped model name → classid `0x0000_0003`, concept = 0) | **133** |
42+
43+
### The 6 aliased classes (WOA_ALIASES convergence pins, `ogar-vocab/src/ports.rs`)
44+
45+
| Class | classid | concept | Same concept converges with |
46+
|---|---|---|---|
47+
| `TimesheetActivity` | `0x0103_0003` | `0x0103` (`BILLABLE_WORK_ENTRY`) | `OpenProjectPort::TimeEntry`, `RedminePort::TimeEntry` |
48+
| `Customer` | `0x0204_0003` | `0x0204` | (CRM-concept alias) |
49+
| `WorkOrder` | `0x0202_0003` | `0x0202` | (matches Odoo's `account.move`-adjacent concept family — same concept id Odoo's `sale.order`/`account.move` land in) |
50+
| `Position` | `0x0201_0003` | `0x0201` | |
51+
| `RecurringInvoice` | `0x0202_0003` | `0x0202` | same concept as `WorkOrder` — both are "billing document" shaped |
52+
| `TaxRate` | `0x0203_0003` | `0x0203` | |
53+
54+
The remaining 133 models mint the **bootstrap** classid `0x0000_0003`
55+
(concept `0x0000`, WoA app prefix `0x0003`) — `WOA_ALIASES` is a small,
56+
deliberately curated table (per `ports.rs` docs, a handful of named
57+
convergence pins), not a name-for-name mirror of all 139 WoA models. This is
58+
the honest, measured state (matches `sqlalchemy.rs`'s own doc comment on
59+
`compile_graph_sqlalchemy`, which names this exact caveat for
60+
`TimesheetActivity`) — no attempt was made to mint new aliases (mint
61+
governance: no new Codebook concepts without an Operator ruling).
62+
63+
### Convergence spot-check (mission-mandated)
64+
65+
```
66+
TimesheetActivity -> classid 0x01030003 (concept 0x0103, app 0x0003)
67+
```
68+
69+
Matches the fixture in `ogar-from-ruff/src/mint.rs`'s own doc comment on
70+
`compile_graph_sqlalchemy` and its test
71+
`compile_graph_sqlalchemy_timesheet_activity_converges_via_alias_not_bootstrap`
72+
byte-for-byte. `TimesheetActivity`'s harvested shape also matches WoA source
73+
`models.py:1746-1753` exactly: `id` (required), `beschreibung` (required),
74+
`created_at` (nullable — no `nullable=False` in source), `timesheet_id`
75+
FK-shadowed by the `timesheet: ToOne["TimeSheet"]` association (not
76+
double-projected).
77+
78+
## Gates run
79+
80+
- `python3 -m py_compile models.py`**PASS** (module parses; see "Known
81+
gaps" below for what this gate does NOT prove).
82+
- `cargo test -p ruff_sqlalchemy_spo` corpus gate (`WOA_SRC=/home/user/WoA/models.py`)
83+
already asserts `>= 139` models upstream in the frontend crate itself (not
84+
re-run here — this harvest's own driver run independently reproduces the
85+
same 139).
86+
87+
## Reproduction
88+
89+
```sh
90+
# 1. Scratch driver (path deps + local-only [patch], never committed):
91+
mkdir -p /tmp/harvest-woa/src
92+
cat > /tmp/harvest-woa/Cargo.toml <<'TOML'
93+
[package]
94+
name = "harvest-woa"
95+
version = "0.1.0"
96+
edition = "2021"
97+
publish = false
98+
[[bin]]
99+
name = "harvest-woa"
100+
path = "src/main.rs"
101+
[dependencies]
102+
ruff_sqlalchemy_spo = { path = "/tmp/wt-gr/crates/ruff_sqlalchemy_spo" }
103+
ogar-from-ruff = { path = "/workspace/ogar/crates/ogar-from-ruff" }
104+
ogar-vocab = { path = "/workspace/ogar/crates/ogar-vocab" }
105+
ogar-adapter-postgres-ddl = { path = "/workspace/ogar/crates/ogar-adapter-postgres-ddl" }
106+
[patch."https://github.com/AdaWorldAPI/ruff"]
107+
ruff_spo_triplet = { path = "/tmp/wt-gr/crates/ruff_spo_triplet" }
108+
ruff_spo_address = { path = "/tmp/wt-gr/crates/ruff_spo_address" }
109+
TOML
110+
cp /workspace/ogar/rust-toolchain.toml /tmp/harvest-woa/rust-toolchain.toml # pins 1.95.0
111+
# (src/main.rs: extract_file -> compile_graph_sqlalchemy::<WoaPort> -> emit_python
112+
# + a classid-keyed association walk for woa_graph.spo + the postgres-ddl adapter
113+
# calls for woa_facet.sql — see this harvest's provenance pins below for the
114+
# exact commit this was run against.)
115+
116+
cd /tmp/harvest-woa
117+
cargo run --quiet -- /home/user/WoA/models.py /tmp/harvest-woa/out
118+
python3 -m py_compile /tmp/harvest-woa/out/models.py
119+
```
120+
121+
## Provenance
122+
123+
| Input | Pin |
124+
|---|---|
125+
| WoA (`AdaWorldAPI/WoA`, `models.py`, READ-ONLY) | `4427b3d715d841290ea9108e3bf94b22d0cb72c2` (last commit touching `models.py`) |
126+
| ruff (`AdaWorldAPI/ruff`, `ruff_sqlalchemy_spo`) | `/tmp/wt-gr`, branch `claude/spo-python-main`, HEAD `66db5c417eddf6017e924706031a23b019c17e81` |
127+
| OGAR (`ogar-from-ruff`, `ogar-vocab`, `ogar-adapter-postgres-ddl`) | `/workspace/ogar`, branch `claude/v3-criticals-woa-parity`, HEAD `d5479ce382136b3aedad3c122e13d3aab6f9695e` |
128+
129+
## Known gaps (honest, not papered over)
130+
131+
1. **Behavior = names only.** `Model::functions` (methods) are harvested
132+
name-only by `ruff_sqlalchemy_spo::functions` (v0, per its module doc) —
133+
no params, no `reads`/`writes`, no `body_source`. `emit_python` therefore
134+
emits **zero** methods; the generated dataclasses are schema-only mirrors
135+
of WoA's `db.Model` classes, not behavior-complete ports. This is the same
136+
gap the mission's Critical #1 (`behavior`) names for `lift_actions`
137+
generally (`ogar-from-ruff/src/lib.rs:495`) — this SQLAlchemy harvest
138+
doesn't lift `ActionDef`/`KausalSpec` at all (v0 doesn't wire it), so the
139+
gap is total rather than partial here.
140+
2. **`woa/models_shop.py` (12 more `db.Model` classes) is out of scope for
141+
this v1.** Only the monolithic `/home/user/WoA/models.py` (139 classes)
142+
was harvested, per the mission's explicit instruction. Follow-up: run
143+
`ruff_sqlalchemy_spo::extract_file` a second time against
144+
`woa/models_shop.py` (or `extract_with` over the `woa/` tree) and merge
145+
the two `ModelGraph`s before minting, so shop-domain FKs into the core 139
146+
resolve rather than dangling.
147+
3. **`emit_python`'s import list is incomplete — `models.py` does not
148+
`import` (nor is `ogar_sdk.py` shipped alongside).** The header only
149+
imports `OgScalar, ToOne, ToMany` from `ogar_sdk` (mirroring the PR #154
150+
Python-emit precedent's own header), but `emit_python`'s
151+
`og_scalar_type()` mapping emits bare names — `OgInt`, `OgStr`, `OgBool`,
152+
`OgDateTime`, `OgFloat`, `OgMoney`, `OgDate`, `OgBytes`, `OgSelection`,
153+
`OgJson` — that are **never imported**. `python3 -m py_compile` still
154+
passes because compiling to bytecode does not evaluate the class-body
155+
annotation expressions at import time in a way that raises — it is a
156+
syntax-level gate only, not proof the module is importable/runnable.
157+
Actually running `import models` would raise `NameError` on the first
158+
annotated attribute. This is `ogar-from-ruff::emit_python`'s existing gap
159+
(not introduced by this harvest), reported per the mission's instruction
160+
to name the "emit_python required-Lücke" honestly rather than
161+
hand-patching the generated output.
162+
4. **`woa_graph.spo` target-classid resolution: measured, not assumed.** An
163+
association's target (`Association::class_name`, e.g. `TimeSheet` for
164+
`TimesheetActivity.timesheet`) is looked up by name against the 139
165+
harvested+minted classes; a miss (renamed target, target lives in
166+
`models_shop.py`, or a `class_name` string that doesn't match any
167+
harvested class) is written as `[--------]` rather than silently guessed.
168+
Measured over the actual 107-edge output: **0 of 107 edges are
169+
`[--------]`** — every association target in `models.py` resolves within
170+
the same 139-class corpus (the file is self-contained; nothing points
171+
into the excluded `models_shop.py`). This is a stronger result than
172+
expected going in and is called out explicitly so it isn't mistaken for
173+
an unverified assumption.
174+
5. **`PostgreSQL` DDL is the relational (`emit_postgres_ddl`) shape, not yet
175+
wired to the facet table.** `woa_facet.sql` emits the two pieces
176+
side-by-side (facet table via `emit_facet_table_ddl("facet")`, then one
177+
`CREATE TABLE` per class via `emit_postgres_ddl`) but does **not** attempt
178+
the dual-write / parity-checker wiring the Operator's ruling (b, refined)
179+
describes — that is explicitly a "follow-up, NOT built here" per
180+
`ogar-adapter-postgres-ddl`'s own module doc.
181+
6. **Falsifizierer #1 (WP-Parity)-style field-by-field diff against the WoA
182+
source was not run for all 139 classes** — only the `TimesheetActivity`
183+
fixture (§ "Convergence spot-check" above) was checked field-for-field
184+
against source. A full N/N-columns-typed parity metric (mission's
185+
D-PARITY-PROBE-style measure) across all 139 classes is a reasonable
186+
next step but out of scope for this harvest pass.

.claude/harvest/woa-rs/PARKED.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# PARKED — belongs in `AdaWorldAPI/woa-rs`
2+
3+
This directory is the ruff → OGAR transcode of `AdaWorldAPI/WoA`'s
4+
Flask-SQLAlchemy `models.py` (139 `db.Model` classes) into the OGAR V3
5+
sink-in substrate. Its real home is `AdaWorldAPI/woa-rs` (the Rust port
6+
repo this session's WoA-side context — `/home/user/WoA/.claude/CLAUDE.md`
7+
§4 "Zwei-Welten-Pattern" — names as the sibling repo, read-only from the
8+
WoA checkout: `../woa-rs/`).
9+
10+
It is parked here **only** because `woa-rs` is not in this session's write
11+
scope — this OGAR session has no clone/checkout of `AdaWorldAPI/woa-rs` and
12+
no registered write access to it (same shape of gap `openstreetmap-website-rs`
13+
hit in OGAR PR #152: the target repo isn't reachable/writable from this
14+
session, so the artifacts are committed here — an in-scope, writable repo —
15+
as the durable save, rather than lost to an ephemeral scratch directory).
16+
17+
## Relocation (when `woa-rs` is in scope)
18+
19+
```sh
20+
git clone <proxy>/AdaWorldAPI/woa-rs /tmp/woa-rs
21+
cp -r .claude/harvest/woa-rs/. /tmp/woa-rs/<target-subpath>/ # excluding this PARKED.md
22+
cd /tmp/woa-rs && git add -A && git commit && git push
23+
```
24+
25+
The natural landing spot is a `python/` (or `generated/`) subtree mirroring
26+
the `osm-website-rs` precedent's `python/osm/models.py` placement — consult
27+
`woa-rs`'s own `CLAUDE.md`/`board/Stand.md` (per `WoA`'s `CLAUDE.md` §2
28+
"Im Rust-Port arbeitest" row) for its actual layout convention before
29+
copying in, since this session cannot read that repo to confirm.
30+
31+
## What's in this harvest
32+
33+
See `HARVEST.md` (same directory) for the full metrics, provenance, gates,
34+
and — importantly — the honestly-documented gaps (behavior is names-only,
35+
`models_shop.py`'s 12 classes are out of scope, `emit_python`'s import list
36+
is incomplete, and others). Read `HARVEST.md` before relying on `models.py`
37+
here as anything more than a structural (schema-stratum) reality check.
38+
39+
## Provenance
40+
41+
| Input | Pin |
42+
|---|---|
43+
| WoA (`AdaWorldAPI/WoA`, `models.py`, READ-ONLY) | `4427b3d715d841290ea9108e3bf94b22d0cb72c2` |
44+
| ruff (`AdaWorldAPI/ruff`, `ruff_sqlalchemy_spo`) | `/tmp/wt-gr`, branch `claude/spo-python-main`, `66db5c417eddf6017e924706031a23b019c17e81` |
45+
| OGAR (`ogar-from-ruff` / `ogar-vocab` / `ogar-adapter-postgres-ddl`) | `/workspace/ogar`, branch `claude/v3-criticals-woa-parity`, `d5479ce382136b3aedad3c122e13d3aab6f9695e` |
46+
47+
Regenerate with the scratch driver documented in `HARVEST.md`'s
48+
"Reproduction" section (not itself committed anywhere, per the mission's
49+
leitplanken — path-deps + a local-only `[patch]` block).

0 commit comments

Comments
 (0)