From 7d585a3cbb2ce44ae4ec9f12f8703267d055abe0 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Jul 2026 07:36:07 +0000 Subject: [PATCH] ogar-vocab: classview() accessor + D-CLASSID-HI-U16-SPELLING homonym note on APP_PREFIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lo-u16 render-skin slot is the 'classview' in the operator's domain:appid:classview (2:2:4 nibble) spelling — but the const is named APP_PREFIX, exactly the homonym D-CLASSID-HI-U16-SPELLING warns about (the 'appid byte' lives in the HI half = shared concept slot; the per- vendor render skin is the LO u16). A reader (and a recent session) can mistake APP_PREFIX for the appid. Non-breaking clarification: keep APP_PREFIX as the underlying const (every consumer re-exports it) and add a default trait method classview() -> Self::APP_PREFIX as the memorable name that matches the canon layout, plus a doc block on APP_PREFIX naming its position and the homonym. Pin: classview() == APP_PREFIX for all six ports. No value change, no consumer break. 29 ports tests green, clippy clean. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fy8D6Boh4ZBaHSBpadSENN --- crates/ogar-vocab/src/ports.rs | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/ogar-vocab/src/ports.rs b/crates/ogar-vocab/src/ports.rs index 94c0a3d..7c5b22d 100644 --- a/crates/ogar-vocab/src/ports.rs +++ b/crates/ogar-vocab/src/ports.rs @@ -61,9 +61,29 @@ pub trait PortSpec: 'static + Send + Sync { /// (`APP-CLASS-CODEBOOK-LAYOUT.md` §2; the prefix VALUES are /// order-invariant). /// + /// # Position in the `domain : appid : classview` spelling + /// + /// Per `DISCOVERY-MAP.md` D-CLASSID-HI-U16-SPELLING the composed + /// classid u32 reads **`domain(2 nibbles) : appid(2 nibbles) : + /// classview(4 nibbles)`** — i.e. `0xDDCCVVVV`, where the hi u16 + /// `0xDDCC` (`domain byte ++ appid byte`) is the shared CANON concept + /// and the lo u16 `0xVVVV` is the per-vendor render skin. **`APP_PREFIX` + /// IS that lo-u16 `classview` slot** — see [`Self::classview`], the + /// preferred name for it. + /// + /// **Homonym warning** (the reason the two names coexist): the word + /// "app" appears in BOTH halves with different meanings. The **appid + /// byte** (hi half) is the shared app-concept slot within a domain + /// (e.g. `0x0102` = project work item, converged on by OpenProject + /// `0x0102_0001` AND Redmine `0x0102_0007`); the **APP render prefix** + /// here (lo half) is the per-vendor ClassView skin. They are + /// positionally distinct registers — `APP_PREFIX` is the *classview*, + /// NOT the appid. + /// /// Composing the full render classid: /// ```text /// render_classid = (concept as u32) << 16 | APP_PREFIX + /// // └──── hi u16: domain:appid ────┘ └ lo u16: classview ┘ /// ``` /// /// `0x0000` is the **shared canonical core** — the cross-app ontology @@ -78,6 +98,18 @@ pub trait PortSpec: 'static + Send + Sync { /// data — consumers re-export it instead of hardcoding `0x0001` etc. const APP_PREFIX: u16 = 0x0000; + /// The **classview** — the memorable name for [`Self::APP_PREFIX`] in + /// the operator's `domain : appid : classview` spelling + /// (D-CLASSID-HI-U16-SPELLING). Identical value; this accessor exists + /// so call sites can read the lo-u16 render-skin slot by the name that + /// matches the canon layout instead of the `APP_PREFIX` homonym. New + /// code should prefer `Port::classview()`; `APP_PREFIX` stays as the + /// underlying const (every existing consumer re-exports it). + #[must_use] + fn classview() -> u16 { + Self::APP_PREFIX + } + /// All `(port-public-name, canonical-class-id)` aliases for this /// port. Order is not significant for resolution but kept stable /// for human readability. @@ -1070,6 +1102,15 @@ mod tests { ); assert_eq!(OdooPort::APP_PREFIX, 0x0002, "Odoo prefix must be 0x0002"); assert_eq!(WoaPort::APP_PREFIX, 0x0003, "WoA prefix must be 0x0003"); + // `classview()` is the memorable name for the same lo-u16 slot + // (D-CLASSID-HI-U16-SPELLING); it must equal `APP_PREFIX` for every + // port so the two names never drift. + assert_eq!(OpenProjectPort::classview(), OpenProjectPort::APP_PREFIX); + assert_eq!(OdooPort::classview(), OdooPort::APP_PREFIX); + assert_eq!(WoaPort::classview(), WoaPort::APP_PREFIX); + assert_eq!(SmbPort::classview(), SmbPort::APP_PREFIX); + assert_eq!(HealthcarePort::classview(), HealthcarePort::APP_PREFIX); + assert_eq!(RedminePort::classview(), RedminePort::APP_PREFIX); assert_eq!( SmbPort::APP_PREFIX, 0x0004,