Substantial design artifact + canonical-source ingest for the TRM business plane. Schema draft (synthesis): - wiki/synthesis/directus-schema-draft.md — working agreement for the multi-tenant schema. Pseudo multi-tenant under organizations; entries as the unit of timing; course definition (stages/segments/geofences/ waypoints/SLZs); penalty system "numbers in DB, math in code" with an evaluator registry and progressive bracket math; per-entry timing tables; per-stage start-order strategies (manual / previous_stage_clean_result / inverse_top_n_then_natural / inverse_of_overall) covering both Tirana 24h and Rally Albania patterns. Two role surfaces (org role vs racing role) called out explicitly. Decisions captured; Open questions reduced to one (geometry retroactivity engine, deferred to Phase 2.5). Source ingest: - raw/Regulations_2025.pdf + wiki/sources/rally-albania-regulations- 2025.md — formal ingest of the canonical Rally Albania 2025 rulebook. Section numbers preserved as §X.Y so the schema draft and future SPA work can cite precisely. Flagged follow-ups: the SLZ formula lives in the Supplementary Regulations (don't hardcode); M-7 numbering bug; unmodeled neutralization zones. Faulty-position flag (cross-plane operator workflow): - entities/postgres-timescaledb.md, entities/processor.md, concepts/position-record.md — operator-controlled boolean on the positions hypertable; processor filters WHERE faulty = false on every read; flagging triggers windowed recompute via the recompute:requests stream. Implementation strategy on entity pages: - entities/directus.md — Schema management section documenting the snapshots/ + db-init/ convention, container-startup apply pipeline. - entities/processor.md — Phase 2 long-lived branch model with PROCESSOR_PHASE_2_ENABLED flag-gating for incremental main merges; Phase 2.5 deferral note. Index and log updated.
11 KiB
Log
Chronological activity log. Append-only. Entry headers use the format ## [YYYY-MM-DD] <op> | <title> so they can be grepped:
grep "^## \[" log.md | tail -10
[2026-04-30] note | Wiki bootstrapped
Created CLAUDE.md (schema + workflows), index.md (empty catalog), and this log. Wiki directory structure (wiki/sources, wiki/entities, wiki/concepts, wiki/synthesis) will be created on first ingest.
[2026-04-30] ingest | gps-tracking-architecture.md + teltonika-ingestion-architecture.md
Ingested both initial architecture docs in one pass. Created:
- Source pages: gps-tracking-architecture, teltonika-ingestion-architecture.
- Entity pages: tcp-ingestion, processor, directus, react-spa, redis-streams, postgres-timescaledb, teltonika.
- Concept pages: plane-separation, protocol-adapter, codec-dispatch, position-record, failure-domains, phase-2-commands.
- Updated index.md with all 15 new pages.
No contradictions to flag — the two docs are coherent (the Teltonika doc explicitly cites and respects the system architecture). Open follow-ups: TRM business domain not yet captured; per-model IO dictionary location TBD; Phase 2 timing unspecified.
[2026-04-30] ingest | Teltonika Data Sending Protocols (official wiki)
Ingested the canonical Teltonika spec covering all codec families. New additions:
- Source page: teltonika-data-sending-protocols.
- New concept: avl-data-format — byte-level reference for codecs 8/8E/16, including UDP envelope.
Updates to existing pages (no contradictions; refinements + additions):
- teltonika — added full codec table with hex IDs, Codec 15 (out of scope), Codec 14 ACK/nACK, packet size limits, UDP support note.
- codec-dispatch — corrected hex IDs, added directionality table covering codecs 8–15.
- position-record — concrete priority enum (0/1/2), two's-complement lat/lon note, Speed=0 means GPS invalid, Generation Type and NX section flagged.
- phase-2-commands — clarified Codec 12 vs 14 selection, added
nackstatus for Codec 14 IMEI-mismatch (Type0x11); noted 13/15 are not part of the outbound design.
Cleanup: removed stale duplicate concept files from earlier passes (system-planes.md, protocol-adapter-pattern.md, codec-dispatch-registry.md) — superseded by plane-separation.md, protocol-adapter.md, codec-dispatch.md respectively. Fixed dangling protocol-adapter-pattern link in io-element-bag.
Open questions surfaced by the canonical doc: Codec 16 Generation Type — promote to typed position-record field? Codec 8E NX values land as Buffer in attributes; needs explicit fixture coverage. SMS-based protocols (Codec 4 + binary SMS) probably out of scope but worth a deliberate decision.
[2026-05-01] note | Stream-name canonicalization
Documented the canonical stream/key names in redis-streams — the wiki was previously silent on the actual telemetry:teltonika name, so anyone reading it had no way to find out what stream the services use. Added a "Stream and key naming" table covering the inbound telemetry stream, Phase 2 command streams, and registry/heartbeat keys. Also added the naming convention (telemetry:{vendor}) so future adapters fit predictably. Cross-referenced the actual stream name in processor and tcp-ingestion entities so each entity is self-contained but the convention has one canonical home.
Triggered by a stage-side bug where tcp-ingestion's compiled default (telemetry:teltonika) and processor's compiled default (telemetry:t) had drifted; pipeline ran with both services talking past each other for ~7 hours before symptoms surfaced. Fix landed in deploy stack (shared env var) and processor (default realigned). Wiki update closes the documentation loop.
[2026-05-01] synthesis | Live channel architecture (corrects a wiki claim)
Researched Directus's WebSocket subscription mechanism via context7. Confirmed that subscriptions only fire for writes that go through Directus's ItemsService (REST/GraphQL/Admin UI mutations, not direct database INSERTs). The previous claim in directus — "When Processor writes a row, Directus broadcasts the change to subscribed clients" — was wrong.
Wrote live-channel-architecture documenting the corrected design: two WebSocket channels, each in its own plane. Processor exposes its own WebSocket endpoint for high-volume telemetry fan-out (auth via Directus-issued JWT, authorization delegated to Directus once at subscribe time). Directus's built-in WebSocket subscriptions cover business-plane events. Reasoning: preserves plane-separation and gives the gentlest failure mode (Directus down blocks only new authorizations, not the live firehose).
Updated processor (added Live broadcast section, multi-instance consumer-group plumbing note), directus (corrected the real-time-delivery section), and index.md.
[2026-05-01] synthesis | Directus schema — working draft
Captured the business-plane schema agreement reached during today's discussion as directus-schema-draft. Marked as a working draft, open for revision.
Shape: pseudo multi-tenant under organizations; users / teams / vehicles / devices are all m2m with orgs (durable catalog); events scoped to a single org; entries is the per-event timing unit with nullable vehicle_id (foot races) and nullable team_id (lone racers); entry_crew and entry_devices are junctions off entries (no separate crews collection — teams already provide durable group identity). Vehicle ownership intentionally soft (owner_user_id?, owner_team_id?), not enforced. Per-event classes. events.discipline drives validation. Per-org-per-user role lives on organization_users.role.
Open: entries.status enum, permission policy definitions per role, stages/timing records (Phase 2 processor), geofences (Phase 2 processor).
[2026-05-01] synthesis | Schema draft — course definition + penalty system
Major expansion of directus-schema-draft. Added course definition (stages → segments → geofences/waypoints/SLZs) and the full penalty system. Vehicle ownership idea dropped (org-level only, no owner FKs). entries.status enum pinned with semantics. Permission policies confirmed as Directus 11 dynamic-filter Policies, one per logical role.
Penalty system landed as: numbers in DB, math in code. A penalty_formulas collection holds all values (bracket multipliers, per-miss penalties); the processor holds one evaluator per type in a registry. Speed limit penalties are progressive slice-by-slice (income-tax math, confirmed against the Tirana 24h rulebook): each bracket contributes only the portion of the peak overspeed within its range — slice × rate summed across all brackets the peak crossed. Worked example with peak=58 included in the doc.
Retroactive flag lives on penalty_formulas (default true) and on geofences / speed_limit_zones (default false). Per-edit override at save time. Formula recomputes are cheap (snapshotted inputs on entry_penalties rows). Geometry recomputes are expensive (replay from positions hypertable) and deferred to Phase 2.5 of processor.
Other decisions: checkpoints are typed geofences with manual_verification=true, not a separate collection. Stages are containers; segments (liaison / special-stage / parc-ferme) are the atomic rule unit. SLZs carry an evaluation_window_meters so the 2km rule from real federations is data, not code.
Per-entry timing layer (entry_segment_starts, entry_crossings, entry_penalties) and results layer (stage_results) are the processor Phase 2 write target. Schema is laid out so Phase 1 (positions only) can ship without it.
[2026-05-01] note | Faulty position flagging
Added a faulty boolean DEFAULT false column to the positions hypertable, controlled by track operators through directus (the hypertable is exposed as a Directus collection for read+update). processor filters WHERE faulty = false on every read of position data — peak-speed, crossing detection, replay-based recompute. Flagging triggers a windowed recompute of affected entry_penalties. Updated postgres-timescaledb, position-record (storage shape vs. wire shape), processor (faulty position handling), and directus-schema-draft (cross-plane operator workflow + third recompute kind).
[2026-05-01] synthesis | Schema draft — start-order strategies + secondary observations
Read two real-world rulebooks to pin the start-order question: Tirana 24h 2017 (static every leg) and Rally Albania 2025 (dynamic, several variants). Rally Albania's §5.5–5.10 settle it — start order is per-stage, declarative, and rule-driven. Stage 1 bikes invert the top 20 of the prologue; stages 2 onward seed from previous-stage clean SS time (penalties explicitly excluded); epilogue inverts overall standings; intervals are decided per stage.
Updates to directus-schema-draft:
stagesgainsrole(prologue/regular/epilogue),start_interval_seconds,start_order_strategy,start_order_strategy_params,start_order_input_stage_id.- New "Start order strategies" subsection enumerating
manual/previous_stage_result/previous_stage_clean_result/inverse_top_n_then_natural/inverse_of_overallwith real-world mappings. Tirana 24h covered bymanual; Rally Albania covered by the other four. entry_segment_startsaddsstart_positionandmanual_override(latter for late-arrival reseeding by Race Marshals — both rulebooks leave that operator-driven).- Materialization is per-category (categories share grids independently per Rally Albania §2.8 + §5.10).
- Decisions list grows: stage roles, CP-missing vs CP-late-past-closing as distinct event types sharing a formula row, reverse-stage tiebreaker.
- Open questions shrink: dropped the start-interval question (now pinned) and the permission-policy-filters question (admin/deployment task, not architectural).
[2026-05-01] ingest | Rally Albania 2025 — Race Rules and Regulations
Formal ingest of raw/Regulations_2025.pdf (Motorsport Club Albania, October 2024). Created rally-albania-regulations-2025 as the canonical real-world reference for federation rule shapes — classes, start-order rules, penalty taxonomy, tracking requirements, timekeeping, protests. Section numbers preserved as §X.Y so the schema draft and future SPA work can cite precisely.
Wired the source into directus-schema-draft (added to sources: frontmatter; framing note near the top; inline citation at start-order strategies section). Most of the schema-relevant content was already absorbed into the draft during the prior synthesis step — this ingest formalizes the citation chain.
Open follow-ups flagged on the source page: §12.11 SLZ formula lives in the Supplementary Regulations (not the general regs), so we shouldn't hardcode a default; M-7 numbering bug (Veteran and Female driver share the code — likely a typo); neutralization zones (§8.12) not yet modeled in the schema.
Index updated: new source row. No new entity/concept pages created — the doc supports existing pages rather than introducing new domain objects.