Files
pig/docs/ontology.md
T
karti c747eb2aa7 Add deployment: Dockerfile, compose, proxy config, and docs
One container plus a Postgres behind any TLS-terminating proxy. Nothing is
specific to a particular host.

The app and API are served from a SINGLE origin. This is not tidiness: browser
auth sessions live in per-origin storage, so splitting them across two
hostnames makes sign-in loop in a way that presents as a server fault. The
short alias redirects rather than serving a second origin.

Two safety properties verified by running the image, not by reading the code:

- With NODE_ENV=production and no SUPABASE_URL, the process refuses to start
  and says why. Serving the whole CRM unauthenticated is a worse outcome than
  failing to deploy, so the failure is deliberate and loud.
- In production the development auth bypass does not apply: an unauthenticated
  request to /api/dashboard returns 401 rather than adopting the first user in
  the table.

The Dockerfile typechecks all six packages as a build gate, so a deploy that
does not compile fails at build time rather than in front of a user. Runtime
runs unprivileged as `node`, and Postgres is not published to the host.

Docs cover the ontology and why it is shaped this way, agent connection for
Claude Code / Codex / prime-agent / Buzz, and the provenance rules governing
seed data about real people — including how to have your record removed.

Verified: image builds, container reports healthy, serves the SPA, enforces
auth, and the production guard exits non-zero.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 19:19:53 -07:00

107 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# The ontology
Why PIG is shaped the way it is. Read `packages/core/src/ontology.ts` alongside
this — the code carries the same reasoning in comments, and it is the version
that cannot go stale.
## The one table that matters
```
capacity_commitment ──┐
(what we bought, │
at a known cost) │
├──▶ allocation ──▶ margin, utilisation, idle
│ (what we sold,
demand_deal ──┘ at a known price)
(what we sold)
```
Margin, utilisation and idle capacity all fall out of that single join. No
generic CRM can compute any of them, because none has a concept of a
cost-bearing commitment sitting behind the pipeline.
**Cost is charged against the full commitment, not only the hours that sold.**
Unsold hours are already paid for. Charging only the allocated share would
report a healthy margin on a block that is losing money — precisely the failure
this system exists to prevent.
## Three teams
**Supply**, **demand**, and **research**. Research is first-class rather than an
afterthought: internal research burn is real capacity consumption competing with
revenue for the same GPUs, and margin math that cannot see it is wrong.
## Pipelines
**Demand**`qualification → legal → scoping → proposal → procurement → POC →
deployment → expansion`. Note that **legal sits second**. Customers do not hand
workloads to an infrastructure provider before paper is executed. Most CRMs put
contracting at the end of the funnel and are simply wrong about it here.
**Supply**`sourced → qualifying → technical diligence → financial diligence →
pricing → contracting → onboarding → live → renewal`. Qualification is split in
two because accepting capacity is a two-key decision: engineering judges whether
the cluster can do the work, finance judges whether the economics clear. Both
verdicts are recorded attributably.
## Capacity is a shape, not a rectangle
A commitment carries `shape: {intervals[], quantities[]}` — how many GPUs are
held during each interval. Real contracts ramp across tranches and step down at
checkpoints. A single start/end/total flattens that and then reports
availability that does not exist in the month someone wants it.
Availability at any instant is therefore:
```
available(t) = shapeQuantityAt(t) Σ overlapping allocations(t)
```
## Holds reserve; they do not sell
A live hold removes capacity from everyone else's availability — otherwise two
sellers promise the same GPUs — but does not count toward utilisation or
revenue, because it has not sold. Conflating the two is how a pipeline of
optimistic holds comes to look like a full book. Holds expire on a timer so a
stalled deal releases inventory automatically.
## Service levels come in three shapes
A compute aggregator generally **cannot** offer a conventional uptime guarantee
on capacity it resells and does not control, and says so publicly. So `slaKind`
distinguishes:
- `none` — self-serve, no commitment at all
- `credits_policy` — a reliability tier plus service credits. **Not** an uptime
guarantee, and must never be displayed as one
- `negotiated` — a real signed SLA with committed, measurable metrics
Remedies matter as much as targets. `remedyType` includes `fee_abatement`,
where payment obligations are *cancelled* for affected capacity until service is
restored — uncapped in duration and materially better than a capped credit. It
cannot be expressed as a credit percentage, so it gets its own representation.
## Export control is a predicate, not a flag
US controls on advanced computing apply an **ultimate parent** test that reaches
through the corporate tree: an entity can be restricted because of where its
parent is headquartered, even when the entity itself sits somewhere
unrestricted. Country of incorporation is therefore not a valid key.
Compliance is evaluated **on the allocation edge** — this buyer, this beneficial
owner, this physical jurisdiction — recorded with its reasoning and rule
version, and re-evaluated on resale or migration. See
`packages/db/src/schema/compliance.ts`. PIG records and surfaces; it does not
make the legal determination for you.
## Evidence
Agent-derived claims land in `facts` with a confidence score, a band, evidence
and a source URL. Only `verified` claims self-apply; anything weaker waits for a
human. An agent permitted to write unattributed claims will eventually write a
wrong one, and nobody will be able to tell which.
The same principle governs seed data about real people: every record carries a
grade and a citation, authorship is never promoted to employment, and no email
address is ever inferred.