From 50318b1f7e2ab647533e8dc022cf44a0269ec120 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Wed, 4 Nov 2026 21:23:38 +0100 Subject: [PATCH 01/22] docs(wiki): explain the LLM interface from keypress to provider The README claims the LLM-interface major, but nothing in groot showed a reviewer where each claimed bullet lives. This page follows one question through twelve hops (file:line at the develop pin 1c1d5d84), maps each subject bullet to its files, tests and osionos CI job, and records what osionos #270 (in the pin) and #275 (merged, not yet in the pin) added. Refs #155 --- wiki/project/ai-llm-interface.md | 143 +++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 wiki/project/ai-llm-interface.md diff --git a/wiki/project/ai-llm-interface.md b/wiki/project/ai-llm-interface.md new file mode 100644 index 000000000..b4fb9ff1e --- /dev/null +++ b/wiki/project/ai-llm-interface.md @@ -0,0 +1,143 @@ +# The LLM interface, explained + +> **Status:** Partial · 2026-11-04 +> **Evidence:** read-only reads of osionos at groot's `develop` pin `1c1d5d84` (the AI code is +> identical to osionos `develop` `d374c21f`, per `git diff --stat` on `services/`, `docs/ai` and +> `src/features/{ai,voice,recs}`). Each cited `file:line` was opened at that pin. #275 was read +> at its merge commit `1e757c3a`. No container was run and no question was asked for this page +> **To check:** the nginx buffering and timeouts (no test covers them); the provider-error +> patterns against live providers (`upstreamError.ts:14-19`); the groot pin bump that brings in +> #275 +> **Sources:** groot #155 · osionos #270, #275 · osionos `docs/adr/0007-upstream-error-codes.md`, +> `0008-quota-aware-failover.md` · [ai-stall-diagnosis-2026-10-29](ai-stall-diagnosis-2026-10-29.md) +> · [runbooks/osionos-ai](../runbooks/osionos-ai.md) + +The README claims the **Complete LLM system interface** major (row 15) for text, streaming, +error handling and rate limiting. This page follows one question from the keyboard to the model +and back, so a reviewer can open each step and check that claim. Image generation exists, but it +is off by default and is not part of the claim. + +Paths are in osionos (`apps/osionos/app`) unless prefixed `G` (groot). Paths under +`services/osionos-ai/` drop that prefix after the first hop that enters the service (hop 5). + +--- + +## One question, start to finish + +```mermaid +sequenceDiagram + autonumber + actor U as User + participant C as Chat UI
ChatComposer, useChatStore + participant P as Inference port
aiInferencePort, runStream + participant N as nginx :4000
/api/ai/ + participant S as osionos-ai :4300
routes/runs.ts + participant R as Runner
runner.ts + Redis + participant L as Provider
gateway/resolve.ts + U->>C: Enter + C->>P: runTurn(prompt) + P->>N: POST /api/ai/runs (runId) + N->>S: proxy, buffering off + S->>R: start the run + R->>R: checkRunRateLimit (20/min per user) + alt over the limit + R-->>S: refused 429 rate_limited + S-->>P: 429 + Retry-After + P-->>C: countdown, then retry offered + else allowed + S-->>P: 200 text/event-stream + R->>L: stream call (failover chain) + loop each token + L-->>R: part + R-->>S: frame + S-->>P: id / event / data + P-->>C: append text + end + Note over S,P: ": ping" every 15 s keeps the line open + opt connection drops + P->>N: GET events, Last-Event-ID + N->>S: resume from the last id + end + S-->>P: done, or error with a stable code + P-->>C: final message or error notice + end +``` + +## The twelve hops + +| # | Hop | file:line | +|---|---|---| +| 1 | Send (Enter or the button) | `src/widgets/chat-shell/ui/ChatComposer.tsx:204`, `:305`; slash expansion `src/widgets/chat-shell/model/useSlashPalette.ts:159-169`; `ChatShell.tsx:169-179` | +| 2 | Chat store `send` and `runTurn` | `src/features/chat/model/useChatStore.ts:373`, `:204`, `:409`; error patch `:222-232`; stop `:434` | +| 3 | Inference port | `src/features/ai/model/aiInferencePort.ts:111-157` (runId `:113`, abort → cancel `:121`) | +| 3b | Stream client and resume | `src/features/ai/model/runStream.ts:77-135`: 3 resumes after 500, 1000 and 2000 ms (`:34`, `:124`); dedup + `Last-Event-ID` (`:89-95`); 410 → `run_expired` (`:115`); a 4xx is never resumed (`:109`) | +| 3c | Transport | `src/features/ai/api/aiClient.ts:118` (`/api/ai`), `:188-207`, `:330` start, `:350` resume, `:358` cancel | +| 4 | nginx | `G infrastructure/tls/nginx.conf:178-200`: upstream `osionos-ai:4300` `:179`, `proxy_buffering off` `:195`, `proxy_read_timeout 300s` `:197`. Public limit: `G infrastructure/tls/public.d/ai-public.conf:4` + `public.d/http-limits.conf:19` (2 r/s, burst 10) | +| 5 | Route table | `services/osionos-ai/src/routes/table.ts:148` (POST /runs), `:151` (events), `:157` (cancel), `:141` (/images) | +| 6 | `handleRuns` | `routes/runs.ts:178-293`: refusal + `Retry-After` `:276-280`; SSE opens `:283`; ping every 15 s `:118`; resume endpoint `:295-324` | +| 7 | Runner and per-user limit | `runs/runner.ts:205`; `checkRunRateLimit` `:260-264`; `orderByRest` `:388`; `reserveTarget` `:397` | +| 8 | Failover loop | `runs/upstream.ts:241`, `:248` (`maxRetries` 0 when a chain exists), `:274-289` move on, catch `:362-390`; `chain.ts:26`, `cooldown.ts:99,172`, `moveOn.ts:32-66`, `attempt.ts:49` (3 attempts) | +| 9 | Stream pump | `runs/streamPump.ts:232-252`; timeouts 30 s idle and 120 s total (`:25`, `:27`) | +| 10 | Provider | `gateway/resolve.ts:124-140` (anthropic, google, openai-compatible), `:176`; `gateway/platform.ts:28-32`; `connections/providers.ts:13,16` | +| 11 | SSE framing | `http.ts:108-129` (`x-accel-buffering: no`, id/event/data, `: ping`) | +| 12 | Frame dispatch → UI error | `src/features/chat/model/runEventDispatch.ts:204-214`; `ChatThread.tsx:278-285`; `src/features/chat/model/runErrorNotice.ts:42-59`; `src/features/chat/model/runErrors.ts:79-124` | + +**Why the hops are shaped this way.** The browser never talks to a provider (hops 4–10 run on +the server), so a provider key never reaches the client. The answer streams over SSE instead +of one long response, and nginx must not buffer it (hop 4, hop 11). A dropped connection resumes +from the last event id instead of starting the question again (hop 3b). And every failure ends +as a stable code the UI can name (hop 12). + +--- + +## Subject bullet → code → tests → CI + +The CI jobs are in osionos `.github/workflows/ci.yml`. "AI service" is the job +`AI service (tsc + suite)` (`:314`), which runs `services/osionos-ai/scripts/ci.sh`. "Canvas" is +the `Canvas unit tests` step of `quality (root)` (`:285`). + +| Subject bullet | Main files | Tests that prove it | CI job | What is not proven | +|---|---|---|---|---| +| Generate text | hops 1–12 | `tests/canvas/ai-chat-store.test.ts`, `ai-run-dispatch.test.ts`; `services/osionos-ai/tests/runs.test.ts`, `complete.test.ts` | Canvas; AI service | — | +| Streaming | `runStream.ts`, `aiInferencePort.ts`, `routes/runs.ts:283-324`, `http.ts:108-129` | `tests/canvas/ai-run-stream.test.ts`; `runs.test.ts`; `failover.test.ts` | Canvas; AI service | nginx buffering and timeouts; the ping and the idle/total timeouts on the happy path | +| Error handling | `runs/upstreamError.ts`, `upstream.ts:362-390`, `failover.ts`, `routes/complete.ts`; client `runErrors.ts:79-124` | `tests/upstreamError.test.ts`, `upstreamErrorRuns.test.ts`, `upstreamErrorLeak.test.ts`; `tests/canvas/ai-run-dispatch.test.ts` | AI service; Canvas | the UI shows one sentence for all the new codes (`runErrors.ts:72`, `:87-90`); the patterns were not checked against live providers | +| Rate limiting | `src/rateLimit.ts:62-84` (fixed 60 s window, Redis `INCR` + `EXPIRE NX`), `OSIONOS_AI_RUNS_PER_MINUTE` default 20 (`config.ts:48`), used at `runner.ts:260`; nginx `public_ai`; UI countdown `runErrorNotice.ts` | `tests/runRateLimit.test.ts`, `approvalRateLimit.test.ts`; `tests/canvas/ai-run-stream.test.ts` | AI service; Canvas | no direct unit test of `rateLimit.ts`; a fixed window lets up to twice the limit through at a boundary (its own caveat, `rateLimit.ts:6-9`) | +| Generate images (**not claimed**) | `routes/images.ts:141-282`, `images/engine.ts`, `promptGate.ts`, `outputCheck.ts`; client `imageRun.ts`, `AiImageJobView.tsx` | `tests/images.test.ts`, `imagesOff`, `imagesOutputCheck`, `imagesPromptGate`; `tests/canvas/ai-image-run.test.ts` | AI service; Canvas | off by default (404 unless `imagesEnabled`, `images.ts:144`); CI uses a mock engine only | + +**No groot workflow builds `--profile ai`.** The tests above run in osionos CI against the +service alone. Nothing in groot CI starts the composed stack with the AI profile. + +--- + +## What #270 and #275 added + +**osionos #270: stable codes for provider failures** (merged 2026-11-03, on develop as +`553f2afc`, **in** groot's pin). Before it, every provider failure reached the browser as +`upstream_error`, so a 429, a daily cap and an oversized prompt looked the same. + +- `runs/upstreamError.ts` maps a failure to `rate_limited`, `quota_exhausted`, + `provider_unavailable`, `context_too_long` or `upstream_error`. The error frame carries the + code, and `ai_runs.error` records `code[:status[:type]]`. +- Provider bodies and prompts are kept out of the service logs (`upstreamErrorLeak.test.ts`). +- The client reads the new codes (`runErrors.ts:88-90`), but still shows them as one sentence. +- Decision record: `docs/adr/0007-upstream-error-codes.md`. + +**osionos #275: failover that knows the free quota is shared** (merged 2026-11-04 by LESdylan, +on develop as `1e757c3a`, **not yet in groot's pin `1c1d5d84`**). Every public user spends one +OpenRouter key on `:free` routes, and the SDK retried each step twice, so one question could +spend 15 calls. + +- The SDK never retries (`maxRetries: 0`). The chain is the retry, and a run with one route + retries once on a 5xx or a network failure. +- `runs/quota.ts`: one Redis key rests every free route for everyone, for up to 300 s. While it + rests, a run whose routes are all free is refused with 429 and `Retry-After`. +- A run makes at most 7 provider calls (14 in research mode). +- Tests: `tests/quota.test.ts`, `tests/quotaFailover.test.ts`. Decision record: + `docs/adr/0008-quota-aware-failover.md`. +- It does not touch `rateLimit.ts`, the per-user limit. + +--- + +See also: [README Modules](../../README.md#modules) · [02-modules](02-modules.md) · +[ai-stall-diagnosis-2026-10-29](ai-stall-diagnosis-2026-10-29.md) · +[runbooks/osionos-ai](../runbooks/osionos-ai.md) From fd935abc6769cf2f5bdae87a2f04ad2ed6707d73 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Wed, 4 Nov 2026 21:23:38 +0100 Subject: [PATCH 02/22] docs(readme): grade every module by one rule, with its evidence The Modules table mixed two legends and claimed rows that cannot be shown on the pinned tree. Each row now names its core files, tests and CI job, docs and a three-step demo, and is graded by the osionos docs/ai rule (A = default stack and measured in CI; B = needs a switch or only unit-level evidence; C = not claimed). Claimed points: 31 listed / 10 A before, 23 claimed / 6 A after, for 14 required. OAuth (opposite-osiris pin ea8836db is on no branch), sentiment, image tagging, ML recommendations, Prometheus+Grafana and file upload move to "Not claimed yet". The LLM row claims text, streaming, errors and rate limiting; images stay off by default. Also fixes three contradictions: osionos-bridge paths replace grobase flags in rows 5/9/10/11, DynamoDB is an opt-in build (wiki/platform/08-engines.md), and --profile ai-vlm exists only in docker-compose.public.yml. Adds the AI-off-on-public caveat to Known limitations. Refs #155 --- README.md | 132 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index eed2c38a9..2abc809aa 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,10 @@ media server for video rooms). with its own database and scoped API key. - **Per-request owner isolation.** The Rust data plane scopes every query to its owner on every request; permissions are rows (ABAC/RBAC), not `if` statements. -- **One API over many databases.** PostgreSQL, MySQL, MongoDB, Redis, SQLite, MSSQL, DynamoDB and - even remote HTTP APIs are queried through the same envelope and the same API key. +- **One API over many databases.** PostgreSQL, MySQL, MongoDB, Redis, SQLite, MSSQL and even + remote HTTP APIs are queried through the same envelope and the same API key. DynamoDB is an + opt-in build, left out of the default one + ([`wiki/platform/08-engines.md`](wiki/platform/08-engines.md)). - **Collaborative editor.** Block-based pages, a database block with table / board / calendar views, real-time co-editing, channels and direct messages, video rooms. - **Single-command deployment.** `make all` builds and starts the whole stack in Docker, serves @@ -392,7 +394,8 @@ independently — each written in the language that suits it. transactional guarantees, and a mature ecosystem. RLS is what makes per-owner isolation enforceable inside the database itself, not only in application code. - **MySQL, MongoDB, Redis, MinIO** (object storage) run in the default edition; **SQLite, MSSQL, - DynamoDB** and remote **HTTP** APIs are supported through the same data-plane interface. This is a + DynamoDB** (opt-in build, [`wiki/platform/08-engines.md`](wiki/platform/08-engines.md)) and + remote **HTTP** APIs are supported through the same data-plane interface. This is a deliberate feature of the platform (one API over many engines), not a need of osionos itself. ### Other significant technologies @@ -539,7 +542,7 @@ foreign-key clash (`scripts/apply-models-migrations.sh:27-38`). | Calendar | Google Calendar events via Google OAuth | | Contract-driven provisioning | One JSON contract → isolated database, roles, keys and frontend `.env` | | Self-serve applications | `POST /v1/tenants/me/apps` creates a new isolated app with its own database and key | -| Multi-engine data API | One API and one key over PostgreSQL, MySQL, MongoDB, SQLite, MSSQL, DynamoDB, Redis, HTTP | +| Multi-engine data API | One API and one key over PostgreSQL, MySQL, MongoDB, SQLite, MSSQL, Redis, HTTP; DynamoDB in an opt-in build | | Public API | Key-authenticated, rate-limited API behind Kong, documented with OpenAPI | --- @@ -547,55 +550,69 @@ foreign-key clash (`scripts/apply-models-migrations.sh:27-38`). ## Modules The subject requires **14 points** (Major = 2, Minor = 1). A module that cannot be demonstrated -live scores zero, so the confidence column is honest about where each one stands: - -- **A** — works as-is in the default stack -- **B** — backend exists; needs a feature flag and a migration, no new code -- **C** — backend exists; needs a user-facing screen to be demonstrable - -Only the **A** rows — **10 points**, including the two modules of choice, are -demonstrable in the default stack today, which is four points below the 14 required. - -| # | Module | Category | Type | Pts | Conf | How it is implemented | -|---|---|---|---|--:|:--:|---| -| 1 | Public API (key, rate limit, docs, ≥5 endpoints) | Web | Major | 2 | A | Kong gateway with key auth and rate limiting; OpenAPI specs in grobase `infra/config/openapi/` | -| 2 | Backend as microservices | DevOps | Major | 2 | A | 15 compose planes (Go control, Rust data, Rust realtime, TS app, storage, auth…) talking over an internal network with HMAC-signed service calls | -| 3 | Real-time features via WebSockets | Web | Major | 2 | A | Rust realtime plane; changes published as events; protected channel namespaces (gate `m175`) | -| 4 | Real-time collaboration | Web | Minor | 1 | A | osionos live co-editing over `collab:` on the realtime plane | -| 5 | Advanced permissions | User management | Major | 2 | C | Roles and policies as rows, ABAC conditions; needs `PERMISSION_CONDITIONS_ENABLED` + `API_KEY_ABAC_ENABLED`, migration `063` | -| 6 | Organisation system | User management | Major | 2 | C | Organisations are **on in production**; only a management screen is missing | -| 7 | Monitoring with Prometheus + Grafana | DevOps | Major | 2 | C | Observability plane; needs `TENANT_OBS_ENABLED` **and** `DATA_PLANE_TENANT_OBS` | -| 8 | Health/status page, backups, disaster recovery | DevOps | Minor | 1 | C | `TENANT_BACKUP_ENABLED`, migration `042` | -| 9 | GDPR compliance | Data | Minor | 1 | B | Data export and hard erase: `TENANT_EXPORT_ENABLED` + `HARD_ERASE_ENABLED`; `gdpr_requests` table | -| 10 | Two-factor authentication | User management | Minor | 1 | B | TOTP (grobase `one` shape) or passkeys (`PASSKEYS_ENABLED`) | -| 11 | Remote authentication (OAuth 2.0) | User management | Minor | 1 | B | `SSO_ENABLED`, migration `053` | -| 12 | File upload and management | Web | Minor | 1 | C | Storage plane on MinIO, `STORAGE_BUCKET_SCOPE_ENABLED` | -| 13 | **Module of choice:** contract-driven application factory | Free choice | Major | 2 | A | See justification below | -| 14 | **Module of choice:** SSRF guard on the HTTP engine | Free choice | Minor | 1 | A | See justification below | -| 15 | Complete LLM system interface (text + images) | Artificial Intelligence | Major | 2 | B | Text streams with resume, cancel and rate limits; image generation needs `OSIONOS_AI_IMAGES=on`, `--profile ai --profile ai-gpu-vulkan` and the prompt guard (C72), without which the service refuses to start; off on the public stack. [M1 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m1-images.md) | -| 16 | Complete RAG on a large dataset | Artificial Intelligence | Major | 2 | B | `--profile ai`: permission-aware hybrid search with citations; the reranker is off by default, and the 110k-chunk corpus is a separate eval stack. [M2 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m2-rag.md) | -| 17 | ML recommendation system | Artificial Intelligence | Major | 2 | B | iALS + logistic ranker; needs `OSIONOS_RECS_FOR_YOU=1`, the beacon is opt-in, and the nightly job skips under 20 users. [M3 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m3-recs.md) | -| 18 | Content moderation AI | Artificial Intelligence | Minor | 1 | B | L0 rules + L1 classifier; needs `OSIONOS_MODERATION_ACTIONS=hold` and `OSIONOS_MODERATION_STATE=1`; L1 is log-only (no auto-removal); the public stack runs `log`. [M4 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m4-moderation.md) | -| 19 | Voice / speech | Artificial Intelligence | Minor | 1 | B | `--profile ai` with the speech model in its volume: dictation and read-aloud; off on the public stack (`503 voice_unavailable`). [M5 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m5-voice.md) | -| 20 | Sentiment analysis | Artificial Intelligence | Minor | 1 | C | Opt-in per workspace (owner/admin, Settings › AI) with `OSIONOS_SENTIMENT_URL`; off on the public stack; the model licence is undeclared. [M6 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m6-sentiment.md) | -| 21 | Image recognition and tagging | Artificial Intelligence | Minor | 1 | C | `--profile ai --profile ai-vlm` with the VLM in its volume; the browser flow and in-app search are not verified end to end; off on the public stack. [M7 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m7-images-tags.md) | - -**Point calculation** - -| | Points | -|---|--:| -| Catalogue modules listed (rows 1–12) | 18 | -| Modules of choice (rows 13–14) | 3 | -| Artificial Intelligence modules (rows 15–21: 2 + 2 + 2 + 1 + 1 + 1 + 1) | 10 | -| **Total listed** | **31** | -| Demonstrable today (confidence A: rows 1–4 = 7, rows 13–14 = 3) | **10** | -| Required | 14 | - -The **AI opponent** module is not claimed: osionos has no game. - -The **Multiple languages** module is not claimed: osionos lists four languages in its settings, -but switching only records a stub action (`i18n_change_stub` in osionos -`src/features/settings/SettingsCenter.tsx`); no translation resources are loaded. +live scores zero. Every row is graded by **one rule**, the one in osionos +[`docs/ai/README.md`](https://github.com/Univers42/osionos/blob/develop/docs/ai/README.md) (lines 7–8: a row is never A when its +demonstration needs something switched off or unmeasured): + +- **A**: the demo works on the default stack (`make all SKIP_SYNC=1`, nothing switched on), and a + green CI job drives that path against a running service. +- **B**: it works, but the demo needs something switched on (a flag, a profile, an edition), or + its only evidence is unit tests with fakes or a run that was never repeated. +- **C**: partial. **Not claimed.** These rows are listed under [Not claimed yet](#not-claimed-yet). + +**Claimed = A and B only: 23 points against the 14 required. 6 of them are A.** +Paths are prefixed by repository: `G` groot, `GB` grobase (`apps/grobase`), `OS` osionos +(`apps/osionos/app`), `OO` opposite-osiris (`apps/opposite-osiris`). They point at the commits +groot `develop` pins. CI names a workflow job: `GB-CI` is grobase `ci.yml`, `OS-CI` is osionos +`ci.yml`. + +| # | Module | Category | Type | Pts | Grade | Core files | Tests → CI job | Docs | Demo (3 steps) | +|---|---|---|---|--:|:--:|---|---|---|---| +| 1 | Public API (key, rate limit, docs, ≥5 endpoints) | Web | Major | 2 | **A** | `GB infra/docker/services/kong/conf/kong.yml:221-248` (`/rest/v1`: key-auth + rate-limiting); `GB infra/config/openapi/grobase-public.json` | `GB scripts/verify/m102-gateway-query-path.sh` → GB-CI "Integration Tests" (`ci.yml:927`) | `GB infra/config/openapi/README.md` | `make all SKIP_SYNC=1` → `/rest/v1` without `apikey` answers 401, with it 200 → repeat until 429 | +| 2 | Backend as microservices | DevOps | Major | 2 | **A** | `GB orchestrators/compose/base/*.yml` (16 files); `GB orchestrators/makes/30-planes.mk:33`; `GB src/control-plane`; `GB src/data-plane-router` | GB-CI unit suites (`ci.yml:1436`) + "Engine conformance" legs (`ci.yml:1532`) | [`wiki/platform/02-planes.md`](wiki/platform/02-planes.md) | `make -C apps/grobase planes` → `docker compose ps` → `make healthcheck` | +| 3 | Real-time features via WebSockets | Web | Major | 2 | **A** | `GB infra/docker/services/realtime/realtime-agnostic/crates/realtime-auth/src/jwt/mod.rs:90-94`; `GB kong.yml:314-315` (`/realtime/v1/ws`); `OS scripts/bridge-collab.mjs:626` | GB-CI `rust-realtime` suite (`ci.yml:1436`), live gates m184, m189, m201 (`ci.yml:735,855,1479`) | [`wiki/platform/05-realtime.md`](wiki/platform/05-realtime.md) | two browsers on one page → type in one → the other updates | +| 4 | Real-time collaboration | Web | Minor | 1 | **B** | `OS src/features/collab/model/{remoteCursors,collabPresence,blockSync}.ts`; `OS scripts/bridge-collab.mjs:626` | `OS tests/bridge/bridge-collab-*` (9) → OS-CI "quality (root)" Bridge tests (`ci.yml:291`); `G tests/e2e/specs/dw8-realtime.spec.ts` (run by hand) | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | as row 3 → watch the remote cursor and presence → edit the same block from both | +| 5 | Advanced permissions | User management | Major | 2 | **B** | `OS scripts/bridge-roles.mjs:28-29`; `OS scripts/bridge-share-rules.mjs:38`; `OS scripts/bridge-page-access.mjs:217`; `OS src/features/admin-users/api.ts` | `OS tests/bridge/bridge-page-access*` (7), `bridge-share-rules-*` (2) → OS-CI Bridge tests | [`wiki/platform/07-isolation.md`](wiki/platform/07-isolation.md) | sign in as admin → change a member's role → that member loses access | +| 6 | Organisation system | User management | Major | 2 | **B** | `OS scripts/bridge-workspace-teams.mjs:229`; `OS scripts/bridge-workspace-invites.mjs:134`; `OS src/features/settings/teamspaces/TeamspacesPanel.tsx` | `OS tests/bridge/bridge-workspace-*` (7) → OS-CI Bridge tests | [`wiki/platform/06-contracts.md`](wiki/platform/06-contracts.md) | create a workspace → create a teamspace → invite a user, who accepts | +| 8 | Health/status page, backups, disaster recovery | DevOps | Minor | 1 | **B** | `GB infra/docker/services/status-page/{server,availability}.py`; `GB orchestrators/compose/base/ops.yml`; `GB scripts/verify/m241-status-backup-recovery.sh` | m241 → GB `operational-reliability.yml:27`; m192 → GB-CI (`ci.yml:582`), **red on grobase `develop`** ([run 41870904860](https://github.com/Univers42/grobase/actions/runs/41870904860)) | [`wiki/operations/04-troubleshooting.md`](wiki/operations/04-troubleshooting.md) | bring up the `ops` plane (not in the default edition) → open the status page → stop a container, then `m241 --live` | +| 9 | GDPR compliance | Data | Minor | 1 | **B** | `OS scripts/bridge-account-export.mjs:143`; `OS scripts/bridge-account-erasure.mjs:79`; `OS src/features/settings/ui/AccountExportSection.tsx`; `OS src/features/settings/ui/danger/AccountDangerZone.tsx` | `OS tests/bridge/bridge-account-export*` (3), `bridge-account-erasure` (1) → OS-CI Bridge tests; `G models-grants.yml` | [`wiki/security/01-model.md`](wiki/security/01-model.md) | Settings › export my data → open the archive → delete the account | +| 10 | Two-factor authentication | User management | Minor | 1 | **B** | `OS scripts/bridge-account-mfa-totp.mjs:68`; `OS scripts/bridge-account-mfa.mjs:187`; `OS scripts/bridge-account-passkeys.mjs:100`; `OS src/features/settings/profile/TwoFactorModal.tsx` | `OS tests/bridge/bridge-account-mfa-*` (6), `bridge-account-passkeys` (1) → OS-CI Bridge tests | osionos `docs/account-platform` | enable TOTP → sign out → sign in with the code | +| 13 | **Module of choice:** contract-driven application factory | Free choice | Major | 2 | **B** | `GB src/control-plane/internal/tenants/selfserve_apps.go:55-58`; `GB src/control-plane/cmd/tenant-control/mount_appsselfserve.go:26`; `GB scripts/verify/m177-selfserve-apps.sh` | m176 → GB-CI (`ci.yml:192`); **m177 in no workflow** | [`wiki/platform/06-contracts.md`](wiki/platform/06-contracts.md), [justification](#justification--module-of-choice-major-contract-driven-application-factory) | set `APPS_SELFSERVE_ENABLED` (empty by default) → OTP login, `POST /v1/tenants/me/apps` twice → one app's key reads the other: 4xx | +| 14 | **Module of choice:** SSRF guard on the HTTP engine | Free choice | Minor | 1 | **B** | `GB src/data-plane-router/crates/data-plane-pool/src/dial_guard/classify.rs:91-127`; `GB src/data-plane-router/crates/data-plane-pool/src/http/validate.rs:83-98` | `GB …/dial_guard/classify_tests.rs` → GB-CI `rust-data-plane` + "Engine conformance (http)" | [`wiki/security/04-network.md`](wiki/security/04-network.md), [justification](#justification--module-of-choice-minor-ssrf-guard-on-the-http-engine) | mount an `http` source at `169.254.169.254` → query it → refused. Whether the default edition mounts the `http` engine is unverified (guess: it does not) | +| 15 | Complete LLM system interface: text, streaming, error handling, rate limiting. Images exist but are **off by default** and not part of this claim | Artificial Intelligence | Major | 2 | **B** | osionos `services/osionos-ai/src/routes/runs.ts:178-324`, `src/runs/{runner,upstream,upstreamError,streamPump}.ts`, `src/rateLimit.ts:84`, `src/http.ts:108-129`; client `src/features/ai/model/runStream.ts`. All 12 hops: [`wiki/project/ai-llm-interface.md`](wiki/project/ai-llm-interface.md) | `services/osionos-ai/tests/{runs,complete,upstreamError*,runRateLimit,failover,quotaFailover}.test.ts` → OS-CI "AI service (tsc + suite)" (`ci.yml:314`); `tests/canvas/ai-{chat-store,run-dispatch,run-stream}.test.ts` → "quality (root)" Canvas unit tests (`ci.yml:285`) | [`wiki/project/ai-llm-interface.md`](wiki/project/ai-llm-interface.md), [`wiki/runbooks/osionos-ai.md`](wiki/runbooks/osionos-ai.md), [M1 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m1-images.md) | `docker compose --profile ai up -d --build` → ask a question and watch it stream → reload mid-answer (it resumes), or stop it | +| 16 | Complete RAG on a large dataset | Artificial Intelligence | Major | 2 | **B** | osionos `services/osionos-ai/src/retrieval/search.ts:277,469,564`, `src/retrieval/rerank.ts:16`; `G models/osionos-ai-rag-migration.sql:60,91` | `services/osionos-ai/tests/{retrieval,aclAgreement,rerank}.test.ts` → OS-CI AI service | [M2 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m2-rag.md), osionos `services/osionos-ai/eval/wiki/RESULTS-rag.md` | `--profile ai` → ask a workspace question → click a citation, then show the 110 363-chunk measurement (run on a separate eval stack; the reranker is off by default) | +| 18 | Content moderation AI | Artificial Intelligence | Minor | 1 | **B** | osionos `scripts/bridge-moderation-gate.mjs:70`; `services/osionos-ai/src/moderation/l1.ts:99` | `services/osionos-ai/tests/moderation*.test.ts` (4) → OS-CI AI service; `tests/bridge/bridge-moderation*` (5) → Bridge tests | [M4 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m4-moderation.md) | set `OSIONOS_MODERATION_ACTIONS=hold` and `OSIONOS_MODERATION_STATE=1` → post a toxic comment → it waits in the admin console (no auto-removal, by design) | +| 19 | Voice / speech | Artificial Intelligence | Minor | 1 | **B** | osionos `services/osionos-ai/src/routes/voice.ts:104`, `src/features/voice/ui/DictationButton.tsx`, `src/features/voice/model/readAloud.ts`; `G docker-compose.yml:777` | `services/osionos-ai/tests/voice.test.ts` → OS-CI AI service | [M5 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m5-voice.md) | `--profile ai`, with the speech model fetched into its volume → dictate into a page → read it aloud (read-aloud voices not measured yet) | + +The table skips the numbers 7, 11, 12, 17, 20 and 21. Those rows moved to the next table. + +**Point calculation** (free choice is capped at 3, [`wiki/project/01-subject.md`](wiki/project/01-subject.md#points)) + +| | Before (2026-10) | After | +|---|--:|--:| +| Catalogue modules claimed (rows 1–12) | 18 | 14: 6 A (rows 1–3) + 8 B (rows 4–6, 8–10) | +| Modules of choice (rows 13–14, cap 3) | 3 | 3, all B | +| Artificial Intelligence modules (rows 15–21) | 10 | 6, all B (rows 15, 16, 18, 19) | +| **Total claimed** | **31 listed** | **23 (A + B)** | +| Of which A | 10 | **6** | +| Required | 14 | 14 | + +What moved: rows 1–4, 13 and 14 were A under the old legend ("works as-is"). Under one rule, +the rows that need a switch or have only unit-level evidence are B: rows 4, 13 and 14. The six +rows below no longer count. + +### Not claimed yet + +| Module | Was | Why it is not claimed, in one line | +|---|---|---| +| Remote authentication (OAuth 2.0), User management, Minor | 1, B | The opposite-osiris commit groot pins (`ea8836db`) is on no branch and has no `scripts/auth/oauth-providers.mjs`. Claim it after the opposite-osiris pin bump | +| Monitoring with Prometheus + Grafana, DevOps, Major | 2, C | The default edition ships no observability plane, and its gate m85 runs in no workflow | +| File upload and management, Web, Minor | 1, C | Avatars and page files upload (`OS scripts/bridge-media.mjs:160`), but no general file manager is verified, and gate m159 runs in no workflow | +| ML recommendation system, AI, Major | 2, B | Needs 20+ real users, the offline numbers are synthetic, and the `osionos-ml` Python tests run in no CI | +| Sentiment analysis, AI, Minor | 1, C | The model licence is undeclared | +| Image recognition and tagging, AI, Minor | 1, C | The browser flow is unverified. Locally the VLM starts with `--profile ai` (`G docker-compose.yml:993-995`); `--profile ai-vlm` exists only in `docker-compose.public.yml:207` | +| AI opponent, AI | — | osionos has no game | +| Multiple languages, Accessibility | — | `i18next` is a dependency (osionos `package.json:92`), but no source file imports it and no translation resource exists | ### Justification — Module of choice (Major): contract-driven application factory @@ -692,9 +709,14 @@ This project was built with **heavy AI assistance**, and we state it plainly. rules must be expressed as policies, schema constraints or database triggers. - **Documented security weaknesses.** Known and declared in [`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md). -- **Several features are behind flags that are off by default** — see the confidence column in +- **Several features are behind flags that are off by default** — see the Grade column in [Modules](#modules). -- **No interface translation.** The language setting in osionos is a stub (see [Modules](#modules)). +- **No interface translation.** osionos ships no translation resources (see + [Not claimed yet](#not-claimed-yet)). +- **Most AI features are off on the public stack.** `docker-compose.public.yml:103-135` empties + `OSIONOS_AI_IMAGES`, `OSIONOS_AI_STT_URL` (voice answers `503 voice_unavailable`) and + `OSIONOS_AI_VLM_URL`, and sets `OSIONOS_MODERATION_ACTIONS` to `log`. The AI modules are + demonstrated on the local stack with `docker compose --profile ai`, not on the public URL. - **Whiteboard editing is loopback-only and has no per-user authorization yet** (see [Demo](#demo)). From 20521ba531782d9270e53314b493a8b967c9c0ab Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Wed, 4 Nov 2026 21:23:38 +0100 Subject: [PATCH 03/22] docs(wiki): mark the AI audit superseded and fix the ledger counts ai-audit-2026-10-28 says the pin has no AI code; the develop pin 1c1d5d84 ships services/osionos-ai and #270. 02-modules said "eight A" (its table sums to 7), "four open items" (the table has two) and that the AI category was dismissed (the README claims four AI modules). The wiki index and STATUS now list the three AI pages. Refs #155 --- wiki/README.md | 3 +++ wiki/STATUS.md | 5 ++++- wiki/project/02-modules.md | 15 +++++++++------ wiki/project/ai-audit-2026-10-28.md | 5 +++++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/wiki/README.md b/wiki/README.md index 9a94c2ec6..90b29762f 100644 --- a/wiki/README.md +++ b/wiki/README.md @@ -88,6 +88,9 @@ zero per-project server code. | [02-modules](project/02-modules.md) | Module ledger: points, flags, evidence | | [03-team](project/03-team.md) | Roles and contributions | | [04-glossary](project/04-glossary.md) | Project vocabulary | +| [ai-llm-interface](project/ai-llm-interface.md) | The LLM interface: one question through twelve hops, and the tests behind each claim | +| [ai-audit-2026-10-28](project/ai-audit-2026-10-28.md) | Superseded 2026-11-04: the AI modules against the old pin | +| [ai-stall-diagnosis-2026-10-29](project/ai-stall-diagnosis-2026-10-29.md) | Why the assistant could stop after a few questions (diagnosis only) | --- diff --git a/wiki/STATUS.md b/wiki/STATUS.md index a46715e7c..7a1e08831 100644 --- a/wiki/STATUS.md +++ b/wiki/STATUS.md @@ -40,9 +40,12 @@ Update this table whenever a page's status block changes. It is the working list | product/03-opposite-osiris | Partial | **Privacy Policy / ToS existence unverified** | | product/04-repos | Partial | What is actually inside the delivered perimeter | | project/01-subject | Unverified by nature | Source is private; re-check on each subject version | -| project/02-modules | Partial | Four open checks worth ~6 points | +| project/02-modules | Partial | Two open checks worth ~6 points; grades superseded by the README Modules table (2026-11-04) | | project/03-team | **Template** | Facts not held anywhere; fill with the team | | project/04-glossary | Verified | — | +| project/ai-llm-interface | Partial | nginx buffering/timeouts untested; #275 not in groot's pin yet | +| project/ai-audit-2026-10-28 | Superseded | Pin facts replaced by the README Modules table, 2026-11-04 | +| project/ai-stall-diagnosis-2026-10-29 | Diagnosis only | Hypotheses not tested live | --- diff --git a/wiki/project/02-modules.md b/wiki/project/02-modules.md index 55517aa0d..6e2c7d2ff 100644 --- a/wiki/project/02-modules.md +++ b/wiki/project/02-modules.md @@ -3,8 +3,10 @@ > **Status:** Partial · 2026-09-15 > **Evidence:** flag states read from `deploy/fly/boot.sh`; every gate named here exists in the > gate index -> **To check:** four items in the "open" table below are worth up to 6 points between them and -> none has been checked. Do those before building any screen. +> **To check:** the two items in the "open" table below are worth up to 6 points between them +> and neither has been checked. The current grades are in the +> [README Modules table](../../README.md#modules) (2026-11-04), which supersedes this ledger's +> letters. > **Sources:** `deploy/fly/boot.sh` · `apps/grobase/CLAUDE.md` §flag-gating · [01-subject](01-subject.md) Only catalogue modules count. **A module that cannot be demonstrated scores zero**, so each row @@ -32,7 +34,7 @@ the screen does not. | OAuth 2.0 (User mgmt, minor) | 1 | `SSO_ENABLED`, migration `053` | `m110`, `m163` | **B** | | File upload (Web, minor) | 1 | storage plane, `STORAGE_BUCKET_SCOPE_ENABLED` | `m159` | **C** | -Nominal total without free choice: **18**. Eight of those points are **A**. +Nominal total without free choice: **18**. Seven of those points are **A** (rows 1–4). **The key distinction:** organisation-system's backend is already running in production, so it needs only a screen. The **B** rows need a flag, a migration and a gate run — but no new code. @@ -65,9 +67,10 @@ in the project but hard to demonstrate live — better as an oral argument than | Does `VaultProvider` talk to HashiCorp Vault? (credential layer, migration `060`) | 2 pts and the only cybersecurity module | | What are `src/apps/ai/` and `src/apps/analytics/`? | Up to 4 pts from categories written off | -The AI category was dismissed because gaming modules need a game and we have none — but the -*LLM interface* major needs no game, and neither does the analytics dashboard major. Half a -morning of reading; six points in play. +The AI category was first dismissed because gaming modules need a game and we have none. That +no longer holds: the README now claims four AI modules (LLM interface, RAG, moderation, voice; +6 points, all B), and the analytics dashboard major is still unchecked. The LLM interface is +explained in [ai-llm-interface](ai-llm-interface.md). --- diff --git a/wiki/project/ai-audit-2026-10-28.md b/wiki/project/ai-audit-2026-10-28.md index 46c507879..4051308dc 100644 --- a/wiki/project/ai-audit-2026-10-28.md +++ b/wiki/project/ai-audit-2026-10-28.md @@ -1,5 +1,10 @@ # AI audit — 2026-10-28 +> **Superseded · 2026-11-04.** The pin facts below are history. groot `develop` now pins osionos +> `1c1d5d84`, which ships `services/osionos-ai` (745 files) and #270. The "0 of 10 AI points" +> line no longer holds. The current grades are in the [README Modules table](../../README.md#modules), +> and the LLM interface is explained in [ai-llm-interface](ai-llm-interface.md). + > **Status:** Partial · 2026-10-28 > **Evidence:** read-only `git grep` / `git ls-tree` against named refs (commands at the bottom); > no test suite and no AI container was run for this page From 1e7e14d6c7e350d955937569734d0254c3be907d Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Wed, 4 Nov 2026 23:18:41 +0100 Subject: [PATCH 04/22] docs(readme): name the grading rule as groot's, stricter than osionos The legend cited osionos docs/ai/README.md as its source, but that file grades a documented profile A, while the README grades it B. Keep the grades, say which rule is whose, and pin the link to the osionos commit instead of develop. Also reword the pin sentence that read ambiguously. --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2abc809aa..b41330a95 100644 --- a/README.md +++ b/README.md @@ -550,9 +550,10 @@ foreign-key clash (`scripts/apply-models-migrations.sh:27-38`). ## Modules The subject requires **14 points** (Major = 2, Minor = 1). A module that cannot be demonstrated -live scores zero. Every row is graded by **one rule**, the one in osionos -[`docs/ai/README.md`](https://github.com/Univers42/osionos/blob/develop/docs/ai/README.md) (lines 7–8: a row is never A when its -demonstration needs something switched off or unmeasured): +live scores zero. Every row is graded by **one rule**, groot's own. It keeps the clause of osionos +[`docs/ai/README.md`](https://github.com/Univers42/osionos/blob/1c1d5d849c1dc43460a194f7ee3d97e17505205c/docs/ai/README.md) +lines 7–8 (a row is never A when its demonstration needs something switched off or unmeasured), +but it is stricter than that file's legend, which grades a documented profile A: - **A**: the demo works on the default stack (`make all SKIP_SYNC=1`, nothing switched on), and a green CI job drives that path against a running service. @@ -563,7 +564,7 @@ demonstration needs something switched off or unmeasured): **Claimed = A and B only: 23 points against the 14 required. 6 of them are A.** Paths are prefixed by repository: `G` groot, `GB` grobase (`apps/grobase`), `OS` osionos (`apps/osionos/app`), `OO` opposite-osiris (`apps/opposite-osiris`). They point at the commits -groot `develop` pins. CI names a workflow job: `GB-CI` is grobase `ci.yml`, `OS-CI` is osionos +pinned by groot's `develop` branch. CI names a workflow job: `GB-CI` is grobase `ci.yml`, `OS-CI` is osionos `ci.yml`. | # | Module | Category | Type | Pts | Grade | Core files | Tests → CI job | Docs | Demo (3 steps) | From e3791f05343c3ed0eecc11c45e0d9ce3a8098536 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Wed, 4 Nov 2026 23:18:41 +0100 Subject: [PATCH 05/22] docs(wiki): give the AI audit one status, Superseded The notice said Superseded while the status block still said Partial, and the blank line between the two blockquotes tripped MD028. Merge them into one block that states the current status and the original one. --- wiki/project/ai-audit-2026-10-28.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/project/ai-audit-2026-10-28.md b/wiki/project/ai-audit-2026-10-28.md index 4051308dc..df9a89d96 100644 --- a/wiki/project/ai-audit-2026-10-28.md +++ b/wiki/project/ai-audit-2026-10-28.md @@ -4,8 +4,8 @@ > `1c1d5d84`, which ships `services/osionos-ai` (745 files) and #270. The "0 of 10 AI points" > line no longer holds. The current grades are in the [README Modules table](../../README.md#modules), > and the LLM interface is explained in [ai-llm-interface](ai-llm-interface.md). - -> **Status:** Partial · 2026-10-28 +> +> **Status:** Superseded · 2026-11-04 (written as Partial · 2026-10-28) > **Evidence:** read-only `git grep` / `git ls-tree` against named refs (commands at the bottom); > no test suite and no AI container was run for this page > **To check:** every line marked ⟨unverified⟩; the five open questions at the end From 3902ff4f4e0035c9572a1c2deed0db7fc6d41a9d Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:01 +0100 Subject: [PATCH 06/22] docs(readme): name the project Prismatica and build the defense stack from main The README still called the project Track Binocle and described a stack that had moved on (README-R1 audit, 2026-11-04). - Title and intro say Prismatica; a naming note keeps track-binocle in the infrastructure identifiers that scripts and certificates depend on. - Defense bring-up checks out main. `git describe --tags --abbrev=0 origin/main` returned v1.0.0-rc5 while v1.1.1 exists, so it did not name the defense build. - Description and Instructions take the audit's corrections: grobase is about a third of the code by lines, the auth-gateway is Node, the WAF fronts Kong, hydrawn is a product, make all runs with SKIP_SYNC=1. - Debian 13 is cited to the born2root VM (docker/Dockerfile:14, generate/create_custom_iso.sh:120). The 2026-10-08 trust-store transcript and the snap revision anecdote are dropped: nothing in the repository records them. --- README.md | 152 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 82959f271..8dbf9ae80 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,18 @@ *This project has been created as part of the 42 curriculum by dlesieur, serjimen, danfern3, vjan-nie, shashemi.* -# Track Binocle — ft_transcendence +# Prismatica — ft_transcendence -**Track Binocle** is a collaborative workspace built on top of our own self-hostable -Backend-as-a-Service. Users sign up on a public site, land in **osionos** — a Notion-style block -editor with real-time collaboration, chat and video rooms — and can connect their Gmail and -Google Calendar. Every one of those apps is served by **grobase**, a generic backend that the team -wrote in Go, Rust and TypeScript, and which contains no application-specific code. +**Prismatica** is a collaborative workspace built on our own self-hostable Backend-as-a-Service. +Users sign up on the public **prismatica** site, land in **osionos** — a Notion-style block editor +with real-time collaboration, chat and video rooms — and can connect their Gmail and Google +Calendar. Every one of those apps is served by **grobase**, a generic backend that the team wrote +in Go, Rust and TypeScript, with no per-application server code. + +> Naming: *Prismatica* is the project; *osionos* is the workspace app; *prismatica* +> (`apps/opposite-osiris`, repository [`Univers42/prismatica`](https://github.com/Univers42/prismatica)) +> is the marketing landing. Infrastructure identifiers keep the old codename `track-binocle` +> (the compose project, image names, `TRACK_BINOCLE_*` variables, `*.track-binocle.test` hosts, +> the local CA file): renaming them would break scripts and issued certificates. --- @@ -38,40 +44,46 @@ code** — and to prove it by building a real product on it. The project therefore has two halves: -- **grobase** (roughly 70% of the work) — a Backend-as-a-Service. An application is declared in a - JSON *contract* (its database, isolation strategy, roles, permissions and API keys); a generic - provisioner creates everything from that file. Routes carry no domain logic: a request names the - table it targets, and access rules are stored as data, not code. -- **The products** that run on it — a marketing and authentication site, the osionos editor, and - mail and calendar integrations. +- **grobase** — a Backend-as-a-Service (about 290,000 lines of Go, Rust and TypeScript at its + pin, roughly a third of the code the team wrote; lines include tests). An application is + declared in a JSON *contract* (its database, isolation strategy, roles, permissions and API + keys); a generic provisioner creates everything from that file. Routes carry no domain + logic: a request names the table it targets, and access rules are stored as data, not code. +- **The products** that run on it — the prismatica landing and sign-in site, the osionos + workspace, the hydrawn whiteboard, and mail and calendar integrations. ### Overview | Product | Tech | What it is | |---|---|---| -| **opposite-osiris** | Astro | Public site: landing page, sign-up / sign-in, legal pages. The entry point. | +| **prismatica** (`apps/opposite-osiris`) | Astro | Public site: landing page, docs, sign-up / sign-in, legal pages. The entry point. | | **osionos** | React + Vite | The block editor: pages, databases-as-blocks, real-time collaboration, chat, video rooms. **The flagship.** | | **mail** | React + Vite | Gmail integration over Google OAuth | | **calendar** | React + Vite | Google Calendar integration over Google OAuth | +| **hydrawn** | SvelteKit + Fastify + Rust/WASM | Collaborative whiteboard, embedded in osionos | -These four products are supported by four platform services (not applications in their own -right): the **auth-gateway** (Go, sessions), the **osionos-bridge** (turns a site session into an -editor session), **Kong** (the single API gateway in front of grobase) and **LiveKit** (the WebRTC -media server for video rooms). +These products are supported by platform services (not applications in their own right): the +**auth-gateway** (Node, shipped by the prismatica repository: sessions and sign-in), the +**osionos-bridge** (Node: turns a site session into an editor session), **Kong** (grobase's API +gateway, behind its WAF) and **LiveKit** (the WebRTC media server for video rooms). ### Key features - **Contract-driven backend.** A whole application — database, isolation, roles, keys, frontend configuration — is one JSON file. `POST /v1/tenants/me/apps` creates a new isolated application - with its own database and scoped API key. -- **Per-request owner isolation.** The Rust data plane scopes every query to its owner on every - request; permissions are rows (ABAC/RBAC), not `if` statements. -- **One API over many databases.** PostgreSQL, MySQL, MongoDB, Redis, SQLite, MSSQL, DynamoDB and - even remote HTTP APIs are queried through the same envelope and the same API key. + with its own database and scoped API key (mounted only when `APPS_SELFSERVE_ENABLED` is on). +- **Per-request owner isolation.** The Rust data plane scopes queries to their owner on each + request, not by connection-pool state; permissions are rows (RBAC, plus flag-gated ABAC + conditions), not `if` statements. +- **One API over many databases.** PostgreSQL, MySQL (MariaDB image), MongoDB, Redis, SQLite, + SQL Server and even remote HTTP APIs are queried through the same envelope and the same API + key. DynamoDB is an opt-in build, left out of the default one + ([`wiki/platform/08-engines.md`](wiki/platform/08-engines.md)). - **Collaborative editor.** Block-based pages, a database block with table / board / calendar views, real-time co-editing, channels and direct messages, video rooms. -- **Single-command deployment.** `make all` builds and starts the whole stack in Docker, serves - every frontend over trusted local HTTPS, and health-checks it. +- **Single-command deployment.** `make all SKIP_SYNC=1` builds the pinned commits in Docker, + starts the backend and the frontends over local HTTPS with a trusted CA, and health-checks + them (`utils/mk/pipeline.mk:10`). --- @@ -81,14 +93,14 @@ media server for video rooms). | Requirement | Detail | Source | |---|---|---| -| **Linux host** | Tested on Debian 13; the CA-trust step uses `sudo` + `update-ca-certificates` | `utils/mk/certs.mk` | +| **Linux host** | Tested on Debian 13 (trixie), the system the born2root VM installs; the CA-trust step uses `sudo` + `update-ca-certificates` | `vendor/born2root/docker/Dockerfile:14`, `vendor/born2root/generate/create_custom_iso.sh:120`; `utils/mk/certs.mk` | | **Docker Engine ≥ 25** + **Compose v2** | Healthchecks use `start_interval`, which needs Docker 25. Tested with Docker 29.8. | `docker-compose.yml:10` | -| **RAM ≥ 8 GB** | Measured: the VM peaked at ~6.5 GB of 8 GB during `make all` | measured, 2026-09-30 | +| **RAM ≥ 8 GB** | Measured: the VM peaked at ~6.5 GB of 8 GB during `make all` | `wiki/runbooks/fresh-machine.md` (6266 MiB peak, v1.0.0-rc4, 2026-10-05) | | **Disk ≥ 30 GB free for Docker** | Measured on the dev VM with the stack running (`docker system df`, 2026-10-01): images 13.5 GB, build cache 9.5 GB, volumes 1.4 GB | measured | -| **GNU Make, git, curl, openssl** | Make drives everything; curl runs the health check; openssl generates the local secrets | `utils/mk/app.mk`, `scripts/gen-local-env.sh:68` | +| **bash, GNU Make, git, curl, openssl, ssh** | Make drives everything; curl runs the health check; openssl generates the local secrets | `utils/mk/app.mk:12-15`, `scripts/gen-local-env.sh:253` | | **A GitHub SSH key** | `.gitmodules` uses `git@github.com:` URLs, so the recursive clone needs SSH access to GitHub | `.gitmodules` | -| **Google Chrome** | Current stable — the browser the project is evaluated on | | -| `certutil` (optional) | Imports the local CA into the browsers' NSS stores. Absent, `make certs-trust-user` unpacks `libnss3-tools` into `~/.cache/born2root/nss` without root; if that fails it warns and exits 0, and the CA is imported by hand (see [Access](#access-and-the-local-ca)) | `scripts/certs-trust-user.sh` | +| **Google Chrome** | Current stable — the browser the project is evaluated on | [`wiki/project/01-subject.md`](wiki/project/01-subject.md) | +| `certutil` (optional) | Imports the local CA into the browsers' NSS stores. Absent, `make certs-trust-user` unpacks `libnss3-tools` into `~/.cache/born2root/nss` without root (Debian only: it needs `apt-get` and `dpkg-deb`, bounded at 120 s); if that fails it warns and exits 0, and the CA is imported by hand (see [Access](#access-and-the-local-ca)) | `scripts/certs-trust-user.sh` | **Nothing else is installed on the host** — no Node, npm, Go or Cargo. Everything builds and runs in containers. @@ -101,25 +113,25 @@ sudo, `CERT_TRUST_MODE=user` trusts the browsers only and `skip` trusts nothing **Ports bound on the host** (from `docker-compose.yml`, all on `127.0.0.1` except inside a QEMU/VirtualBox NAT VM, where `infrastructure/scripts/detect-bind-addr.sh` binds `0.0.0.0` so the host can reach the guest): 443, 3001, 3002, 3003, 3007 (always loopback), 4000, 4100, 4200, 4322, -4323 and 7880 (always loopback: plain HTTP), 7881, 8444, 8787 and UDP 50000–50060. grobase adds Kong on `127.0.0.1:8000` -(literal loopback in its `orchestrators/compose/base/gateway.yml`). +4323 and 7880 (always loopback: plain HTTP), 7881, 8444, 8446 (always loopback: the IDE edge), +8787 and UDP 50000–50060. A busy port moves to the next free one (`scripts/host-ports.sh`). +grobase adds Kong on `127.0.0.1:8000` (literal loopback in its +`orchestrators/compose/base/gateway.yml:56`; its WAF is the public entry). ### Defense bring-up (pinned) -This is the path rehearsed on a clean machine. It checks out the release tag and does **not** -follow submodule branch tips (`SKIP_SYNC=1`, see `sync-submodules-soft` in -`utils/mk/pipeline.mk`). +This is the path rehearsed on a clean machine, and the stack the [Modules](#modules) are graded +on. It builds `main` and the submodule commits `main` pins, and does **not** follow submodule +branch tips (`SKIP_SYNC=1`, see `sync-submodules-soft` in `utils/mk/pipeline.mk`). ```bash git clone --recursive git@github.com:Univers42/groot.git cd groot -git checkout "$(git describe --tags --abbrev=0 origin/main)" +git checkout main git submodule update --init --recursive make all SKIP_SYNC=1 ``` -The `git checkout` line checks out the latest release tag on `main`; `git tag -l 'v*'` lists them. - Requirements, the VM + host-browser case, the verify script (`scripts/verify/fresh-bringup.sh`) and troubleshooting: [`wiki/runbooks/fresh-machine.md`](wiki/runbooks/fresh-machine.md). @@ -132,13 +144,16 @@ demo rows to the app's API key (`make link-live-data-ensure`) and trusts the local CA in this user's browser stores (`make certs-trust-user`, no sudo). Both end with `make link-verify`: one request per grobase service from inside every frontend, the TLS edge, then the browser stores — [`wiki/runbooks/grobase-link.md`](wiki/runbooks/grobase-link.md). -To serve the frontends to the internet through this host's Tailscale Funnel (443 first, then -8443 and 10000), `make public-env` and `make public-up`; `make public-down` closes it: +To serve the frontends to the internet through this host's Tailscale Funnel (443; add 8443 and +10000 with `PUBLIC_PORTS=all`), `make public-env` and `make public-up`; `make public-down` +closes it: [`wiki/runbooks/public-funnel.md`](wiki/runbooks/public-funnel.md). `make roundtrip` then proves persistence (account, sign-in, editor hand-off, a page, the rows in postgres) and `make link-e2e` runs the Playwright smoke through the link. -Measured time from a cold machine: **9–17 minutes**. +Measured time from a cold machine: **9–17 minutes** (8m55s on a fresh VM, 16m44s on a laptop, +2026-09-30, [`wiki/STATUS.md`](wiki/STATUS.md); later runs in +[`wiki/runbooks/fresh-machine.md`](wiki/runbooks/fresh-machine.md)). No `.env` needs to be written by hand. With no vault key present, grobase generates its own secrets into `apps/grobase/.env`, and `env-local-ensure` derives the root `./.env.local` from it, @@ -148,7 +163,11 @@ including random `OSIONOS_*` secrets and the demo account's `DEMO_LOGIN_PASSWORD `make all` runs, in order (`utils/mk/pipeline.mk`): submodule sync → secrets → local TLS certificates → trust the local CA → grobase backend → derive `.env.local` → restore -data if the engines are empty → set the demo account's password → SQL migrations → frontends → health check → URL list. +data if the engines are empty → set the demo account's password → SQL migrations → live-data key +and owner fix → mount re-encryption → frontends → health check → URL list. On a machine that +holds vault42 credentials, `make all` deploys against the data-center VM instead and starts no +local grobase (ADR 0047, [`wiki/runbooks/datacenter.md`](wiki/runbooks/datacenter.md)); +`make all GROBASE_DATACENTER=` forces the local path. ### Development bring-up @@ -159,7 +178,8 @@ make all Without `SKIP_SYNC=1`, `make all` first fast-forwards every submodule to the tip of its tracked branch (`sync-submodules-soft`), so you build the newest code rather than the pinned commits. -It skips dirty submodules and never blocks the pipeline. +It skips dirty submodules, and leaves at its recorded commit any submodule whose branch tip does +not contain that commit; it never blocks the pipeline. The exception is any submodule that `.gitmodules` marks `update = none`, today `apps/graph_render`. Its gitlink is the build input, so neither mode moves it: @@ -201,7 +221,7 @@ are in [ADR 0016](docs/adr/0016-self-documenting-pruned-root-make.md). | Service | URL | |---|---| -| opposite-osiris (start here) | `https://localhost:4322` | +| prismatica site (start here) | `https://localhost:4322` | | osionos editor | `https://localhost:3001` | | Whiteboard (hydrawn) | `https://localhost:3007` | | mail (opt-in) | `https://localhost:3002` | @@ -226,8 +246,9 @@ store (one `sudo`) and every browser store this user owns, through `scripts/cert and the flatpak locations. It matches old copies by the CA's subject, not by nickname, replaces them, and adds the current file as "Track Binocle Local Development CA". -- `make certs-trust-check` prints one line per store (`ok|FAIL current|stale|missing`) - and exits 1 if any store is not current. Without `certutil` it fails. +- `make certs-trust-check` prints one line per store + (`ok|FAIL current|stale|missing|untrusted`) and exits 1 if any store is not + current. Without `certutil` it fails. - `make certs-trust-user` fixes the stores without sudo; it mints the CA first only if it is missing. - `CERT_TRUST_MODE=system|user|skip` (or `TRACK_BINOCLE_CERT_TRUST`) picks what `certs-trust-local` does: system store plus browsers (default), browsers only, or nothing. @@ -239,20 +260,11 @@ osionos stays blank**, because the embedded `:3007` iframe is refused silently. warning while `curl --cacert` succeeds: - **The CA was regenerated.** `make certs` on a fresh tree mints a new CA, and a store still holding - an older copy does not trust it. On 2026-10-08 the CA was regenerated at 17:06 and 7 stores were - stale and 1 missing: - - ```text - $ make certs-trust-check - FAIL chrome /home/dlesieur/.pki/nssdb stale - FAIL chrome /home/dlesieur/snap/chromium/current/.pki/nssdb stale - FAIL firefox /home/dlesieur/snap/firefox/common/.mozilla/firefox/pqdn9c63.default-release-1 stale - FAIL firefox /home/dlesieur/.var/app/org.mozilla.firefox/config/mozilla/firefox/2vgnvz7b.default missing - [certs] 8 browser store(s) do not hold the current CA; run: make certs-trust-user, then relaunch the browser - ``` + an older copy does not trust it. `make certs-trust-check` then reports those stores `stale`, and + `make certs-trust-user` replaces the old copy. - **A snap refresh.** Snap Chromium's `HOME` is the revision directory behind - `~/snap/chromium/current`, so a new revision (3507 to 3551 overnight) starts without the store. + `~/snap/chromium/current`, so a new revision starts without the store. `make certs-trust-check` reports it missing; `make certs-trust-user` recreates it. Flatpak Firefox profiles can exist without the flatpak installed; they are imported too, harmlessly. @@ -273,7 +285,7 @@ certificates → Authorities → Import, or run `make certs-trust`. Honest limitations of this demo: board editing is **loopback-only** and has **no per-user authorization yet** — hydrawn is bound to `127.0.0.1:3007` for exactly that reason -(`docker-compose.yml:27-32`). We make **no end-to-end-encryption claim**: traffic is TLS to the +(`docker-compose.yml:35-40`). We make **no end-to-end-encryption claim**: traffic is TLS to the local proxy, nothing more. ### Environment configuration @@ -285,14 +297,18 @@ local proxy, nothing more. - `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET` — default to a local dev value; video rooms still work. - `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` in `apps/mail/.env.local` and `apps/calendar/.env.local` — without them, the mail and calendar OAuth flows are disabled. - - `SONAR_TOK`, `FLY_API_TOKEN`, `DOCKER_PAT` — CI and operations only. + - `SONAR_TOK`, `FLY_API_TOKEN`, `DOCKER_PAT` — operator tooling only (a local SonarCloud scan, + the Fly deploy, a Docker Hub login); CI uses its own repository secrets. ### Team setup (with the vault) Inside the team, secrets are shared through **vault42**, our zero-knowledge secret store, via the -**42ctl** CLI. A machine that holds a vault identity in `~/.config/42ctl/` pulls the whole `.env` -tree automatically during `make all` (or with `make vault42-pull-all APPLY=1`). A new identity is -created with `42ctl keys init` and enrolled with an invitation from the vault's operator. +**42ctl** CLI. A machine that holds a vault identity in `~/.config/42ctl/` pulls the `.env` +tree during `make all` when `apps/grobase/.env` is absent (`secrets-ensure`), or on demand with +`make vault42-pull-all APPLY=1`. With the vault passphrase also present, `make all` deploys +against the data-center VM instead (see [Defense bring-up](#defense-bring-up-pinned)). A new +identity is created with `42ctl keys init` and enrolled with an invitation from the vault's +operator. Details: [`DATA-MIGRATION.md`](DATA-MIGRATION.md). The vault42 CLI is wired in beside that path: the `Secrets (vault42)` section of `make help`, and @@ -303,23 +319,23 @@ checklist: [ADR 0017](docs/adr/0017-vault42-cli-beside-the-old-path.md). | Command | What it does | |---|---| -| `make all` | Full lifecycle: certs → backend → frontends → health check → URLs | +| `make all` | Full lifecycle: secrets → certs → backend → env → data → migrations → frontends → health check → URLs | | `make healthcheck` | Probe backend, site, editor, bridge, auth gateway and whiteboard | | `make showcase` | Print the URL list for what is actually running | -| `make pulls` | Update all submodules | +| `make pulls` | Fetch and pull the root repository and every submodule | | `make -C apps/grobase editions` | List the available backend shapes | -| `make all GROBASE_EDITION=full` | Bring up everything, including extra engines and monitoring | +| `make all GROBASE_EDITION=full` | Bring up every grobase plane except the playground demo UI, including extra engines and monitoring | | `docker compose ps` | Service status | | `docker compose logs -f ` | Follow one service's logs | | `docker compose down` | Stop the frontends (data is kept) | **Backend editions.** `make all` starts grobase in the **`devlean`** edition (`GROBASE_EDITION ?= devlean` in `utils/mk/grobase.mk`; listed in grobase's -`orchestrators/makes/00-config.mk:68`): the core engines (PostgreSQL, MySQL, MongoDB, Redis, +`orchestrators/makes/00-config.mk:148-154`): the core engines (PostgreSQL, MySQL, MongoDB, Redis, MinIO), the full application / control / data planes and realtime — without the heavy extra engines and without the monitoring stack. `GROBASE_EDITION=migrate` adds every snapshot engine; -`GROBASE_EDITION=full` turns everything on. Some module demonstrations need a larger edition or a -feature flag — see [Modules](#modules). +`GROBASE_EDITION=full` turns on every plane except the playground demo. Some module +demonstrations need a larger edition or a feature flag — see [Modules](#modules). --- From f1c5a46c18843a5b849757db582f496a8ef6164b Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:01 +0100 Subject: [PATCH 07/22] docs(readme): state "nobody indispensable" as the aim and measure it Project Management claimed shared ownership that the history does not show yet. It now states the aim and publishes how far the team got: 86 % of human commits by one author, one author over half the commits in 17 of 18 areas, 0-22 % second-person approvals in a sample of recent PRs. Sprints are two weeks long since the start (team account); the repositories record no milestone or sprint label, which the section says. Team Information drops its open marker: no responsibility beyond development is recorded for shashemi. --- README.md | 80 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 8dbf9ae80..2d0fc7188 100644 --- a/README.md +++ b/README.md @@ -352,9 +352,7 @@ The "Areas in the history" column is what each member's commits touch | Daniel Fernández | `danfern3` | [@danielfdez17](https://github.com/danielfdez17) | Tech Lead · Developer | Architecture, stack decisions, code quality, reviews | monkey-bot (security test bot), grobase Docker and Kubernetes deployment, osionos editor fixes | | Sergio Jiménez de la Cruz | `serjimen` | [@DjSurgeon](https://github.com/DjSurgeon) | Developer | Frontend, secrets management, deployment | the public site (opposite-osiris), osionos accessibility and editor features | | Vadim Jan Nieto | `vjan-nie` | [@vjan-nie](https://github.com/vjan-nie) | Project Manager · Developer | Planning, tracking, communication, unblocking | QA tooling, end-to-end tests, documentation, Docker | -| Seyed Mostafa Hashemian | `shashemi` | [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) | Developer | TO CONFIRM by the team | security fixes and SAST, the site's legal pages, TLS edge | - -> TO CONFIRM by the team: `shashemi`'s responsibilities. +| Seyed Mostafa Hashemian | `shashemi` | [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) | Developer | No responsibility beyond development is recorded | security fixes and SAST, the site's legal pages, TLS edge | `rstancu` (Roxana Stancu, [@esettes](https://github.com/esettes)) is on the original roster ([`archive/wiki-2026-09/CONTRIBUTORS.md`](archive/wiki-2026-09/CONTRIBUTORS.md)) and committed @@ -364,37 +362,57 @@ between 2026-03-18 and 2026-05-02; see [Who committed where](#who-committed-wher ## Project Management -What the repository records: - -- **Task tracking:** GitHub Issues on [`Univers42/groot`](https://github.com/Univers42/groot/issues) - and on each submodule's repository; milestones (M1 hardening, M2 federation, M3 coherence, - M4 observability, M5 security, M11 external-app integration) in - [`archive/wiki-2026-09/todo/`](archive/wiki-2026-09/todo/). -- **Tools:** GitHub — pull requests, Dependabot for dependency updates - ([`.github/dependabot.yml`](.github/dependabot.yml)), GitHub Actions for CI - ([`.github/workflows/`](.github/workflows/)). -- **Branch model:** work lands on short-lived `feat/`, `fix/`, `docs/`, `test/` and `chore/` - branches, merged into `develop` by pull request; `develop` is merged into `main` by pull request - (`git log --merges --format=%s | grep 'pull request'`). -- **Code workflow:** submodule-based monorepo — changes are committed inside a submodule first, - then the root records the new commit. Numbered **verification gates** - (`apps/grobase/scripts/verify/run-gate-battery.sh`) are the team's definition of "done": - grobase's CI runs named gates on pull requests and the full `--enterprise` battery, with a - nightly schedule (grobase `.github/workflows/ci.yml`). - -What the team confirmed (2026-11-04), which the repository cannot show: +Part of this project was an experiment in managing a team. We ran it as if it were a demanding, +high-output professional team, with a Scrum mindset in which every member is treated as an +expert and anyone may change anyone's code. The aim was that **nobody is indispensable**. The +evidence below separates what the repositories record from what is the team's own account, and +the last part measures how far we got towards that aim. -- **Communication channel:** Discord. -- **Meeting rhythm:** a weekly meeting. +**How the tracking evolved.** Work started in February 2026: the first commits by `dlesieur`, +`danfern3` and `vjan-nie` date from that month (`git log --reverse` across the submodules). +Between then and the autumn the team tried GitHub Projects, Jira tickets and Notion pages +(team account: none of the three left a trace in commit messages, and the Projects board was not +readable with our token). The only written trace is osionos +[`docs/DoD.md:39`](https://github.com/Univers42/osionos/blob/develop/docs/DoD.md), a +Definition-of-Done template that asks for evidence "in your Pull Request description or your +Trello/Jira" ticket (2026-04-11). -What the repository does not record: +**How it works now: issues, labels and pull requests on GitHub.** -- **Task distribution and code review:** not recorded beyond the merged pull requests per login - ([Who committed where](#who-committed-where)). - -> TO CONFIRM by the team: who attended the weekly meeting and where its decisions were written. - -> TO CONFIRM by the team: who assigned work, and who reviewed whose pull requests. +| Practice | What the repositories record (2026-11-04) | +|---|---| +| Issues | 129 on osionos, 38 on groot, 20 on prismatica, 16 on grobase (`gh issue list --state all`). Branches and commits name them: `fix/issue-278-database-probe-diagnostics` (osionos #284), `fixes #N` in 40 commit messages across groot, grobase, osionos and prismatica | +| Labels | Triage labels `priority: high`, `subject-blocker` and `account-platform` on groot and osionos, plus GitHub's defaults (`gh label list`) | +| Pull requests | 144 on groot, 182 on osionos, 78 on grobase, 50 on prismatica; merged into `develop`, and `develop` promoted to `main` by a merge commit | +| Peer review | Since 2026-09-21 (grobase, hydrawn) and up to 2026-11-04 (groot `develop`), a GitHub ruleset on each main repository requires one approving review and forbids force-pushes and branch deletion (`gh api repos//rulesets`). CodeRabbit reviews every PR since 2026-10-23 | +| Stacked branches | Feature chains merged one on top of another: groot #84–#87 (`feat/ide-*`), grobase #69–#70 (`feat/multidb-g1b…g1d`), the osionos `release/acct-w1` … `w9` series | +| Commit rhythm | At least one commit on 174 of the 232 days between 2026-03-18 and 2026-11-04, across all repositories | + +**Strict CI from the start.** CI arrived within days of each repository's first commit: grobase +`ci.yml` on 2026-03-29, osionos on 2026-04-12, groot on 2026-05-13. SonarCloud is configured in +groot since 2026-05-04 and comments on its pull requests since #9 (2026-06-01). Security scans +(Semgrep, Trivy, gitleaks, TruffleHog, ZAP, cargo-audit, govulncheck) run on every pull request, +and groot rejects one-word commit subjects (`.github/workflows/commit-subjects.yml`). + +**Rituals.** Two-week sprints since the start, daily stand-ups and a weekly meeting, mostly on +Discord (team account, confirmed 2026-11-04; Discord leaves no trace in the repositories). The +method was Scrumban (Scrum rituals plus a Kanban board), as described in +[`docs/dossier-project-dylan/dossier-projet.md:390-416`](https://github.com/Univers42/osionos/blob/develop/docs/dossier-project-dylan/dossier-projet.md) +in osionos. + +**How far we got.** We publish these numbers so the claims above can be checked: + +- **Sprints.** The sprints were planned outside GitHub: no milestone and no sprint label exists + in any repository. Merges come in bursts: 250 of the 442 merged pull requests on the six main + repositories landed in two weeks (ISO weeks 43–44). +- **Review.** The rulesets let a maintainer bypass them, and in a sample of the 40 most recent + merged pull requests per repository, 0–22 % carry an approval from someone other than the + author. +- **Nobody indispensable.** Shared ownership is real in breadth: `vjan-nie` committed in 12 areas + and `shashemi` in 8, osionos has six authors with five or more commits, and prismatica's main + author is `serjimen`. In depth we are not there yet: `dlesieur` wrote 86 % of the 8,571 human + commits, and in 17 of 18 areas one author holds more than half of the commits. Commit counts + are not effort: one large commit and a typo fix weigh the same. --- From 090cc2981e7193b9142c2baf23a71756646046c6 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:01 +0100 Subject: [PATCH 08/22] docs(readme): recount the Features List at main's pins The Who column mixed counts from all branches and from before the 2026-11-04 history rewrite. Every row is now counted one way: non-merge commits reachable from the commit groot main pins, through .mailmap, bots and AI-agent identities left out. Adds rows for two-factor authentication, the AI assistant and the whiteboard, which are claimed modules or default products. Drops the claim that OTP and collaboration are on in the public stack, which nothing here verifies. Technical Stack and Database Schema take the audit's corrections (Astro 7, no Radix import, legacy-node services, seven skipped migrations). --- README.md | 101 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 2d0fc7188..2810a852b 100644 --- a/README.md +++ b/README.md @@ -422,13 +422,14 @@ in osionos. | Technology | Used in | Why | |---|---|---| -| **Astro 6** + **Sass** | opposite-osiris | Mostly static marketing content: Astro ships near-zero JavaScript by default and pre-renders pages, which keeps the public site fast. | +| **Astro 7** + **Sass** | prismatica (`apps/opposite-osiris`) | Mostly static marketing content: Astro ships near-zero JavaScript by default and pre-renders pages, which keeps the public site fast. | | **React 19** + **Vite 6** + **TypeScript** | osionos, mail, calendar | A block editor is a heavily interactive UI; React's component model fits, and Vite gives fast builds. | -| **Tailwind CSS 4**, **Radix UI**, **lucide-react** | osionos | Utility-first styling framework plus accessible, unstyled primitives for menus and popovers. | +| **Tailwind CSS 4**, **lucide-react** | osionos | Utility-first styling framework and an icon set. | | **Zustand** | osionos | Small, explicit client state store. | -| **Zod** | osionos | Schema validation of user input on the client side. | +| **Zod 4** | osionos | Schema validation: the diagram spec on the client, and the inputs of the AI service and the MCP server. | | **livekit-client** | osionos | WebRTC video rooms. | -| **Playwright** | osionos | End-to-end browser tests. | +| **Playwright** | osionos, groot `tests/e2e/` | End-to-end browser tests. | +| **SvelteKit**, **Fastify**, **Rust → WebAssembly** | hydrawn | The whiteboard: a WASM drawing engine with its own API and realtime services. | | **Tailwind CSS 4** | mail, calendar | `src/styles.css` imports Tailwind's theme and utilities through `@tailwindcss/vite`, without preflight; the app's own rules sit on top. | ### Backend — grobase @@ -440,43 +441,47 @@ independently — each written in the language that suits it. |---|---|---|---| | **Control plane** | **Go** | Provisioning, tenancy, identity (`POST /v1/keys/verify` turns an API key into an identity) | Long-running, concurrent I/O; a provisioner needs to be correct and readable, not fast. | | **Data plane** | **Rust** | Executes every query, applies per-owner scoping and ABAC locally | The hot path: predictable latency with no GC pauses, and memory safety where a bug would be a cross-tenant data leak. | -| **Realtime plane** | **Rust** | Turns data changes into events; WebSocket subscriptions | Same reasons; pluggable event bus. | -| **Application plane** | **TypeScript / NestJS** | Query and storage routers, schema, session, permissions, email, GDPR services | The original backend, progressively replaced by the Go and Rust planes. | -| **Auth** | **GoTrue** + Go **auth-gateway** | Sign-up, sign-in, sessions, email OTP | Battle-tested auth server rather than a hand-rolled one. | -| **Gateway** | **Kong** | The only public entry to the backend; key auth and rate limiting | Keeps every internal service off the public network. | -| **Media** | **LiveKit** | WebRTC SFU for video rooms | | +| **Realtime plane** | **Rust** | Turns data changes into events; WebSocket subscriptions (an opt-in profile, included in the `devlean` edition `make all` starts) | Same reasons; pluggable event bus. | +| **Application plane** | **TypeScript / NestJS** | Query and storage routers, schema service, permission engine. The older session, email and GDPR services remain only under the `legacy-node` profile; the Go orchestrator does their work | The original backend, progressively replaced by the Go and Rust planes. | +| **Auth** | **GoTrue** (grobase) + a Node **auth-gateway** (shipped by prismatica) | Sign-up, sign-in, sessions, email OTP, the hand-off to osionos | Battle-tested auth server rather than a hand-rolled one. | +| **Gateway** | **WAF** (nginx + ModSecurity/OWASP CRS) in front of **Kong** | The WAF is the public entry; Kong behind it does key auth and rate limiting | Keeps every internal service off the public network. | ### Database -- **PostgreSQL** is the primary database: the control-plane registries (tenants, roles, policies, +- **PostgreSQL 16** is the primary database: the control-plane registries (tenants, roles, policies, API keys) and all application data (see [Database Schema](#database-schema)). **Why:** row-level security (RLS), JSONB for block content and flexible properties, strong transactional guarantees, and a mature ecosystem. RLS is what makes per-owner isolation enforceable inside the database itself, not only in application code. -- **MySQL, MongoDB, Redis, MinIO** (object storage) run in the default edition; **SQLite, MSSQL, - DynamoDB** and remote **HTTP** APIs are supported through the same data-plane interface. This is a +- **MySQL, MongoDB, Redis, MinIO** (object storage) run in the `devlean` edition that `make all` + starts; **SQLite**, **SQL Server** (needs the `engines` plane), **DynamoDB** (an opt-in build) + and remote **HTTP** APIs are supported through the same data-plane interface. This is a deliberate feature of the platform (one API over many engines), not a need of osionos itself. ### Other significant technologies - **Docker / Docker Compose** — every component runs in a container; one `make all`. - **A local certificate authority + TLS proxy** — all frontends served over trusted HTTPS locally. +- **LiveKit** — the WebRTC SFU for video rooms, a groot compose service started by `make all`; + the osionos bridge mints its tokens. - **vault42 / 42ctl** — our own zero-knowledge secret store and CLI (separate repositories). - **CI security scanning** — on every pull request, [`.github/workflows/mini-baas-security.yml`](.github/workflows/mini-baas-security.yml) - runs Semgrep (SAST), `npm`/`pnpm audit`, Snyk (when a token is set) and Trivy; Dependabot - opens dependency updates. `sonar-project.properties` and `renovate.json` are present, but no - workflow in this repository runs them. + runs Semgrep (SAST), `npm`/`pnpm audit`, Snyk (when a token is set) and Trivy; Semgrep and Snyk + report without blocking. Dependabot opens dependency updates. SonarCloud analyses every pull + request through its GitHub app (`.sonarcloud.properties`), not through a workflow; + `renovate.json` is present but nothing runs it. ### Justification of the major choices - **Why build a BaaS instead of a single backend?** Because the same backend pieces are rebuilt for every project. We moved everything that varies between projects — routes, schemas, access rules, configuration — from code into data, so a new application is a contract, not a server. -- **Why three languages?** Each plane has a different job. Go for boring, correct orchestration; +- **Why three languages?** Each grobase plane has a different job (Node also runs the site's + auth-gateway and the osionos bridge). Go for boring, correct orchestration; Rust where performance and memory safety protect tenant isolation; TypeScript where it already - existed. The data plane was migrated from TypeScript to Rust behind a per-request switch with a - *shadow mode* (Rust computes and discards results for comparison), so the migration needed no - downtime and could be rolled back without a deployment. + existed. The data plane was migrated from TypeScript to Rust behind a per-request switch + (`RUST_DATA_PLANE_FORWARD`, on in the default compose), so the migration needed no downtime + and could be rolled back without a deployment. - **Why per-request isolation?** Scoping on every request (instead of per connection) means a pooled connection can never carry one user's permissions into another user's query. @@ -489,9 +494,11 @@ The schema lives in two places: 1. **Application schema** — idempotent SQL migrations in [`models/`](models/) (`*-migration.sql`), applied to grobase's PostgreSQL by `make all` through [`scripts/apply-models-migrations.sh`](scripts/apply-models-migrations.sh). That runner - deliberately skips the files written for the auth gateway's own database (`user.sql`, - `gdpr-migration.sql`, `auth-security-migration.sql`, `rls-hardening-migration.sql`, `seeds.sql`); - its header explains why. + deliberately skips seven files that target a database with an integer `users.id` (used by + the Electron native edition) or that later files supersede: `user.sql`, `gdpr-migration.sql`, + `auth-security-migration.sql`, `rls-hardening-migration.sql`, `seeds.sql`, + `osionos-folder-surface-migration.sql` and `osionos-wiki-surface-migration.sql`; its header + explains why. 2. **Platform schema** — grobase's control-plane registries (tenants, mounts, roles, policies, API keys), created by grobase's own migrations, plus per-application databases created at runtime from each contract (e.g. `infra/config/contracts/website.schema.sql` in grobase). @@ -539,7 +546,7 @@ erDiagram osionos_channels { uuid id PK uuid workspace_id FK - text kind "text | dm | voice | video" + text kind "text | dm | voice | video | group" text name boolean is_private jsonb abac @@ -561,19 +568,20 @@ Other table groups, by migration file: | Area | Tables | Migration | |---|---|---| | Users & sessions (auth gateway DB) | `users`, `sessions`, `user_activities`, `user_tokens` | `user.sql` | -| Auth security & GDPR (auth gateway DB) | `auth_audit_events`, `gdpr_requests`, `user_consents`, `newsletter_optins` | `auth-security-migration.sql`, `gdpr-migration.sql` | +| Auth security & GDPR | `auth_audit_events`, `gdpr_requests`, `user_consents`, `newsletter_optins` | `auth-security-migration.sql`, `gdpr-migration.sql` (integer-id flavour); `auth-audit-events-migration.sql`, `newsletter-optin-migration.sql` (applied to grobase) | | Site ↔ editor bridge | `osionos_bridge_identities`, `osionos_bridge_audit_events` | `osionos-bridge-migration.sql` | -| Social & communities | `osionos_communities`, `osionos_community_members`, `osionos_community_channels`, `osionos_connections`, `osionos_user_blocks`, `osionos_user_reports`, `osionos_feed_*` | `osionos-communities-`, `-social-`, `-feed-engagement-migration.sql` | +| Social & communities | `osionos_communities`, `osionos_community_members`, `osionos_community_channels`, `osionos_connections`, `osionos_user_blocks`, `osionos_user_reports`, `osionos_feed_*` | `osionos-communities-`, `-social-`, `-chat-`, `-feed-engagement-migration.sql` | | Databases-as-blocks | `osionos_object_databases`, `osionos_workspace_databases`, `osionos_app_connections` | `osionos-object-databases-`, `-workspace-databases-`, `-app-connections-migration.sql` | | Publishing & sharing | `osionos_published_pages`, `osionos_share_rules`, `osionos_page_links` | `osionos-publish-`, `-share-rules-`, `-page-links-migration.sql` | -| Tasks & notifications | `osionos_tasks`, `osionos_notifications`, `osionos_push_subscriptions` | `osionos-tasks-`, `-push-migration.sql` | +| Tasks & notifications | `osionos_tasks`, `osionos_notifications`, `osionos_push_subscriptions` | `osionos-tasks-`, `-engagement-`, `-push-migration.sql` | | Mail & calendar | `mail_accounts`, `mail_messages`, `calendar_accounts`, `calendar_sources`, `calendar_event_cache` | `mail-migration.sql`, `calendar-migration.sql` | ### Platform (grobase) registries Access control is stored as data: `roles`, `user_roles` and `resource_policies` tables, evaluated by the SQL function `public.has_permission(...)` and mirrored by the Rust data plane's own ABAC -evaluator. Every table generated by grobase receives an `owner_id` column automatically, which is +evaluator. Every table created through grobase's schema API gets an `owner_id` column +appended when the caller does not declare one (contract schemas declare it themselves), which is what makes one isolation rule apply to any table. **Two `users` tables.** `models/user.sql` defines `users.id` as `SERIAL` (integer): it belongs to @@ -585,28 +593,33 @@ foreign-key clash (`scripts/apply-models-migrations.sh:27-38`). ## Features List -"Who" lists the authors of the commits that touch the feature's code, largest share first, with -the count (`scripts/contributors.sh --paths ...`; the paths are in the last column). -A commit count is not effort, and pairing or review does not show in it. +"Who" counts the non-merge commits that touch the feature's paths (last column), reachable from +the commit groot `main` pins for that repository, read through the root [`.mailmap`](.mailmap), +with bots and AI-agent identities left out; largest share first. How the identities are joined: +[`wiki/project/contributions-method.md`](wiki/project/contributions-method.md). A commit count is +not effort, and pairing or review does not show in it. | Feature | Description | Who (commits) | Paths counted | |---|---|---|---| -| Sign-up / sign-in | Email and password (hashed and salted) on the public site; email OTP enabled in production with real SMTP | dlesieur 11, serjimen 1 | opposite-osiris `src/pages/auth`, `src/pages/api/auth` | -| Site → editor handoff | After login, a one-time bridge session hands the user to osionos (`/api/auth/bridge/consume`) — no token in a query string | dlesieur 4 | osionos `scripts/bridge-auth*` | +| Sign-up / sign-in | Email and password on the public site, stored hashed by GoTrue; an email-OTP second step is off by default (`AUTH_LOGIN_EMAIL_OTP`) | dlesieur 9, serjimen 1 | opposite-osiris `src/pages/auth`, `src/pages/api/auth` | +| Site → editor handoff | After login, a one-time bridge session hands the user to osionos (`/api/auth/bridge/consume`) — the one-time token travels in the URL fragment and is redeemed once by `POST`, never in a query string | dlesieur 4 | osionos `scripts/bridge-auth*` | | Legal pages | Privacy Policy, Terms of Service, Cookie Policy, Data Rights, linked from the site | shashemi 5, vjan-nie 3, serjimen 2, dlesieur 2 | opposite-osiris `src/pages/legal` | -| Block editor | Pages built from blocks, nested pages, templates, covers, favourites, search | dlesieur 162, vjan-nie 42, danfern3 29, serjimen 14, rstancu 9, shashemi 2 | osionos `src/features/block-editor` | -| Database block | A block that is a database, with table / board / calendar views over any mounted data source | dlesieur 126, vjan-nie 2, serjimen 2, rstancu 2 | osionos `src/widgets/database*`, `src/features/*database*`, `src/shared/database*` | -| Real-time collaboration | Several users editing the same space live, over the protected `collab:` channel | dlesieur 46, shashemi 1 | osionos `src/features/collab`, `scripts/bridge-*collab*` | -| Chat | Workspace channels and direct messages, reactions, mentions, attachments, read receipts | dlesieur 72, vjan-nie 1 | osionos `src/features/chat`, `src/features/group-chat`, `scripts/bridge-*chat*` | -| Video rooms | LiveKit-based video channels inside workspaces | dlesieur 13 | osionos `scripts/bridge-*livekit*`, `src/**/*livekit*`, `src/**/*Video*` | -| Comments, sharing, publishing | Page comments, share rules, public page publishing | dlesieur 44 | osionos `src/features/comments`, `src/features/share`, `scripts/bridge-*publish*`, `scripts/bridge-*share*` | -| Communities & social feed | Communities, connections, feed with likes, comments and shares; blocking and reporting | dlesieur 38, serjimen 2 | osionos `src/features/communities`, `src/features/connections`, `scripts/bridge-*social*`, `scripts/bridge-*feed*` | -| Mail | Read Gmail inside the workspace via Google OAuth | dlesieur 35 | `apps/mail` | -| Calendar | Google Calendar events via Google OAuth | dlesieur 18 | `apps/calendar` | +| Block editor | Pages built from blocks, nested pages, templates, covers, favourites, search | dlesieur 164, vjan-nie 42, danfern3 29, rstancu 9, serjimen 8, shashemi 2 | osionos `src/features/block-editor` | +| Database block | A block that is a database, with table, board and calendar views over any mounted data source (the views live in the `notion-database-sys` submodule, `src/components/views/`) | dlesieur 125, vjan-nie 2, rstancu 2, shashemi 1, serjimen 1 | osionos `src/widgets/database*`, `src/features/*database*`, `src/shared/database*` | +| Real-time collaboration | Several users editing the same space live, over the protected `collab:` channel. Off in the default local build; `VITE_OSIO_COLLAB_SHARED=1` turns it on (osionos `src/shared/config/featureFlags.ts:73`) | dlesieur 45, shashemi 2 | osionos `src/features/collab`, `scripts/bridge-*collab*` | +| Chat | Workspace channels and direct messages, reactions, mentions, attachments, unread markers; new messages arrive over grobase's realtime WebSocket | dlesieur 72, vjan-nie 1 | osionos `src/features/chat`, `src/features/group-chat`, `scripts/bridge-*chat*` | +| Video rooms | LiveKit-based video channels inside workspaces | dlesieur 11, shashemi 1 | osionos `src/widgets/video-room`, `scripts/bridge-rtc*` | +| Comments, sharing, publishing | Page comments, share rules, public page publishing | dlesieur 45 | osionos `src/features/comments`, `src/features/share`, `scripts/bridge-*publish*`, `scripts/bridge-*share*` | +| Communities & social feed | Communities, connections, feed with likes, comments and shares; blocking and reporting | dlesieur 37, serjimen 2, shashemi 1 | osionos `src/features/communities`, `src/features/connections`, `scripts/bridge-*social*`, `scripts/bridge-*feed*` | +| Two-factor authentication and passkeys | TOTP codes and passkeys on the account | dlesieur 15 | osionos `scripts/bridge-account-mfa*`, `scripts/bridge-account-passkeys*`, `src/features/settings/profile/TwoFactorModal.tsx` | +| AI assistant | Streaming answers, retrieval over the workspace with citations, moderation, dictation and read-aloud; started with `--profile ai` | dlesieur 317, vjan-nie 9, shashemi 1 | osionos `services/osionos-ai`, `src/features/ai` | +| Whiteboard | Shared boards in osionos's Whiteboard tab; strokes reach every open copy of the board live | dlesieur 569, danfern3 20, shashemi 6, vjan-nie 4 | hydrawn, whole repository | +| Mail | Read Gmail inside the workspace via Google OAuth. Opt-in: `make mail-up` and Google OAuth credentials | dlesieur 39 | `apps/mail`, whole repository | +| Calendar | Google Calendar events via Google OAuth. Opt-in: `make calendar-up` and Google OAuth credentials | dlesieur 22 | `apps/calendar`, whole repository | | Contract-driven provisioning | One JSON contract → isolated database, roles, keys and frontend `.env` | dlesieur 9 | grobase `scripts/provision-contract.sh`, `infra/config/contracts` | -| Self-serve applications | `POST /v1/tenants/me/apps` creates a new isolated app with its own database and key | dlesieur 33 | grobase `src/control-plane/internal/tenants` | -| Multi-engine data API | One API and one key over PostgreSQL, MySQL, MongoDB, SQLite, MSSQL, DynamoDB, Redis, HTTP | dlesieur 99, vjan-nie 3 | grobase `src/data-plane-router` | -| Public API | Key-authenticated, rate-limited API behind Kong, documented with OpenAPI at `/docs/` | dlesieur 41, vjan-nie 1 | grobase `infra/docker/services/kong`, `infra/config/openapi` | +| Self-serve applications | `POST /v1/tenants/me/apps` creates a new isolated app with its own database and key, behind `APPS_SELFSERVE_ENABLED` (off unless set) | dlesieur 32 | grobase `src/control-plane/internal/tenants` | +| Multi-engine data API | One API and one key over PostgreSQL, MySQL, MongoDB, Redis (default edition), SQLite, SQL Server (`engines` plane), HTTP and DynamoDB (opt-in build) | dlesieur 95, vjan-nie 3 | grobase `src/data-plane-router` | +| Public API | Key-authenticated, rate-limited API behind Kong, documented with OpenAPI at `/docs/` on the `:8444` edge | dlesieur 64, vjan-nie 5, shashemi 1 | grobase `infra/docker/services/kong`, `infra/config/openapi`; groot `infrastructure/tls/nginx.conf` | --- From b6d6f14ddc09098d8038b2c084090eefca76f65b Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:01 +0100 Subject: [PATCH 09/22] docs(readme): grade 19 modules on main's local stack, 30 points, 8 A The table graded against develop's pins and left out three Majors develop had claimed. Every row is now graded by the one rule against the stack built from main (git checkout main, make all SKIP_SYNC=1, devlean). - Row 3 (WebSockets) demos live chat, on by default (osionos wsTransport.ts:81); collaboration is off by default. Its A rests on m201 driving /ws on a running realtime in grobase "Integration Tests". - Framework for frontend and backend: A (osionos Browser tests, grobase Integration Tests, both green at the pins). - Interact with other users and Standard user management: B, unit tests with fakes only. - OAuth: B, needs Google provider credentials. - Rows renumbered 1-19; the points table is recomputed with free choice capped at 3: 21 catalogue + 3 choice + 6 AI = 30. --- README.md | 76 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 2810a852b..8e3669a19 100644 --- a/README.md +++ b/README.md @@ -626,68 +626,77 @@ not effort, and pairing or review does not show in it. ## Modules The subject requires **14 points** (Major = 2, Minor = 1). A module that cannot be demonstrated -live scores zero. Every row is graded by **one rule**, groot's own. It keeps the clause of osionos +live scores zero. Every row is graded against **the local stack built from `main`** +(`git checkout main`, `make all SKIP_SYNC=1`, which starts grobase's `devlean` edition; see +[Defense bring-up](#defense-bring-up-pinned)) by **one rule**, groot's own. It keeps the +clause of osionos [`docs/ai/README.md`](https://github.com/Univers42/osionos/blob/1c1d5d849c1dc43460a194f7ee3d97e17505205c/docs/ai/README.md) lines 7–8 (a row is never A when its demonstration needs something switched off or unmeasured), but it is stricter than that file's legend, which grades a documented profile A: -- **A**: the demo works on the default stack (`make all SKIP_SYNC=1`, nothing switched on), and a - green CI job drives that path against a running service. -- **B**: it works, but the demo needs something switched on (a flag, a profile, an edition), or - its only evidence is unit tests with fakes or a run that was never repeated. +- **A**: the demo works on that stack with nothing switched on, and a green CI job drives that + path against a running service. +- **B**: it works, but the demo needs something switched on (a flag, a profile, an edition, a + provider credential), or its only evidence is unit tests with fakes or a run that was never + repeated. - **C**: partial. **Not claimed.** These rows are listed under [Not claimed yet](#not-claimed-yet). -**Claimed = A and B only: 23 points against the 14 required. 6 of them are A.** +**Claimed = A and B only: 30 points against the 14 required. 8 of them are A.** Paths are prefixed by repository: `G` groot, `GB` grobase (`apps/grobase`), `OS` osionos (`apps/osionos/app`), `OO` opposite-osiris (`apps/opposite-osiris`). They point at the commits -pinned by groot's `develop` branch. CI names a workflow job: `GB-CI` is grobase `ci.yml`, `OS-CI` is osionos -`ci.yml`. +pinned by groot's `main` branch. CI names a workflow job: `GB-CI` is grobase `ci.yml`, `OS-CI` +is osionos `ci.yml`, `OO-CI` is prismatica `ci.yml`. | # | Module | Category | Type | Pts | Grade | Core files | Tests → CI job | Docs | Demo (3 steps) | |---|---|---|---|--:|:--:|---|---|---|---| -| 1 | Public API (key, rate limit, docs, ≥5 endpoints) | Web | Major | 2 | **A** | `GB infra/docker/services/kong/conf/kong.yml:221-248` (`/rest/v1`: key-auth + rate-limiting); `GB infra/config/openapi/grobase-public.json` | `GB scripts/verify/m102-gateway-query-path.sh` → GB-CI "Integration Tests" (`ci.yml:927`) | `GB infra/config/openapi/README.md` | `make all SKIP_SYNC=1` → `/rest/v1` without `apikey` answers 401, with it 200 → repeat until 429 | +| 1 | Public API (key, rate limit, docs, ≥5 endpoints) | Web | Major | 2 | **A** | `GB infra/docker/services/kong/conf/kong.yml:221-245` (`/rest/v1`: key-auth + rate-limiting); `GB infra/config/openapi/grobase-public.json` | `GB scripts/verify/m102-gateway-query-path.sh` → GB-CI "Integration Tests" (`ci.yml:927`) | `GB infra/config/openapi/README.md` | `make all SKIP_SYNC=1` → `/rest/v1` without `apikey` answers 401, with it 200 → repeat until 429 | | 2 | Backend as microservices | DevOps | Major | 2 | **A** | `GB orchestrators/compose/base/*.yml` (16 files); `GB orchestrators/makes/30-planes.mk:33`; `GB src/control-plane`; `GB src/data-plane-router` | GB-CI unit suites (`ci.yml:1436`) + "Engine conformance" legs (`ci.yml:1532`) | [`wiki/platform/02-planes.md`](wiki/platform/02-planes.md) | `make -C apps/grobase planes` → `docker compose ps` → `make healthcheck` | -| 3 | Real-time features via WebSockets | Web | Major | 2 | **A** | `GB infra/docker/services/realtime/realtime-agnostic/crates/realtime-auth/src/jwt/mod.rs:90-94`; `GB kong.yml:314-315` (`/realtime/v1/ws`); `OS scripts/bridge-collab.mjs:626` | GB-CI `rust-realtime` suite (`ci.yml:1436`), live gates m184, m189, m201 (`ci.yml:735,855,1479`) | [`wiki/platform/05-realtime.md`](wiki/platform/05-realtime.md) | two browsers on one page → type in one → the other updates | -| 4 | Real-time collaboration | Web | Minor | 1 | **B** | `OS src/features/collab/model/{remoteCursors,collabPresence,blockSync}.ts`; `OS scripts/bridge-collab.mjs:626` | `OS tests/bridge/bridge-collab-*` (9) → OS-CI "quality (root)" Bridge tests (`ci.yml:291`); `G tests/e2e/specs/dw8-realtime.spec.ts` (run by hand) | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | as row 3 → watch the remote cursor and presence → edit the same block from both | -| 5 | Advanced permissions | User management | Major | 2 | **B** | `OS scripts/bridge-roles.mjs:28-29`; `OS scripts/bridge-share-rules.mjs:38`; `OS scripts/bridge-page-access.mjs:217`; `OS src/features/admin-users/api.ts` | `OS tests/bridge/bridge-page-access*` (7), `bridge-share-rules-*` (2) → OS-CI Bridge tests | [`wiki/platform/07-isolation.md`](wiki/platform/07-isolation.md) | sign in as admin → change a member's role → that member loses access | -| 6 | Organisation system | User management | Major | 2 | **B** | `OS scripts/bridge-workspace-teams.mjs:229`; `OS scripts/bridge-workspace-invites.mjs:134`; `OS src/features/settings/teamspaces/TeamspacesPanel.tsx` | `OS tests/bridge/bridge-workspace-*` (7) → OS-CI Bridge tests | [`wiki/platform/06-contracts.md`](wiki/platform/06-contracts.md) | create a workspace → create a teamspace → invite a user, who accepts | -| 8 | Health/status page, backups, disaster recovery | DevOps | Minor | 1 | **B** | `GB infra/docker/services/status-page/{server,availability}.py`; `GB orchestrators/compose/base/ops.yml`; `GB scripts/verify/m241-status-backup-recovery.sh` | m241 → GB `operational-reliability.yml:27`; m192 → GB-CI (`ci.yml:582`), **red on grobase `develop`** ([run 41870904860](https://github.com/Univers42/grobase/actions/runs/41870904860)) | [`wiki/operations/04-troubleshooting.md`](wiki/operations/04-troubleshooting.md) | bring up the `ops` plane (not in the default edition) → open the status page → stop a container, then `m241 --live` | -| 9 | GDPR compliance | Data | Minor | 1 | **B** | `OS scripts/bridge-account-export.mjs:143`; `OS scripts/bridge-account-erasure.mjs:79`; `OS src/features/settings/ui/AccountExportSection.tsx`; `OS src/features/settings/ui/danger/AccountDangerZone.tsx` | `OS tests/bridge/bridge-account-export*` (3), `bridge-account-erasure` (1) → OS-CI Bridge tests; `G models-grants.yml` | [`wiki/security/01-model.md`](wiki/security/01-model.md) | Settings › export my data → open the archive → delete the account | -| 10 | Two-factor authentication | User management | Minor | 1 | **B** | `OS scripts/bridge-account-mfa-totp.mjs:68`; `OS scripts/bridge-account-mfa.mjs:187`; `OS scripts/bridge-account-passkeys.mjs:100`; `OS src/features/settings/profile/TwoFactorModal.tsx` | `OS tests/bridge/bridge-account-mfa-*` (6), `bridge-account-passkeys` (1) → OS-CI Bridge tests | osionos `docs/account-platform` | enable TOTP → sign out → sign in with the code | -| 13 | **Module of choice:** contract-driven application factory | Free choice | Major | 2 | **B** | `GB src/control-plane/internal/tenants/selfserve_apps.go:55-58`; `GB src/control-plane/cmd/tenant-control/mount_appsselfserve.go:26`; `GB scripts/verify/m177-selfserve-apps.sh` | m176 → GB-CI (`ci.yml:192`); **m177 in no workflow** | [`wiki/platform/06-contracts.md`](wiki/platform/06-contracts.md), [justification](#justification--module-of-choice-major-contract-driven-application-factory) | set `APPS_SELFSERVE_ENABLED` (empty by default) → OTP login, `POST /v1/tenants/me/apps` twice → one app's key reads the other: 4xx | -| 14 | **Module of choice:** SSRF guard on the HTTP engine | Free choice | Minor | 1 | **B** | `GB src/data-plane-router/crates/data-plane-pool/src/dial_guard/classify.rs:91-127`; `GB src/data-plane-router/crates/data-plane-pool/src/http/validate.rs:83-98` | `GB …/dial_guard/classify_tests.rs` → GB-CI `rust-data-plane` + "Engine conformance (http)" | [`wiki/security/04-network.md`](wiki/security/04-network.md), [justification](#justification--module-of-choice-minor-ssrf-guard-on-the-http-engine) | mount an `http` source at `169.254.169.254` → query it → refused. Whether the default edition mounts the `http` engine is unverified (guess: it does not) | -| 15 | Complete LLM system interface: text, streaming, error handling, rate limiting. Images exist but are **off by default** and not part of this claim | Artificial Intelligence | Major | 2 | **B** | osionos `services/osionos-ai/src/routes/runs.ts:178-324`, `src/runs/{runner,upstream,upstreamError,streamPump}.ts`, `src/rateLimit.ts:84`, `src/http.ts:108-129`; client `src/features/ai/model/runStream.ts`. All 12 hops: [`wiki/project/ai-llm-interface.md`](wiki/project/ai-llm-interface.md) | `services/osionos-ai/tests/{runs,complete,upstreamError*,runRateLimit,failover,quotaFailover}.test.ts` → OS-CI "AI service (tsc + suite)" (`ci.yml:314`); `tests/canvas/ai-{chat-store,run-dispatch,run-stream}.test.ts` → "quality (root)" Canvas unit tests (`ci.yml:285`) | [`wiki/project/ai-llm-interface.md`](wiki/project/ai-llm-interface.md), [`wiki/runbooks/osionos-ai.md`](wiki/runbooks/osionos-ai.md), [M1 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m1-images.md) | `docker compose --profile ai up -d --build` → ask a question and watch it stream → reload mid-answer (it resumes), or stop it | -| 16 | Complete RAG on a large dataset | Artificial Intelligence | Major | 2 | **B** | osionos `services/osionos-ai/src/retrieval/search.ts:277,469,564`, `src/retrieval/rerank.ts:16`; `G models/osionos-ai-rag-migration.sql:60,91` | `services/osionos-ai/tests/{retrieval,aclAgreement,rerank}.test.ts` → OS-CI AI service | [M2 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m2-rag.md), osionos `services/osionos-ai/eval/wiki/RESULTS-rag.md` | `--profile ai` → ask a workspace question → click a citation, then show the 110 363-chunk measurement (run on a separate eval stack; the reranker is off by default) | +| 3 | Real-time features via WebSockets | Web | Major | 2 | **A** | `GB infra/docker/services/realtime/realtime-agnostic/crates/realtime-server/src/server.rs:243` (`/ws`); `GB kong.yml:314-315` (`/realtime/v1/ws`); `OS scripts/bridge-social-core.mjs:192-201` (the bridge publishes); `OS src/services/realtime-messages/wsTransport.ts:81` (chat over the socket, on whenever a session exists) | `GB scripts/verify/m201-realtime-issuer.sh` opens `/ws` on the running realtime and expects `AUTH_OK` → GB-CI "Integration Tests" (`ci.yml:855`); m189 (`ci.yml:735`); `rust-realtime` suite and m184 (`ci.yml:1436,1479`) | [`wiki/platform/05-realtime.md`](wiki/platform/05-realtime.md) | sign in as two users in two browsers → open the same direct message in both → a message sent in one appears in the other without a reload. A second default demo: two windows on one Whiteboard board, where each stroke appears in the other (`G tests/e2e/specs/dw8-realtime.spec.ts`, `make e2e`, run by hand) | +| 4 | Use a framework for both the frontend and backend | Web | Major | 2 | **A** | Frontend: React 19 (`OS package.json:105-106`). Backend: axum 0.7 (`GB src/data-plane-router/Cargo.toml:59`; `GB infra/docker/services/realtime/realtime-agnostic/Cargo.toml:44`) | React: OS-CI "Browser tests", Playwright against the served app in 6 shards (`ci.yml:338-339`); axum: GB-CI "Integration Tests" (`ci.yml:652-653`) runs the data plane and realtime built from the pin | [`wiki/platform/02-planes.md`](wiki/platform/02-planes.md) | `make all SKIP_SYNC=1` → `docker compose ps` lists `mini-baas-data-plane-router-rust` and `mini-baas-realtime` (`GB orchestrators/compose/base/data-plane.yml:28,178`) → open osionos at `https://localhost:3001` | +| 5 | Allow users to interact with other users (chat, profile, friends) | Web | Major | 2 | **B** | `OS scripts/bridge-chat.mjs`; `OS scripts/bridge-account-profile.mjs`; `OS scripts/bridge-social.mjs`; `OS src/features/chat`; `OS src/features/connections` | `OS tests/canvas/chat-catch-up.test.ts` → OS-CI "quality (root)" Canvas unit tests (`ci.yml:285`); `OS tests/bridge/bridge-chat-reply-notify`, `bridge-account-profile`, `bridge-social-connections`, `bridge-connection-transitions` → Bridge tests (`ci.yml:291`). Unit tests with fakes: no CI job drives two users against a running stack | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | as row 3 → user A sends a friend request, user B accepts → each opens the other's profile | +| 6 | Standard user management and authentication | User management | Major | 2 | **B** | `OS scripts/bridge-account-profile.mjs`; `OS scripts/bridge-avatar.mjs`; `OS scripts/bridge-presence.mjs`; `OS src/features/collab/model/collabPresence.ts:63` (initials when there is no avatar) | `OS tests/bridge/bridge-avatar` (upload, type and size refusal), `bridge-presence` (online status), `bridge-account-profile` → OS-CI Bridge tests (`ci.yml:291`). Unit tests with fakes | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | sign up on `https://localhost:4322` → upload an avatar and edit the profile → a friend sees you online | +| 7 | Real-time collaboration | Web | Minor | 1 | **B** | `OS src/features/collab/model/{remoteCursors,collabPresence,blockSync}.ts`; `OS scripts/bridge-collab.mjs:626`; `GB …/realtime-auth/src/jwt/mod.rs:90-94` (`collab:` closed to wildcard tokens) | `OS tests/bridge/bridge-collab-*` (9) → OS-CI Bridge tests (`ci.yml:291`) | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | rebuild osionos with `VITE_OSIO_COLLAB_SHARED=1` (off by default) → two browsers on one page → watch the remote cursor and edit the same block from both | +| 8 | Advanced permissions | User management | Major | 2 | **B** | `OS scripts/bridge-roles.mjs:28-29`; `OS scripts/bridge-share-rules.mjs:38`; `OS scripts/bridge-page-access.mjs:217`; `OS src/features/admin-users/api.ts` | `OS tests/bridge/bridge-page-access*` (7), `bridge-share-rules-*` (2) → OS-CI Bridge tests | [`wiki/platform/07-isolation.md`](wiki/platform/07-isolation.md) | sign in as admin → change a member's role → that member loses access | +| 9 | Organisation system | User management | Major | 2 | **B** | `OS scripts/bridge-workspace-teams.mjs:229`; `OS scripts/bridge-workspace-invites.mjs:134`; `OS src/features/settings/teamspaces/TeamspacesPanel.tsx` | `OS tests/bridge/bridge-workspace-*` (7) → OS-CI Bridge tests | [`wiki/platform/06-contracts.md`](wiki/platform/06-contracts.md) | create a workspace → create a teamspace → invite a user, who accepts | +| 10 | Remote authentication with OAuth 2.0 | User management | Minor | 1 | **B** | `OO scripts/auth/oauth-providers.mjs`; `OO scripts/auth/oauth-link.mjs`; `OO src/scripts/portal-oauth.ts`; `GB orchestrators/compose/base/auth-api.yml:64-67` (GoTrue's Google provider) | `OO tests/unit/auth/oauth-providers`, `oauth-link`, `gateway-oauth-{start,link,collision}` (5) → OO-CI "Quality Gate" `pnpm test` (`ci.yml:31-32`) | `OO docs/adr/0002-oauth-link-existing-account.md` | set `GOOGLE_OAUTH_ENABLED=true`, `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` for grobase (Google provider credentials, not shipped) → `make all SKIP_SYNC=1` → "Continue with Google" on `https://localhost:4322` | +| 11 | Health/status page, backups, disaster recovery | DevOps | Minor | 1 | **B** | `GB infra/docker/services/status-page/{server,availability}.py`; `GB orchestrators/compose/base/ops.yml`; `GB scripts/verify/m241-status-backup-recovery.sh` | m241 → GB `operational-reliability.yml:27`; m192 → GB-CI (`ci.yml:582`), **red on grobase `develop`** ([run 41870904860](https://github.com/Univers42/grobase/actions/runs/41870904860)) | [`wiki/operations/04-troubleshooting.md`](wiki/operations/04-troubleshooting.md) | bring up the `ops` plane (not in the default edition) → open the status page → stop a container, then `m241 --live` | +| 12 | GDPR compliance | Data | Minor | 1 | **B** | `OS scripts/bridge-account-export.mjs:143`; `OS scripts/bridge-account-erasure.mjs:79`; `OS src/features/settings/ui/AccountExportSection.tsx`; `OS src/features/settings/ui/danger/AccountDangerZone.tsx` | `OS tests/bridge/bridge-account-export*` (3), `bridge-account-erasure` (1) → OS-CI Bridge tests; `G .github/workflows/models-grants.yml` | [`wiki/security/01-model.md`](wiki/security/01-model.md) | Settings › export my data → open the archive → delete the account | +| 13 | Two-factor authentication | User management | Minor | 1 | **B** | `OS scripts/bridge-account-mfa-totp.mjs:68`; `OS scripts/bridge-account-mfa.mjs:187`; `OS scripts/bridge-account-passkeys.mjs:100`; `OS src/features/settings/profile/TwoFactorModal.tsx` | `OS tests/bridge/bridge-account-mfa-*` (5), `bridge-account-passkeys` (1) → OS-CI Bridge tests | osionos `docs/account-platform` | enable TOTP → sign out → sign in with the code | +| 14 | **Module of choice:** contract-driven application factory | Free choice | Major | 2 | **B** | `GB src/control-plane/internal/tenants/selfserve_apps.go:55-58`; `GB src/control-plane/cmd/tenant-control/mount_appsselfserve.go:26`; `GB scripts/verify/m177-selfserve-apps.sh` | m176 → GB-CI (`ci.yml:192`, static leg, in the Shellcheck job); m176 and m177 → groot `modules-of-choice.yml:39-40`, static mode only | [`wiki/platform/06-contracts.md`](wiki/platform/06-contracts.md), [justification](#justification--module-of-choice-major-contract-driven-application-factory) | set `APPS_SELFSERVE_ENABLED` (empty by default) → OTP login, `POST /v1/tenants/me/apps` twice → one app's key reads the other: 4xx | +| 15 | **Module of choice:** SSRF guard on the HTTP engine | Free choice | Minor | 1 | **B** | `GB src/data-plane-router/crates/data-plane-pool/src/dial_guard/classify.rs:90-155`; `GB src/data-plane-router/crates/data-plane-pool/src/http/validate.rs:83-153` | `GB …/dial_guard/classify_tests.rs` → GB-CI `rust-data-plane` + "Engine conformance (http)" | [`wiki/security/04-network.md`](wiki/security/04-network.md), [justification](#justification--module-of-choice-minor-ssrf-guard-on-the-http-engine) | mount an `http` source at `169.254.169.254` → query it → refused. Whether the default edition mounts the `http` engine is unverified (guess: it does not) | +| 16 | Complete LLM system interface: text, streaming, error handling, rate limiting. Images exist but are **off by default** and not part of this claim | Artificial Intelligence | Major | 2 | **B** | osionos `services/osionos-ai/src/routes/runs.ts:178-324`, `src/runs/{runner,upstream,upstreamError,streamPump}.ts`, `src/rateLimit.ts:84`, `src/http.ts:108-129`; client `src/features/ai/model/runStream.ts`. All 12 hops: [`wiki/project/ai-llm-interface.md`](wiki/project/ai-llm-interface.md) | `services/osionos-ai/tests/{runs,complete,upstreamError*,runRateLimit,failover,quotaFailover}.test.ts` → OS-CI "AI service (tsc + suite)" (`ci.yml:314`); `tests/canvas/ai-{chat-store,run-dispatch,run-stream}.test.ts` → "quality (root)" Canvas unit tests (`ci.yml:285`) | [`wiki/project/ai-llm-interface.md`](wiki/project/ai-llm-interface.md), [`wiki/runbooks/osionos-ai.md`](wiki/runbooks/osionos-ai.md), [M1 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m1-images.md) | `docker compose --profile ai up -d --build` → ask a question and watch it stream → reload mid-answer (it resumes), or stop it | +| 17 | Complete RAG on a large dataset | Artificial Intelligence | Major | 2 | **B** | osionos `services/osionos-ai/src/retrieval/search.ts:277,469,564`, `src/retrieval/rerank.ts:16`; `G models/osionos-ai-rag-migration.sql:60,91` | `services/osionos-ai/tests/{retrieval,aclAgreement,rerank}.test.ts` → OS-CI AI service | [M2 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m2-rag.md), osionos `services/osionos-ai/eval/wiki/RESULTS-rag.md` | `--profile ai` → ask a workspace question → click a citation, then show the 110 363-chunk measurement (run on a separate eval stack; the reranker is off by default) | | 18 | Content moderation AI | Artificial Intelligence | Minor | 1 | **B** | osionos `scripts/bridge-moderation-gate.mjs:70`; `services/osionos-ai/src/moderation/l1.ts:99` | `services/osionos-ai/tests/moderation*.test.ts` (4) → OS-CI AI service; `tests/bridge/bridge-moderation*` (5) → Bridge tests | [M4 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m4-moderation.md) | set `OSIONOS_MODERATION_ACTIONS=hold` and `OSIONOS_MODERATION_STATE=1` → post a toxic comment → it waits in the admin console (no auto-removal, by design) | -| 19 | Voice / speech | Artificial Intelligence | Minor | 1 | **B** | osionos `services/osionos-ai/src/routes/voice.ts:104`, `src/features/voice/ui/DictationButton.tsx`, `src/features/voice/model/readAloud.ts`; `G docker-compose.yml:777` | `services/osionos-ai/tests/voice.test.ts` → OS-CI AI service | [M5 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m5-voice.md) | `--profile ai`, with the speech model fetched into its volume → dictate into a page → read it aloud (read-aloud voices not measured yet) | +| 19 | Voice / speech | Artificial Intelligence | Minor | 1 | **B** | osionos `services/osionos-ai/src/routes/voice.ts:104`, `src/features/voice/ui/DictationButton.tsx`, `src/features/voice/model/readAloud.ts`; `G docker-compose.yml:788-790` | `services/osionos-ai/tests/voice.test.ts` → OS-CI AI service | [M5 sheet](https://github.com/Univers42/osionos/blob/develop/docs/ai/modules/m5-voice.md) | `--profile ai`, with the speech model fetched into its volume → dictate into a page → read it aloud (read-aloud voices not measured yet) | -The table skips the numbers 7, 11, 12, 17, 20 and 21. Those rows moved to the next table. +No separate framework Minor is claimed beside row 4. **Point calculation** (free choice is capped at 3, [`wiki/project/01-subject.md`](wiki/project/01-subject.md#points)) | | Before (2026-10) | After | |---|--:|--:| -| Catalogue modules claimed (rows 1–12) | 18 | 14: 6 A (rows 1–3) + 8 B (rows 4–6, 8–10) | -| Modules of choice (rows 13–14, cap 3) | 3 | 3, all B | -| Artificial Intelligence modules (rows 15–21) | 10 | 6, all B (rows 15, 16, 18, 19) | -| **Total claimed** | **31 listed** | **23 (A + B)** | -| Of which A | 10 | **6** | +| Catalogue modules claimed (rows 1–13) | 18 | 21: 8 A (rows 1–4) + 13 B (rows 5–13) | +| Modules of choice (rows 14–15, cap 3) | 3 | 3, all B | +| Artificial Intelligence modules (rows 16–19) | 10 | 6, all B | +| **Total claimed** | **31 listed** | **30 (A + B)** | +| Of which A | 10 | **8** | | Required | 14 | 14 | -What moved: rows 1–4, 13 and 14 were A under the old legend ("works as-is"). Under one rule, -the rows that need a switch or have only unit-level evidence are B: rows 4, 13 and 14. The six -rows below no longer count. +What moved: under the old legend ("works as-is"), six rows were A. Under one rule, the rows +whose demonstration needs a switch or whose only evidence is unit-level are B: real-time +collaboration (off by default), the contract factory and the SSRF guard. Row 3 stays A on the +chat demo, which needs nothing switched on, and row 4 is new at A. The rows below no longer +count. ### Not claimed yet | Module | Was | Why it is not claimed, in one line | |---|---|---| -| Remote authentication (OAuth 2.0), User management, Minor | 1, B | The opposite-osiris commit groot pins (`ea8836db`) is on no branch and has no `scripts/auth/oauth-providers.mjs`. Claim it after the opposite-osiris pin bump | | Monitoring with Prometheus + Grafana, DevOps, Major | 2, C | The default edition ships no observability plane, and its gate m85 runs in no workflow | | File upload and management, Web, Minor | 1, C | Avatars and page files upload (`OS scripts/bridge-media.mjs:160`), but no general file manager is verified, and gate m159 runs in no workflow | | ML recommendation system, AI, Major | 2, B | Needs 20+ real users, the offline numbers are synthetic, and the `osionos-ml` Python tests run in no CI | | Sentiment analysis, AI, Minor | 1, C | The model licence is undeclared | -| Image recognition and tagging, AI, Minor | 1, C | The browser flow is unverified. Locally the VLM starts with `--profile ai` (`G docker-compose.yml:993-995`); `--profile ai-vlm` exists only in `docker-compose.public.yml:207` | +| Image recognition and tagging, AI, Minor | 1, C | The browser flow is unverified. Locally the VLM starts with `--profile ai` (`G docker-compose.yml:1004-1006`); `--profile ai-vlm` exists only in `docker-compose.public.yml:211-212` | | AI opponent, AI | — | osionos has no game | | Multiple languages, Accessibility | — | `i18next` is a dependency (osionos `package.json:92`), but no source file imports it and no translation resource exists | @@ -699,8 +708,7 @@ rows below no longer count. database, apply its schema, create roles and policies, mint scoped API keys and emit the frontend's `PUBLIC_*` configuration — idempotently, on every boot. The self-serve endpoint `POST /v1/tenants/me/apps` does it on demand, with a fresh `CREATE DATABASE` per application. -- **Value.** A new application costs a contract instead of a new server. The public site and - vault42 are both provisioned this way in production. +- **Value.** A new application costs a contract instead of a new server. - **Why it deserves a Major.** It spans the Go control plane, the Rust data plane and the database layer, and it comes with isolation proofs: gate `m177` proves self-serve creation, and gate `m176` proves one application cannot read another's data (a foreign mount resolves to zero From 601dc410969318f87f91544fc73132386c88f63f Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:10 +0100 Subject: [PATCH 10/22] docs(readme): move the identity joins to the wiki and recount contributions Individual Contributions carried long identity notes and counts from all branches. The README keeps the two short tables, recounted at main's pins with the Features List's method; the joins (mailmap, rstancu, the shashemi alias, opencode, Space Bunny, unknown authors) move to wiki/project/contributions-method.md with the command that reproduces them. .mailmap gains the SMOSTAFAH1 noreply address without the numeric id, which split shashemi into two authors. Per-member feature counts follow the new Features List; paragraphs no longer cite old module row numbers. --- .mailmap | 3 +- README.md | 134 +++++++++------------------ wiki/README.md | 1 + wiki/STATUS.md | 1 + wiki/project/contributions-method.md | 72 ++++++++++++++ 5 files changed, 118 insertions(+), 93 deletions(-) create mode 100644 wiki/project/contributions-method.md diff --git a/.mailmap b/.mailmap index f8105ac12..ac4909da4 100644 --- a/.mailmap +++ b/.mailmap @@ -7,7 +7,7 @@ # git -C apps/grobase -c mailmap.file="$PWD/.mailmap" shortlog -sne --all # # Caveat: two author/email pairs mix two members and are resolved by inference, not by -# proof (see the README, "Individual Contributions"). A new address a member starts +# proof (see wiki/project/contributions-method.md). A new address a member starts # committing with shows up as an extra line until it is added here. # dlesieur @@ -42,6 +42,7 @@ Seyed Mostafa Hashemian (shashemi) <1.318674e+08+S Seyed Mostafa Hashemian (shashemi) # prismatica 93e6b65 by "La Cebolla" carries Signed-off-by: Seyed Mostafa Hashemian. Seyed Mostafa Hashemian (shashemi) +Seyed Mostafa Hashemian (shashemi) # rstancu, a member of the original team roster (archive/wiki-2026-09/CONTRIBUTORS.md), GitHub @esettes Roxana Stancu (rstancu) diff --git a/README.md b/README.md index 8e3669a19..e01d78796 100644 --- a/README.md +++ b/README.md @@ -731,28 +731,27 @@ count. ### Who committed where -Commits per member reachable from the commit groot pins for each repository, one line per person, -read through the root [`.mailmap`](.mailmap) (counted on 2026-11-04 at root `01654173`): - -```sh -git -C -c mailmap.file="$PWD/.mailmap" shortlog -sn # pins: git ls-tree HEAD apps vendor -``` +Non-merge commits per member reachable from the commit groot `main` pins for each repository, +read through the root [`.mailmap`](.mailmap), bots and AI-agent identities left out (counted on +2026-11-05 at `main` = `0bef3cb3`). The command, the identity joins and what is left out: +[`wiki/project/contributions-method.md`](wiki/project/contributions-method.md). Several members work almost only in submodules, so the root alone understates them. | Member | GitHub | root | osionos | grobase | opposite-osiris | hydrawn | mail | calendar | QA | monkey-bot | First → last commit | |---|---|--:|--:|--:|--:|--:|--:|--:|--:|--:|---| -| `dlesieur` | @LESdylan | 1577 | 3375 | 1569 | 126 | 676 | 42 | 27 | 1 | 2 | 2026-05-10 → 2026-11-04 | -| `danfern3` | @danielfdez17 | | 94 | 74 | 8 | 25 | | | 1 | 10 | 2026-03-24 → 2026-10-02 | -| `serjimen` | @DjSurgeon | | 81 | | 160 | | | | | | 2026-04-11 → 2026-10-29 | -| `vjan-nie` | @vjan-nie | 173 | 141 | 49 | 23 | 6 | | | 39 | | 2026-03-19 → 2026-11-01 | -| `shashemi` | @SMOSTAFAH1 | 59 | 18 | 18 | 59 | 9 | | | | | 2026-09-20 → 2026-11-02 | -| `rstancu` | @esettes | | 104 | | | | | | 2 | | 2026-03-18 → 2026-05-02 | - -Work that is not on a pinned commit does not show above: `danfern3`'s 44 root commits sit on -`fix/ci`, open as [#165](https://github.com/Univers42/groot/pull/165), and most of their 133 -monkey-bot commits are on branches the pin does not reach. A commit count is not effort: one -large commit and one typo fix weigh the same, and pairing and review do not show in it. +| `dlesieur` | @LESdylan | 1394 | 2469 | 1279 | 103 | 569 | 39 | 22 | 1 | 2 | 2026-04-05 → 2026-11-05 | +| `vjan-nie` | @vjan-nie | 136 | 119 | 29 | 12 | 4 | | | 38 | | 2026-03-19 → 2026-11-04 | +| `serjimen` | @DjSurgeon | | 82 | | 134 | | | | | | 2026-04-09 → 2026-11-03 | +| `danfern3` | @danielfdez17 | | 84 | 73 | 4 | 20 | | | 1 | 10 | 2026-03-18 → 2026-10-02 | +| `shashemi` | @SMOSTAFAH1 | 42 | 17 | 15 | 39 | 8 | | | | | 2026-09-20 → 2026-11-04 | +| `rstancu` | @esettes | | 90 | | | | | | 2 | | 2026-03-18 → 2026-05-02 | + +Dates are author dates in these nine repositories only. Work that is not on a pinned commit does +not show above: `danfern3`'s 44 root commits sit on `fix/ci`, open as +[#165](https://github.com/Univers42/groot/pull/165), and most of their 133 monkey-bot commits are +on branches the pin does not reach. A commit count is not effort: one large commit and one typo +fix weigh the same, and pairing and review do not show in it. Merged pull requests per login in the project's repositories (groot, osionos, grobase, prismatica = opposite-osiris, osionos-mail, osionos-calendar, hydrawn, QA, monkey-bot), from @@ -766,60 +765,19 @@ prismatica = opposite-osiris, osionos-mail, osionos-calendar, hydrawn, QA, monke | @DjSurgeon | 8 | prismatica 7, osionos 1 | | @danielfdez17 | 4 | prismatica 4 | -The Who columns of the [Features List](#features-list) and [Modules](#modules) were counted -on 2026-11-04, before the history rewrite of that day, with `scripts/contributors.sh --paths` -(all branches). Until the pre-rewrite refs are deleted from a clone, `--all` counts each of those -commits twice; count from the pinned commit as above instead. - -How the identities were joined (the evidence is in [`.mailmap`](.mailmap)): - -- Each member committed under several addresses, including GitHub's `noreply` ones; `.mailmap` - joins them. A commit count is not effort: one large commit and one typo fix weigh the same. -- `settes ` is **`rstancu`** (Roxana Stancu): the address belongs to GitHub - account [@esettes](https://github.com/esettes), listed for `rstancu` on the original roster - ([`archive/wiki-2026-09/CONTRIBUTORS.md`](archive/wiki-2026-09/CONTRIBUTORS.md)). The 104 - osionos commits (2026-04-10 → 2026-05-02) touch mostly the Playwright browser tests - (`tests/browser`), their CI job and committed build assets. `rstancu` is not in the current - team table. - - > TO CONFIRM by the team: `rstancu`'s status in the team, and whether that work counts for - > this evaluation. -- `La Cebolla ` is **`shashemi`**: opposite-osiris commit `93e6b65` carries - `Signed-off-by: Seyed Mostafa Hashemian`. -- Two groups of grobase commits pair one member's name with another's address. They are - attributed by inference: - - `LESdylan ` (3 commits on grobase's pinned commit, 5 on all branches, - 2026-09-21 → 2026-11-02) goes to `dlesieur`: the author name - is `LESdylan`, and `b4c1d33f` landed through grobase PR #89, opened by `LESdylan`. - - `dlesieur ` (5 commits, 2026-03-20/21) goes to `danfern3`: they sit inside - `danielfdez17`'s own Docker and Kubernetes series of the same two days. - - > TO CONFIRM by the team: both attributions above. -- `opencode` (6 commits: 1 root, 5 osionos) is an AI coding agent committing under its own name. -- `bunny`, `Space Bunny` and `builder` (111 hydrawn commits, 2026-09-27/28, addresses on - `local`, `localhost` and `drawnosaurus.local`) are not mapped: no address, sign-off or pull - request ties them to a member. - - > TO CONFIRM by the team: which member ran `opencode`, and who committed as `bunny`, - > `Space Bunny` and `builder` in hydrawn. -- Bots (`dependabot`, `coderabbitai`, `copilot-swe-agent`) are left as they are. -- On 2026-11-04 the history of groot, osionos and grobase was rewritten to remove - `Co-authored-by` trailers; trees and subjects are unchanged, and every commit from the first rewritten one onward has a new SHA. 148 root commits on `main` have a one-word subject - (147 `dlesieur`, 1 `vjan-nie`, 2026-05-01 → 2026-10-09); the - [`Commit subjects`](.github/workflows/commit-subjects.yml) check refuses new ones. +The numbers in brackets below are the member's commits in that row of the +[Features List](#features-list). ### dlesieur — Dylan Lesieur - **Areas:** grobase (Go control plane, Rust data plane and realtime, Kong gateway, contracts - and self-serve apps), osionos (editor, chat, collaboration, social, profile, the bridge), mail, - calendar, the root's infrastructure, TLS edge and CI; hydrawn (676 commits: `apps/web`, - the engine, `docs/reference`). + and self-serve apps), osionos (editor, chat, collaboration, social, profile, the bridge, the AI + service), mail, calendar, the root's infrastructure, TLS edge and CI; hydrawn (569 commits: + `apps/web`, the engine, `docs/reference`). - **Pull requests:** 260 merged (osionos 138, grobase 61, groot 56). -- **Features and modules:** most rows of the [Features List](#features-list) and every claimed - module row, as the Who columns show. -- **Challenges:** not recorded. - - > TO CONFIRM by the team: the challenges this member met. +- **Features:** the largest share of every row of the Features List except the legal pages, for + example the block editor (164), the database block (125), chat (72) and the AI assistant (317). +- **Challenges:** not recorded yet. ### danfern3 — Daniel Fernández @@ -827,63 +785,55 @@ How the identities were joined (the evidence is in [`.mailmap`](.mailmap)): and mutation testing, configuration); grobase Docker images built from scratch, Kubernetes deployment, the playground and Makefile (March 2026); osionos breadcrumbs, trash, multi-line text in blocks, the markdown engine and - code-quality fixes; hydrawn (25 commits, `apps/web`, `apps/api`, `packages/contract`, + code-quality fixes; hydrawn (20 commits, `apps/web`, `apps/api`, `packages/contract`, 2026-09-24: submodule clone paths, formatting); root submodule pins and the `make all` bats fix, on `fix/ci` ([#165](https://github.com/Univers42/groot/pull/165), open). - **Pull requests:** 4 merged (prismatica). -- **Features and modules:** block editor (29 commits), frameworks, frontend half (row 6, 78), OAuth - (row 5, 1). -- **Challenges:** not recorded. - - > TO CONFIRM by the team: the challenges this member met. +- **Features:** block editor (29), whiteboard (20). +- **Challenges:** not recorded yet. ### serjimen — Sergio Jiménez de la Cruz -- **Areas:** the public site, opposite-osiris (160 commits on the pinned commit: hero animation +- **Areas:** the public site, opposite-osiris (134 commits on the pinned commit: hero animation performance, unit tests and benchmarks, security fixes, auth pages); osionos accessibility fixes, page links, move and delete, shared UI refactor, the node installer's self-update (#277) and database probe diagnostics (#278), the changelog. - **Pull requests:** 8 merged (prismatica 7, osionos 1), among them the landing page in English, Spanish and Arabic with right-to-left layout (prismatica #21, #22, #23, #35), the accessible privacy policy and terms (#38) and a WCAG 2.2 AA audit pipeline with axe-core fixes (#39). -- **Features and modules:** sign-in pages (1), legal pages (2), block editor (14), connections - (2), frameworks, frontend half (row 6, 76). -- **Challenges:** not recorded. - - > TO CONFIRM by the team: the challenges this member met. +- **Features:** block editor (8), legal pages (2), communities and social feed (2), sign-up / + sign-in (1), database block (1). +- **Challenges:** not recorded yet. ### vjan-nie — Vadim Jan Nieto -- **Areas:** `vendor/QA` (39 commits: registry, migrations, hooks, CLI); root end-to-end tests, +- **Areas:** `vendor/QA` (38 commits: registry, migrations, hooks, CLI); root end-to-end tests, the wiki and README, graph-studio tests, the hydrawn TLS edge and its CORS, submodule pins; osionos whiteboard and graph-studio fixes; grobase Docker infrastructure and dependency - fixes; hydrawn (6 commits: engine bumps, the nested-shape binding fix). + fixes; hydrawn (4 commits: engine bumps, the nested-shape binding fix). - **Pull requests:** 72 merged (groot 45, osionos 17, prismatica 6, grobase 4). -- **Features and modules:** block editor (42), legal pages (3), real-time (row 2, 5), - frameworks, frontend half (row 6, 77). -- **Challenges:** not recorded. - - > TO CONFIRM by the team: the challenges this member met. +- **Features:** block editor (42), AI assistant (9), public API (5), whiteboard (4), legal pages + (3), multi-engine data API (3), database block (2), chat (1). +- **Challenges:** not recorded yet. ### shashemi — Seyed Mostafa Hashemian - **Areas:** security fixes across root, grobase and opposite-osiris (SAST findings, nginx scan suppressions, IDE socket proxy hardening); the site's legal pages, SEO and accessibility; root - CI triggers and the models' export erasure paths; osionos end-to-end fixes; hydrawn (9 + CI triggers and the models' export erasure paths; osionos end-to-end fixes; hydrawn (8 commits, `apps/web`, `apps/api`, `packages/contract`: trail and notes, hydrawn #1, and the pen-thickness-with-zoom test, #8). - **Pull requests:** 57 merged (prismatica 20, groot 19, osionos 12, grobase 6). -- **Features and modules:** legal pages (5), collaboration (row 10, 1), real-time (row 2, 1). -- **Challenges:** not recorded. - - > TO CONFIRM by the team: the challenges this member met. +- **Features:** whiteboard (6), legal pages (5), real-time collaboration (2), block editor (2), + database block, video rooms, communities, AI assistant and public API (1 each). +- **Challenges:** not recorded yet. ### Team-level challenges From the project's history: -- **Migrating the data plane from TypeScript to Rust with no downtime**, using a per-request - switch and a shadow mode that compared both implementations under real traffic. +- **Migrating the data plane from TypeScript to Rust with no downtime**, behind a per-request + switch (`RUST_DATA_PLANE_FORWARD`). - **Keeping eight database adapters at parity**, enforced by a conformance battery that runs every adapter against a real engine and checks it serves exactly what it advertises. - **Auditing our own authorisation path** and shipping a reversible mitigation for a weakness we diff --git a/wiki/README.md b/wiki/README.md index 90b29762f..2a60055cb 100644 --- a/wiki/README.md +++ b/wiki/README.md @@ -87,6 +87,7 @@ zero per-project server code. | [01-subject](project/01-subject.md) | What ft_transcendence asks for | | [02-modules](project/02-modules.md) | Module ledger: points, flags, evidence | | [03-team](project/03-team.md) | Roles and contributions | +| [contributions-method](project/contributions-method.md) | How the README's commit counts are made, and the identity joins behind them | | [04-glossary](project/04-glossary.md) | Project vocabulary | | [ai-llm-interface](project/ai-llm-interface.md) | The LLM interface: one question through twelve hops, and the tests behind each claim | | [ai-audit-2026-10-28](project/ai-audit-2026-10-28.md) | Superseded 2026-11-04: the AI modules against the old pin | diff --git a/wiki/STATUS.md b/wiki/STATUS.md index 7a1e08831..813c4893a 100644 --- a/wiki/STATUS.md +++ b/wiki/STATUS.md @@ -43,6 +43,7 @@ Update this table whenever a page's status block changes. It is the working list | project/02-modules | Partial | Two open checks worth ~6 points; grades superseded by the README Modules table (2026-11-04) | | project/03-team | **Template** | Facts not held anywhere; fill with the team | | project/04-glossary | Verified | — | +| project/contributions-method | Verified · 2026-11-05 | Counts age with every new pin; recount with the command on the page | | project/ai-llm-interface | Partial | nginx buffering/timeouts untested; #275 not in groot's pin yet | | project/ai-audit-2026-10-28 | Superseded | Pin facts replaced by the README Modules table, 2026-11-04 | | project/ai-stall-diagnosis-2026-10-29 | Diagnosis only | Hypotheses not tested live | diff --git a/wiki/project/contributions-method.md b/wiki/project/contributions-method.md new file mode 100644 index 000000000..c28e348dc --- /dev/null +++ b/wiki/project/contributions-method.md @@ -0,0 +1,72 @@ +# How the contribution counts are made + +The README's [Features List](../../README.md#features-list) and +[Who committed where](../../README.md#who-committed-where) count commits one way, described here +with the identity joins it rests on. + +## The method + +Non-merge commits reachable from the commit groot `main` pins for each repository, read through +the root [`.mailmap`](../../.mailmap), with bots and AI-agent identities left out: + +```sh +pin=$(git ls-tree origin/main apps/osionos/app | awk '{print $3}') # root: origin/main itself +git -C apps/osionos/app -c mailmap.file="$PWD/.mailmap" \ + log --no-merges --format='%aN' "$pin" -- | + grep -viE 'bot|AI agent' | sort | uniq -c | sort -rn +``` + +Counted on 2026-11-05, groot `main` = `0bef3cb3`. Repositories: groot, osionos, grobase, +opposite-osiris (prismatica), hydrawn, mail, calendar, QA, monkey-bot. + +Caveat: a commit count is not effort. One large commit and one typo fix weigh the same; pairing, +review and work committed by someone else do not show; a commit that touches several features +counts once for each. Work that is not on a pinned commit (an open branch, an unmerged pull +request) is not counted. + +`scripts/contributors.sh` counts all refs (`--all`), not the pins. Until a clone drops the refs +from before the 2026-11-04 history rewrite, `--all` counts each rewritten commit twice. + +## Left out of the counts + +At the pins, on 2026-11-05: + +| Identity | Kind | Commits | +|---|---|---| +| `Space Bunny` (`bunny`, `Space Bunny`, `builder`) | the OpenCode agent team `dlesieur` ran on hydrawn (hydrawn `BUNNY.md`) | 68 hydrawn | +| `opencode` | AI coding agent committing under its own name | 1 root, 5 osionos | +| `dependabot[bot]`, `coderabbitai[bot]`, `copilot-swe-agent[bot]`, `Grok CI Bot` | bots | 8 + 3 + 2 root (dependabot, coderabbit, Grok), 4 osionos (coderabbit), 9 opposite-osiris (copilot) | + +## How the identities are joined + +The evidence for each join is in [`.mailmap`](../../.mailmap). + +- Each member committed under several addresses, including GitHub's `noreply` ones; `.mailmap` + joins them. +- `settes ` is **`rstancu`** (Roxana Stancu): the address belongs to GitHub + account [@esettes](https://github.com/esettes), listed for `rstancu` on the original roster + ([`archive/wiki-2026-09/CONTRIBUTORS.md`](../../archive/wiki-2026-09/CONTRIBUTORS.md)). The + osionos commits (2026-04-10 → 2026-05-02) touch mostly the Playwright browser tests + (`tests/browser`), their CI job and committed build assets. `rstancu` is not in the current + team table. +- `La Cebolla ` is **`shashemi`**: opposite-osiris commit `93e6b65` carries + `Signed-off-by: Seyed Mostafa Hashemian`. +- `SMOSTAFAH1 ` is **`shashemi`**: it is the GitHub login + [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) of the team table, without the numeric id + `.mailmap` already maps (2 osionos commits at the pin). +- Two groups of grobase commits pair one member's name with another's address. They are + attributed by inference, not by proof: + - `LESdylan ` (3 commits on grobase's pinned commit, 5 on all branches, + 2026-09-21 → 2026-11-02) goes to `dlesieur`: the author name is `LESdylan`, and `b4c1d33f` + landed through grobase PR #89, opened by `LESdylan`. + - `dlesieur ` (5 commits, 2026-03-20/21) goes to `danfern3`: they sit inside + `danielfdez17`'s own Docker and Kubernetes series of the same two days. +- `opencode` and `Space Bunny` are AI agents, shown under their own names and left out of the + member counts (table above). +- `qwO-Owp` (born2root, 2026-10-08/09) and `Alex Caceres` (vendor/scripts, 2026-01-26) are tied + to no member by any address, sign-off or pull request. Neither repository is counted. +- On 2026-11-04 the history of groot, osionos and grobase was rewritten to remove + `Co-authored-by` trailers; trees, authors, dates and subjects are unchanged, and every commit + from the first rewritten one onward has a new SHA. 148 root commits on `main` have a one-word + subject (147 `dlesieur`, 1 `vjan-nie`, 2026-05-01 → 2026-10-09); the + [`Commit subjects`](../../.github/workflows/commit-subjects.yml) check refuses new ones. From 9393ee4a70e535ee48ee59a15f2acd7f86259ac4 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:10 +0100 Subject: [PATCH 11/22] docs(readme): name the AI tools, the trailer rewrite and the licence facts The AI disclosure named no tool. It now lists what the repositories record: Claude Code with the team's kit in .claude, Gemini and opencode in osionos, the Space Bunny agent team on hydrawn, Copilot and CodeRabbit on PRs. It says plainly that the 2026-11-04 rewrite removed Co-authored-by trailers, so the history must not be read as AI-free. License states facts only: no root LICENSE, grobase AGPL-3.0 open-core, no licence file in osionos, prismatica, hydrawn, mail or calendar. --- README.md | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e01d78796..ea5cac1eb 100644 --- a/README.md +++ b/README.md @@ -864,7 +864,19 @@ From the project's history: This project was built with **heavy AI assistance**, and we state it plainly. -- **Tools.** Team members used AI assistants in different forms, according to their own work. +- **Tools.** The repositories record these: + - **Claude Code**, with the team's own configuration kit in groot's [`.claude`](.claude) + submodule (`Univers42/claude-deal-with-the-devil`: agents, rules, skills and hooks). + - **Gemini** in osionos (plans under `.gemini/plan/`), beside `.agents/` and an `.mcp.json`. + - **opencode**, an AI coding agent that committed under its own name (1 root and 5 osionos + commits at the pins), and the OpenCode agent team "Space Bunny" on hydrawn (68 commits at + the pin, hydrawn `BUNNY.md`). + - **GitHub Copilot** (`copilot-swe-agent`, 9 commits at prismatica's pin, and Copilot review on + pull requests) and **CodeRabbit** (reviews on pull requests since 2026-10-23). +- **Commit history.** On 2026-11-04 the history of groot, osionos and grobase was rewritten to + remove `Co-authored-by` trailers. Since then no commit carries a co-author line, so the history + does not show which commits were written with an AI tool, and must not be read as AI-free + ([`wiki/project/contributions-method.md`](wiki/project/contributions-method.md)). - **Code.** AI wrote and refactored code across the stack: grobase planes and adapters, the frontends, SQL migrations, the Makefile pipeline and the Docker setup. - **Testing and verification.** AI wrote verification gates and test scripts, including the @@ -873,29 +885,35 @@ This project was built with **heavy AI assistance**, and we state it plainly. path ([`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md)). - **Documentation.** The wiki and this README were drafted and distilled with AI assistance from the project's own design documents and code, then checked against the repository. -- **How we kept control.** A human reviews and merges every pull request; nothing reaches - `develop` or `main` by an agent alone. A change is accepted only when its verification gate - passes. Every member must be able to explain the AI-assisted code in their area. +- **How we kept control.** A human merges every pull request; nothing reaches `develop` or + `main` by an agent alone. Approval by a second member is required by the rulesets but thin in + practice (see [Project Management](#project-management)). A change is accepted only when its + verification gate passes. Every member must be able to explain the AI-assisted code in their + area. --- ## Known limitations - **No game.** All gaming-dependent modules are out of scope. -- **Expressiveness is narrow by design.** grobase has no place for custom server logic; business - rules must be expressed as policies, schema constraints or database triggers. +- **Expressiveness is narrow by design.** grobase has no per-application server code; business + rules are expressed as policies, schema constraints, database triggers, or functions in the + flag-gated functions plane. - **Documented security weaknesses.** Known and declared in [`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md). -- **Several features are behind flags that are off by default** — see the confidence column in +- **Several features are behind flags that are off by default** — see the Grade column in [Modules](#modules). -- **No interface translation.** The language setting in osionos is a stub (see [Modules](#modules)). +- **No interface translation in osionos.** `i18next` is declared but no translation resource is + loaded (see [Modules](#modules)). The prismatica site itself ships English, Spanish and Arabic. - **Whiteboard editing is loopback-only and has no per-user authorization yet** (see [Demo](#demo)). ## License -There is no `LICENSE` file at the repository root. grobase carries its own licence files inside -its submodule (`apps/grobase/LICENSE`, `apps/grobase/LICENSING.md`). +- There is no `LICENSE` file at the repository root. +- grobase is open-core under the GNU AGPL v3 (`apps/grobase/LICENSE`); `apps/grobase/LICENSING.md` + maps which parts carry which licence. +- osionos, opposite-osiris (prismatica), hydrawn, mail and calendar carry no licence file. --- @@ -908,3 +926,4 @@ its submodule (`apps/grobase/LICENSE`, `apps/grobase/LICENSING.md`). - [`wiki/security/`](wiki/security/) — security model, proofs, known weaknesses, network - [`DATA-MIGRATION.md`](DATA-MIGRATION.md) — fresh-machine and migration runbook - `apps/grobase/CLAUDE.md` — grobase's own authoritative technical document (inside the submodule) +- [Prismatica docs](https://prismatica-beta.vercel.app/docs/) — the landing's documentation site From 12bb8a38a052522ec343050c0b783bd9980c3109 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 07:07:10 +0100 Subject: [PATCH 12/22] docs(wiki): mark the module ledger wholly superseded 02-modules.md's legend, letters and totals disagree with the README's one rule (CodeRabbit on #182, threads 3 and 4). The whole page is now marked Superseded and points at the README Modules table; STATUS.md and the wiki index say the same. --- wiki/README.md | 2 +- wiki/STATUS.md | 2 +- wiki/project/02-modules.md | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wiki/README.md b/wiki/README.md index 2a60055cb..e28db7995 100644 --- a/wiki/README.md +++ b/wiki/README.md @@ -85,7 +85,7 @@ zero per-project server code. | Page | What it answers | |---|---| | [01-subject](project/01-subject.md) | What ft_transcendence asks for | -| [02-modules](project/02-modules.md) | Module ledger: points, flags, evidence | +| [02-modules](project/02-modules.md) | Module ledger, superseded by the README Modules table | | [03-team](project/03-team.md) | Roles and contributions | | [contributions-method](project/contributions-method.md) | How the README's commit counts are made, and the identity joins behind them | | [04-glossary](project/04-glossary.md) | Project vocabulary | diff --git a/wiki/STATUS.md b/wiki/STATUS.md index 813c4893a..4921ea4d5 100644 --- a/wiki/STATUS.md +++ b/wiki/STATUS.md @@ -40,7 +40,7 @@ Update this table whenever a page's status block changes. It is the working list | product/03-opposite-osiris | Partial | **Privacy Policy / ToS existence unverified** | | product/04-repos | Partial | What is actually inside the delivered perimeter | | project/01-subject | Unverified by nature | Source is private; re-check on each subject version | -| project/02-modules | Partial | Two open checks worth ~6 points; grades superseded by the README Modules table (2026-11-04) | +| project/02-modules | Superseded | Whole ledger replaced by the README Modules table (2026-11-05) | | project/03-team | **Template** | Facts not held anywhere; fill with the team | | project/04-glossary | Verified | — | | project/contributions-method | Verified · 2026-11-05 | Counts age with every new pin; recount with the command on the page | diff --git a/wiki/project/02-modules.md b/wiki/project/02-modules.md index 6e2c7d2ff..ac387e73d 100644 --- a/wiki/project/02-modules.md +++ b/wiki/project/02-modules.md @@ -1,12 +1,12 @@ # Module ledger -> **Status:** Partial · 2026-09-15 +> **Superseded · 2026-11-05.** This whole page is history: its rows, letters, legend and +> point totals. The current grades, one rule and the points table are in the +> [README Modules table](../../README.md#modules). +> +> **Status:** Superseded · 2026-11-05 (written as Partial · 2026-09-15) > **Evidence:** flag states read from `deploy/fly/boot.sh`; every gate named here exists in the > gate index -> **To check:** the two items in the "open" table below are worth up to 6 points between them -> and neither has been checked. The current grades are in the -> [README Modules table](../../README.md#modules) (2026-11-04), which supersedes this ledger's -> letters. > **Sources:** `deploy/fly/boot.sh` · `apps/grobase/CLAUDE.md` §flag-gating · [01-subject](01-subject.md) Only catalogue modules count. **A module that cannot be demonstrated scores zero**, so each row From fd1e60af96659358a9aafc073ae8437ff7b8cb04 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 08:04:07 +0100 Subject: [PATCH 13/22] docs: wrap the new prose at 80 columns markdownlint-cli2 (default config, no repo override) flagged more MD013 hits than develop. Every prose block holding a new line over 80 columns is rewrapped; tables, headings and code are untouched, and the rendered HTML is unchanged (markdown-it-py, CommonMark + tables, whitespace-collapsed). contributions-method.md's "left out" table becomes a list, its code sample moves a comment onto its own line, and the two new STATUS.md rows are shortened. MD013: README 286 on develop -> 162, 02-modules 33 -> 30; the lines still over 80 are single link targets. --- README.md | 577 +++++++++++++++------------ wiki/STATUS.md | 4 +- wiki/project/02-modules.md | 18 +- wiki/project/contributions-method.md | 107 ++--- 4 files changed, 388 insertions(+), 318 deletions(-) diff --git a/README.md b/README.md index ea5cac1eb..037d83d61 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,20 @@ # Prismatica — ft_transcendence -**Prismatica** is a collaborative workspace built on our own self-hostable Backend-as-a-Service. -Users sign up on the public **prismatica** site, land in **osionos** — a Notion-style block editor -with real-time collaboration, chat and video rooms — and can connect their Gmail and Google -Calendar. Every one of those apps is served by **grobase**, a generic backend that the team wrote -in Go, Rust and TypeScript, with no per-application server code. - -> Naming: *Prismatica* is the project; *osionos* is the workspace app; *prismatica* -> (`apps/opposite-osiris`, repository [`Univers42/prismatica`](https://github.com/Univers42/prismatica)) -> is the marketing landing. Infrastructure identifiers keep the old codename `track-binocle` -> (the compose project, image names, `TRACK_BINOCLE_*` variables, `*.track-binocle.test` hosts, -> the local CA file): renaming them would break scripts and issued certificates. +**Prismatica** is a collaborative workspace built on our own self-hostable +Backend-as-a-Service. Users sign up on the public **prismatica** site, land in +**osionos** — a Notion-style block editor with real-time collaboration, chat and +video rooms — and can connect their Gmail and Google Calendar. Every one of +those apps is served by **grobase**, a generic backend that the team wrote in +Go, Rust and TypeScript, with no per-application server code. + +> Naming: *Prismatica* is the project; *osionos* is the workspace app; +> *prismatica* (`apps/opposite-osiris`, repository +> [`Univers42/prismatica`](https://github.com/Univers42/prismatica)) is the +> marketing landing. Infrastructure identifiers keep the old codename +> `track-binocle` (the compose project, image names, `TRACK_BINOCLE_*` +> variables, `*.track-binocle.test` hosts, the local CA file): renaming them +> would break scripts and issued certificates. --- @@ -44,13 +47,14 @@ code** — and to prove it by building a real product on it. The project therefore has two halves: -- **grobase** — a Backend-as-a-Service (about 290,000 lines of Go, Rust and TypeScript at its - pin, roughly a third of the code the team wrote; lines include tests). An application is - declared in a JSON *contract* (its database, isolation strategy, roles, permissions and API - keys); a generic provisioner creates everything from that file. Routes carry no domain - logic: a request names the table it targets, and access rules are stored as data, not code. -- **The products** that run on it — the prismatica landing and sign-in site, the osionos - workspace, the hydrawn whiteboard, and mail and calendar integrations. +- **grobase** — a Backend-as-a-Service (about 290,000 lines of Go, Rust and + TypeScript at its pin, roughly a third of the code the team wrote; lines + include tests). An application is declared in a JSON *contract* (its database, + isolation strategy, roles, permissions and API keys); a generic provisioner + creates everything from that file. Routes carry no domain logic: a request + names the table it targets, and access rules are stored as data, not code. +- **The products** that run on it — the prismatica landing and sign-in site, the + osionos workspace, the hydrawn whiteboard, and mail and calendar integrations. ### Overview @@ -62,28 +66,31 @@ The project therefore has two halves: | **calendar** | React + Vite | Google Calendar integration over Google OAuth | | **hydrawn** | SvelteKit + Fastify + Rust/WASM | Collaborative whiteboard, embedded in osionos | -These products are supported by platform services (not applications in their own right): the -**auth-gateway** (Node, shipped by the prismatica repository: sessions and sign-in), the -**osionos-bridge** (Node: turns a site session into an editor session), **Kong** (grobase's API -gateway, behind its WAF) and **LiveKit** (the WebRTC media server for video rooms). +These products are supported by platform services (not applications in their own +right): the **auth-gateway** (Node, shipped by the prismatica repository: +sessions and sign-in), the **osionos-bridge** (Node: turns a site session into +an editor session), **Kong** (grobase's API gateway, behind its WAF) and +**LiveKit** (the WebRTC media server for video rooms). ### Key features -- **Contract-driven backend.** A whole application — database, isolation, roles, keys, frontend - configuration — is one JSON file. `POST /v1/tenants/me/apps` creates a new isolated application - with its own database and scoped API key (mounted only when `APPS_SELFSERVE_ENABLED` is on). -- **Per-request owner isolation.** The Rust data plane scopes queries to their owner on each - request, not by connection-pool state; permissions are rows (RBAC, plus flag-gated ABAC - conditions), not `if` statements. -- **One API over many databases.** PostgreSQL, MySQL (MariaDB image), MongoDB, Redis, SQLite, - SQL Server and even remote HTTP APIs are queried through the same envelope and the same API - key. DynamoDB is an opt-in build, left out of the default one +- **Contract-driven backend.** A whole application — database, isolation, roles, + keys, frontend configuration — is one JSON file. `POST /v1/tenants/me/apps` + creates a new isolated application with its own database and scoped API key + (mounted only when `APPS_SELFSERVE_ENABLED` is on). +- **Per-request owner isolation.** The Rust data plane scopes queries to their + owner on each request, not by connection-pool state; permissions are rows + (RBAC, plus flag-gated ABAC conditions), not `if` statements. +- **One API over many databases.** PostgreSQL, MySQL (MariaDB image), MongoDB, + Redis, SQLite, SQL Server and even remote HTTP APIs are queried through the + same envelope and the same API key. DynamoDB is an opt-in build, left out of + the default one ([`wiki/platform/08-engines.md`](wiki/platform/08-engines.md)). - **Collaborative editor.** Block-based pages, a database block with table / board / calendar views, real-time co-editing, channels and direct messages, video rooms. -- **Single-command deployment.** `make all SKIP_SYNC=1` builds the pinned commits in Docker, - starts the backend and the frontends over local HTTPS with a trusted CA, and health-checks - them (`utils/mk/pipeline.mk:10`). +- **Single-command deployment.** `make all SKIP_SYNC=1` builds the pinned + commits in Docker, starts the backend and the frontends over local HTTPS with + a trusted CA, and health-checks them (`utils/mk/pipeline.mk:10`). --- @@ -110,19 +117,22 @@ trust store. This is intended (`certs-trust-local` in `utils/mk/certs.mk`). With sudo, `CERT_TRUST_MODE=user` trusts the browsers only and `skip` trusts nothing (see [Access](#access-and-the-local-ca)). -**Ports bound on the host** (from `docker-compose.yml`, all on `127.0.0.1` except inside a -QEMU/VirtualBox NAT VM, where `infrastructure/scripts/detect-bind-addr.sh` binds `0.0.0.0` so the -host can reach the guest): 443, 3001, 3002, 3003, 3007 (always loopback), 4000, 4100, 4200, 4322, -4323 and 7880 (always loopback: plain HTTP), 7881, 8444, 8446 (always loopback: the IDE edge), -8787 and UDP 50000–50060. A busy port moves to the next free one (`scripts/host-ports.sh`). -grobase adds Kong on `127.0.0.1:8000` (literal loopback in its +**Ports bound on the host** (from `docker-compose.yml`, all on `127.0.0.1` +except inside a QEMU/VirtualBox NAT VM, where +`infrastructure/scripts/detect-bind-addr.sh` binds `0.0.0.0` so the host can +reach the guest): 443, 3001, 3002, 3003, 3007 (always loopback), 4000, 4100, +4200, 4322, 4323 and 7880 (always loopback: plain HTTP), 7881, 8444, 8446 +(always loopback: the IDE edge), 8787 and UDP 50000–50060. A busy port moves to +the next free one (`scripts/host-ports.sh`). grobase adds Kong on +`127.0.0.1:8000` (literal loopback in its `orchestrators/compose/base/gateway.yml:56`; its WAF is the public entry). ### Defense bring-up (pinned) -This is the path rehearsed on a clean machine, and the stack the [Modules](#modules) are graded -on. It builds `main` and the submodule commits `main` pins, and does **not** follow submodule -branch tips (`SKIP_SYNC=1`, see `sync-submodules-soft` in `utils/mk/pipeline.mk`). +This is the path rehearsed on a clean machine, and the stack the +[Modules](#modules) are graded on. It builds `main` and the submodule commits +`main` pins, and does **not** follow submodule branch tips (`SKIP_SYNC=1`, see +`sync-submodules-soft` in `utils/mk/pipeline.mk`). ```bash git clone --recursive git@github.com:Univers42/groot.git @@ -135,24 +145,27 @@ make all SKIP_SYNC=1 Requirements, the VM + host-browser case, the verify script (`scripts/verify/fresh-bringup.sh`) and troubleshooting: [`wiki/runbooks/fresh-machine.md`](wiki/runbooks/fresh-machine.md). -grobase on another machine (the born2root VM, a LAN box, a VPS, a Kong URL) with the frontends -here, no sudo: put the kind of connection in `./.env.grobase-link` (`GROBASE_TARGET=ssh://b2b`; -`.env.grobase-link.example` lists the kinds), then `make link` and `make link-frontends-up`. The -latter also applies `models/*.sql` to that grobase (`make link-models-migrate`), sets the demo -account's password there (`make link-demo-login-ensure`; `make demo-login` prints it), hands the +grobase on another machine (the born2root VM, a LAN box, a VPS, a Kong URL) with +the frontends here, no sudo: put the kind of connection in `./.env.grobase-link` +(`GROBASE_TARGET=ssh://b2b`; `.env.grobase-link.example` lists the kinds), then +`make link` and `make link-frontends-up`. The latter also applies `models/*.sql` +to that grobase (`make link-models-migrate`), sets the demo account's password +there (`make link-demo-login-ensure`; `make demo-login` prints it), hands the demo rows to the app's API key (`make link-live-data-ensure`) and trusts the -local CA in this user's browser stores (`make certs-trust-user`, no sudo). Both end with -`make link-verify`: one request per grobase service from inside every frontend, the TLS edge, -then the browser stores — [`wiki/runbooks/grobase-link.md`](wiki/runbooks/grobase-link.md). -To serve the frontends to the internet through this host's Tailscale Funnel (443; add 8443 and -10000 with `PUBLIC_PORTS=all`), `make public-env` and `make public-up`; `make public-down` -closes it: -[`wiki/runbooks/public-funnel.md`](wiki/runbooks/public-funnel.md). -`make roundtrip` then proves persistence (account, sign-in, editor hand-off, a page, the rows -in postgres) and `make link-e2e` runs the Playwright smoke through the link. - -Measured time from a cold machine: **9–17 minutes** (8m55s on a fresh VM, 16m44s on a laptop, -2026-09-30, [`wiki/STATUS.md`](wiki/STATUS.md); later runs in +local CA in this user's browser stores (`make certs-trust-user`, no sudo). Both +end with `make link-verify`: one request per grobase service from inside every +frontend, the TLS edge, then the browser stores — +[`wiki/runbooks/grobase-link.md`](wiki/runbooks/grobase-link.md). To serve the +frontends to the internet through this host's Tailscale Funnel (443; add 8443 +and 10000 with `PUBLIC_PORTS=all`), `make public-env` and `make public-up`; +`make public-down` closes it: +[`wiki/runbooks/public-funnel.md`](wiki/runbooks/public-funnel.md). `make +roundtrip` then proves persistence (account, sign-in, editor hand-off, a page, +the rows in postgres) and `make link-e2e` runs the Playwright smoke through the +link. + +Measured time from a cold machine: **9–17 minutes** (8m55s on a fresh VM, 16m44s +on a laptop, 2026-09-30, [`wiki/STATUS.md`](wiki/STATUS.md); later runs in [`wiki/runbooks/fresh-machine.md`](wiki/runbooks/fresh-machine.md)). No `.env` needs to be written by hand. With no vault key present, grobase generates its own @@ -162,12 +175,14 @@ including random `OSIONOS_*` secrets and the demo account's `DEMO_LOGIN_PASSWORD `make all`, which says so by name. `make all` runs, in order (`utils/mk/pipeline.mk`): submodule sync → secrets → -local TLS certificates → trust the local CA → grobase backend → derive `.env.local` → restore -data if the engines are empty → set the demo account's password → SQL migrations → live-data key -and owner fix → mount re-encryption → frontends → health check → URL list. On a machine that -holds vault42 credentials, `make all` deploys against the data-center VM instead and starts no -local grobase (ADR 0047, [`wiki/runbooks/datacenter.md`](wiki/runbooks/datacenter.md)); -`make all GROBASE_DATACENTER=` forces the local path. +local TLS certificates → trust the local CA → grobase backend → derive +`.env.local` → restore data if the engines are empty → set the demo account's +password → SQL migrations → live-data key and owner fix → mount re-encryption → +frontends → health check → URL list. On a machine that holds vault42 +credentials, `make all` deploys against the data-center VM instead and starts no +local grobase (ADR 0047, +[`wiki/runbooks/datacenter.md`](wiki/runbooks/datacenter.md)); `make all +GROBASE_DATACENTER=` forces the local path. ### Development bring-up @@ -176,10 +191,11 @@ git checkout develop make all ``` -Without `SKIP_SYNC=1`, `make all` first fast-forwards every submodule to the tip of its tracked -branch (`sync-submodules-soft`), so you build the newest code rather than the pinned commits. -It skips dirty submodules, and leaves at its recorded commit any submodule whose branch tip does -not contain that commit; it never blocks the pipeline. +Without `SKIP_SYNC=1`, `make all` first fast-forwards every submodule to the tip +of its tracked branch (`sync-submodules-soft`), so you build the newest code +rather than the pinned commits. It skips dirty submodules, and leaves at its +recorded commit any submodule whose branch tip does not contain that commit; it +never blocks the pipeline. The exception is any submodule that `.gitmodules` marks `update = none`, today `apps/graph_render`. Its gitlink is the build input, so neither mode moves it: @@ -246,9 +262,9 @@ store (one `sudo`) and every browser store this user owns, through `scripts/cert and the flatpak locations. It matches old copies by the CA's subject, not by nickname, replaces them, and adds the current file as "Track Binocle Local Development CA". -- `make certs-trust-check` prints one line per store - (`ok|FAIL current|stale|missing|untrusted`) and exits 1 if any store is not - current. Without `certutil` it fails. +- `make certs-trust-check` prints one line per store (`ok|FAIL + current|stale|missing|untrusted`) and exits 1 if any store is not current. + Without `certutil` it fails. - `make certs-trust-user` fixes the stores without sudo; it mints the CA first only if it is missing. - `CERT_TRUST_MODE=system|user|skip` (or `TRACK_BINOCLE_CERT_TRUST`) picks what `certs-trust-local` does: system store plus browsers (default), browsers only, or nothing. @@ -259,9 +275,10 @@ If the CA is not trusted, the browser shows a warning on each port, and the **Wh osionos stays blank**, because the embedded `:3007` iframe is refused silently. Two causes of a warning while `curl --cacert` succeeds: -- **The CA was regenerated.** `make certs` on a fresh tree mints a new CA, and a store still holding - an older copy does not trust it. `make certs-trust-check` then reports those stores `stale`, and - `make certs-trust-user` replaces the old copy. +- **The CA was regenerated.** `make certs` on a fresh tree mints a new CA, and a + store still holding an older copy does not trust it. `make certs-trust-check` + then reports those stores `stale`, and `make certs-trust-user` replaces the + old copy. - **A snap refresh.** Snap Chromium's `HOME` is the revision directory behind `~/snap/chromium/current`, so a new revision starts without the store. @@ -283,10 +300,10 @@ certificates → Authorities → Import, or run `make certs-trust`. 3. Open the same board URL in a second window and draw: the strokes appear live in the other window (the e2e smoke asserts within 5 s — `tests/e2e/specs/dw8-realtime.spec.ts`). -Honest limitations of this demo: board editing is **loopback-only** and has **no per-user -authorization yet** — hydrawn is bound to `127.0.0.1:3007` for exactly that reason -(`docker-compose.yml:35-40`). We make **no end-to-end-encryption claim**: traffic is TLS to the -local proxy, nothing more. +Honest limitations of this demo: board editing is **loopback-only** and has **no +per-user authorization yet** — hydrawn is bound to `127.0.0.1:3007` for exactly +that reason (`docker-compose.yml:35-40`). We make **no end-to-end-encryption +claim**: traffic is TLS to the local proxy, nothing more. ### Environment configuration @@ -297,19 +314,21 @@ local proxy, nothing more. - `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET` — default to a local dev value; video rooms still work. - `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` in `apps/mail/.env.local` and `apps/calendar/.env.local` — without them, the mail and calendar OAuth flows are disabled. - - `SONAR_TOK`, `FLY_API_TOKEN`, `DOCKER_PAT` — operator tooling only (a local SonarCloud scan, - the Fly deploy, a Docker Hub login); CI uses its own repository secrets. + - `SONAR_TOK`, `FLY_API_TOKEN`, `DOCKER_PAT` — operator tooling only (a local + SonarCloud scan, the Fly deploy, a Docker Hub login); CI uses its own + repository secrets. ### Team setup (with the vault) -Inside the team, secrets are shared through **vault42**, our zero-knowledge secret store, via the -**42ctl** CLI. A machine that holds a vault identity in `~/.config/42ctl/` pulls the `.env` -tree during `make all` when `apps/grobase/.env` is absent (`secrets-ensure`), or on demand with -`make vault42-pull-all APPLY=1`. With the vault passphrase also present, `make all` deploys -against the data-center VM instead (see [Defense bring-up](#defense-bring-up-pinned)). A new -identity is created with `42ctl keys init` and enrolled with an invitation from the vault's -operator. -Details: [`DATA-MIGRATION.md`](DATA-MIGRATION.md). +Inside the team, secrets are shared through **vault42**, our zero-knowledge +secret store, via the **42ctl** CLI. A machine that holds a vault identity in +`~/.config/42ctl/` pulls the `.env` tree during `make all` when +`apps/grobase/.env` is absent (`secrets-ensure`), or on demand with `make +vault42-pull-all APPLY=1`. With the vault passphrase also present, `make all` +deploys against the data-center VM instead (see [Defense +bring-up](#defense-bring-up-pinned)). A new identity is created with `42ctl keys +init` and enrolled with an invitation from the vault's operator. Details: +[`DATA-MIGRATION.md`](DATA-MIGRATION.md). The vault42 CLI is wired in beside that path: the `Secrets (vault42)` section of `make help`, and [`vendor/scripts/vault42/README.md`](vendor/scripts/vault42/README.md). Status and retirement @@ -331,11 +350,12 @@ checklist: [ADR 0017](docs/adr/0017-vault42-cli-beside-the-old-path.md). **Backend editions.** `make all` starts grobase in the **`devlean`** edition (`GROBASE_EDITION ?= devlean` in `utils/mk/grobase.mk`; listed in grobase's -`orchestrators/makes/00-config.mk:148-154`): the core engines (PostgreSQL, MySQL, MongoDB, Redis, -MinIO), the full application / control / data planes and realtime — without the heavy extra -engines and without the monitoring stack. `GROBASE_EDITION=migrate` adds every snapshot engine; -`GROBASE_EDITION=full` turns on every plane except the playground demo. Some module -demonstrations need a larger edition or a feature flag — see [Modules](#modules). +`orchestrators/makes/00-config.mk:148-154`): the core engines (PostgreSQL, +MySQL, MongoDB, Redis, MinIO), the full application / control / data planes and +realtime — without the heavy extra engines and without the monitoring stack. +`GROBASE_EDITION=migrate` adds every snapshot engine; `GROBASE_EDITION=full` +turns on every plane except the playground demo. Some module demonstrations need +a larger edition or a feature flag — see [Modules](#modules). --- @@ -362,20 +382,22 @@ between 2026-03-18 and 2026-05-02; see [Who committed where](#who-committed-wher ## Project Management -Part of this project was an experiment in managing a team. We ran it as if it were a demanding, -high-output professional team, with a Scrum mindset in which every member is treated as an -expert and anyone may change anyone's code. The aim was that **nobody is indispensable**. The -evidence below separates what the repositories record from what is the team's own account, and -the last part measures how far we got towards that aim. - -**How the tracking evolved.** Work started in February 2026: the first commits by `dlesieur`, -`danfern3` and `vjan-nie` date from that month (`git log --reverse` across the submodules). -Between then and the autumn the team tried GitHub Projects, Jira tickets and Notion pages -(team account: none of the three left a trace in commit messages, and the Projects board was not -readable with our token). The only written trace is osionos -[`docs/DoD.md:39`](https://github.com/Univers42/osionos/blob/develop/docs/DoD.md), a -Definition-of-Done template that asks for evidence "in your Pull Request description or your -Trello/Jira" ticket (2026-04-11). +Part of this project was an experiment in managing a team. We ran it as if it +were a demanding, high-output professional team, with a Scrum mindset in which +every member is treated as an expert and anyone may change anyone's code. The +aim was that **nobody is indispensable**. The evidence below separates what the +repositories record from what is the team's own account, and the last part +measures how far we got towards that aim. + +**How the tracking evolved.** Work started in February 2026: the first commits +by `dlesieur`, `danfern3` and `vjan-nie` date from that month (`git log +--reverse` across the submodules). Between then and the autumn the team tried +GitHub Projects, Jira tickets and Notion pages (team account: none of the three +left a trace in commit messages, and the Projects board was not readable with +our token). The only written trace is osionos +[`docs/DoD.md:39`](https://github.com/Univers42/osionos/blob/develop/docs/DoD.md), +a Definition-of-Done template that asks for evidence "in your Pull Request +description or your Trello/Jira" ticket (2026-04-11). **How it works now: issues, labels and pull requests on GitHub.** @@ -388,31 +410,36 @@ Trello/Jira" ticket (2026-04-11). | Stacked branches | Feature chains merged one on top of another: groot #84–#87 (`feat/ide-*`), grobase #69–#70 (`feat/multidb-g1b…g1d`), the osionos `release/acct-w1` … `w9` series | | Commit rhythm | At least one commit on 174 of the 232 days between 2026-03-18 and 2026-11-04, across all repositories | -**Strict CI from the start.** CI arrived within days of each repository's first commit: grobase -`ci.yml` on 2026-03-29, osionos on 2026-04-12, groot on 2026-05-13. SonarCloud is configured in -groot since 2026-05-04 and comments on its pull requests since #9 (2026-06-01). Security scans -(Semgrep, Trivy, gitleaks, TruffleHog, ZAP, cargo-audit, govulncheck) run on every pull request, -and groot rejects one-word commit subjects (`.github/workflows/commit-subjects.yml`). - -**Rituals.** Two-week sprints since the start, daily stand-ups and a weekly meeting, mostly on -Discord (team account, confirmed 2026-11-04; Discord leaves no trace in the repositories). The -method was Scrumban (Scrum rituals plus a Kanban board), as described in +**Strict CI from the start.** CI arrived within days of each repository's first +commit: grobase `ci.yml` on 2026-03-29, osionos on 2026-04-12, groot on +2026-05-13. SonarCloud is configured in groot since 2026-05-04 and comments on +its pull requests since #9 (2026-06-01). Security scans (Semgrep, Trivy, +gitleaks, TruffleHog, ZAP, cargo-audit, govulncheck) run on every pull request, +and groot rejects one-word commit subjects +(`.github/workflows/commit-subjects.yml`). + +**Rituals.** Two-week sprints since the start, daily stand-ups and a weekly +meeting, mostly on Discord (team account, confirmed 2026-11-04; Discord leaves +no trace in the repositories). The method was Scrumban (Scrum rituals plus a +Kanban board), as described in [`docs/dossier-project-dylan/dossier-projet.md:390-416`](https://github.com/Univers42/osionos/blob/develop/docs/dossier-project-dylan/dossier-projet.md) in osionos. **How far we got.** We publish these numbers so the claims above can be checked: -- **Sprints.** The sprints were planned outside GitHub: no milestone and no sprint label exists - in any repository. Merges come in bursts: 250 of the 442 merged pull requests on the six main - repositories landed in two weeks (ISO weeks 43–44). -- **Review.** The rulesets let a maintainer bypass them, and in a sample of the 40 most recent - merged pull requests per repository, 0–22 % carry an approval from someone other than the - author. -- **Nobody indispensable.** Shared ownership is real in breadth: `vjan-nie` committed in 12 areas - and `shashemi` in 8, osionos has six authors with five or more commits, and prismatica's main - author is `serjimen`. In depth we are not there yet: `dlesieur` wrote 86 % of the 8,571 human - commits, and in 17 of 18 areas one author holds more than half of the commits. Commit counts - are not effort: one large commit and a typo fix weigh the same. +- **Sprints.** The sprints were planned outside GitHub: no milestone and no + sprint label exists in any repository. Merges come in bursts: 250 of the 442 + merged pull requests on the six main repositories landed in two weeks (ISO + weeks 43–44). +- **Review.** The rulesets let a maintainer bypass them, and in a sample of the + 40 most recent merged pull requests per repository, 0–22 % carry an approval + from someone other than the author. +- **Nobody indispensable.** Shared ownership is real in breadth: `vjan-nie` + committed in 12 areas and `shashemi` in 8, osionos has six authors with five + or more commits, and prismatica's main author is `serjimen`. In depth we are + not there yet: `dlesieur` wrote 86 % of the 8,571 human commits, and in 17 of + 18 areas one author holds more than half of the commits. Commit counts are not + effort: one large commit and a typo fix weigh the same. --- @@ -448,40 +475,45 @@ independently — each written in the language that suits it. ### Database -- **PostgreSQL 16** is the primary database: the control-plane registries (tenants, roles, policies, - API keys) and all application data (see [Database Schema](#database-schema)). - **Why:** row-level security (RLS), JSONB for block content and flexible properties, strong - transactional guarantees, and a mature ecosystem. RLS is what makes per-owner isolation - enforceable inside the database itself, not only in application code. -- **MySQL, MongoDB, Redis, MinIO** (object storage) run in the `devlean` edition that `make all` - starts; **SQLite**, **SQL Server** (needs the `engines` plane), **DynamoDB** (an opt-in build) - and remote **HTTP** APIs are supported through the same data-plane interface. This is a - deliberate feature of the platform (one API over many engines), not a need of osionos itself. +- **PostgreSQL 16** is the primary database: the control-plane registries + (tenants, roles, policies, API keys) and all application data (see [Database + Schema](#database-schema)). **Why:** row-level security (RLS), JSONB for block + content and flexible properties, strong transactional guarantees, and a mature + ecosystem. RLS is what makes per-owner isolation enforceable inside the + database itself, not only in application code. +- **MySQL, MongoDB, Redis, MinIO** (object storage) run in the `devlean` edition + that `make all` starts; **SQLite**, **SQL Server** (needs the `engines` + plane), **DynamoDB** (an opt-in build) and remote **HTTP** APIs are supported + through the same data-plane interface. This is a deliberate feature of the + platform (one API over many engines), not a need of osionos itself. ### Other significant technologies - **Docker / Docker Compose** — every component runs in a container; one `make all`. - **A local certificate authority + TLS proxy** — all frontends served over trusted HTTPS locally. -- **LiveKit** — the WebRTC SFU for video rooms, a groot compose service started by `make all`; - the osionos bridge mints its tokens. +- **LiveKit** — the WebRTC SFU for video rooms, a groot compose service started + by `make all`; the osionos bridge mints its tokens. - **vault42 / 42ctl** — our own zero-knowledge secret store and CLI (separate repositories). -- **CI security scanning** — on every pull request, [`.github/workflows/mini-baas-security.yml`](.github/workflows/mini-baas-security.yml) - runs Semgrep (SAST), `npm`/`pnpm audit`, Snyk (when a token is set) and Trivy; Semgrep and Snyk - report without blocking. Dependabot opens dependency updates. SonarCloud analyses every pull - request through its GitHub app (`.sonarcloud.properties`), not through a workflow; - `renovate.json` is present but nothing runs it. +- **CI security scanning** — on every pull request, + [`.github/workflows/mini-baas-security.yml`](.github/workflows/mini-baas-security.yml) + runs Semgrep (SAST), `npm`/`pnpm audit`, Snyk (when a token is set) and Trivy; + Semgrep and Snyk report without blocking. Dependabot opens dependency updates. + SonarCloud analyses every pull request through its GitHub app + (`.sonarcloud.properties`), not through a workflow; `renovate.json` is present + but nothing runs it. ### Justification of the major choices - **Why build a BaaS instead of a single backend?** Because the same backend pieces are rebuilt for every project. We moved everything that varies between projects — routes, schemas, access rules, configuration — from code into data, so a new application is a contract, not a server. -- **Why three languages?** Each grobase plane has a different job (Node also runs the site's - auth-gateway and the osionos bridge). Go for boring, correct orchestration; - Rust where performance and memory safety protect tenant isolation; TypeScript where it already - existed. The data plane was migrated from TypeScript to Rust behind a per-request switch - (`RUST_DATA_PLANE_FORWARD`, on in the default compose), so the migration needed no downtime - and could be rolled back without a deployment. +- **Why three languages?** Each grobase plane has a different job (Node also + runs the site's auth-gateway and the osionos bridge). Go for boring, correct + orchestration; Rust where performance and memory safety protect tenant + isolation; TypeScript where it already existed. The data plane was migrated + from TypeScript to Rust behind a per-request switch + (`RUST_DATA_PLANE_FORWARD`, on in the default compose), so the migration + needed no downtime and could be rolled back without a deployment. - **Why per-request isolation?** Scoping on every request (instead of per connection) means a pooled connection can never carry one user's permissions into another user's query. @@ -493,12 +525,13 @@ The schema lives in two places: 1. **Application schema** — idempotent SQL migrations in [`models/`](models/) (`*-migration.sql`), applied to grobase's PostgreSQL by `make all` through - [`scripts/apply-models-migrations.sh`](scripts/apply-models-migrations.sh). That runner - deliberately skips seven files that target a database with an integer `users.id` (used by - the Electron native edition) or that later files supersede: `user.sql`, `gdpr-migration.sql`, - `auth-security-migration.sql`, `rls-hardening-migration.sql`, `seeds.sql`, - `osionos-folder-surface-migration.sql` and `osionos-wiki-surface-migration.sql`; its header - explains why. + [`scripts/apply-models-migrations.sh`](scripts/apply-models-migrations.sh). + That runner deliberately skips seven files that target a database with an + integer `users.id` (used by the Electron native edition) or that later files + supersede: `user.sql`, `gdpr-migration.sql`, `auth-security-migration.sql`, + `rls-hardening-migration.sql`, `seeds.sql`, + `osionos-folder-surface-migration.sql` and + `osionos-wiki-surface-migration.sql`; its header explains why. 2. **Platform schema** — grobase's control-plane registries (tenants, mounts, roles, policies, API keys), created by grobase's own migrations, plus per-application databases created at runtime from each contract (e.g. `infra/config/contracts/website.schema.sql` in grobase). @@ -578,11 +611,12 @@ Other table groups, by migration file: ### Platform (grobase) registries -Access control is stored as data: `roles`, `user_roles` and `resource_policies` tables, evaluated -by the SQL function `public.has_permission(...)` and mirrored by the Rust data plane's own ABAC -evaluator. Every table created through grobase's schema API gets an `owner_id` column -appended when the caller does not declare one (contract schemas declare it themselves), which is -what makes one isolation rule apply to any table. +Access control is stored as data: `roles`, `user_roles` and `resource_policies` +tables, evaluated by the SQL function `public.has_permission(...)` and mirrored +by the Rust data plane's own ABAC evaluator. Every table created through +grobase's schema API gets an `owner_id` column appended when the caller does not +declare one (contract schemas declare it themselves), which is what makes one +isolation rule apply to any table. **Two `users` tables.** `models/user.sql` defines `users.id` as `SERIAL` (integer): it belongs to the auth gateway's database. The osionos tables reference users by `UUID`, in grobase's @@ -593,11 +627,12 @@ foreign-key clash (`scripts/apply-models-migrations.sh:27-38`). ## Features List -"Who" counts the non-merge commits that touch the feature's paths (last column), reachable from -the commit groot `main` pins for that repository, read through the root [`.mailmap`](.mailmap), -with bots and AI-agent identities left out; largest share first. How the identities are joined: -[`wiki/project/contributions-method.md`](wiki/project/contributions-method.md). A commit count is -not effort, and pairing or review does not show in it. +"Who" counts the non-merge commits that touch the feature's paths (last column), +reachable from the commit groot `main` pins for that repository, read through +the root [`.mailmap`](.mailmap), with bots and AI-agent identities left out; +largest share first. How the identities are joined: +[`wiki/project/contributions-method.md`](wiki/project/contributions-method.md). +A commit count is not effort, and pairing or review does not show in it. | Feature | Description | Who (commits) | Paths counted | |---|---|---|---| @@ -625,27 +660,30 @@ not effort, and pairing or review does not show in it. ## Modules -The subject requires **14 points** (Major = 2, Minor = 1). A module that cannot be demonstrated -live scores zero. Every row is graded against **the local stack built from `main`** -(`git checkout main`, `make all SKIP_SYNC=1`, which starts grobase's `devlean` edition; see -[Defense bring-up](#defense-bring-up-pinned)) by **one rule**, groot's own. It keeps the -clause of osionos +The subject requires **14 points** (Major = 2, Minor = 1). A module that cannot +be demonstrated live scores zero. Every row is graded against **the local stack +built from `main`** (`git checkout main`, `make all SKIP_SYNC=1`, which starts +grobase's `devlean` edition; see [Defense bring-up](#defense-bring-up-pinned)) +by **one rule**, groot's own. It keeps the clause of osionos [`docs/ai/README.md`](https://github.com/Univers42/osionos/blob/1c1d5d849c1dc43460a194f7ee3d97e17505205c/docs/ai/README.md) -lines 7–8 (a row is never A when its demonstration needs something switched off or unmeasured), -but it is stricter than that file's legend, which grades a documented profile A: - -- **A**: the demo works on that stack with nothing switched on, and a green CI job drives that - path against a running service. -- **B**: it works, but the demo needs something switched on (a flag, a profile, an edition, a - provider credential), or its only evidence is unit tests with fakes or a run that was never - repeated. -- **C**: partial. **Not claimed.** These rows are listed under [Not claimed yet](#not-claimed-yet). +lines 7–8 (a row is never A when its demonstration needs something switched off +or unmeasured), but it is stricter than that file's legend, which grades a +documented profile A: + +- **A**: the demo works on that stack with nothing switched on, and a green CI + job drives that path against a running service. +- **B**: it works, but the demo needs something switched on (a flag, a profile, + an edition, a provider credential), or its only evidence is unit tests with + fakes or a run that was never repeated. +- **C**: partial. **Not claimed.** These rows are listed under [Not claimed + yet](#not-claimed-yet). **Claimed = A and B only: 30 points against the 14 required. 8 of them are A.** -Paths are prefixed by repository: `G` groot, `GB` grobase (`apps/grobase`), `OS` osionos -(`apps/osionos/app`), `OO` opposite-osiris (`apps/opposite-osiris`). They point at the commits -pinned by groot's `main` branch. CI names a workflow job: `GB-CI` is grobase `ci.yml`, `OS-CI` -is osionos `ci.yml`, `OO-CI` is prismatica `ci.yml`. +Paths are prefixed by repository: `G` groot, `GB` grobase (`apps/grobase`), `OS` +osionos (`apps/osionos/app`), `OO` opposite-osiris (`apps/opposite-osiris`). +They point at the commits pinned by groot's `main` branch. CI names a workflow +job: `GB-CI` is grobase `ci.yml`, `OS-CI` is osionos `ci.yml`, `OO-CI` is +prismatica `ci.yml`. | # | Module | Category | Type | Pts | Grade | Core files | Tests → CI job | Docs | Demo (3 steps) | |---|---|---|---|--:|:--:|---|---|---|---| @@ -671,7 +709,8 @@ is osionos `ci.yml`, `OO-CI` is prismatica `ci.yml`. No separate framework Minor is claimed beside row 4. -**Point calculation** (free choice is capped at 3, [`wiki/project/01-subject.md`](wiki/project/01-subject.md#points)) +**Point calculation** (free choice is capped at 3, +[`wiki/project/01-subject.md`](wiki/project/01-subject.md#points)) | | Before (2026-10) | After | |---|--:|--:| @@ -682,11 +721,11 @@ No separate framework Minor is claimed beside row 4. | Of which A | 10 | **8** | | Required | 14 | 14 | -What moved: under the old legend ("works as-is"), six rows were A. Under one rule, the rows -whose demonstration needs a switch or whose only evidence is unit-level are B: real-time -collaboration (off by default), the contract factory and the SSRF guard. Row 3 stays A on the -chat demo, which needs nothing switched on, and row 4 is new at A. The rows below no longer -count. +What moved: under the old legend ("works as-is"), six rows were A. Under one +rule, the rows whose demonstration needs a switch or whose only evidence is +unit-level are B: real-time collaboration (off by default), the contract factory +and the SSRF guard. Row 3 stays A on the chat demo, which needs nothing switched +on, and row 4 is new at A. The rows below no longer count. ### Not claimed yet @@ -722,8 +761,9 @@ count. the cloud metadata endpoint `169.254.169.254` — CGNAT, IPv6 ULA and link-local, IPv4-mapped addresses and internal hostnames, then **pins** the connection to the validated public IP so a later DNS rebind cannot redirect it inward. -- **Value and weight.** Small, self-contained and demonstrable in seconds (a mount pointing at - `169.254.169.254` is refused), and it shows security judgement on a feature we chose to build. +- **Value and weight.** Small, self-contained and demonstrable in seconds (a + mount pointing at `169.254.169.254` is refused), and it shows security + judgement on a feature we chose to build. --- @@ -731,9 +771,10 @@ count. ### Who committed where -Non-merge commits per member reachable from the commit groot `main` pins for each repository, -read through the root [`.mailmap`](.mailmap), bots and AI-agent identities left out (counted on -2026-11-05 at `main` = `0bef3cb3`). The command, the identity joins and what is left out: +Non-merge commits per member reachable from the commit groot `main` pins for +each repository, read through the root [`.mailmap`](.mailmap), bots and AI-agent +identities left out (counted on 2026-11-05 at `main` = `0bef3cb3`). The command, +the identity joins and what is left out: [`wiki/project/contributions-method.md`](wiki/project/contributions-method.md). Several members work almost only in submodules, so the root alone understates them. @@ -747,11 +788,12 @@ Several members work almost only in submodules, so the root alone understates th | `shashemi` | @SMOSTAFAH1 | 42 | 17 | 15 | 39 | 8 | | | | | 2026-09-20 → 2026-11-04 | | `rstancu` | @esettes | | 90 | | | | | | 2 | | 2026-03-18 → 2026-05-02 | -Dates are author dates in these nine repositories only. Work that is not on a pinned commit does -not show above: `danfern3`'s 44 root commits sit on `fix/ci`, open as -[#165](https://github.com/Univers42/groot/pull/165), and most of their 133 monkey-bot commits are -on branches the pin does not reach. A commit count is not effort: one large commit and one typo -fix weigh the same, and pairing and review do not show in it. +Dates are author dates in these nine repositories only. Work that is not on a +pinned commit does not show above: `danfern3`'s 44 root commits sit on `fix/ci`, +open as [#165](https://github.com/Univers42/groot/pull/165), and most of their +133 monkey-bot commits are on branches the pin does not reach. A commit count is +not effort: one large commit and one typo fix weigh the same, and pairing and +review do not show in it. Merged pull requests per login in the project's repositories (groot, osionos, grobase, prismatica = opposite-osiris, osionos-mail, osionos-calendar, hydrawn, QA, monkey-bot), from @@ -770,70 +812,77 @@ The numbers in brackets below are the member's commits in that row of the ### dlesieur — Dylan Lesieur -- **Areas:** grobase (Go control plane, Rust data plane and realtime, Kong gateway, contracts - and self-serve apps), osionos (editor, chat, collaboration, social, profile, the bridge, the AI - service), mail, calendar, the root's infrastructure, TLS edge and CI; hydrawn (569 commits: - `apps/web`, the engine, `docs/reference`). +- **Areas:** grobase (Go control plane, Rust data plane and realtime, Kong + gateway, contracts and self-serve apps), osionos (editor, chat, collaboration, + social, profile, the bridge, the AI service), mail, calendar, the root's + infrastructure, TLS edge and CI; hydrawn (569 commits: `apps/web`, the engine, + `docs/reference`). - **Pull requests:** 260 merged (osionos 138, grobase 61, groot 56). -- **Features:** the largest share of every row of the Features List except the legal pages, for - example the block editor (164), the database block (125), chat (72) and the AI assistant (317). +- **Features:** the largest share of every row of the Features List except the + legal pages, for example the block editor (164), the database block (125), + chat (72) and the AI assistant (317). - **Challenges:** not recorded yet. ### danfern3 — Daniel Fernández -- **Areas:** `vendor/monkey-bot` (133 commits on all branches, 10 on the pinned commit: form-XSS - and mutation testing, configuration); - grobase Docker images built from scratch, Kubernetes deployment, the playground and Makefile - (March 2026); osionos breadcrumbs, trash, multi-line text in blocks, the markdown engine and - code-quality fixes; hydrawn (20 commits, `apps/web`, `apps/api`, `packages/contract`, - 2026-09-24: submodule clone paths, formatting); root submodule pins and the `make all` bats fix, - on `fix/ci` ([#165](https://github.com/Univers42/groot/pull/165), open). +- **Areas:** `vendor/monkey-bot` (133 commits on all branches, 10 on the pinned + commit: form-XSS and mutation testing, configuration); grobase Docker images + built from scratch, Kubernetes deployment, the playground and Makefile (March + 2026); osionos breadcrumbs, trash, multi-line text in blocks, the markdown + engine and code-quality fixes; hydrawn (20 commits, `apps/web`, `apps/api`, + `packages/contract`, 2026-09-24: submodule clone paths, formatting); root + submodule pins and the `make all` bats fix, on `fix/ci` + ([#165](https://github.com/Univers42/groot/pull/165), open). - **Pull requests:** 4 merged (prismatica). - **Features:** block editor (29), whiteboard (20). - **Challenges:** not recorded yet. ### serjimen — Sergio Jiménez de la Cruz -- **Areas:** the public site, opposite-osiris (134 commits on the pinned commit: hero animation - performance, unit tests and benchmarks, security fixes, auth pages); osionos accessibility fixes, page links, - move and delete, shared UI refactor, the node installer's self-update (#277) and database probe +- **Areas:** the public site, opposite-osiris (134 commits on the pinned commit: + hero animation performance, unit tests and benchmarks, security fixes, auth + pages); osionos accessibility fixes, page links, move and delete, shared UI + refactor, the node installer's self-update (#277) and database probe diagnostics (#278), the changelog. - **Pull requests:** 8 merged (prismatica 7, osionos 1), among them the landing page in English, Spanish and Arabic with right-to-left layout (prismatica #21, #22, #23, #35), the accessible privacy policy and terms (#38) and a WCAG 2.2 AA audit pipeline with axe-core fixes (#39). -- **Features:** block editor (8), legal pages (2), communities and social feed (2), sign-up / - sign-in (1), database block (1). +- **Features:** block editor (8), legal pages (2), communities and social feed + (2), sign-up / sign-in (1), database block (1). - **Challenges:** not recorded yet. ### vjan-nie — Vadim Jan Nieto -- **Areas:** `vendor/QA` (38 commits: registry, migrations, hooks, CLI); root end-to-end tests, - the wiki and README, graph-studio tests, the hydrawn TLS edge and its CORS, submodule - pins; osionos whiteboard and graph-studio fixes; grobase Docker infrastructure and dependency - fixes; hydrawn (4 commits: engine bumps, the nested-shape binding fix). +- **Areas:** `vendor/QA` (38 commits: registry, migrations, hooks, CLI); root + end-to-end tests, the wiki and README, graph-studio tests, the hydrawn TLS + edge and its CORS, submodule pins; osionos whiteboard and graph-studio fixes; + grobase Docker infrastructure and dependency fixes; hydrawn (4 commits: engine + bumps, the nested-shape binding fix). - **Pull requests:** 72 merged (groot 45, osionos 17, prismatica 6, grobase 4). -- **Features:** block editor (42), AI assistant (9), public API (5), whiteboard (4), legal pages - (3), multi-engine data API (3), database block (2), chat (1). +- **Features:** block editor (42), AI assistant (9), public API (5), whiteboard + (4), legal pages (3), multi-engine data API (3), database block (2), chat (1). - **Challenges:** not recorded yet. ### shashemi — Seyed Mostafa Hashemian -- **Areas:** security fixes across root, grobase and opposite-osiris (SAST findings, nginx scan - suppressions, IDE socket proxy hardening); the site's legal pages, SEO and accessibility; root - CI triggers and the models' export erasure paths; osionos end-to-end fixes; hydrawn (8 - commits, `apps/web`, `apps/api`, `packages/contract`: trail and notes, hydrawn #1, and the +- **Areas:** security fixes across root, grobase and opposite-osiris (SAST + findings, nginx scan suppressions, IDE socket proxy hardening); the site's + legal pages, SEO and accessibility; root CI triggers and the models' export + erasure paths; osionos end-to-end fixes; hydrawn (8 commits, `apps/web`, + `apps/api`, `packages/contract`: trail and notes, hydrawn #1, and the pen-thickness-with-zoom test, #8). - **Pull requests:** 57 merged (prismatica 20, groot 19, osionos 12, grobase 6). -- **Features:** whiteboard (6), legal pages (5), real-time collaboration (2), block editor (2), - database block, video rooms, communities, AI assistant and public API (1 each). +- **Features:** whiteboard (6), legal pages (5), real-time collaboration (2), + block editor (2), database block, video rooms, communities, AI assistant and + public API (1 each). - **Challenges:** not recorded yet. ### Team-level challenges From the project's history: -- **Migrating the data plane from TypeScript to Rust with no downtime**, behind a per-request - switch (`RUST_DATA_PLANE_FORWARD`). +- **Migrating the data plane from TypeScript to Rust with no downtime**, behind + a per-request switch (`RUST_DATA_PLANE_FORWARD`). - **Keeping eight database adapters at parity**, enforced by a conformance battery that runs every adapter against a real engine and checks it serves exactly what it advertises. - **Auditing our own authorisation path** and shipping a reversible mitigation for a weakness we @@ -865,17 +914,21 @@ From the project's history: This project was built with **heavy AI assistance**, and we state it plainly. - **Tools.** The repositories record these: - - **Claude Code**, with the team's own configuration kit in groot's [`.claude`](.claude) - submodule (`Univers42/claude-deal-with-the-devil`: agents, rules, skills and hooks). - - **Gemini** in osionos (plans under `.gemini/plan/`), beside `.agents/` and an `.mcp.json`. - - **opencode**, an AI coding agent that committed under its own name (1 root and 5 osionos - commits at the pins), and the OpenCode agent team "Space Bunny" on hydrawn (68 commits at - the pin, hydrawn `BUNNY.md`). - - **GitHub Copilot** (`copilot-swe-agent`, 9 commits at prismatica's pin, and Copilot review on - pull requests) and **CodeRabbit** (reviews on pull requests since 2026-10-23). -- **Commit history.** On 2026-11-04 the history of groot, osionos and grobase was rewritten to - remove `Co-authored-by` trailers. Since then no commit carries a co-author line, so the history - does not show which commits were written with an AI tool, and must not be read as AI-free + - **Claude Code**, with the team's own configuration kit in groot's + [`.claude`](.claude) submodule (`Univers42/claude-deal-with-the-devil`: + agents, rules, skills and hooks). + - **Gemini** in osionos (plans under `.gemini/plan/`), beside `.agents/` and + an `.mcp.json`. + - **opencode**, an AI coding agent that committed under its own name (1 root + and 5 osionos commits at the pins), and the OpenCode agent team "Space + Bunny" on hydrawn (68 commits at the pin, hydrawn `BUNNY.md`). + - **GitHub Copilot** (`copilot-swe-agent`, 9 commits at prismatica's pin, and + Copilot review on pull requests) and **CodeRabbit** (reviews on pull + requests since 2026-10-23). +- **Commit history.** On 2026-11-04 the history of groot, osionos and grobase + was rewritten to remove `Co-authored-by` trailers. Since then no commit + carries a co-author line, so the history does not show which commits were + written with an AI tool, and must not be read as AI-free ([`wiki/project/contributions-method.md`](wiki/project/contributions-method.md)). - **Code.** AI wrote and refactored code across the stack: grobase planes and adapters, the frontends, SQL migrations, the Makefile pipeline and the Docker setup. @@ -885,35 +938,38 @@ This project was built with **heavy AI assistance**, and we state it plainly. path ([`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md)). - **Documentation.** The wiki and this README were drafted and distilled with AI assistance from the project's own design documents and code, then checked against the repository. -- **How we kept control.** A human merges every pull request; nothing reaches `develop` or - `main` by an agent alone. Approval by a second member is required by the rulesets but thin in - practice (see [Project Management](#project-management)). A change is accepted only when its - verification gate passes. Every member must be able to explain the AI-assisted code in their - area. +- **How we kept control.** A human merges every pull request; nothing reaches + `develop` or `main` by an agent alone. Approval by a second member is required + by the rulesets but thin in practice (see [Project + Management](#project-management)). A change is accepted only when its + verification gate passes. Every member must be able to explain the AI-assisted + code in their area. --- ## Known limitations - **No game.** All gaming-dependent modules are out of scope. -- **Expressiveness is narrow by design.** grobase has no per-application server code; business - rules are expressed as policies, schema constraints, database triggers, or functions in the - flag-gated functions plane. +- **Expressiveness is narrow by design.** grobase has no per-application server + code; business rules are expressed as policies, schema constraints, database + triggers, or functions in the flag-gated functions plane. - **Documented security weaknesses.** Known and declared in [`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md). -- **Several features are behind flags that are off by default** — see the Grade column in - [Modules](#modules). -- **No interface translation in osionos.** `i18next` is declared but no translation resource is - loaded (see [Modules](#modules)). The prismatica site itself ships English, Spanish and Arabic. +- **Several features are behind flags that are off by default** — see the Grade + column in [Modules](#modules). +- **No interface translation in osionos.** `i18next` is declared but no + translation resource is loaded (see [Modules](#modules)). The prismatica site + itself ships English, Spanish and Arabic. - **Whiteboard editing is loopback-only and has no per-user authorization yet** (see [Demo](#demo)). ## License - There is no `LICENSE` file at the repository root. -- grobase is open-core under the GNU AGPL v3 (`apps/grobase/LICENSE`); `apps/grobase/LICENSING.md` - maps which parts carry which licence. -- osionos, opposite-osiris (prismatica), hydrawn, mail and calendar carry no licence file. +- grobase is open-core under the GNU AGPL v3 (`apps/grobase/LICENSE`); + `apps/grobase/LICENSING.md` maps which parts carry which licence. +- osionos, opposite-osiris (prismatica), hydrawn, mail and calendar carry no + licence file. --- @@ -926,4 +982,5 @@ This project was built with **heavy AI assistance**, and we state it plainly. - [`wiki/security/`](wiki/security/) — security model, proofs, known weaknesses, network - [`DATA-MIGRATION.md`](DATA-MIGRATION.md) — fresh-machine and migration runbook - `apps/grobase/CLAUDE.md` — grobase's own authoritative technical document (inside the submodule) -- [Prismatica docs](https://prismatica-beta.vercel.app/docs/) — the landing's documentation site +- [Prismatica docs](https://prismatica-beta.vercel.app/docs/) — the landing's + documentation site diff --git a/wiki/STATUS.md b/wiki/STATUS.md index 4921ea4d5..ea648fc9a 100644 --- a/wiki/STATUS.md +++ b/wiki/STATUS.md @@ -40,10 +40,10 @@ Update this table whenever a page's status block changes. It is the working list | product/03-opposite-osiris | Partial | **Privacy Policy / ToS existence unverified** | | product/04-repos | Partial | What is actually inside the delivered perimeter | | project/01-subject | Unverified by nature | Source is private; re-check on each subject version | -| project/02-modules | Superseded | Whole ledger replaced by the README Modules table (2026-11-05) | +| project/02-modules | Superseded | By the README Modules table, 2026-11-05 | | project/03-team | **Template** | Facts not held anywhere; fill with the team | | project/04-glossary | Verified | — | -| project/contributions-method | Verified · 2026-11-05 | Counts age with every new pin; recount with the command on the page | +| project/contributions-method | Verified | Counts age; recount on each pin | | project/ai-llm-interface | Partial | nginx buffering/timeouts untested; #275 not in groot's pin yet | | project/ai-audit-2026-10-28 | Superseded | Pin facts replaced by the README Modules table, 2026-11-04 | | project/ai-stall-diagnosis-2026-10-29 | Diagnosis only | Hypotheses not tested live | diff --git a/wiki/project/02-modules.md b/wiki/project/02-modules.md index ac387e73d..9661d14dd 100644 --- a/wiki/project/02-modules.md +++ b/wiki/project/02-modules.md @@ -1,8 +1,8 @@ # Module ledger -> **Superseded · 2026-11-05.** This whole page is history: its rows, letters, legend and -> point totals. The current grades, one rule and the points table are in the -> [README Modules table](../../README.md#modules). +> **Superseded · 2026-11-05.** This whole page is history: its rows, letters, +> legend and point totals. The current grades, one rule and the points table are +> in the [README Modules table](../../README.md#modules). > > **Status:** Superseded · 2026-11-05 (written as Partial · 2026-09-15) > **Evidence:** flag states read from `deploy/fly/boot.sh`; every gate named here exists in the @@ -34,7 +34,8 @@ the screen does not. | OAuth 2.0 (User mgmt, minor) | 1 | `SSO_ENABLED`, migration `053` | `m110`, `m163` | **B** | | File upload (Web, minor) | 1 | storage plane, `STORAGE_BUCKET_SCOPE_ENABLED` | `m159` | **C** | -Nominal total without free choice: **18**. Seven of those points are **A** (rows 1–4). +Nominal total without free choice: **18**. Seven of those points are **A** (rows +1–4). **The key distinction:** organisation-system's backend is already running in production, so it needs only a screen. The **B** rows need a flag, a migration and a gate run — but no new code. @@ -67,10 +68,11 @@ in the project but hard to demonstrate live — better as an oral argument than | Does `VaultProvider` talk to HashiCorp Vault? (credential layer, migration `060`) | 2 pts and the only cybersecurity module | | What are `src/apps/ai/` and `src/apps/analytics/`? | Up to 4 pts from categories written off | -The AI category was first dismissed because gaming modules need a game and we have none. That -no longer holds: the README now claims four AI modules (LLM interface, RAG, moderation, voice; -6 points, all B), and the analytics dashboard major is still unchecked. The LLM interface is -explained in [ai-llm-interface](ai-llm-interface.md). +The AI category was first dismissed because gaming modules need a game and we +have none. That no longer holds: the README now claims four AI modules (LLM +interface, RAG, moderation, voice; 6 points, all B), and the analytics dashboard +major is still unchecked. The LLM interface is explained in +[ai-llm-interface](ai-llm-interface.md). --- diff --git a/wiki/project/contributions-method.md b/wiki/project/contributions-method.md index c28e348dc..6ebb79ffa 100644 --- a/wiki/project/contributions-method.md +++ b/wiki/project/contributions-method.md @@ -1,72 +1,83 @@ # How the contribution counts are made -The README's [Features List](../../README.md#features-list) and -[Who committed where](../../README.md#who-committed-where) count commits one way, described here -with the identity joins it rests on. +The README's [Features List](../../README.md#features-list) and [Who committed +where](../../README.md#who-committed-where) count commits one way, described +here with the identity joins it rests on. ## The method -Non-merge commits reachable from the commit groot `main` pins for each repository, read through -the root [`.mailmap`](../../.mailmap), with bots and AI-agent identities left out: +Non-merge commits reachable from the commit groot `main` pins for each +repository, read through the root [`.mailmap`](../../.mailmap), with bots and +AI-agent identities left out: ```sh -pin=$(git ls-tree origin/main apps/osionos/app | awk '{print $3}') # root: origin/main itself +# for the root repository, use origin/main itself as the pin +pin=$(git ls-tree origin/main apps/osionos/app | awk '{print $3}') git -C apps/osionos/app -c mailmap.file="$PWD/.mailmap" \ log --no-merges --format='%aN' "$pin" -- | grep -viE 'bot|AI agent' | sort | uniq -c | sort -rn ``` -Counted on 2026-11-05, groot `main` = `0bef3cb3`. Repositories: groot, osionos, grobase, -opposite-osiris (prismatica), hydrawn, mail, calendar, QA, monkey-bot. +Counted on 2026-11-05, groot `main` = `0bef3cb3`. Repositories: groot, osionos, +grobase, opposite-osiris (prismatica), hydrawn, mail, calendar, QA, monkey-bot. -Caveat: a commit count is not effort. One large commit and one typo fix weigh the same; pairing, -review and work committed by someone else do not show; a commit that touches several features -counts once for each. Work that is not on a pinned commit (an open branch, an unmerged pull -request) is not counted. +Caveat: a commit count is not effort. One large commit and one typo fix weigh +the same; pairing, review and work committed by someone else do not show; a +commit that touches several features counts once for each. Work that is not on a +pinned commit (an open branch, an unmerged pull request) is not counted. -`scripts/contributors.sh` counts all refs (`--all`), not the pins. Until a clone drops the refs -from before the 2026-11-04 history rewrite, `--all` counts each rewritten commit twice. +`scripts/contributors.sh` counts all refs (`--all`), not the pins. Until a clone +drops the refs from before the 2026-11-04 history rewrite, `--all` counts each +rewritten commit twice. ## Left out of the counts At the pins, on 2026-11-05: -| Identity | Kind | Commits | -|---|---|---| -| `Space Bunny` (`bunny`, `Space Bunny`, `builder`) | the OpenCode agent team `dlesieur` ran on hydrawn (hydrawn `BUNNY.md`) | 68 hydrawn | -| `opencode` | AI coding agent committing under its own name | 1 root, 5 osionos | -| `dependabot[bot]`, `coderabbitai[bot]`, `copilot-swe-agent[bot]`, `Grok CI Bot` | bots | 8 + 3 + 2 root (dependabot, coderabbit, Grok), 4 osionos (coderabbit), 9 opposite-osiris (copilot) | +- `Space Bunny` (also `bunny` and `builder`): the OpenCode agent team `dlesieur` + ran on hydrawn (hydrawn `BUNNY.md`). 68 hydrawn commits. +- `opencode`: an AI coding agent committing under its own name. 1 root and 5 + osionos commits. +- Bots: `dependabot[bot]` 8 root; `coderabbitai[bot]` 3 root and 4 osionos; + `Grok CI Bot` 2 root; `copilot-swe-agent[bot]` 9 opposite-osiris. ## How the identities are joined The evidence for each join is in [`.mailmap`](../../.mailmap). -- Each member committed under several addresses, including GitHub's `noreply` ones; `.mailmap` - joins them. -- `settes ` is **`rstancu`** (Roxana Stancu): the address belongs to GitHub - account [@esettes](https://github.com/esettes), listed for `rstancu` on the original roster - ([`archive/wiki-2026-09/CONTRIBUTORS.md`](../../archive/wiki-2026-09/CONTRIBUTORS.md)). The - osionos commits (2026-04-10 → 2026-05-02) touch mostly the Playwright browser tests - (`tests/browser`), their CI job and committed build assets. `rstancu` is not in the current - team table. -- `La Cebolla ` is **`shashemi`**: opposite-osiris commit `93e6b65` carries - `Signed-off-by: Seyed Mostafa Hashemian`. -- `SMOSTAFAH1 ` is **`shashemi`**: it is the GitHub login - [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) of the team table, without the numeric id - `.mailmap` already maps (2 osionos commits at the pin). -- Two groups of grobase commits pair one member's name with another's address. They are - attributed by inference, not by proof: - - `LESdylan ` (3 commits on grobase's pinned commit, 5 on all branches, - 2026-09-21 → 2026-11-02) goes to `dlesieur`: the author name is `LESdylan`, and `b4c1d33f` - landed through grobase PR #89, opened by `LESdylan`. - - `dlesieur ` (5 commits, 2026-03-20/21) goes to `danfern3`: they sit inside - `danielfdez17`'s own Docker and Kubernetes series of the same two days. -- `opencode` and `Space Bunny` are AI agents, shown under their own names and left out of the - member counts (table above). -- `qwO-Owp` (born2root, 2026-10-08/09) and `Alex Caceres` (vendor/scripts, 2026-01-26) are tied - to no member by any address, sign-off or pull request. Neither repository is counted. -- On 2026-11-04 the history of groot, osionos and grobase was rewritten to remove - `Co-authored-by` trailers; trees, authors, dates and subjects are unchanged, and every commit - from the first rewritten one onward has a new SHA. 148 root commits on `main` have a one-word - subject (147 `dlesieur`, 1 `vjan-nie`, 2026-05-01 → 2026-10-09); the - [`Commit subjects`](../../.github/workflows/commit-subjects.yml) check refuses new ones. +- Each member committed under several addresses, including GitHub's `noreply` + ones; `.mailmap` joins them. +- `settes ` is **`rstancu`** (Roxana Stancu): the address + belongs to GitHub account [@esettes](https://github.com/esettes), listed for + `rstancu` on the original roster + ([`archive/wiki-2026-09/CONTRIBUTORS.md`](../../archive/wiki-2026-09/CONTRIBUTORS.md)). + The osionos commits (2026-04-10 → 2026-05-02) touch mostly the Playwright + browser tests (`tests/browser`), their CI job and committed build assets. + `rstancu` is not in the current team table. +- `La Cebolla ` is **`shashemi`**: opposite-osiris commit + `93e6b65` carries `Signed-off-by: Seyed Mostafa Hashemian`. +- `SMOSTAFAH1 ` is **`shashemi`**: it is + the GitHub login [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) of the team + table, without the numeric id `.mailmap` already maps (2 osionos commits at + the pin). +- Two groups of grobase commits pair one member's name with another's address. + They are attributed by inference, not by proof: + - `LESdylan ` (3 commits on grobase's pinned commit, 5 on all + branches, 2026-09-21 → 2026-11-02) goes to `dlesieur`: the author name is + `LESdylan`, and `b4c1d33f` landed through grobase PR #89, opened by + `LESdylan`. + - `dlesieur ` (5 commits, 2026-03-20/21) goes to `danfern3`: + they sit inside `danielfdez17`'s own Docker and Kubernetes series of the + same two days. +- `opencode` and `Space Bunny` are AI agents, shown under their own names and + left out of the member counts (list above). +- `qwO-Owp` (born2root, 2026-10-08/09) and `Alex Caceres` (vendor/scripts, + 2026-01-26) are tied to no member by any address, sign-off or pull request. + Neither repository is counted. +- On 2026-11-04 the history of groot, osionos and grobase was rewritten to + remove `Co-authored-by` trailers; trees, authors, dates and subjects are + unchanged, and every commit from the first rewritten one onward has a new SHA. + 148 root commits on `main` have a one-word subject (147 `dlesieur`, 1 + `vjan-nie`, 2026-05-01 → 2026-10-09); the [`Commit + subjects`](../../.github/workflows/commit-subjects.yml) check refuses new + ones. From b749bc6e5d2749fab500e9071decd0aadcf2edae Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:11:16 +0100 Subject: [PATCH 14/22] docs(readme): grade WebSockets B and cite NestJS for the framework row Team answer, 2026-11-05: m201 checks the /ws handshake on a running realtime, not delivery between two users, and osionos's chat browser test runs against a stub bridge. Row 3 is therefore B. Row 4 now names NestJS, grobase's application plane, as the backend framework: grobase "Integration Tests" builds query-router from the pin, starts it and drives /query/v1/execute through Kong (m213). axum stays as a supporting example. Points: 30, of which 6 A (rows 1, 2, 4). --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 037d83d61..f9e33fd08 100644 --- a/README.md +++ b/README.md @@ -678,7 +678,7 @@ documented profile A: - **C**: partial. **Not claimed.** These rows are listed under [Not claimed yet](#not-claimed-yet). -**Claimed = A and B only: 30 points against the 14 required. 8 of them are A.** +**Claimed = A and B only: 30 points against the 14 required. 6 of them are A.** Paths are prefixed by repository: `G` groot, `GB` grobase (`apps/grobase`), `OS` osionos (`apps/osionos/app`), `OO` opposite-osiris (`apps/opposite-osiris`). They point at the commits pinned by groot's `main` branch. CI names a workflow @@ -689,8 +689,8 @@ prismatica `ci.yml`. |---|---|---|---|--:|:--:|---|---|---|---| | 1 | Public API (key, rate limit, docs, ≥5 endpoints) | Web | Major | 2 | **A** | `GB infra/docker/services/kong/conf/kong.yml:221-245` (`/rest/v1`: key-auth + rate-limiting); `GB infra/config/openapi/grobase-public.json` | `GB scripts/verify/m102-gateway-query-path.sh` → GB-CI "Integration Tests" (`ci.yml:927`) | `GB infra/config/openapi/README.md` | `make all SKIP_SYNC=1` → `/rest/v1` without `apikey` answers 401, with it 200 → repeat until 429 | | 2 | Backend as microservices | DevOps | Major | 2 | **A** | `GB orchestrators/compose/base/*.yml` (16 files); `GB orchestrators/makes/30-planes.mk:33`; `GB src/control-plane`; `GB src/data-plane-router` | GB-CI unit suites (`ci.yml:1436`) + "Engine conformance" legs (`ci.yml:1532`) | [`wiki/platform/02-planes.md`](wiki/platform/02-planes.md) | `make -C apps/grobase planes` → `docker compose ps` → `make healthcheck` | -| 3 | Real-time features via WebSockets | Web | Major | 2 | **A** | `GB infra/docker/services/realtime/realtime-agnostic/crates/realtime-server/src/server.rs:243` (`/ws`); `GB kong.yml:314-315` (`/realtime/v1/ws`); `OS scripts/bridge-social-core.mjs:192-201` (the bridge publishes); `OS src/services/realtime-messages/wsTransport.ts:81` (chat over the socket, on whenever a session exists) | `GB scripts/verify/m201-realtime-issuer.sh` opens `/ws` on the running realtime and expects `AUTH_OK` → GB-CI "Integration Tests" (`ci.yml:855`); m189 (`ci.yml:735`); `rust-realtime` suite and m184 (`ci.yml:1436,1479`) | [`wiki/platform/05-realtime.md`](wiki/platform/05-realtime.md) | sign in as two users in two browsers → open the same direct message in both → a message sent in one appears in the other without a reload. A second default demo: two windows on one Whiteboard board, where each stroke appears in the other (`G tests/e2e/specs/dw8-realtime.spec.ts`, `make e2e`, run by hand) | -| 4 | Use a framework for both the frontend and backend | Web | Major | 2 | **A** | Frontend: React 19 (`OS package.json:105-106`). Backend: axum 0.7 (`GB src/data-plane-router/Cargo.toml:59`; `GB infra/docker/services/realtime/realtime-agnostic/Cargo.toml:44`) | React: OS-CI "Browser tests", Playwright against the served app in 6 shards (`ci.yml:338-339`); axum: GB-CI "Integration Tests" (`ci.yml:652-653`) runs the data plane and realtime built from the pin | [`wiki/platform/02-planes.md`](wiki/platform/02-planes.md) | `make all SKIP_SYNC=1` → `docker compose ps` lists `mini-baas-data-plane-router-rust` and `mini-baas-realtime` (`GB orchestrators/compose/base/data-plane.yml:28,178`) → open osionos at `https://localhost:3001` | +| 3 | Real-time features via WebSockets | Web | Major | 2 | **B** | `GB infra/docker/services/realtime/realtime-agnostic/crates/realtime-server/src/server.rs:243` (`/ws`); `GB kong.yml:314-315` (`/realtime/v1/ws`); `OS scripts/bridge-social-core.mjs:192-201` (the bridge publishes); `OS src/services/realtime-messages/wsTransport.ts:81` (chat over the socket, on whenever a session exists) | `GB scripts/verify/m201-realtime-issuer.sh` → GB-CI "Integration Tests" (`ci.yml:855`): it checks the `/ws` handshake (`AUTH_OK`) on the running realtime, not delivery between two users; m189 (`ci.yml:735`); `rust-realtime` suite and m184 (`ci.yml:1436,1479`). osionos's chat browser test runs against a stub bridge (OS-CI "Browser tests (stub bridge URL)", `ci.yml:432-433`) | [`wiki/platform/05-realtime.md`](wiki/platform/05-realtime.md) | sign in as two users in two browsers → open the same direct message in both → a message sent in one appears in the other without a reload. A second default demo: two windows on one Whiteboard board, where each stroke appears in the other (`G tests/e2e/specs/dw8-realtime.spec.ts`, `make e2e`, run by hand) | +| 4 | Use a framework for both the frontend and backend | Web | Major | 2 | **A** | Frontend: React 19 (`OS package.json:105-106`). Backend: NestJS 11, grobase's application plane (`GB src/package.json:52`; `GB src/apps/query-router/src/main.ts:30`, `NestFactory`); axum 0.7 is a supporting example (`GB src/data-plane-router/Cargo.toml:59`) | React: OS-CI "Browser tests", Playwright against the served app in 6 shards (`ci.yml:338-339`). NestJS: GB-CI "Integration Tests" builds query-router from the pin and starts it (`ci.yml:900-904`), then m213 sends `/query/v1/execute` through Kong to it (`ci.yml:917`); the `nestjs` unit suite (`ci.yml:1436`) | [`wiki/platform/02-planes.md`](wiki/platform/02-planes.md) | `make all SKIP_SYNC=1` → `docker compose ps` lists `mini-baas-query-router` (`GB orchestrators/compose/base/app-services.yml:12`, in the `devlean` edition) → open osionos at `https://localhost:3001` | | 5 | Allow users to interact with other users (chat, profile, friends) | Web | Major | 2 | **B** | `OS scripts/bridge-chat.mjs`; `OS scripts/bridge-account-profile.mjs`; `OS scripts/bridge-social.mjs`; `OS src/features/chat`; `OS src/features/connections` | `OS tests/canvas/chat-catch-up.test.ts` → OS-CI "quality (root)" Canvas unit tests (`ci.yml:285`); `OS tests/bridge/bridge-chat-reply-notify`, `bridge-account-profile`, `bridge-social-connections`, `bridge-connection-transitions` → Bridge tests (`ci.yml:291`). Unit tests with fakes: no CI job drives two users against a running stack | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | as row 3 → user A sends a friend request, user B accepts → each opens the other's profile | | 6 | Standard user management and authentication | User management | Major | 2 | **B** | `OS scripts/bridge-account-profile.mjs`; `OS scripts/bridge-avatar.mjs`; `OS scripts/bridge-presence.mjs`; `OS src/features/collab/model/collabPresence.ts:63` (initials when there is no avatar) | `OS tests/bridge/bridge-avatar` (upload, type and size refusal), `bridge-presence` (online status), `bridge-account-profile` → OS-CI Bridge tests (`ci.yml:291`). Unit tests with fakes | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | sign up on `https://localhost:4322` → upload an avatar and edit the profile → a friend sees you online | | 7 | Real-time collaboration | Web | Minor | 1 | **B** | `OS src/features/collab/model/{remoteCursors,collabPresence,blockSync}.ts`; `OS scripts/bridge-collab.mjs:626`; `GB …/realtime-auth/src/jwt/mod.rs:90-94` (`collab:` closed to wildcard tokens) | `OS tests/bridge/bridge-collab-*` (9) → OS-CI Bridge tests (`ci.yml:291`) | [`wiki/product/02-osionos.md`](wiki/product/02-osionos.md) | rebuild osionos with `VITE_OSIO_COLLAB_SHARED=1` (off by default) → two browsers on one page → watch the remote cursor and edit the same block from both | @@ -714,18 +714,18 @@ No separate framework Minor is claimed beside row 4. | | Before (2026-10) | After | |---|--:|--:| -| Catalogue modules claimed (rows 1–13) | 18 | 21: 8 A (rows 1–4) + 13 B (rows 5–13) | +| Catalogue modules claimed (rows 1–13) | 18 | 21: 6 A (rows 1, 2, 4) + 15 B (rows 3, 5–13) | | Modules of choice (rows 14–15, cap 3) | 3 | 3, all B | | Artificial Intelligence modules (rows 16–19) | 10 | 6, all B | | **Total claimed** | **31 listed** | **30 (A + B)** | -| Of which A | 10 | **8** | +| Of which A | 10 | **6** | | Required | 14 | 14 | What moved: under the old legend ("works as-is"), six rows were A. Under one rule, the rows whose demonstration needs a switch or whose only evidence is -unit-level are B: real-time collaboration (off by default), the contract factory -and the SSRF guard. Row 3 stays A on the chat demo, which needs nothing switched -on, and row 4 is new at A. The rows below no longer count. +unit-level are B: WebSockets (CI checks the handshake, not delivery), real-time +collaboration (off by default), the contract factory and the SSRF guard. Row 4 +is new at A. The rows below no longer count. ### Not claimed yet From 706e1aad63f9f2faa2fc71cbbfcef66c9161698f Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:11:31 +0100 Subject: [PATCH 15/22] docs(readme): record the team's roles and its former members Team answer, 2026-11-05: all five are developers; roles evolved, and the main one of each is listed with a one-line responsibility. A short note names the former temporary members, thanks rstancu for her work on the osionos frontend and the QA workflow in the first months, and says the defense covers the current five. --- README.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f9e33fd08..30a25f482 100644 --- a/README.md +++ b/README.md @@ -361,22 +361,24 @@ a larger edition or a feature flag — see [Modules](#modules). ## Team Information -One owner per role, as the team confirmed on 2026-11-04 (the earlier working notes in -[`wiki/project/03-team.md`](wiki/project/03-team.md) named two Product Owners and two Project Managers). -The "Areas in the history" column is what each member's commits touch -([Individual Contributions](#individual-contributions) has the numbers). +All five members are developers. Roles evolved during the project; the main +role of each is below (team answer, 2026-11-05). The "Areas in the history" +column is what each member's commits touch ([Individual +Contributions](#individual-contributions) has the numbers). -| Member | Login | GitHub | Role(s) | Responsibilities | Areas in the history | +| Member | Login | GitHub | Main role | Responsibilities | Areas in the history | |---|---|---|---|---|---| -| Dylan Lesieur | `dlesieur` | [@LESdylan](https://github.com/LESdylan) | Product Owner · Developer | Product vision, backlog and priorities; validates completed work | grobase, osionos, mail, calendar, root infrastructure and CI | -| Daniel Fernández | `danfern3` | [@danielfdez17](https://github.com/danielfdez17) | Tech Lead · Developer | Architecture, stack decisions, code quality, reviews | monkey-bot (security test bot), grobase Docker and Kubernetes deployment, osionos editor fixes | -| Sergio Jiménez de la Cruz | `serjimen` | [@DjSurgeon](https://github.com/DjSurgeon) | Developer | Frontend, secrets management, deployment | the public site (opposite-osiris), osionos accessibility and editor features | -| Vadim Jan Nieto | `vjan-nie` | [@vjan-nie](https://github.com/vjan-nie) | Project Manager · Developer | Planning, tracking, communication, unblocking | QA tooling, end-to-end tests, documentation, Docker | -| Seyed Mostafa Hashemian | `shashemi` | [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) | Developer | No responsibility beyond development is recorded | security fixes and SAST, the site's legal pages, TLS edge | - -`rstancu` (Roxana Stancu, [@esettes](https://github.com/esettes)) is on the original roster -([`archive/wiki-2026-09/CONTRIBUTORS.md`](archive/wiki-2026-09/CONTRIBUTORS.md)) and committed -between 2026-03-18 and 2026-05-02; see [Who committed where](#who-committed-where). +| Dylan Lesieur | `dlesieur` | [@LESdylan](https://github.com/LESdylan) | Product Owner | Product vision and priorities | grobase, osionos, mail, calendar, root infrastructure and CI | +| Vadim Jan Nieto | `vjan-nie` | [@vjan-nie](https://github.com/vjan-nie) | Project Manager | Planning, tracking and coordination | QA tooling, end-to-end tests, documentation, Docker | +| Sergio Jiménez de la Cruz | `serjimen` | [@DjSurgeon](https://github.com/DjSurgeon) | Frontend tech lead | Frontend architecture and quality | the public site (opposite-osiris), osionos accessibility and editor features | +| Daniel Fernández | `danfern3` | [@danielfdez17](https://github.com/danielfdez17) | Backend tech lead | Backend architecture and deployment | monkey-bot (security test bot), grobase Docker and Kubernetes deployment, osionos editor fixes | +| Seyed Mostafa Hashemian | `shashemi` | [@SMOSTAFAH1](https://github.com/SMOSTAFAH1) | QA / quality tech lead | Testing and code quality; joined in the last part of the project | security fixes and SAST, the site's legal pages, TLS edge | + +**Former members.** The team changed along the way: `rstancu` (Roxana Stancu, +[@esettes](https://github.com/esettes)) and Alex Caceres were temporary members +who left. Special thanks to `rstancu`, who contributed significantly to the +osionos frontend and the QA workflow during the first, toughest months. The +defense covers the current five. --- From becb54a2080fd619bcf1bcc774c194b742b5b022 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:11:44 +0100 Subject: [PATCH 16/22] docs(readme): keep Project Management about the team, not individuals Per-person specifics leave the section; the evidence stays. A short paragraph says how planning and decisions work: meetings, mostly on Discord, then issues, pull requests and the wiki; dedicated meetings for blocking problems; TDD and DevOps practices toward a frictionless workflow. --- README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 30a25f482..ffb65387a 100644 --- a/README.md +++ b/README.md @@ -392,8 +392,7 @@ repositories record from what is the team's own account, and the last part measures how far we got towards that aim. **How the tracking evolved.** Work started in February 2026: the first commits -by `dlesieur`, `danfern3` and `vjan-nie` date from that month (`git log ---reverse` across the submodules). Between then and the autumn the team tried +date from that month (`git log --reverse` across the submodules). Between then and the autumn the team tried GitHub Projects, Jira tickets and Notion pages (team account: none of the three left a trace in commit messages, and the Projects board was not readable with our token). The only written trace is osionos @@ -427,6 +426,12 @@ Kanban board), as described in [`docs/dossier-project-dylan/dossier-projet.md:390-416`](https://github.com/Univers42/osionos/blob/develop/docs/dossier-project-dylan/dossier-projet.md) in osionos. +**Planning and decisions.** Work is planned and decided in meetings, mostly on +Discord, then recorded in issues, pull requests and the wiki. When a problem +blocked the team, it got a dedicated meeting. Test-driven development and +DevOps practices (CI on every pull request, Docker-first builds, one-command +bring-up) were the means to a frictionless workflow. + **How far we got.** We publish these numbers so the claims above can be checked: - **Sprints.** The sprints were planned outside GitHub: no milestone and no @@ -436,12 +441,12 @@ in osionos. - **Review.** The rulesets let a maintainer bypass them, and in a sample of the 40 most recent merged pull requests per repository, 0–22 % carry an approval from someone other than the author. -- **Nobody indispensable.** Shared ownership is real in breadth: `vjan-nie` - committed in 12 areas and `shashemi` in 8, osionos has six authors with five - or more commits, and prismatica's main author is `serjimen`. In depth we are - not there yet: `dlesieur` wrote 86 % of the 8,571 human commits, and in 17 of - 18 areas one author holds more than half of the commits. Commit counts are not - effort: one large commit and a typo fix weigh the same. +- **Nobody indispensable.** Shared ownership is real in breadth: every active + member committed in at least three areas, and osionos has six authors with + five or more commits. In depth we are not there yet: one member wrote 86 % of + the 8,571 human commits, and in 17 of 18 areas one author holds more than half + of the commits. Commit counts are not effort: one large commit and a typo fix + weigh the same. --- From b457f011b2b362a0d49a7dfff315208de5e652a5 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:12:30 +0100 Subject: [PATCH 17/22] docs(readme): shorten Individual Contributions to roles, areas and counts Each member keeps one line: main role and main areas; the two counts tables stay. The five "Challenges: not recorded" lines and the old team-level bullets become one "Challenges and lessons" paragraph, backed by three rebuilds verified in the repositories: the data plane moved from TypeScript to Rust (app-services.yml:96), grobase's Node session, email and GDPR services retired for the Go orchestrator (app-services.yml:133,190, 448), and osionos's legacy second brain replaced by graph_render (fresh-machine.yml:363). drawnosaurus to hydrawn is not cited: it was a rename (5b1378ba), not a rebuild. --- README.md | 121 ++++++++++++++++-------------------------------------- 1 file changed, 35 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index ffb65387a..96879287b 100644 --- a/README.md +++ b/README.md @@ -793,14 +793,12 @@ Several members work almost only in submodules, so the root alone understates th | `serjimen` | @DjSurgeon | | 82 | | 134 | | | | | | 2026-04-09 → 2026-11-03 | | `danfern3` | @danielfdez17 | | 84 | 73 | 4 | 20 | | | 1 | 10 | 2026-03-18 → 2026-10-02 | | `shashemi` | @SMOSTAFAH1 | 42 | 17 | 15 | 39 | 8 | | | | | 2026-09-20 → 2026-11-04 | -| `rstancu` | @esettes | | 90 | | | | | | 2 | | 2026-03-18 → 2026-05-02 | +| `rstancu` (former member) | @esettes | | 90 | | | | | | 2 | | 2026-03-18 → 2026-05-02 | Dates are author dates in these nine repositories only. Work that is not on a -pinned commit does not show above: `danfern3`'s 44 root commits sit on `fix/ci`, -open as [#165](https://github.com/Univers42/groot/pull/165), and most of their -133 monkey-bot commits are on branches the pin does not reach. A commit count is -not effort: one large commit and one typo fix weigh the same, and pairing and -review do not show in it. +pinned commit (open branches and pull requests) does not show above. A commit +count is not effort: one large commit and one typo fix weigh the same, and +pairing and review do not show in it. Merged pull requests per login in the project's repositories (groot, osionos, grobase, prismatica = opposite-osiris, osionos-mail, osionos-calendar, hydrawn, QA, monkey-bot), from @@ -814,86 +812,37 @@ prismatica = opposite-osiris, osionos-mail, osionos-calendar, hydrawn, QA, monke | @DjSurgeon | 8 | prismatica 7, osionos 1 | | @danielfdez17 | 4 | prismatica 4 | -The numbers in brackets below are the member's commits in that row of the -[Features List](#features-list). - -### dlesieur — Dylan Lesieur - -- **Areas:** grobase (Go control plane, Rust data plane and realtime, Kong - gateway, contracts and self-serve apps), osionos (editor, chat, collaboration, - social, profile, the bridge, the AI service), mail, calendar, the root's - infrastructure, TLS edge and CI; hydrawn (569 commits: `apps/web`, the engine, - `docs/reference`). -- **Pull requests:** 260 merged (osionos 138, grobase 61, groot 56). -- **Features:** the largest share of every row of the Features List except the - legal pages, for example the block editor (164), the database block (125), - chat (72) and the AI assistant (317). -- **Challenges:** not recorded yet. - -### danfern3 — Daniel Fernández - -- **Areas:** `vendor/monkey-bot` (133 commits on all branches, 10 on the pinned - commit: form-XSS and mutation testing, configuration); grobase Docker images - built from scratch, Kubernetes deployment, the playground and Makefile (March - 2026); osionos breadcrumbs, trash, multi-line text in blocks, the markdown - engine and code-quality fixes; hydrawn (20 commits, `apps/web`, `apps/api`, - `packages/contract`, 2026-09-24: submodule clone paths, formatting); root - submodule pins and the `make all` bats fix, on `fix/ci` - ([#165](https://github.com/Univers42/groot/pull/165), open). -- **Pull requests:** 4 merged (prismatica). -- **Features:** block editor (29), whiteboard (20). -- **Challenges:** not recorded yet. - -### serjimen — Sergio Jiménez de la Cruz - -- **Areas:** the public site, opposite-osiris (134 commits on the pinned commit: - hero animation performance, unit tests and benchmarks, security fixes, auth - pages); osionos accessibility fixes, page links, move and delete, shared UI - refactor, the node installer's self-update (#277) and database probe - diagnostics (#278), the changelog. -- **Pull requests:** 8 merged (prismatica 7, osionos 1), among them the landing page in English, - Spanish and Arabic with right-to-left layout (prismatica #21, #22, #23, #35), the accessible - privacy policy and terms (#38) and a WCAG 2.2 AA audit pipeline with axe-core fixes (#39). -- **Features:** block editor (8), legal pages (2), communities and social feed - (2), sign-up / sign-in (1), database block (1). -- **Challenges:** not recorded yet. - -### vjan-nie — Vadim Jan Nieto - -- **Areas:** `vendor/QA` (38 commits: registry, migrations, hooks, CLI); root - end-to-end tests, the wiki and README, graph-studio tests, the hydrawn TLS - edge and its CORS, submodule pins; osionos whiteboard and graph-studio fixes; - grobase Docker infrastructure and dependency fixes; hydrawn (4 commits: engine - bumps, the nested-shape binding fix). -- **Pull requests:** 72 merged (groot 45, osionos 17, prismatica 6, grobase 4). -- **Features:** block editor (42), AI assistant (9), public API (5), whiteboard - (4), legal pages (3), multi-engine data API (3), database block (2), chat (1). -- **Challenges:** not recorded yet. - -### shashemi — Seyed Mostafa Hashemian - -- **Areas:** security fixes across root, grobase and opposite-osiris (SAST - findings, nginx scan suppressions, IDE socket proxy hardening); the site's - legal pages, SEO and accessibility; root CI triggers and the models' export - erasure paths; osionos end-to-end fixes; hydrawn (8 commits, `apps/web`, - `apps/api`, `packages/contract`: trail and notes, hydrawn #1, and the - pen-thickness-with-zoom test, #8). -- **Pull requests:** 57 merged (prismatica 20, groot 19, osionos 12, grobase 6). -- **Features:** whiteboard (6), legal pages (5), real-time collaboration (2), - block editor (2), database block, video rooms, communities, AI assistant and - public API (1 each). -- **Challenges:** not recorded yet. - -### Team-level challenges - -From the project's history: - -- **Migrating the data plane from TypeScript to Rust with no downtime**, behind - a per-request switch (`RUST_DATA_PLANE_FORWARD`). -- **Keeping eight database adapters at parity**, enforced by a conformance battery that runs every - adapter against a real engine and checks it serves exactly what it advertises. -- **Auditing our own authorisation path** and shipping a reversible mitigation for a weakness we - found (see [`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md)). +### Per member + +- **`dlesieur`**, Product Owner: grobase (control plane, data plane, realtime, + gateway, contracts), osionos (editor, chat, collaboration, the bridge, the AI + service), mail, calendar, the root's infrastructure and CI. +- **`vjan-nie`**, Project Manager: QA tooling, end-to-end tests, the wiki and + README, submodule pins, Docker infrastructure. +- **`serjimen`**, frontend tech lead: the public site (opposite-osiris), + osionos accessibility and editor features. +- **`danfern3`**, backend tech lead: grobase Docker images and Kubernetes + deployment, monkey-bot, osionos editor features. +- **`shashemi`**, QA / quality tech lead: security fixes and SAST, the site's + legal pages, the TLS edge, end-to-end fixes. + +### Challenges and lessons + +The project met many productive problems and blockers: lack of autonomy, +communication problems, frustration. We addressed them with dedicated meetings +and by applying TDD and DevOps practices, toward a frictionless workflow. We +acknowledge our technical debt openly +([`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md) +is one record of it). Several technologies and architectures were rebuilt from +scratch when the first choice proved wrong late: the data plane moved from +TypeScript to Rust behind a per-request switch (`RUST_DATA_PLANE_FORWARD`, on +by default in grobase `orchestrators/compose/base/app-services.yml:96`); +grobase's Node session, email and GDPR services were retired and their work +moved to the Go orchestrator (`app-services.yml:133,190,448`); and osionos's +legacy second brain was replaced by graph_render (groot `fresh-machine.yml:363` +checks it on a live stack; the legacy one survives only behind a gate, osionos +`ci.yml:383-388`). The project's maturity comes from that intense team +experience, with its ups and downs. --- From 6a511c48b36d7910d58490319f265446a1013579 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:12:40 +0100 Subject: [PATCH 18/22] docs(readme): make the AI disclosure generic about people Every member used a variety of AI tools across code, tests, reviews and documentation. One line keeps the repository evidence (Claude Code and the .claude kit, Gemini and opencode in osionos, the OpenCode agent team on hydrawn, Copilot and CodeRabbit on PRs); the 2026-11-04 trailer rewrite and "how we kept control" stay. --- README.md | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 96879287b..d58a267b2 100644 --- a/README.md +++ b/README.md @@ -869,31 +869,18 @@ experience, with its ups and downs. This project was built with **heavy AI assistance**, and we state it plainly. -- **Tools.** The repositories record these: - - **Claude Code**, with the team's own configuration kit in groot's - [`.claude`](.claude) submodule (`Univers42/claude-deal-with-the-devil`: - agents, rules, skills and hooks). - - **Gemini** in osionos (plans under `.gemini/plan/`), beside `.agents/` and - an `.mcp.json`. - - **opencode**, an AI coding agent that committed under its own name (1 root - and 5 osionos commits at the pins), and the OpenCode agent team "Space - Bunny" on hydrawn (68 commits at the pin, hydrawn `BUNNY.md`). - - **GitHub Copilot** (`copilot-swe-agent`, 9 commits at prismatica's pin, and - Copilot review on pull requests) and **CodeRabbit** (reviews on pull - requests since 2026-10-23). +- **Tools and tasks.** Every member used a variety of AI tools (chat + assistants, coding agents, review bots) across code, tests, reviews and + documentation. +- **What the repositories record.** Claude Code with the team's kit in groot's + [`.claude`](.claude) submodule; Gemini (`.gemini/`) and the opencode agent in + osionos; an OpenCode agent team on hydrawn (`BUNNY.md`); GitHub Copilot and + CodeRabbit on pull requests. - **Commit history.** On 2026-11-04 the history of groot, osionos and grobase was rewritten to remove `Co-authored-by` trailers. Since then no commit carries a co-author line, so the history does not show which commits were written with an AI tool, and must not be read as AI-free ([`wiki/project/contributions-method.md`](wiki/project/contributions-method.md)). -- **Code.** AI wrote and refactored code across the stack: grobase planes and adapters, the - frontends, SQL migrations, the Makefile pipeline and the Docker setup. -- **Testing and verification.** AI wrote verification gates and test scripts, including the - Playwright smoke in [`tests/e2e/`](tests/e2e/), and ran them against the live stack. -- **Reviews.** AI-assisted code review of pull requests and security review of the authorisation - path ([`wiki/security/03-known-weaknesses.md`](wiki/security/03-known-weaknesses.md)). -- **Documentation.** The wiki and this README were drafted and distilled with AI assistance from - the project's own design documents and code, then checked against the repository. - **How we kept control.** A human merges every pull request; nothing reaches `develop` or `main` by an agent alone. Approval by a second member is required by the rulesets but thin in practice (see [Project From 97e5cd8e31599825b63e3964b0da5a6bec454752 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:13:15 +0100 Subject: [PATCH 19/22] docs(wiki): name unidentified and AI-agent authors without guessing contributions-method.md states opencode and Space Bunny (bunny, builder) as AI-agent identities whose operator is not identified, qwO-Owp as unidentified, and Alex Caceres and rstancu as former members (team answer, 2026-11-05). .mailmap drops "run by dlesieur" from the Space Bunny display name and its comment; the counts are unchanged (68 hydrawn commits still match the "AI agent" exclusion). --- .mailmap | 20 ++++++++++---------- wiki/project/contributions-method.md | 24 ++++++++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.mailmap b/.mailmap index ac4909da4..bdc46477a 100644 --- a/.mailmap +++ b/.mailmap @@ -52,13 +52,13 @@ opencode (AI agent) opencode (AI agent) opencode (AI agent) -# Space Bunny: the OpenCode agent team the owner ran on hydrawn (BUNNY.md, "You run a team -# of agents"), on local addresses. An AI agent, not a member, shown as one line like opencode. -Space Bunny (AI agent team, run by dlesieur) bunny -Space Bunny (AI agent team, run by dlesieur) bunny -Space Bunny (AI agent team, run by dlesieur) Space Bunny -Space Bunny (AI agent team, run by dlesieur) Space Bunny -Space Bunny (AI agent team, run by dlesieur) builder -Space Bunny (AI agent team, run by dlesieur) builder -Space Bunny (AI agent team, run by dlesieur) builder -Space Bunny (AI agent team, run by dlesieur) builder +# Space Bunny: an AI-agent identity on hydrawn (BUNNY.md describes a team of agents), on +# local addresses. Who ran it is not identified. Shown as one line, like opencode. +Space Bunny (AI agent team) bunny +Space Bunny (AI agent team) bunny +Space Bunny (AI agent team) Space Bunny +Space Bunny (AI agent team) Space Bunny +Space Bunny (AI agent team) builder +Space Bunny (AI agent team) builder +Space Bunny (AI agent team) builder +Space Bunny (AI agent team) builder diff --git a/wiki/project/contributions-method.md b/wiki/project/contributions-method.md index 6ebb79ffa..b2a41fbaf 100644 --- a/wiki/project/contributions-method.md +++ b/wiki/project/contributions-method.md @@ -34,10 +34,12 @@ rewritten commit twice. At the pins, on 2026-11-05: -- `Space Bunny` (also `bunny` and `builder`): the OpenCode agent team `dlesieur` - ran on hydrawn (hydrawn `BUNNY.md`). 68 hydrawn commits. -- `opencode`: an AI coding agent committing under its own name. 1 root and 5 - osionos commits. +- `Space Bunny` (also `bunny` and `builder`): an AI-agent identity. Its + addresses are local (for example `bunny@local`, `builder@bunny`, + `bunny@drawnosaurus.local`) and hydrawn `BUNNY.md` describes a team of agents. + Who ran it is not identified. 68 hydrawn commits. +- `opencode`: an AI-agent identity committing under its own name. Who ran it is + not identified. 1 root and 5 osionos commits. - Bots: `dependabot[bot]` 8 root; `coderabbitai[bot]` 3 root and 4 osionos; `Grok CI Bot` 2 root; `copilot-swe-agent[bot]` 9 opposite-osiris. @@ -53,7 +55,7 @@ The evidence for each join is in [`.mailmap`](../../.mailmap). ([`archive/wiki-2026-09/CONTRIBUTORS.md`](../../archive/wiki-2026-09/CONTRIBUTORS.md)). The osionos commits (2026-04-10 → 2026-05-02) touch mostly the Playwright browser tests (`tests/browser`), their CI job and committed build assets. - `rstancu` is not in the current team table. + `rstancu` is a former member (README, Team Information). - `La Cebolla ` is **`shashemi`**: opposite-osiris commit `93e6b65` carries `Signed-off-by: Seyed Mostafa Hashemian`. - `SMOSTAFAH1 ` is **`shashemi`**: it is @@ -69,11 +71,13 @@ The evidence for each join is in [`.mailmap`](../../.mailmap). - `dlesieur ` (5 commits, 2026-03-20/21) goes to `danfern3`: they sit inside `danielfdez17`'s own Docker and Kubernetes series of the same two days. -- `opencode` and `Space Bunny` are AI agents, shown under their own names and - left out of the member counts (list above). -- `qwO-Owp` (born2root, 2026-10-08/09) and `Alex Caceres` (vendor/scripts, - 2026-01-26) are tied to no member by any address, sign-off or pull request. - Neither repository is counted. +- `opencode` and `Space Bunny` are AI-agent identities, shown under their own + names and left out of the member counts (list above). +- `qwO-Owp` (born2root, 2026-10-08/09) is unidentified: no address, sign-off or + pull request ties it to anyone. +- `Alex Caceres` (vendor/scripts, 2026-01-26) is a former member (team answer, + 2026-11-05). +- Neither born2root nor vendor/scripts is counted. - On 2026-11-04 the history of groot, osionos and grobase was rewritten to remove `Co-authored-by` trailers; trees, authors, dates and subjects are unchanged, and every commit from the first rewritten one onward has a new SHA. From 698ed6c87a8a1c1714b74d0d10ee19093725d903 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:14:05 +0100 Subject: [PATCH 20/22] docs(readme): keep only the instructions a file or command backs - Disk: the 13.5 / 9.5 / 1.4 GB figures had no source in the repository (the runbook cites the README back). The row now says no minimum is measured and points at `docker system df`. - Vault enrolment: the commands wiki/runbooks/another-device.md:263-264 documents (vault42-ctl.sh keys init, keys enroll, an org admin grants). - `docker compose down` from a plain shell: replaced by `COMPOSE_PROFILES=dev docker compose down`, since make sets that profile (utils/mk/common.mk:45) and a plain shell does not. - Mail and Calendar: cite each repository's Google OAuth bridge (bridge/server.mjs); nothing claims the flows were run. --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d58a267b2..1ca2f539e 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ an editor session), **Kong** (grobase's API gateway, behind its WAF) and | **Linux host** | Tested on Debian 13 (trixie), the system the born2root VM installs; the CA-trust step uses `sudo` + `update-ca-certificates` | `vendor/born2root/docker/Dockerfile:14`, `vendor/born2root/generate/create_custom_iso.sh:120`; `utils/mk/certs.mk` | | **Docker Engine ≥ 25** + **Compose v2** | Healthchecks use `start_interval`, which needs Docker 25. Tested with Docker 29.8. | `docker-compose.yml:10` | | **RAM ≥ 8 GB** | Measured: the VM peaked at ~6.5 GB of 8 GB during `make all` | `wiki/runbooks/fresh-machine.md` (6266 MiB peak, v1.0.0-rc4, 2026-10-05) | -| **Disk ≥ 30 GB free for Docker** | Measured on the dev VM with the stack running (`docker system df`, 2026-10-01): images 13.5 GB, build cache 9.5 GB, volumes 1.4 GB | measured | +| **Free disk space for Docker** | Images, the build cache and data volumes all live in Docker's storage; no minimum is measured in the repository. `docker system df` shows the current use | — | | **bash, GNU Make, git, curl, openssl, ssh** | Make drives everything; curl runs the health check; openssl generates the local secrets | `utils/mk/app.mk:12-15`, `scripts/gen-local-env.sh:253` | | **A GitHub SSH key** | `.gitmodules` uses `git@github.com:` URLs, so the recursive clone needs SSH access to GitHub | `.gitmodules` | | **Google Chrome** | Current stable — the browser the project is evaluated on | [`wiki/project/01-subject.md`](wiki/project/01-subject.md) | @@ -326,8 +326,10 @@ secret store, via the **42ctl** CLI. A machine that holds a vault identity in `apps/grobase/.env` is absent (`secrets-ensure`), or on demand with `make vault42-pull-all APPLY=1`. With the vault passphrase also present, `make all` deploys against the data-center VM instead (see [Defense -bring-up](#defense-bring-up-pinned)). A new identity is created with `42ctl keys -init` and enrolled with an invitation from the vault's operator. Details: +bring-up](#defense-bring-up-pinned)). A new identity: `scripts/vault42-ctl.sh +keys init`, then `scripts/vault42-ctl.sh keys enroll --org univers42`, then an +org admin grants the project +([`wiki/runbooks/another-device.md`](wiki/runbooks/another-device.md)). Details: [`DATA-MIGRATION.md`](DATA-MIGRATION.md). The vault42 CLI is wired in beside that path: the `Secrets (vault42)` section of `make help`, and @@ -346,7 +348,7 @@ checklist: [ADR 0017](docs/adr/0017-vault42-cli-beside-the-old-path.md). | `make all GROBASE_EDITION=full` | Bring up every grobase plane except the playground demo UI, including extra engines and monitoring | | `docker compose ps` | Service status | | `docker compose logs -f ` | Follow one service's logs | -| `docker compose down` | Stop the frontends (data is kept) | +| `COMPOSE_PROFILES=dev docker compose down` | Stop and remove the root project's containers; named volumes stay (no `-v`). `make` sets `COMPOSE_PROFILES=dev` (`utils/mk/common.mk:45`), a plain shell does not | **Backend editions.** `make all` starts grobase in the **`devlean`** edition (`GROBASE_EDITION ?= devlean` in `utils/mk/grobase.mk`; listed in grobase's @@ -656,8 +658,8 @@ A commit count is not effort, and pairing or review does not show in it. | Two-factor authentication and passkeys | TOTP codes and passkeys on the account | dlesieur 15 | osionos `scripts/bridge-account-mfa*`, `scripts/bridge-account-passkeys*`, `src/features/settings/profile/TwoFactorModal.tsx` | | AI assistant | Streaming answers, retrieval over the workspace with citations, moderation, dictation and read-aloud; started with `--profile ai` | dlesieur 317, vjan-nie 9, shashemi 1 | osionos `services/osionos-ai`, `src/features/ai` | | Whiteboard | Shared boards in osionos's Whiteboard tab; strokes reach every open copy of the board live | dlesieur 569, danfern3 20, shashemi 6, vjan-nie 4 | hydrawn, whole repository | -| Mail | Read Gmail inside the workspace via Google OAuth. Opt-in: `make mail-up` and Google OAuth credentials | dlesieur 39 | `apps/mail`, whole repository | -| Calendar | Google Calendar events via Google OAuth. Opt-in: `make calendar-up` and Google OAuth credentials | dlesieur 22 | `apps/calendar`, whole repository | +| Mail | Read Gmail inside the workspace via Google OAuth (mail `bridge/server.mjs`). Opt-in: `make mail-up` and Google OAuth credentials | dlesieur 39 | `apps/mail`, whole repository | +| Calendar | Google Calendar events via Google OAuth (calendar `bridge/server.mjs`). Opt-in: `make calendar-up` and Google OAuth credentials | dlesieur 22 | `apps/calendar`, whole repository | | Contract-driven provisioning | One JSON contract → isolated database, roles, keys and frontend `.env` | dlesieur 9 | grobase `scripts/provision-contract.sh`, `infra/config/contracts` | | Self-serve applications | `POST /v1/tenants/me/apps` creates a new isolated app with its own database and key, behind `APPS_SELFSERVE_ENABLED` (off unless set) | dlesieur 32 | grobase `src/control-plane/internal/tenants` | | Multi-engine data API | One API and one key over PostgreSQL, MySQL, MongoDB, Redis (default edition), SQLite, SQL Server (`engines` plane), HTTP and DynamoDB (opt-in build) | dlesieur 95, vjan-nie 3 | grobase `src/data-plane-router` | From b506d59fea181de030cb507ca5b67235baa990e3 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:15:30 +0100 Subject: [PATCH 21/22] docs(readme): rewrap the edited Project Management paragraph at 80 columns Removing the per-person names joined two lines into one of 108 columns. Rendered HTML is unchanged (markdown-it-py, CommonMark + tables). --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1ca2f539e..046770765 100644 --- a/README.md +++ b/README.md @@ -394,10 +394,11 @@ repositories record from what is the team's own account, and the last part measures how far we got towards that aim. **How the tracking evolved.** Work started in February 2026: the first commits -date from that month (`git log --reverse` across the submodules). Between then and the autumn the team tried -GitHub Projects, Jira tickets and Notion pages (team account: none of the three -left a trace in commit messages, and the Projects board was not readable with -our token). The only written trace is osionos +date from that month (`git log --reverse` across the submodules). Between then +and the autumn the team tried GitHub Projects, Jira tickets and Notion pages +(team account: none of the three left a trace in commit messages, and the +Projects board was not readable with our token). The only written trace is +osionos [`docs/DoD.md:39`](https://github.com/Univers42/osionos/blob/develop/docs/DoD.md), a Definition-of-Done template that asks for evidence "in your Pull Request description or your Trello/Jira" ticket (2026-04-11). From 394280db5185df8688b177f7f41c08cc71092463 Mon Sep 17 00:00:00 2001 From: vjan-nie Date: Thu, 5 Nov 2026 09:36:20 +0100 Subject: [PATCH 22/22] docs(runbook): stop citing the removed disk sizes in fresh-machine Requirements row 13 cited the README for 13.5 / 9.5 / 1.4 GB figures that #184 removed for lack of a source. It now matches the README (no measured minimum) and cites only what this repository backs: fresh-bringup.sh warns under 10 GiB free on the Docker data root (scripts/verify/fresh-bringup.sh: 34,120-122), and the 2026-10-05 VM build in Measured results passed with a 65 GB /var on a 91 GB disk. --- wiki/runbooks/fresh-machine.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiki/runbooks/fresh-machine.md b/wiki/runbooks/fresh-machine.md index d5649e908..d04b99a43 100644 --- a/wiki/runbooks/fresh-machine.md +++ b/wiki/runbooks/fresh-machine.md @@ -10,7 +10,7 @@ otherwise. |---|---|---| | Docker Engine ≥ 25 + Compose v2 | healthchecks use `start_interval`; measured on Docker 29.8.2 | `docker-compose.yml:3`, [README prerequisites](../../README.md#prerequisites) | | RAM ≥ 8 GB | `make all` peaked at 6.25 GB used on an 8 GB VM; for a VM, `VM_RAM_MB=8192` | [measured runs](#measured-results) | -| Disk ≥ 30 GB free for Docker | images 13.5 GB + build cache 9.5 GB + volumes 1.4 GB, measured 2026-10-01 | [README prerequisites](../../README.md#prerequisites) | +| Free disk space for Docker | no minimum is measured; `fresh-bringup.sh` warns under 10 GiB free on the Docker data root, and the 2026-10-05 VM build passed with a 65 GB `/var` (91 GB disk) | `scripts/verify/fresh-bringup.sh:34,120-122`, [measured runs](#measured-results) | | Free ports | 443, 3001–3003, 3007, 4000, 4100, 4200, 4322, 4323, 7880, 7881, 8444, 8787, UDP 50000–50060, and Kong on 8000 | `docker-compose.yml`, `apps/grobase/orchestrators/compose/base/gateway.yml` | | One `sudo` password | `make all` copies the local CA into the system store once (`certs-trust-local`); `fresh-bringup.sh` asks for it first, with `sudo -v` | `utils/mk/certs.mk`, targets `certs-trust`, `certs-trust-local`, `scripts/verify/fresh-bringup.sh` (`check_sudo`) | | A GitHub SSH key | submodules use `git@github.com:` URLs | `.gitmodules` |