siax.config.json declared deploy.target: "vercel", which conflicts with
the SIAX Cloud platform pattern every sibling OS repo (n0d, st0re, aud0)
follows: a Dockerfile "for Coolify" (already present in this repo) plus a
.gitea/workflows/deploy.yml that POSTs a restart to a Coolify app UUID.
Investigated before changing anything:
- 0pt.app is confirmed live on Vercel (Server: Vercel, 200 OK) but its own
/api/health reports db/queue "not_configured", and POSTing to /api/orders
creates an order that is not durably persisted (in-memory store only, per
this repo's own docs/08-infrastructure.md and docs/architecture/
ARCHITECTURE.md, both independently verified live 2026-07-19 / 2026-08-07,
and reconfirmed live again today). It's a fully-built marketing/demo
surface with no real backend behind it -- not a live product serving real
customer data. Safe to change deploy config without a cutover plan.
- Dockerfile already exists and is already written "for Coolify" (node:24-
alpine multistage, non-root, /api/health healthcheck) -- no changes needed
there.
- No .gitea/workflows/deploy.yml existed. Added one following the exact
pattern used by n0d and st0re (POST /api/v1/deploy?uuid=...&force=false
with COOLIFY_TOKEN). No Coolify app has been provisioned for 0pt yet, so
the app UUID is a literal placeholder and the workflow fails loudly by
design until a real app + token are in place -- this does not silently
ship a broken deploy config.
This changes only this repo's declared *intent*. It does NOT touch the live
Vercel deployment, delete the Vercel project, or move any traffic --
that cutover (provision Coolify app -> verify -> DNS -> decommission
Vercel) is a separate, larger decision. README and ARCHITECTURE.md updated
to state this plainly rather than let them contradict the new config.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Brings 0pt to the SIAX repo standard. README, LICENSE (proprietary, correct
for this repo), Dockerfile and .gitea/workflows/ci.yml already existed and are
left untouched; no .github/workflows exists.
The architecture document was written by reading the code (entrypoints,
routes, services, migrations, Dockerfile, env, tests) and by probing the live
0pt.app instance -- not from the templates. It therefore contradicts the
existing docs in several places, deliberately:
* /api/0pt/* answers ANONYMOUSLY in production (live-verified 2026-08-07):
GET https://0pt.app/api/0pt returns 200 with no token, and 200 with a
deliberately invalid one. The deployment is current (the newer lakehouse
routes are present), so middleware.ts is simply not running. README lines
49-52 and merge 6531384 claim the opposite. Root cause UNKNOWN -- flagged,
not guessed.
* No handler reads x-0pt-verified-tenant. middleware.ts sets it; nothing else
in the repo reads it. Every /api/0pt/* handler takes tenant_id from the
request body/query instead, so tenant isolation is not implemented.
* Everything outside /api/0pt/* has no auth at all (matcher scope), including
GET /api/admin/metrics and GET /api/orders (both live-verified 200 anon) and
POST /api/payments/{id}/release, which flips an order to "delivered"
regardless of payment.
* CL0UD policy client is fail-open and AUD0 audit is a silent no-op when their
URLs are unset, with no production guard -- unlike AUTH_ENFORCE, which has one.
* connections/db-grant documents AES-GCM encryption it does not implement.
* The FastAPI engine (services/api) has zero authentication despite
lib/engine.ts sending X-Internal-Token.
* services/scrapers/waf_bypass.py (FlareSolverr, Tor, cloudscraper, proxy pool,
undetected browser, fake identities) plus flaresolverr/tor-proxy in
services/infra/docker-compose.data-stack.yml directly contradict CLAUDE.md
§1 and the README's compliance claim. Left in place -- deletion is a Simon
decision, recorded as open question 2.
* Production has NO database (live /api/health reports db:not_configured) and
the whole /api/0pt/* capability layer is per-module in-memory Maps, so state
does not survive a cold start and is not even shared between route modules.
siax.config.json deviates from the template on two fields, on purpose:
deploy.target is "vercel" (live-verified Server: Vercel header), not "coolify",
and designSystem is null because @siax/ui is not a dependency here. Both
deviations are documented in ARCHITECTURE.md §5 and §8.
Docs-only change. No code, CI, LICENSE or workflow files were modified.
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>
bridge_provenance answers which source a field came from; it does not
answer what happened on the wire. 1p (the SIAX egress measurement point)
adds the robots decision + sha256 of the robots.txt it was read from,
body_sha256 per fetch, and blocked_soft detection — HTTP 200 whose body
is a block page, which otherwise gets scored as corroborating data.
Consistent with CLAUDE.md §1: a measurement point, not a bypass.
Documentation only; not in use, no worker routes through it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: full accuracy overhaul, grounded claim-by-claim in real code
Every doc in this repo (CLAUDE.md, README.md, SECURITY.md, docs/*.md) was
audited and rewritten by a multi-pass process: independent rewrite per
cluster, adversarial re-verification of that rewrite against the actual
code, then a final cross-doc consistency pass — each stage re-checking
claims against the repo directly rather than trusting the previous stage.
Two corrections matter most:
1. docs/ICEBERG_WRITE_BOUNDARY.md, docs/11-lakehouse-write-plan.md, and
docs/P0_QUERY_SOURCE_FLOW.md asserted src/services/quality-check-service.ts,
quality-report-service.ts, src/data-platform/services/catalog-service.ts,
and sql/002_p0_dataset_quality.sql/sql/003_*.sql as real, tested code.
git log --all across every branch shows zero commits for any of these
paths, ever. 0pt's data-quality/QA enforcement does not exist in code.
Corrected everywhere, with a new docs/P0_DATASET_QUALITY_FLOW.md added
as an explicit target-spec (not-yet-built) replacement.
2. github.com/sax3l/0pt (this repo) and git.siax.io/sax3l/0pt (Gitea) are
two diverged remotes sharing part of the same history (services/api/
workers/adaptive_router.py is byte-identical between them). Gitea's main
independently accumulated a WAF-bypass/proxy-rotation scraper stack in
three 2026-07-13 commits, since removed via a Gitea PR; GitHub's main
never had it. Which remote is canonical/deployed is unresolved — flagged
consistently across the corpus, not decided here.
Also newly and consistently documented: the tenant_id/project_id-read-from-
client-body gap on the P0 lakehouse/rate-policy/source-query routes (no
auth/session system exists anywhere in this repo yet); that every CL0UD/
N0D/AUD0/ST0RE platform client is real but mock-only (zero process.env
reads for any of their *_URL vars); that two P0 mutation routes
(lakehouse/mappings, sources/rate-policies) always fail over HTTP today
because their prerequisite entity can never be created via any route; a
schema bug in sql/004 (FK references to opt_datasets/opt_sources, which
don't exist); and that 0pt.app's live deployment was independently
confirmed (curled this pass) to be running this exact codebase with
DATABASE_URL/REDIS_URL unset in production.
New file: docs/12-edge-capability-api.md — the edge-native P0 TypeScript
capability contract (app/api/0pt/*, /api/screen, /api/ai/parse), previously
undocumented and distinct from docs/04-api.md's FastAPI-engine-only scope.
Verified before commit: tsc --noEmit clean; vitest run 88 passed, 1 todo,
0 failures (13 files) — docs-only change, no source touched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: reflect PR #5's lakehouse-mapping-registry + status-code fixes
Follow-up to keep docs/12-edge-capability-api.md accurate once both PRs
land: fix/0pt-full-bug-hunt (#5) fixed the shared-instance bug in the
lakehouse mapping routes and added proper status-code mapping to the
document extraction route. This doc was written against the pre-fix
state in the same pass that added it, so it needs the same correction.
Does not claim the lakehouse write path fully works now -- the deeper
dataset-registration gap (no route ever calls DatasetService.registerDataset)
is unchanged and still blocks it end-to-end; only the shared-instance half
of the bug is fixed.
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Re-runs this session's task spec against 0pt's actual repo state, which
turned out to already have a substantial, tested implementation from a
prior pass (35b6ec6): dataset<->Iceberg-table mapping, source rate policy,
and an ST0RE lakehouse client that was honestly marked "not live-verified".
This pass found api.st0re.siax.io IS reachable from this environment and
used it -- first via curl to safely discover the real contract, then
through 0pt's own updated code -- to drive a real namespace -> table ->
snapshot write against production ST0RE (task item 3's "write ONE first
test dataset" proof). That surfaced and fixed three real bugs the
mock-only pass could not have caught:
- ST0RE requires X-Tenant-Id/X-Actor-Id headers on every lakehouse route;
the previous HTTP client sent none. Fixed via a threaded
St0reRequestContext.
- IcebergTableInput.datasetId is a foreign key into ST0RE's OWN dataset
table, not a free-form string -- sending 0pt's dataset_id 400s live with
a Postgres FK violation. Fixed by no longer sending it; 0pt's
dataset<->table linkage lives entirely in DatasetIcebergMapping.
- ST0RE enforces a real unique constraint on lakehouse namespaces
(tenant_id, project_id, name) with no upsert route. Fixed with a
client-side lookup-or-create (listNamespaces + findOrRegisterNamespace).
Also closed a field-level gap against the task's literal schema spec:
0pt.dataset_iceberg_mapping.schema.v1 now carries namespace_id (a real
reference to ST0RE's LakehouseNamespace.namespaceId, not guessed) and
mapped_at, both additive alongside the existing namespace/created_at
fields (sql/005, JSON schema, types, service).
tests/p0/iceberg-write-service.realinfra.test.ts replaces the prior
it.todo with a real SEAM-pattern live test: attempts the real HTTP call,
skips honestly if ST0RE is unreachable, never fabricates success. It ran
successfully against production ST0RE this session (real namespace/table/
snapshot UUIDs logged in docs/ICEBERG_WRITE_BOUNDARY.md).
Two ST0RE-side cross-tenant read bugs were found and flagged (not fixed
here -- out of scope for this repo): GET .../namespaces ignores its own
tenant header and query filters; GET .../tables/:id doesn't check the
caller's tenant against the table's owner.
npm test: 155 passed, 0 failed, 0 todo (up from 154 passed + 1 todo).
npx tsc --noEmit: 1 pre-existing, unrelated error in
quality-report-service.ts (present before this pass, part of the wider
uncommitted P0 data-platform build already in this repo) -- not touched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real, tested implementation of docs/11-lakehouse-write-plan.md's items 2-8
(the "future implementation session" that doc named): 0pt is now the
canonical writer of Iceberg tables through ST0RE's real, shipped
/v1/st0re/lakehouse/* table registry (sax3l/st0re commit 9ea0abb), never
persisting lakehouse table/catalog/snapshot state itself.
- src/types + src/services for 0pt.dataset_iceberg_mapping.schema.v1
(dataset -> ST0RE tableId reference) and 0pt.source_rate_policy.schema.v1
(the sourceRatePolicy ownership repair, moved out of N0D per ADR-0030).
- src/clients/st0re-lakehouse-client.ts: new client matching ST0RE's actual
camelCase route contract, with the same mock/HTTP boundary convention as
this repo's existing cl0ud/n0d/aud0/st0re clients. Honest caveat in its
module doc comment: not verified against a live ST0RE instance in this
pass (no reachable ST0RE_URL); every test exercises the deterministic mock.
- src/services/iceberg-write-service.ts: registers tables/snapshots through
ST0RE, requests N0D jobs only for heavy writes (never executes them
in-process), emits all four AUD0 event names
(dataset_iceberg_table_mapped / iceberg_write_requested /
iceberg_snapshot_created / source_rate_policy_created).
- sql/004, packages/schemas/*.json, app/api/0pt/lakehouse + sources/rate-policies
routes, tests/p0/*.test.ts (154 passed + 1 honest it.todo for the live-ST0RE
case, up from 142 baseline, 0 failures).
- Reconciled a real collision: an earlier untracked draft schema/test pair
(tests/p0/enterprise-data-os-expansion.test.ts) asserted a different,
now-superseded source_rate_policy shape; updated that one test block only.
- docs/ICEBERG_WRITE_BOUNDARY.md states the ownership boundary plainly and
is explicit throughout about what's real-and-tested vs. contract-only.
docs/11-lakehouse-write-plan.md gets a status-update section, not a rewrite.
- Data quality rules (quality-check-service.ts, quality-report-service.ts)
were not touched -- confirmed still 0pt-owned.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Points at n0d's ADR-0030 (Apache Iceberg canonical, Delta rejected for
P0/P1) and lays out 0pt's write-path plan: dataset-to-Iceberg-table
mapping, writes through ST0RE's future table registry, keeping QA and
source-rate/crawl-compliance logic in 0pt. Schema/event names specified
precisely for a future implementation session. Written adjacent to, not
touching, the substantial live P0 data-platform build in progress in this
repo (data-contract/dataset/quality-check services).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Three new, tenant-agnostic P0 capabilities:
- 0pt.query_source: bounded, timeout/row-capped ad-hoc SQL query execution
against registered database sources, via a Fabric/OneLake adapter
(Azure AD credential-based mssql connection), with AUD0 audit events
and an app/api/0pt/sources/[sourceId]/query endpoint.
- 0pt.document_ocr (document capture + extraction): mailbox-based document
intake via Microsoft Graph, OCR/field extraction via Azure Document
Intelligence, with capture/extraction API endpoints and services that
never fabricate extracted values.
- 0pt.write_external_record (external writeback): a generic writeback-adapter
contract plus a concrete Odoo bills adapter that matches partners via
Fabric, backing an external-writeback-service for pushing records to
downstream systems of record.
Known interim gaps:
- src/adapters/local-blob-store.ts is an interim ST0RE substitute pending
the real ST0RE artifact-store integration.
- mssql is used by the Fabric/OneLake adapter but deliberately not yet
added to package.json (pending `pnpm add mssql` once the concurrent
session's package.json/dependency changes settle).
A separate, concurrently-active session has unrelated in-flight changes
in this same working tree (data-platform catalog/lineage/feature-store,
dataset quality, lakehouse/Iceberg docs, deploy scaffolding, package.json/
pnpm-lock.yaml updates, etc.) — none of that is touched or included here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Hero is now a data-native 0pt artifact (no photos, keeps grain/reveal/float); header is the 0pt wordmark with Swedish nav; layout is sv + loads JetBrains Mono + 0pt metadata; globals wires the loaded fonts. Adds CLAUDE.md + docs/01-09 as the build contract. next build green (5 routes).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>