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

4.6 KiB
Raw Blame History

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

Demandqualification → 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.

Supplysourced → 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.