Commit Graph
62 Commits
Author SHA1 Message Date
admin c01deca048 ci: optimize delivery pipelines and add a production smoke gate
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 5s
masterplan-lock / check (pull_request) Successful in 10s
CI (SIAX Cloud) / security (pull_request) Successful in 19s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 21s
CI (SIAX Cloud) / integration (pull_request) Successful in 40s
CI (SIAX Cloud) / quality (pull_request) Successful in 2m13s
- One run per ref (concurrency) for CI, security, nightly and release; branch
  pushes no longer duplicate pull_request runs (push is main-only).
- Deploys keep their own concurrency group so two runs never race Coolify.
- pnpm store cache on every Node job.
- New /api/version returns the deployed commit (no secrets).
- New scheduled prod-smoke workflow: readiness, db/stripe health, running
  commit == main, and the document/credit routes exist (401/405, never 5xx).
2026-11-02 18:24:45 +01:00
admin 48dff2078e fix(admission): zero maximumCredits means pilot mode, not a missing reservation
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 5s
CI (SIAX Cloud) / security (push) Successful in 17s
Security Scan (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / quality (push) Successful in 46s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 5s
CI (SIAX Cloud) / security (pull_request) Successful in 23s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 25s
CI (SIAX Cloud) / integration (pull_request) Successful in 45s
CI (SIAX Cloud) / quality (pull_request) Successful in 59s
The structure route ran the model with maximumCredits=1 and no reservation when
credits were off, so admission returned reservation_required and the route
answered 502. Admission now requires a reservation only when maximumCredits>0.

Verified against the live stack: DOC0 segments -> LiteLLM/Ollama
(inf0-valuation) -> evidence validation -> needs_review (no export).
2026-11-02 16:42:01 +01:00
admin 581a20acd1 chore(workbench): log the structure failure reason and source segment count
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 6s
masterplan-lock / check (pull_request) Successful in 8s
CI (SIAX Cloud) / security (pull_request) Successful in 26s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 26s
CI (SIAX Cloud) / security (push) Successful in 38s
Security Scan (SIAX Cloud) / security (push) Successful in 53s
CI (SIAX Cloud) / quality (push) Successful in 55s
CI (SIAX Cloud) / integration (pull_request) Successful in 58s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m4s
Cloudflare replaces an origin 502 body with its own error page, so the JSON
message never reached the client. Log the reason server-side (codes/messages
only, never source text).
2026-11-02 16:32:55 +01:00
admin e93db5fc1f fix(doc0): call DOC0 as the granted service actor
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (pull_request) Successful in 3s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / security (pull_request) Successful in 1m2s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m11s
masterplan-lock / check (push) Successful in 1m38s
CI (SIAX Cloud) / quality (push) Successful in 1m49s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m50s
DOC0 denies an x-actor-id that the service identity has no actor_grant for, so
every upload/structure call from 0pt failed with DOC0_ACCESS_DENIED and became
outcome_unknown. The journal and project authorization keep the verified
end-user actor; only the DOC0 request acts as the service (DOC0_SERVICE_ACTOR_ID).
2026-11-02 16:17:29 +01:00
admin 35937933b3 chore(auth): log the OIDC failure code (no tokens or claims)
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 5s
masterplan-lock / check (push) Successful in 8s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / security (push) Successful in 23s
Security Scan (SIAX Cloud) / security (push) Successful in 23s
CI (SIAX Cloud) / integration (pull_request) Successful in 28s
CI (SIAX Cloud) / quality (pull_request) Successful in 46s
CI (SIAX Cloud) / quality (push) Successful in 54s
2026-11-02 15:58:52 +01:00
admin 71391db132 fix(auth): fall back to the verified access token for the tenant claim
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 4s
masterplan-lock / check (pull_request) Successful in 4s
Security Scan (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 19s
CI (SIAX Cloud) / quality (push) Successful in 1m8s
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / security (pull_request) Successful in 14s
CI (SIAX Cloud) / integration (pull_request) Successful in 27s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m3s
Zitadel does not always copy urn:zitadel:iam:org:id into the id_token; the
access token always carries it. Verify that token (issuer) before trusting its
tenant.
2026-11-02 15:48:51 +01:00
admin 023406c9b6 feat(auth): Zitadel OIDC login for the portal
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 3s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 5s
Security Scan (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / security (push) Successful in 21s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 19s
CI (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / integration (pull_request) Successful in 28s
CI (SIAX Cloud) / quality (push) Successful in 48s
CI (SIAX Cloud) / quality (pull_request) Successful in 45s
The portal had no way to obtain a verified principal: /api/0pt/* requires a
Bearer token, but the browser only had the dev-only HMAC cookie.

- GET /api/auth/login: Authorization Code + PKCE against Zitadel.
- GET /api/auth/callback: code exchange, id_token verification (issuer,
  audience, nonce) and a signed session cookie with sub + tenant.
- middleware accepts the signed session as a verified principal; Bearer wins.
- dev login POST is refused in production.
- Sign-in link in the portal shell.
2026-11-02 15:48:02 +01:00
admin d12b8fa55f feat(workbench): explicit pilot mode without a credit wallet
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 20s
masterplan-lock / check (pull_request) Successful in 23s
CI (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / quality (push) Successful in 48s
CI (SIAX Cloud) / integration (pull_request) Successful in 54s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m12s
OPT_CREDITS_MODE=off skips reserve/settle and reports credits:null, so the
document flow can be piloted before prices are decided. It is never a silent
fallback and purchases remain disabled.
2026-11-02 15:31:52 +01:00
admin e3c4bc28c3 feat(workbench): live LiteLLM gateway adapter + explicit project grants
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 6s
masterplan-lock / check (push) Successful in 6s
CI (SIAX Cloud) / security (push) Successful in 14s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 19s
CI (SIAX Cloud) / security (pull_request) Successful in 21s
Security Scan (SIAX Cloud) / security (push) Successful in 25s
CI (SIAX Cloud) / integration (pull_request) Successful in 29s
CI (SIAX Cloud) / quality (pull_request) Successful in 51s
CI (SIAX Cloud) / quality (push) Successful in 1m29s
- createInf0Gateway prefers the live OpenAI-compatible LiteLLM gateway and
  falls back to the native INF0 surface; admission stays local and fail-closed.
- Project authorization: OpenFGA when configured, otherwise a validated
  server-owned OPT_PROJECT_GRANTS list (deny by default).
- Tests for the gateway adapter, the factory and grants.
2026-11-02 14:50:50 +01:00
admin b3239487b7 feat(document-workbench): wire customer upload, structuring, credits and readiness
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 10s
CI (SIAX Cloud) / sonar (pull_request) Skipped
Security Scan (SIAX Cloud) / security (push) Successful in 13s
masterplan-lock / check (pull_request) Successful in 7s
CI (SIAX Cloud) / security (push) Successful in 26s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / security (pull_request) Successful in 19s
CI (SIAX Cloud) / quality (push) Successful in 1m9s
CI (SIAX Cloud) / quality (pull_request) Successful in 2m26s
CI (SIAX Cloud) / integration (pull_request) Successful in 2m33s
- POST /api/0pt/documents/upload: real multipart bytes into DOC0 through the
  durable attempt journal and the existing coordinator; verified tenant/actor
  only, project authorization fail-closed.
- POST /api/0pt/documents/structure: DOC0 segments -> INF0 -> evidence-bound
  validation -> optional JSON/CSV export, with credit reserve/settle.
- Credits: balance, server-owned price book, Stripe Checkout and idempotent
  webhook reconciliation via a Stripe re-read of session + payment intent.
- /portal/dokument and /portal/krediter: SIAX-styled workspace.
- @siax/access: universal, framework-neutral OpenFGA project relationship
  primitive reusable by DOC0/N0D/other products.
- Readiness: real Redis PING probe instead of presence-only; queue is now a
  live dependency when configured.
- Dockerfile: copy every workspace manifest so --frozen-lockfile works.
- Format/build hygiene: .prettierignore, .worktrees ignored, valid manifest YAML.
2026-11-02 14:46:10 +01:00
admin 5137bf87a1 fix: distinguish failed sources from empty results
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / security (push) Successful in 15s
masterplan-lock / check (pull_request) Successful in 7s
Security Scan (SIAX Cloud) / security (push) Successful in 18s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / security (pull_request) Successful in 20s
CI (SIAX Cloud) / integration (pull_request) Successful in 35s
CI (SIAX Cloud) / quality (pull_request) Successful in 39s
CI (SIAX Cloud) / quality (push) Successful in 48s
2026-11-02 06:58:15 +01:00
admin bd1c20edb2 feat: add guarded document workbench foundations
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 5s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 7s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 21s
CI (SIAX Cloud) / security (pull_request) Successful in 25s
CI (SIAX Cloud) / quality (push) Successful in 1m17s
CI (SIAX Cloud) / integration (pull_request) Successful in 54s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m7s
2026-11-02 01:26:36 +01:00
admin 1c87b82e70 feat(import): ImportDispatchPolicy (DES1GN ADR D3 §31) — ett objekt, en sanning
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 6s
masterplan-lock / check (pull_request) Successful in 7s
CI (SIAX Cloud) / security (push) Failing after 27s
Security Scan (SIAX Cloud) / security (push) Failing after 1m27s
CI (SIAX Cloud) / quality (push) Successful in 1m28s
CI (SIAX Cloud) / quality (pull_request) Successful in 2m29s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m15s
CI (SIAX Cloud) / security (pull_request) Failing after 16s
CI (SIAX Cloud) / sonar (pull_request) Skipped
Security Scan (SIAX Cloud) / security (pull_request) Failing after 17s
- lib/import-dispatch-policy.ts: maxInlineRows=500 (inline-tak, oförändrat
  kontrakt), maxRows=5000 (N0D-dispatch-signal), maxBytes=1_000_000 (bytes,
  UTF-8), format-allowlist ['csv']; ren evaluateImportDispatch() med
  deterministisk precedens format > bytes > rows
- route: taken härstammar från policyn; bytes-koll (ersätter chars); rows >
  maxRows -> 413 n0d_dispatch_required med hint {capability_id:
  0pt.import_execute, job_type: 0pt.import_execute_job, status: UNVERIFIED}
  (descriptor-gate stängd: aldrig tyst trunkering, aldrig tyst dispatch)
- tester: 9 nya (verdict per kombination inkl. gränsvärden 500/501/5000/5001,
  bytes-gräns, allowlist, precedens; route-koppling 200/413/413) — 21/21 gröna
  i sviten; full N0D-worker-integration markeras UNVERIFIED
2026-09-30 21:48:16 +02:00
admin 04813c34b0 feat(collab): order-anteckningar — @siax/collaboration-kernelns första produktkonsument (spår C)
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 7s
Security Scan (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / security (push) Successful in 18s
masterplan-lock / check (pull_request) Successful in 8s
CI (SIAX Cloud) / quality (push) Failing after 33s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 22s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
CI (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / quality (pull_request) Failing after 21s
Kernel 0.3.0 används som capability, inte som paket-dekor:
- lib/order-notes-store.ts: varje note ÄR en CollaborationOperation;
  nextLamportClock för nya klockor, mergeOperationLog/compareOperations
  för deterministisk listning; optimistisk version -> 409 vid stale skrivning.
- lib/order-notes-client.ts: kernel-CollaborationTransport över host-API;
  offline = medvetet no-op + varning (ingen tyst förlust), 409 -> ConflictError.
- app/api/admin/order-notes: requireRouteAuth (fail-closed 401),
  server-authoritative tenant-guard (403), AUD0-audit via hostens klient.
- app/admin/notes: admin-yta med offline-växel, konflikt-banner + reload.
- sql/016_order_notes.sql: persistens (DB-tabell, version + Lamport-klocka).

Tester: API (happy/conflict 409/empty/400/401/403/404), klient-adapter
(offline no-op utan fetch, 409-mappning, presence), SSR-render. 18 nya test.
2026-09-30 17:07:21 +02:00
admin c1648c04a7 feat(orders): CSV-import admin-yta — första riktiga ImportWizard-värden (C8)
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
CI (SIAX Cloud) / security (push) Successful in 22s
Security Scan (SIAX Cloud) / security (push) Successful in 22s
masterplan-lock / check (push) Successful in 31s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 6s
CI (SIAX Cloud) / security (pull_request) Successful in 18s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 20s
CI (SIAX Cloud) / quality (push) Successful in 1m1s
CI (SIAX Cloud) / integration (pull_request) Successful in 30s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m56s
Symmetrisk mot våg 3.4 CSV-export: POST /api/orders/import (validate |
dry_run | execute) + /admin/import som renderar @siax/ui ImportWizard
(0.14.0) över @siax/import-export runtime (0.2.0).

- Servern är enda auktoritet: RFC4180-parse (ingen eval), omvalidering
  via frysta @siax/contracts-kerneln (validateRows) + hostregler,
  exekvering genom BEFINTLIG orderlogik (createOrder, tenant-guardad).
- Fail-closed: 401 utan principal, 400 okänd header, 413 vid radtak
  (500), per-rad-atomsäkra inserts — felrad kan aldrig skada OK-rader.
- Partiell import: OK-rader skapas, felrader rapporteras per rad
  (row/field/code). AUD0-audit via 0pts enda producer-boundary
  (durable outbox under DATABASE_URL).
- Reload-persistens: efter execute läses /api/orders om och de nya
  raderna listas på sidan.
- Tester: 12 route-test (happy, partial, auth fail-closed, tak,
  no-write validate, header, quoting, rad-fel mitt i batch) + 3
  SSR-render-test av ImportWizard över runtime-storen.
- Deps: @siax/ui ^0.14.0, @siax/charts ^0.5.0, @siax/import-export
  ^0.2.0; pnpm-overrides till contracts 0.10.0 / import-export 0.2.0
  (ui 0.14.0 deklarerar 0.11.0/0.2.1 som ännu ej publicerats).
2026-09-30 15:36:02 +02:00
admin bc76ebc5e5 feat(orders): CSV-export-endpoint — export-kernelns första adoption (våg 3.4)
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 14s
CI (SIAX Cloud) / security (push) Failing after 16s
CI (SIAX Cloud) / quality (push) Successful in 52s
Security Scan (SIAX Cloud) / security (push) Successful in 58s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 5s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / quality (pull_request) Successful in 37s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 45s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m35s
CI (SIAX Cloud) / security (push) Trivy vulndb 404 (mirror.gcr.io) - infra-flake; re-run pa identisk sha gron
2026-09-29 17:01:13 +02:00
admin a2377215e7 feat(admin): InboxList — orderkön som universal inkorg (våg 3.3-adoption)
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (pull_request) Successful in 7s
masterplan-lock / check (push) Successful in 8s
CI (SIAX Cloud) / security (pull_request) Successful in 19s
Security Scan (SIAX Cloud) / security (push) Successful in 20s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / security (push) Successful in 24s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
CI (SIAX Cloud) / quality (push) Successful in 44s
CI (SIAX Cloud) / quality (pull_request) Successful in 2m13s
Servern projicerar öppna ordrar (draft/quoted/in_production/review) på
universal-inbox-konvolverna via createInboxItem (buildOrderInboxItem i
lib/order-flow, ADR-0001-mönstret: policy/resolution i serverlagret).
Admin renderar InboxList (@siax/ui 0.11.1) ovanpå orderkön — resolve-
aktionen gateras genom advance_action-state (available krävs). Terminala
statusar ger ingen post. tests/order-flow 6/6; full svit 1144/1144; build ✓.
2026-09-29 16:10:10 +02:00
admin a49bc148fc feat(admin): authz-pilot — server-renderad advance-resolution + ActionGate (ADR-0001)
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 7s
masterplan-lock / check (push) Successful in 8s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 18s
CI (SIAX Cloud) / security (pull_request) Successful in 20s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 19s
CI (SIAX Cloud) / quality (push) Failing after 1m31s
CI (SIAX Cloud) / quality (pull_request) Failing after 1m33s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m34s
GET /api/orders returnerar per order frozen advance_action (resolveAction ur
lib/order-flow); admin renderar via ActionGate — policy i serverlagret,
presentation i klienten (DoD §21). Terminala/okända statusar → read_only med
varför-text i stället för missvisande 'klar'. tests/order-flow.test.ts 3/3;
full svit 1138 godkända; typecheck grön.
2026-09-29 12:21:02 +02:00
Claude 0062edbec3 fix(readiness): /api/ready svarade 200 med en död motor i produktion
CI (SIAX Cloud) / integration (push) Skipped
masterplan-lock / check (push) Successful in 6s
CI (SIAX Cloud) / security (push) Successful in 15s
masterplan-lock / check (pull_request) Successful in 4s
Security Scan (SIAX Cloud) / security (push) Successful in 27s
CI (SIAX Cloud) / security (pull_request) Successful in 23s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / quality (push) Successful in 45s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
CI (SIAX Cloud) / quality (pull_request) Successful in 40s
Mätt live 2026-09-25 mot produktionsdeployen (0pt.app / api.0pt.app,
container shxd6lepxuxfsjsp0ath3z1g-172514162615 på server6, uppe 17,9 h,
Docker-status "healthy" hela tiden):

    GET /api/health -> HTTP/1.1 200 OK
      {"ok":false,"service":"0pt-web","db":"ok","queue":"not_configured",
       "engine":"error","stripe":"not_configured",
       "detail":{"engine":"This operation was aborted"}}

    GET /api/ready  -> HTTP/1.1 200 OK
      {"ready":true,"service":"0pt-web","db":"ok","engine":"error",...}

ENGINE_URL pekade på http://0pt-engine:8000. Mätt inifrån containern:
`getent hosts 0pt-engine` ger ingen post, och det finns ingen sådan
container på någon av server5-11. Ett direktanrop mot motorn misslyckas
efter ~5 s (DNS). Datamotorn — 0pt:s hela produkt — var alltså BORTA, och
samtliga signaler ovanför den var gröna: Docker healthy, /api/health 200,
/api/ready 200.

`ok:false` i en 200-kropp är ingen signal. Ingenting i kedjan läser
kroppar; allt läser statuskoder och exitkoder.

isReady skilde tidigare bara på "db ok". Den skillnad som saknades är inte
konfigurerad-vs-ej-konfigurerad utan FRÅNVARANDE-vs-TRASIG:

  * not_configured / not_integrated -> fortsatt ready. 0pt är byggt för att
    kunna köra utan motor, Stripe och kö (se .env.example).
  * error -> INTE ready. Statusen "error" betyder att någon medvetet
    konfigurerade beroendet och att en riktig round trip mot det just
    misslyckades. Det är inte längre en valfri integration.

Ändrar ingenting i driften i dag: container-HEALTHCHECK pekar på
/api/health (liveness) och Dockerfilen säger uttryckligen att en
readiness-probe inte ska peka dit. Den här ändringen gör bara att den
ärliga ytan faktiskt blir ärlig, så en yttre övervakning kan använda den.

Regressionstest tillagt; verifierat att det FALLER mot den gamla isReady
(1 failed | 18 passed) och passerar mot den nya (24 passed över
health-checks/ready/health).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 13:34:42 +02:00
Claude Code fc1a62bb81 feat: decision-plane wiring — ER-pair decision.match tie-break (@siax/0pt-decision)
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
masterplan-lock / check (pull_request) Successful in 11s
CI (SIAX Cloud) / security (pull_request) Successful in 14s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / integration (pull_request) Successful in 25s
CI (SIAX Cloud) / quality (push) Failing after 32s
CI (SIAX Cloud) / quality (pull_request) Failing after 33s
CI (SIAX Cloud) / integration (push) Has been skipped
- packages/decision: erMatchDecision (0pt.er.pair_match mot siax-decision :4600)
- comparePair async + borderline-band (±0.05 av review_threshold) → decision.match
  (D1 advisory) — deterministisk status GÄLLER om decision abstainar
- OPT_DECISION_ER_ENABLED=1-gate (off tills kalibrering)
- tests async-anpassade (await generateCandidates/rejects.toThrowError)
- typecheck: 13 fel = pre-existing extraction-route (main-paritet), 0 nya fel
- tester: 1108 passed | 184 skipped
2026-09-23 00:15:27 +02:00
admin c7fd9d45a2 fix(prod): map SiaxError in the 7 legacy money routes — DEPENDENCY_UNAVAILABLE/503 instead of opaque 500 (0pt#53)
CI (SIAX Cloud) / integration (push) Has been skipped
masterplan-lock / check (pull_request) Successful in 3s
masterplan-lock / check (push) Successful in 3s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 14s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 18s
CI (SIAX Cloud) / quality (pull_request) Successful in 31s
CI (SIAX Cloud) / quality (push) Successful in 40s
CI (SIAX Cloud) / security (pull_request) Successful in 42s
CI (SIAX Cloud) / integration (pull_request) Successful in 45s
getSqlForDurableStore throws SiaxError(DEPENDENCY_UNAVAILABLE, httpStatus 503,
retryable) when a money-bearing store would fall back to an in-memory Map in a
production runtime (the durable-store guard). The /api/0pt/* surface already
maps it via src/http/siax-error-response.ts; the seven legacy routes outside
the middleware matcher did not — the documented 503 leaked as Next's opaque
500 with no body.

- app/api/siax-error-mapping.ts: shared isSiaxError + siaxErrorResponseForLegacy
- orders (POST/GET), orders/[id] (GET/PATCH), subscriptions (GET/POST),
  payments/deposit, payments/release, admin/metrics: try/catch -> mapper,
  each route's own typed error contract preserved (idempotency conflict 409 etc.)
- webhooks/stripe: store outage -> 503 received:false reason:store_unavailable
  so Stripe's delivery retry path stays open (never a silent received:true)
- tests/api/legacy-routes-siax-error-mapping.test.ts: pins the 503 + body
2026-09-22 04:33:57 +02:00
admin a1557b2a7d feat(payments): bind orders to verified tenant and buyer
CI (SIAX Cloud) / integration (push) Has been skipped
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / security (push) Successful in 14s
masterplan-lock / check (pull_request) Successful in 4s
CI (SIAX Cloud) / security (pull_request) Successful in 14s
Security Scan (SIAX Cloud) / security (push) Successful in 30s
CI (SIAX Cloud) / quality (push) Successful in 35s
CI (SIAX Cloud) / integration (pull_request) Successful in 25s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 54s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m31s
2026-09-15 19:53:58 +02:00
admin cecc2bc637 fix(payments): authenticate order detail and deposit checkout
masterplan-lock / check (push) Successful in 4s
masterplan-lock / check (pull_request) Successful in 4s
Security Scan (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / quality (pull_request) Successful in 36s
CI (SIAX Cloud) / security (push) Successful in 1m14s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 1m12s
CI (SIAX Cloud) / quality (push) Successful in 1m22s
CI (SIAX Cloud) / integration (push) Failing after 1m22s
CI (SIAX Cloud) / integration (pull_request) Failing after 1m22s
2026-09-15 19:09:53 +02:00
admin 7ce92827c0 fix: close demo payment bypass and guard order transitions
masterplan-lock / check (pull_request) Successful in 4s
CI (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / integration (pull_request) Successful in 26s
masterplan-lock / check (push) Successful in 35s
CI (SIAX Cloud) / quality (pull_request) Successful in 37s
Security Scan (SIAX Cloud) / security (push) Successful in 1m4s
CI (SIAX Cloud) / integration (push) Successful in 1m14s
CI (SIAX Cloud) / quality (push) Successful in 2m12s
2026-09-15 18:52:23 +02:00
admin ae190fa60d fix: advance orders only after matching paid Stripe events
masterplan-lock / check (pull_request) Successful in 5s
masterplan-lock / check (push) Successful in 8s
CI (SIAX Cloud) / security (push) Successful in 18s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (push) Successful in 18s
CI (SIAX Cloud) / security (pull_request) Successful in 18s
CI (SIAX Cloud) / integration (push) Successful in 28s
CI (SIAX Cloud) / quality (push) Successful in 36s
CI (SIAX Cloud) / integration (pull_request) Successful in 48s
CI (SIAX Cloud) / quality (pull_request) Successful in 56s
2026-09-15 18:15:42 +02:00
admin 8911709931 fix: do not acknowledge unverified Stripe webhooks
masterplan-lock / check (push) Successful in 10s
Security Scan (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / integration (pull_request) Successful in 27s
CI (SIAX Cloud) / quality (push) Successful in 39s
CI (SIAX Cloud) / quality (pull_request) Successful in 32s
CI (SIAX Cloud) / security (push) Successful in 43s
masterplan-lock / check (pull_request) Successful in 41s
CI (SIAX Cloud) / security (pull_request) Successful in 1m12s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 1m14s
CI (SIAX Cloud) / integration (push) Successful in 1m36s
2026-09-15 18:08:13 +02:00
admin d0cba02ee0 feat: expose idempotent N0D-backed batch ER submission 2026-09-07 18:18:23 +02:00
admin 7d11ea895c feat: expose generic tenant-safe ER candidate API 2026-09-07 18:18:12 +02:00
admin 9782eaf42c refactor: share ER request validation across HTTP surfaces 2026-09-07 18:17:00 +02:00
admin 84945a2ff7 feat: expose tenant and purpose constrained search query route 2026-09-07 18:11:58 +02:00
admin e400afc882 feat: expose governed durable search definitions 2026-09-07 18:11:44 +02:00
admin e13d550837 fix(er): country-qualify company registration identifiers 2026-09-07 18:09:12 +02:00
admin 04d861b920 fix(er): require human review for score-only company matches 2026-09-07 18:07:56 +02:00
admin ccda286022 feat: expose tenant-safe dataset version describe route 2026-09-07 18:07:09 +02:00
admin e70acc8981 feat: expose durable dataset version create and query routes 2026-09-07 18:07:01 +02:00
admin b5ffdbc091 feat: expose tenant-safe dataset describe route 2026-09-07 18:06:46 +02:00
admin 102e1e1616 feat: expose tenant-safe dataset registry HTTP surface 2026-09-07 18:06:36 +02:00
admin 5338975eea fix: make conflicting company identifiers dominate ER matches 2026-09-07 17:57:23 +02:00
admin 4c7132728a fix: use raw AUD0 client in outbox dispatcher 2026-09-07 17:55:10 +02:00
admin 351afc54e1 security(er): validate internal ER bridge thresholds and scope 2026-09-07 17:22:05 +02:00
admin 71f2d13ae1 feat(er): expose canonical ER candidate engine to internal pipeline 2026-09-07 17:19:10 +02:00
admin 56b1ce01b3 feat(evidence): add protected AUD0 outbox dispatch endpoint 2026-09-07 17:15:36 +02:00
Simon AxelssonandClaude Opus 5 9267576b7c feat(data-os): P060-P068 durable ingestion plane — source classification gate, connector contract, common envelope, schema evolution, quality enforcement, queryable lineage, idempotent backfill
CI (SIAX Cloud) / integration (push) Successful in 42s
CI (SIAX Cloud) / quality (push) Successful in 1m17s
CI (SIAX Cloud) / security (push) Successful in 46s
Security Scan (SIAX Cloud) / security (push) Successful in 31s
CI (SIAX Cloud) / integration (pull_request) Successful in 36s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m4s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 27s
CI (SIAX Cloud) / security (pull_request) Successful in 24s
BEFORE_STATE (verified, with evidence):

* P060 PARTIAL/BROKEN. The registry persisted rights/provenance/health/
  freshness to Postgres, but carried no authorization, no schedule, no
  checkpoint, no schema and no owner distinct from created_by — and the
  activation DoD was inverted: postgres-source-repository.ts wrote
  `${input.status ?? "active"}`, so a source with no rights, no provenance
  and no authorization was ACTIVE the instant it was registered. No
  activation operation existed at all.
* P061 MISSING. services/api/sources/connectors.py had per-source fetch_*()
  functions only — no lifecycle, no cursor, no resume, no health, no
  conformance suite.
* P062 MISSING, already documented as such in
  services/api/tests/test_known_gaps.py:10-19 (no CDC pipeline anywhere;
  workers/pipeline.py has no persistence at all).
* P063 MISSING. schema_version existed as a free string; no comparison,
  no policy, no versioned source schema.
* P064 PARTIAL. Rules/runs/issues/scores existed, but a failing rule only
  opened an issue and the data flowed on. No quarantine anywhere.
* P065 DUPLICATE (confirmed). Two ER engines: src/er/entity-resolution-
  service.ts (canonical) and services/api/workers/resolve.py (simplified,
  still called by pipeline.py:110).
* P067 PARTIAL. Lineage was emitted to AUD0 but nothing here could ANSWER a
  lineage question — no store, no query, no route.
* P068 MISSING, documented in test_known_gaps.py:44-52 ("no delivery-store
  persistence layer exists to dedupe a backfill against").

BUILT (only what was PARTIAL/BROKEN/MISSING):

* P060 sql/007_ingestion_plane.sql adds authorization/schedule/schemas/
  checkpoints/ledger/quarantine/lineage tables, owner_id, and flips the
  opt_sources status DEFAULT to 'pending' so even a raw psql INSERT cannot
  produce an unclassified-but-active source. SourceRegistryService gains
  classifySource/activateSource/deactivateSource + authorization/schedule
  accessors; registration NEVER activates (asking for status:"active" goes
  through the gate, not around it); a service identity cannot authorize a
  source. Routes: activate (GET classification / POST activate),
  authorization, schedule.
* P061 src/connectors/connector.ts — all nine operations on one interface.
  src/connectors/conformance.ts — a runnable suite (15 checks, no "skip"
  verdict). HttpJsonConnector (real HTTP, opaque cursor) and
  JsonlFileConnector (real file, line offsets, CDC deletes) both pass it.
  The suite caught a real defect while being written: an API that drops
  next_cursor at the end left the connector unable to resume, which is why
  HttpJsonConnectorConfig has cursor_field.
* P062 src/types/ingestion.ts + src/ingestion/{envelope,ingestion-runner}.ts.
  One envelope for batch/stream/cdc; durable per-(source,partition)
  checkpoints; resume proven by killing a run inside the sink.
* P063 src/schema/{record-schema,compatibility,schema-registry}.ts. Two
  enforcement points, both upstream of any consumer write: a discovery gate
  before the first read, and per-record conformance before the page reaches
  the sink. A producer cannot widen its own policy retroactively.
* P064 src/quality/quality-policy.ts composes the EXISTING ExpectationEngine
  (not a second engine) and adds the missing consequence: block /
  quarantine / warn, with quarantine durable and recoverable. No policy is
  reported as "none_declared", never as a pass; an unexecutable expectation
  counts as a violation, never a silent pass.
* P067 src/lineage/{lineage-edge,lineage-store}.ts + GET /api/0pt/lineage.
  AUD0 stays the system of record; this is 0pt's own queryable projection.
* P068 opt_ingestion_ledger + IngestionRunner.backfill: bounded, idempotent
  on repeat, leaves the live checkpoint alone, still re-emits real changes.

A BUG THIS PASS WROTE AND CAUGHT: the first IngestionRepository draft
combined the idempotency check and its recording into one atomic call
BEFORE the sink. The crash/resume test then delivered 7 of 10 records — the
page in flight when the sink died was already marked delivered, so the
resumed run skipped it as a duplicate. Permanent, silent data loss. Fixed by
splitting peekDeliveries/commitDeliveries and committing both the ledger and
the checkpoint only after the sink resolves.

NOT DONE, stated rather than deferred quietly:

* P065 is NOT met. resolve.py is still a second simplified production
  engine. Closing it means rewriting it as an adapter over the canonical
  service, which cannot be verified from this repo today: services/api is
  not built by this repo's Dockerfile, api.0pt.app answers 404, and NO CI
  workflow runs its pytest suite. The duplication is now stated at both
  sites in code and the removal plan is in STATUS.md. The new ingestion
  plane performs no ER, so it adds no third engine.
* P066 (Iceberg) untouched — ST0RE is owned by another workflow. Contract
  read only.
* Delivery is AT-LEAST-ONCE, not exactly-once (no per-partition run lock).
* No CDC *source* exists; the contract is met, a CDC connector is not built.
* 0pt does not schedule itself — the schedule row is a declaration ACT0
  would read.

VERIFIED: pnpm typecheck clean; pnpm test 365 passed / 25 skipped (was
311/18); pnpm build clean with all four new routes in the route table; lint
unchanged at 12 pre-existing errors. Real Postgres 16
(tests/p0/ingestion-plane-postgres.realinfra.test.ts, 7 passed) plus a real
`docker restart` of that container with an identical read-back through the
production code path — that is P060's "a restart preserves all sources",
measured.

DEPLOYMENT REALITY (curl, 2026-09-04): 0pt.app/api/health returns 200 from
Vercel with db:not_configured; 0pt.app/api/0pt/sources returns 404;
api.0pt.app/health returns 404; cd.yml still guards on a placeholder Coolify
app id. None of the capability layer runs in production. Nothing here is
LIVE_VERIFIED and STATUS.md says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 17:03:14 +02:00
Simon AxelssonandClaude Sonnet 5 dc6aaa0e10 fix(data-os): P014 — close tenant-isolation + idempotency gaps, execute real restore drill
CI (SIAX Cloud) / quality (push) Successful in 51s
Security Scan (SIAX Cloud) / security (push) Successful in 26s
CI (SIAX Cloud) / security (push) Successful in 28s
CI (SIAX Cloud) / integration (push) Successful in 1m1s
CI (SIAX Cloud) / integration (pull_request) Successful in 30s
CI (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / quality (pull_request) Successful in 48s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 22s
Tenant isolation (security-critical): every app/api/0pt/** route reading
tenant_id from client-controlled query/body never cross-checked it against
the token middleware.ts already verified (x-0pt-verified-tenant). Adds a
shared assertTenantMatchesVerified guard and wires it into all 20+ affected
routes. Also closes two full-leak-by-omission bugs found in this pass
(documents/capture and lakehouse/mappings GETs returned every tenant's rows
when tenant_id was simply omitted) and two "no tenant check at all" reads
(rate-policies/[id], lakehouse/mappings/[id]) reachable by ID alone.

Duplicate-delivery idempotency (correctness-critical): POST /api/orders now
honors Idempotency-Key (sql/006, replay-or-409-on-conflict, Postgres +
in-memory); the Python orchestrator's POST /orders/{id}/run — the actual
delivery trigger — is now idempotent under an asyncio lock, closing a real
concurrent-request race, not just the sequential-retry case.

Engine-duplication resolution: adaptive_router.py's docstring wrongly
invited a bypass ("see b0ts for scraping") contradicting the product's own
compliance stance; corrected, and given real (additive, not escalating)
block-signal tracking so a rate-limited/blocked source is excluded from the
plan instead of hammered. Also fixes a previously-undiscovered production
bug: the Python engine's only call into the TS quality bridge
(X-Internal-Token) was unconditionally 401'd by middleware.ts, which never
checked that credential — the advisory quality bridge was unreachable in any
environment enforcing auth.

Restore drill: executed for real against throwaway Docker Postgres
containers (not simulated). Found and fixed two real blockers along the way:
sql/004 referenced opt_datasets, which no migration ever created (chain was
never actually runnable end to end); lib/db.ts hardcoded ssl:"require",
making any non-TLS Postgres (incl. compose.dev.yaml's own local-dev
container) unreachable. After both fixes: full migration chain applies
cleanly, pg_dump/pg_restore round-trip is byte-identical (row counts +
content checksums), and real application code (lib/orders-store.ts,
SourceRegistryService's Postgres repository) reads the restored data back
correctly, including cross-tenant isolation still holding.

82 new tests (55 TS + 27 Python), all passing; full existing suite (291 TS +
55 Python) still green; typecheck clean on every changed/added file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 12:00:43 +02:00
Simon AxelssonandClaude Sonnet 5 9740e20818 feat(data-os): TS/Python quality bridge + provenance fields + fault-injection tests
CI (SIAX Cloud) / security (push) Successful in 23s
Security Scan (SIAX Cloud) / security (push) Successful in 22s
CI (SIAX Cloud) / integration (push) Successful in 29s
CI (SIAX Cloud) / quality (push) Successful in 45s
CI (SIAX Cloud) / security (pull_request) Successful in 27s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 29s
CI (SIAX Cloud) / quality (pull_request) Successful in 48s
Continues P010 (branch renamed from feat/p010-source-registry-persistence):
closes the three remaining BEFORE_STATE.md gaps (§2 TS/Python split-brain,
§3 missing provenance fields, §4 untested failure modes), all additive to
the production pipeline — the Python QA filter's delivery decision is
unchanged by any of this.

TS/Python bridge (§2):
  - New route surface app/api/0pt/quality/* (rules/runs/issues CRUD +
    POST /api/0pt/quality/bridge-run) over the shared QualityService
    singleton (src/services/quality.ts), fixing the same "no shared
    instance" defect the Source Registry had.
  - src/quality/quality-bridge.ts auto-provisions a deterministic,
    tenant-scoped baseline rule set on first use so the Python engine never
    pre-registers rules through the CRUD surface.
  - services/api/workers/quality_bridge.py: the Python-side HTTP client.
    Feature-flagged off by default (OPT_QUALITY_BRIDGE_ENABLED), fails open
    on any error (never raises into run_job, never changes `delivered`).
    Advisory only — real per-row gating against the TS engine isn't
    implementable yet (ExpectationEngine returns dataset-level pass/fail
    counts + samples, not a per-row boolean array); documented, not faked.
  - Live-verified end-to-end: `next dev` (AUTH_ENFORCE=false) + the real
    Python pipeline hitting the real brreg.no API, round-tripping through
    the real bridge route, receiving a real QualityService score.

Provenance (§3): sources/connectors.py's Provenance dataclass gains
retrieved_at, transform, connector_version, producer, quality,
entity_resolution, artifact_ref (all previously absent from the real
dataflow entirely) via a make_provenance() factory used by every connector.
resolve.py stamps entity_resolution on merged records' provenance (never on
unmerged ones). pipeline.py stamps artifact_ref at delivery and quality
once the bridge succeeds.

Failure tests (§4), real fault injection against real code (services/api,
new pytest + respx suite, not vitest mocks):
  - dedup-determinism + duplicate-input + out-of-order: resolve.py under
    shuffled/interleaved/exhaustive-permutation input, plus an explicit,
    verified test of the one case that IS legitimately order-sensitive
    (non-transitive similarity in a greedy clusterer) instead of hiding it.
  - schema-evolution: respx-mocked upstream responses with added/removed/
    alien-shaped fields through the real brreg connector + pipeline.
  - restart: connector exceptions mid-job (including one from respx itself)
    never crash run_job.
  - backfill: the real property that holds given no persistence layer
    exists (replay is compute-idempotent) — NOT a fabricated dedup-store
    test.
  - CDC-interruption and true backfill/delivery-store idempotency:
    explicitly documented as not implementable against this codebase
    (no CDC pipeline, no delivery store exist anywhere) via skip markers
    with reasons, in tests/test_known_gaps.py, rather than silently
    dropped or faked.

Testing: 256/256 vitest (249 pre-existing + 7 new bridge route/service
tests) and 28/28 pytest (2 documented skips) green locally. tsc -p
tsconfig.check.json has zero new errors (14 pre-existing errors, all in
the untracked/unaudited src/fleet, src/graph, src/metrics, src/projections
paths this pass does not touch, per BEFORE_STATE.md).

No PR opened, per instructions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 21:02:14 +02:00
Simon AxelssonandClaude Sonnet 5 07b13bd833 feat(data-os): Source Registry Postgres persistence + full HTTP route surface
Replaces the in-memory (per-instance, not even per-process-shared) Maps in
SourceService/SourceRegistryService with real Postgres persistence, and adds
the register/query/describe/health/rights/provenance/freshness HTTP routes
that never existed (grep for SourceRegistryService in app/ previously
returned nothing).

- sql/002_source_registry.sql: opt_sources, opt_source_rights,
  opt_source_provenance, opt_source_health_checks, opt_source_freshness.
  Numbered 002 (not 006) because 004's opt_source_rate_policies already
  forward-references opt_sources, which no sql/ file defined until now —
  fixes 004's pre-existing broken migration ordering (opt_datasets remains
  a separate, unrelated, still-open gap in 004, flagged not fixed).
- src/repositories/*: SourceRepository / SourceRegistryRepository seams,
  each with an in-memory implementation (business logic extracted verbatim)
  and a Postgres implementation, chosen via resolveStoreMode — production
  still fails hard with no DATABASE_URL (Master-DoD §3), but a configured
  production now actually works instead of always being blocked.
- SourceService / SourceRegistryService: storage moved behind the
  repository seam; getHealth/getFreshness are now async and tenant-scoped
  at the accessor itself (needed once they're reachable directly over HTTP,
  not only after an earlier caller's tenant check).
- src/services/source-registry.ts: shared singleton instances for the
  sources/* route group, fixing the "each route module owned its own
  private registry" defect (source-rate-policies and .../query previously
  couldn't see a source registered via POST /api/0pt/sources).
- New routes: POST/GET /api/0pt/sources, GET /api/0pt/sources/[id],
  GET+PUT .../rights, GET+PUT .../provenance, GET+POST .../health,
  GET .../freshness.
- Business logic unchanged: fail-closed purpose gate, cross-tenant
  NOT_FOUND (no existence oracle, §50), bounded 100-row health history.

Tested against a real Postgres container (not mocked) —
tests/p0/source-registry-postgres.realinfra.test.ts, env-gated on
SOURCE_REGISTRY_TEST_DATABASE_URL, skips honestly when unset. All 249
pre-existing P0 tests + 7 new realinfra tests pass; also smoke-tested the
full HTTP route surface end-to-end against next dev + live Postgres.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 20:42:41 +02:00
admin a88ad04867 fix(health): report real per-dependency status instead of hardcoded ok:true
CI (SIAX Cloud) / security (push) Successful in 21s
Security Scan (SIAX Cloud) / security (push) Successful in 21s
CI (SIAX Cloud) / quality (push) Successful in 41s
CI (SIAX Cloud) / security (pull_request) Successful in 22s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 21s
CI (SIAX Cloud) / quality (pull_request) Successful in 41s
BACKLOG P0-3: /api/health only ever checked *presence* of DATABASE_URL/
REDIS_URL and always returned ok:true regardless of whether anything was
reachable -- ARCHITECTURE.md's own words, "an uptime monitor watching HTTP
200 would show green for a dying instance".

lib/health-checks.ts adds real dependency probes:
  - db: a live `select 1` round trip (not just DATABASE_URL presence)
  - engine: a real HTTP call to the FastAPI engine's own GET /health
  - stripe: Stripe's documented lightweight balance.retrieve() liveness call
  - queue: honestly reports "not_integrated" when REDIS_URL is set but
    unused -- no Redis client is wired anywhere in this repo, so reporting
    "ok" would fabricate a check that doesn't exist

/api/health stays a liveness check (always 200 while the process can
respond; the body's `ok` field is the honest signal). New GET /api/ready
fails closed with 503 when the load-bearing dependency (db) isn't both
configured and reachable -- the "no /ready route" gap.

contracts/openapi.yaml, docs/architecture/ARCHITECTURE.md, and docs/slo.md
updated to match. 17 new unit tests (dependency-injected fakes, no real
network/DB) + 5 route-level tests.
2026-08-11 13:49:23 +02:00
adminandClaude Sonnet 5 15a0dbe3b1 fix(security): require auth on GET /api/orders and GET /api/admin/metrics
Security Scan (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / security (pull_request) Successful in 25s
CI (SIAX Cloud) / quality (pull_request) Successful in 40s
CI (SIAX Cloud) / security (push) Successful in 22s
Security Scan (SIAX Cloud) / security (push) Successful in 20s
CI (SIAX Cloud) / quality (push) Successful in 39s
A live compliance audit against 0pt.app confirmed both endpoints returned
HTTP 200 with zero authentication -- the full order queue and financial
pipeline aggregates (deposit/pipeline totals) were readable by anyone.

Root cause: middleware.ts's matcher only covers /api/0pt/:path*, by design
("does NOT touch ... the unrelated payment/order APIs"), so nothing upstream
of these two handlers ever verified the caller.

Fix: both GET handlers now call the same fail-closed Zitadel verifier
/api/0pt/* relies on (resolveAuthContext, src/auth/context.ts) directly, via
a new thin wrapper (src/auth/require-route-auth.ts) that maps a rejected
decision to the same 401/403 JSON shape middleware.ts already returns. The
wrapper re-verifies the bearer token itself rather than trusting any
x-0pt-verified-* header on the request, since middleware never runs in front
of these routes to overwrite a client-supplied one.

POST /api/orders (anonymous draft/quote creation before the deposit-payment
step) is intentionally left as-is -- only the read paths that leaked data are
gated. Tracked as part of docs/compliance/BACKLOG.md P0-3.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 04:06:13 +02:00
Claude (SIAX platform session)andClaude Opus 5 bcf285f057 merge: unify GitHub main into Gitea main (0pt)
CI (SIAX Cloud) / quality (push) Successful in 38s
CI (SIAX Cloud) / security (push) Successful in 17s
Merges github/main (6 commits: 17-bug audit fix, CI quality gate,
.env.example + .gitignore fix, missing platform clients + registry
services, docs accuracy overhaul) into gitea/main (8 commits: Iceberg
write boundary + live ST0RE verification, lakehouse mapping routes,
Waves 1-4 foundational hardening).

16 conflicts. Both sides had independently written the four
src/clients/*.ts and the two registry services, so those are combined
rather than picked:

- st0re-client.ts: GitHub's endpoint wins on evidence. POST goes to
  /v1/st0re/artifacts/register, not /v1/st0re/artifacts -- verified in
  sax3l/st0re src/api/routes/artifacts.ts, where the bare path is a
  GET-only list route. Gitea's URL normalisation, error-body text and
  mock kept.
- n0d-client.ts: field is `status`, not `state`, with N0D's real 13-state
  union -- verified in sax3l/n0d packages/schemas/n0d.job.schema.json,
  which says explicitly not to add "succeeded". Gitea's mock echo,
  URL normalisation and error-body text kept.
- cl0ud-client.ts: Gitea's fail-closed HTTP normalisation kept (a 200
  with no `decision` reads as "deny", not as a silent allow). GitHub's
  PolicyDecision/PolicyDecisionValue naming kept; PolicyResult retained
  as an alias.
- aud0-client.ts: permissive union of both input types (optional
  payload/metadata/correlation_id), GitHub's echo return, Gitea's URL
  normalisation and error-body text, plus a JSON-parse fallback so a
  successful POST with an empty body does not throw.
- dataset-service.ts / source-service.ts: GitHub's record/DTO split and
  event naming (0pt.source_created / 0pt.create_source, which the merged
  docs already reference) plus Gitea's name validation, description /
  created_by fields and actor_id derivation. List filters are the union.
- lakehouse mapping routes: GitHub's shared lakehouse-mapping-registry
  singletons (without which every write 400'd "mapping not found") AND
  Gitea's Zod parseBody validation. Both, not either.
- src/types/source.ts, src/types/dataset.ts: unions of both vocabularies;
  GitHub's `access` legal-sourcing field kept.
- .env.example: GitHub's audited inventory plus Gitea's Zitadel /
  AUTH_ENFORCE block.
- CLAUDE.md, docs/ICEBERG_WRITE_BOUNDARY.md: GitHub's corrections kept,
  Gitea's live-verification kept and marked as superseding the
  "would 400 outright" finding (Gitea had already added the required
  X-Tenant-Id/X-Actor-Id headers).
- pnpm-lock.yaml: regenerated with pnpm 9.15.9, not merged.

Also corrects CLAUDE.md's claim that the banned services/scrapers stack
was "since removed" -- the removal PR is open, not merged, and this
branch inherits that code from Gitea main. Nothing here resurrects,
extends or re-wires any of it; services/scrapers/ is byte-identical to
Gitea main.

Verified on the merged tree: typecheck (src/ + tests/) clean;
17 test files, 121 passed, 1 skipped (the realinfra test skipping
honestly on ST0RE HTTP 401), 0 failures. Gitea main baseline was the
same 121/1; GitHub main baseline could not even `pnpm install`
("packages field missing or empty") -- Gitea's pnpm-workspace.yaml fix
resolves that. Whole-repo `typecheck:app` reports 9 errors, an identical
set to Gitea main's baseline, so it is advisory in both CI workflows
rather than deleted. Lint: 16 problems, identical to Gitea baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 12:38:01 +02:00
SIAX Foundation BotandClaude Opus 4.8 1d76d50f3d feat(auth,foundation): Wave 2 flag-gated Zitadel JWT verify + validation + eslint + tests
CI (SIAX Cloud) / security (push) Failing after 28s
CI (SIAX Cloud) / quality (push) Failing after 44s
CI (SIAX Cloud) / quality (pull_request) Failing after 33s
CI (SIAX Cloud) / security (pull_request) Failing after 26s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:32:34 +02:00